Fix order filter with embedded and nulls comparison (#4151) · mega/api-platform-core@3930b86 · GitHub
Skip to content

Commit 3930b86

Browse files
authored
Fix order filter with embedded and nulls comparison (api-platform#4151)
1 parent bf2b104 commit 3930b86

8 files changed

Lines changed: 201 additions & 16 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 1 addition & 1 deletion

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* JSON Schema: Manage Sequentially and AtLeastOneOf constraints when generating property metadata (#4139 and #4147)
77
* Doctrine: Fix purging HTTP cache for unreadable relations (#3441)
88
* Doctrine: Revert #3774 support for binary UUID in search filter (#4134)
9+
* Doctrine: Fix order filter when using embedded and nulls comparison (#4151)
910
* GraphQL: Partial pagination support (#3223)
1011
* GraphQL: Manage `pagination_use_output_walkers` and `pagination_fetch_join_collection` for operations (#3311)
1112
* Swagger UI: Remove Google fonts (#4112)

‎src/Bridge/Doctrine/Orm/Filter/OrderFilter.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ protected function filterProperty(string $property, $direction, QueryBuilder $qu
105105
if (null !== $nullsComparison = $this->properties[$property]['nulls_comparison'] ?? null) {
106106
$nullsDirection = self::NULLS_DIRECTION_MAP[$nullsComparison][$direction];
107107

108-
$nullRankHiddenField = sprintf('_%s_%s_null_rank', $alias, $field);
108+
$nullRankHiddenField = sprintf('_%s_%s_null_rank', $alias, str_replace('.', '_', $field));
109109

110110
$queryBuilder->addSelect(sprintf('CASE WHEN %s.%s IS NULL THEN 0 ELSE 1 END AS HIDDEN %s', $alias, $field, $nullRankHiddenField));
111111
$queryBuilder->addOrderBy($nullRankHiddenField, $nullsDirection);

‎src/Test/DoctrineMongoDbOdmFilterTestCase.php‎

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\FilterInterface;
1717
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\Dummy;
18+
use Doctrine\ODM\MongoDB\DocumentManager;
1819
use Doctrine\ODM\MongoDB\Repository\DocumentRepository;
1920
use Doctrine\Persistence\ManagerRegistry;
2021
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
@@ -26,6 +27,11 @@
2627
*/
2728
abstract class DoctrineMongoDbOdmFilterTestCase extends KernelTestCase
2829
{
30+
/**
31+
* @var DocumentManager
32+
*/
33+
protected $manager;
34+
2935
/**
3036
* @var ManagerRegistry
3137
*/
@@ -50,20 +56,20 @@ protected function setUp(): void
5056
{
5157
self::bootKernel();
5258

53-
$manager = DoctrineMongoDbOdmTestCase::createTestDocumentManager();
59+
$this->manager = DoctrineMongoDbOdmTestCase::createTestDocumentManager();
5460
$this->managerRegistry = self::$kernel->getContainer()->get('doctrine_mongodb');
55-
$this->repository = $manager->getRepository(Dummy::class);
61+
$this->repository = $this->manager->getRepository(Dummy::class);
5662
}
5763

5864
/**
5965
* @dataProvider provideApplyTestData
6066
*/
61-
public function testApply(?array $properties, array $filterParameters, array $expectedPipeline, callable $factory = null)
67+
public function testApply(?array $properties, array $filterParameters, array $expectedPipeline, callable $factory = null, string $resourceClass = null)
6268
{
63-
$this->doTestApply($properties, $filterParameters, $expectedPipeline, $factory);
69+
$this->doTestApply($properties, $filterParameters, $expectedPipeline, $factory, $resourceClass);
6470
}
6571

66-
protected function doTestApply(?array $properties, array $filterParameters, array $expectedPipeline, callable $filterFactory = null)
72+
protected function doTestApply(?array $properties, array $filterParameters, array $expectedPipeline, callable $filterFactory = null, string $resourceClass = null)
6773
{
6874
if (null === $filterFactory) {
6975
$filterFactory = function (ManagerRegistry $managerRegistry, array $properties = null): FilterInterface {
@@ -73,10 +79,15 @@ protected function doTestApply(?array $properties, array $filterParameters, arra
7379
};
7480
}
7581

76-
$aggregationBuilder = $this->repository->createAggregationBuilder();
82+
$repository = $this->repository;
83+
if ($resourceClass) {
84+
$repository = $this->manager->getRepository($resourceClass);
85+
}
86+
$resourceClass = $resourceClass ?: $this->resourceClass;
87+
$aggregationBuilder = $repository->createAggregationBuilder();
7788
$filterCallable = $filterFactory($this->managerRegistry, $properties);
7889
$context = ['filters' => $filterParameters];
79-
$filterCallable->apply($aggregationBuilder, $this->resourceClass, null, $context);
90+
$filterCallable->apply($aggregationBuilder, $resourceClass, null, $context);
8091
$pipeline = [];
8192
try {
8293
$pipeline = $aggregationBuilder->getPipeline();

‎src/Test/DoctrineOrmFilterTestCase.php‎

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,21 +65,21 @@ protected function setUp(): void
6565
/**
6666
* @dataProvider provideApplyTestData
6767
*/
68-
public function testApply(?array $properties, array $filterParameters, string $expectedDql, array $expectedParameters = null, callable $factory = null)
68+
public function testApply(?array $properties, array $filterParameters, string $expectedDql, array $expectedParameters = null, callable $factory = null, string $resourceClass = null)
6969
{
70-
$this->doTestApply(false, $properties, $filterParameters, $expectedDql, $expectedParameters, $factory);
70+
$this->doTestApply(false, $properties, $filterParameters, $expectedDql, $expectedParameters, $factory, $resourceClass);
7171
}
7272

7373
/**
7474
* @group legacy
7575
* @dataProvider provideApplyTestData
7676
*/
77-
public function testApplyRequest(?array $properties, array $filterParameters, string $expectedDql, array $expectedParameters = null, callable $factory = null)
77+
public function testApplyRequest(?array $properties, array $filterParameters, string $expectedDql, array $expectedParameters = null, callable $factory = null, string $resourceClass = null)
7878
{
79-
$this->doTestApply(true, $properties, $filterParameters, $expectedDql, $expectedParameters, $factory);
79+
$this->doTestApply(true, $properties, $filterParameters, $expectedDql, $expectedParameters, $factory, $resourceClass);
8080
}
8181

82-
protected function doTestApply(bool $request, ?array $properties, array $filterParameters, string $expectedDql, array $expectedParameters = null, callable $filterFactory = null)
82+
protected function doTestApply(bool $request, ?array $properties, array $filterParameters, string $expectedDql, array $expectedParameters = null, callable $filterFactory = null, string $resourceClass = null)
8383
{
8484
if (null === $filterFactory) {
8585
$filterFactory = function (ManagerRegistry $managerRegistry, array $properties = null, RequestStack $requestStack = null): FilterInterface {
@@ -95,9 +95,15 @@ protected function doTestApply(bool $request, ?array $properties, array $filterP
9595
$requestStack->push(Request::create('/api/dummies', 'GET', $filterParameters));
9696
}
9797

98-
$queryBuilder = $this->repository->createQueryBuilder($this->alias);
98+
$repository = $this->repository;
99+
if ($resourceClass) {
100+
/** @var EntityRepository $repository */
101+
$repository = $this->managerRegistry->getManagerForClass($resourceClass)->getRepository($resourceClass);
102+
}
103+
$resourceClass = $resourceClass ?: $this->resourceClass;
104+
$queryBuilder = $repository->createQueryBuilder($this->alias);
99105
$filterCallable = $filterFactory($this->managerRegistry, $properties, $requestStack);
100-
$filterCallable->apply($queryBuilder, new QueryNameGenerator(), $this->resourceClass, null, $request ? [] : ['filters' => $filterParameters]);
106+
$filterCallable->apply($queryBuilder, new QueryNameGenerator(), $resourceClass, null, $request ? [] : ['filters' => $filterParameters]);
101107

102108
$this->assertEquals($expectedDql, $queryBuilder->getQuery()->getDQL());
103109

‎tests/Bridge/Doctrine/Common/Filter/OrderFilterTestTrait.php‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,26 @@ private function provideApplyTestArguments(): array
249249
'order' => ['relatedDummy.name' => 'ASC'],
250250
],
251251
],
252+
'embedded' => [
253+
[
254+
'embeddedDummy.dummyName' => 'ASC',
255+
],
256+
[
257+
'order' => ['embeddedDummy.dummyName' => 'ASC'],
258+
],
259+
],
260+
'embedded with nulls_comparison' => [
261+
[
262+
'embeddedDummy.dummyName' => [
263+
'nulls_comparison' => 'nulls_largest',
264+
],
265+
],
266+
[
267+
'order' => [
268+
'embeddedDummy.dummyName' => 'ASC',
269+
],
270+
],
271+
],
252272
];
253273
}
254274
}

‎tests/Bridge/Doctrine/MongoDbOdm/Filter/OrderFilterTest.php‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\OrderFilter;
1717
use ApiPlatform\Core\Test\DoctrineMongoDbOdmFilterTestCase;
1818
use ApiPlatform\Core\Tests\Bridge\Doctrine\Common\Filter\OrderFilterTestTrait;
19+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\EmbeddedDummy;
1920
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Serializer\NameConverter\CustomConverter;
2021
use Doctrine\Persistence\ManagerRegistry;
2122

@@ -461,6 +462,28 @@ public function provideApplyTestData(): array
461462
],
462463
$orderFilterFactory,
463464
],
465+
'embedded' => [
466+
[
467+
[
468+
'$sort' => [
469+
'embeddedDummy.dummyName' => 1,
470+
],
471+
],
472+
],
473+
$orderFilterFactory,
474+
EmbeddedDummy::class,
475+
],
476+
'embedded with nulls_comparison' => [
477+
[
478+
[
479+
'$sort' => [
480+
'embeddedDummy.dummyName' => 1,
481+
],
482+
],
483+
],
484+
$orderFilterFactory,
485+
EmbeddedDummy::class,
486+
],
464487
]
465488
);
466489
}

‎tests/Bridge/Doctrine/Orm/Filter/OrderFilterTest.php‎

Lines changed: 124 additions & 0 deletions

0 commit comments

Comments
 (0)