Skip to content

Commit

Permalink
Make sure the order of nested order filters is preserved
Browse files Browse the repository at this point in the history
Order filters are being written with underscores in GraphQL but are
sent along with dots to access nested entities.

The previous solution appended the dot version to the order array.
This leads to an issue where every order filter that accesses a nested
property will always be added to the query after local properties.
  • Loading branch information
Jonas Osburg committed Mar 29, 2021
1 parent a328c65 commit 2fa12b6
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -13,6 +13,7 @@
* Swagger UI: Remove Google fonts (#4112)
* Doctrine: Revert #3774 support for binary UUID in search filter (#4134)
* Do not override Vary headers already set in the Response
* GraphQL: Make sure the order of order filters is preserved if nested resources are used

## 2.6.3

Expand Down
6 changes: 5 additions & 1 deletion src/GraphQl/Resolver/Stage/ReadStage.php
Expand Up @@ -157,7 +157,11 @@ private function getNormalizedFilters(array $args): array

if (\is_string($name) && strpos($name, $this->nestingSeparator)) {
// Gives a chance to relations/nested fields.
$filters[str_replace($this->nestingSeparator, '.', $name)] = $value;
$index = array_search($name, array_keys($filters), true);
$filters =
\array_slice($filters, 0, $index + 1) +
[str_replace($this->nestingSeparator, '.', $name) => $value] +
\array_slice($filters, $index);
}
}

Expand Down
40 changes: 40 additions & 0 deletions tests/GraphQl/Resolver/Stage/ReadStageTest.php
Expand Up @@ -25,6 +25,7 @@
use ApiPlatform\Core\Tests\ProphecyTrait;
use GraphQL\Type\Definition\ResolveInfo;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

Expand Down Expand Up @@ -221,6 +222,45 @@ public function testApplyCollection(array $args, ?string $rootClass, ?array $sou
$this->assertSame($expectedResult, $result);
}

/**
* Test a regression where the order in which order fitlers were applied
* was wrong when the data had been ordered by a nested field.
*/
public function testPreserveOrderOfOrderFitlersIfNested()
{
$operationName = 'collection_query';
$resourceClass = 'myResource';
$info = $this->prophesize(ResolveInfo::class)->reveal();
$fieldName = 'subresource';
$info->fieldName = $fieldName;
$context = [
'is_collection' => true,
'is_mutation' => false,
'is_subscription' => false,
'args' => [
'order' => [
'some_field' => 'ASC',
'localField' => 'ASC',
],
],
'info' => $info,
'source' => null,
];
$this->resourceMetadataFactoryProphecy->create($resourceClass)->willReturn(new ResourceMetadata());

$normalizationContext = ['normalization' => true];
$this->serializerContextBuilderProphecy->create($resourceClass, $operationName, $context, true)->shouldBeCalled()->willReturn($normalizationContext);

($this->readStage)($resourceClass, $resourceClass, $operationName, $context);

$this->collectionDataProviderProphecy->getCollection($resourceClass, $operationName, Argument::that(function ($args) {
// Prophecy does not check the order of items in associative arrays. Checking if some.field comes first manually
return
array_search('some.field', array_keys($args['filters']['order']), true) <
array_search('localField', array_keys($args['filters']['order']), true);
}))->shouldHaveBeenCalled();
}

public function collectionProvider(): array
{
return [
Expand Down

0 comments on commit 2fa12b6

Please sign in to comment.