Skip to content

Commit

Permalink
FIX QuerySort::sort method should support sorting for multi arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
Sabina Talipova committed Nov 23, 2023
1 parent 442cb57 commit 5f2f79c
Show file tree
Hide file tree
Showing 3 changed files with 273 additions and 99 deletions.
80 changes: 75 additions & 5 deletions src/Schema/DataObject/Plugin/QuerySort.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Closure;
use SilverStripe\ORM\Sortable;
use Exception;
use GraphQL\Type\Definition\ResolveInfo;

/**
* Adds a sort parameter to a DataObject query
Expand Down Expand Up @@ -88,6 +89,10 @@ protected function buildAllFieldsConfig(ModelType $modelType, Schema $schema, in
}


/**
* @param array $context
* @return Closure
*/
/**
* @param array $context
* @return Closure
Expand All @@ -96,12 +101,21 @@ public static function sort(array $context): closure
{
$fieldName = $context['fieldName'];
$rootType = $context['rootType'];
return function (?Sortable $list, array $args, array $context) use ($fieldName, $rootType) {
return function (?Sortable $list, array $args, array $context, ResolveInfo $info) use ($fieldName, $rootType) {
if ($list === null) {
return null;
}
$filterArgs = $args[$fieldName] ?? [];
$paths = NestedInputBuilder::buildPathsFromArgs($filterArgs);

if (!isset($args[$fieldName])) {
return $list;
}

$sortArgs = static::getSortArgs($info, $args, $rootType, $fieldName);
$paths = NestedInputBuilder::buildPathsFromArgs($sortArgs);
if (empty($paths)) {
return $list;
}

$schemaContext = SchemaConfigProvider::get($context);
if (!$schemaContext) {
throw new Exception(sprintf(
Expand All @@ -111,6 +125,7 @@ public static function sort(array $context): closure
));
}

$normalisedPaths = [];
foreach ($paths as $path => $value) {
$normalised = $schemaContext->mapPath($rootType, $path);
Schema::invariant(
Expand All @@ -120,13 +135,68 @@ public static function sort(array $context): closure
$path,
$rootType
);
$list = $list->sort($normalised, $value);

$normalisedPaths[$normalised] = $value;
}

return $list;
return $list->sort($normalisedPaths);
};
}

private static function getSortArgs(ResolveInfo $info, array $args, string $rootType, string $fieldName): array
{
$sortArgs = [];
$sortOrder = self::getSortOrder($info, $fieldName);

foreach ($sortOrder as $orderName) {
if (!isset($args[$fieldName][$orderName])) {
continue;
}
$sortArgs[$orderName] = $args[$fieldName][$orderName];
unset($args[$fieldName][$orderName]);
}

return array_merge($sortArgs, $args[$fieldName]);
}

/**
* Gets the original order of fields to be sorted based on the query args order.
*
* This is necessary because the underlying GraphQL implementation we're using ignores the
* order of query args, and uses the order that fields are defined in the schema instead.
*/
private static function getSortOrder(ResolveInfo $info, string $fieldName)
{
if (!method_exists($info->fieldDefinition, 'getName')) {
return [];
}

$relevantNode = $info->fieldDefinition->getName();

// Find the query field node that matches the schema
foreach ($info->fieldNodes as $node) {
if ($node->name->value !== $relevantNode) {
continue;
}

// Find the sort arg
foreach ($node->arguments as $arg) {
if ($arg->name->value !== $fieldName) {
continue;
}

// Get the sort order from the query
$sortOrder = [];
foreach ($arg->value->fields as $field) {
$sortOrder[] = $field->name->value;
}
return $sortOrder;
}
}

return [];
}

/**
* @param NestedInputBuilder $builder
*/
Expand Down
Loading

0 comments on commit 5f2f79c

Please sign in to comment.