Skip to content

Commit b64da31

Browse files
authored
Merge pull request #2183 from ilicmsreten/fix-duplicate-data
Fix duplicate data in Eager loads relations
2 parents ae6a196 + b840fc4 commit b64da31

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

src/Bridge/Doctrine/Orm/Extension/EagerLoadingExtension.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ private function joinRelations(QueryBuilder $queryBuilder, QueryNameGeneratorInt
232232

233233
$this->joinRelations($queryBuilder, $queryNameGenerator, $mapping['targetEntity'], $forceEager, $fetchPartial, $associationAlias, $options, $normalizationContext, 'leftJoin' === $method, $joinCount, $currentDepth);
234234
}
235+
236+
// result is discarded (this is just re-hydrating the collections) see http://ocramius.github.io/blog/doctrine-orm-optimization-hydration/
237+
$queryBuilder->getQuery()->getResult();
235238
}
236239

237240
private function addSelect(QueryBuilder $queryBuilder, string $entity, string $associationAlias, array $propertyMetadataOptions)

tests/Bridge/Doctrine/Orm/Extension/EagerLoadingExtensionTest.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\EmbeddableDummy;
3232
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RelatedDummy;
3333
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\UnknownDummy;
34+
use Doctrine\ORM\AbstractQuery;
3435
use Doctrine\ORM\EntityManager;
3536
use Doctrine\ORM\Mapping\ClassMetadata;
3637
use Doctrine\ORM\Mapping\ClassMetadataInfo;
@@ -122,6 +123,9 @@ public function testApplyToCollection()
122123
$queryBuilderProphecy->addSelect('partial relatedDummy_a1.{id,name,embeddedDummy.name}')->shouldBeCalled(1);
123124
$queryBuilderProphecy->addSelect('partial relatedDummy2_a2.{id,name,embeddedDummy.name}')->shouldBeCalled(1);
124125

126+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
127+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(3);
128+
125129
$queryBuilder = $queryBuilderProphecy->reveal();
126130
$eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, null, null, true);
127131
$eagerExtensionTest->applyToCollection($queryBuilder, new QueryNameGenerator(), Dummy::class, null, $context);
@@ -228,6 +232,9 @@ public function testApplyToItem()
228232
$queryBuilderProphecy->addSelect('partial relatedDummy4_a5.{id}')->shouldBeCalled(1);
229233
$queryBuilderProphecy->addSelect('singleInheritanceRelation_a6')->shouldBeCalled(1);
230234

235+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
236+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(7);
237+
231238
$queryBuilder = $queryBuilderProphecy->reveal();
232239
$orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, null, null, true);
233240

@@ -253,6 +260,8 @@ public function testCreateItemWithOperationName()
253260
$emProphecy->getClassMetadata(Dummy::class)->shouldBeCalled()->willReturn($classMetadataProphecy->reveal());
254261
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
255262
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
263+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
264+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(1);
256265

257266
$orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, null, null, true);
258267
$orderExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class, [], 'item_operation', ['groups' => ['foo']]);
@@ -277,6 +286,8 @@ public function testCreateCollectionWithOperationName()
277286
$emProphecy->getClassMetadata(Dummy::class)->shouldBeCalled()->willReturn($classMetadataProphecy->reveal());
278287
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
279288
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
289+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
290+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(1);
280291

281292
$eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, null, null, true);
282293
$eagerExtensionTest->applyToCollection($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class, 'collection_operation', ['groups' => ['foo']]);
@@ -300,6 +311,8 @@ public function testDenormalizeItemWithCorrectResourceClass()
300311
$queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
301312
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
302313
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
314+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
315+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(1);
303316

304317
$eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, null, null, true);
305318
$eagerExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), RelatedDummy::class, ['id' => 1], 'item_operation', ['resource_class' => Dummy::class]);
@@ -322,6 +335,8 @@ public function testDenormalizeItemWithExistingGroups()
322335
$queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
323336
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
324337
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
338+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
339+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(1);
325340

326341
$eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, null, null, true);
327342
$eagerExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), RelatedDummy::class, ['id' => 1], 'item_operation', [AbstractNormalizer::GROUPS => 'some_groups']);
@@ -442,6 +457,8 @@ public function testMaxDepth()
442457

443458
$queryBuilderProphecy->innerJoin(Argument::type('string'), Argument::type('string'))->shouldBeCalledTimes(2);
444459
$queryBuilderProphecy->addSelect(Argument::type('string'))->shouldBeCalled();
460+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
461+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(3);
445462

446463
$eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, null, null, true, $classMetadataFactoryProphecy->reveal());
447464
$eagerExtensionTest->applyToCollection($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class);
@@ -487,6 +504,9 @@ public function testForceEager()
487504
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
488505
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
489506

507+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
508+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(2);
509+
490510
$orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, true, null, null, true);
491511
$orderExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class, []);
492512
}
@@ -523,6 +543,9 @@ public function testExtraLazy()
523543
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
524544
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
525545

546+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
547+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(1);
548+
526549
$orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, true, null, null, true);
527550
$orderExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class, []);
528551
}
@@ -546,6 +569,8 @@ public function testResourceClassNotFoundException()
546569
$queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
547570
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
548571
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
572+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
573+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(1);
549574

550575
$orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, true, null, null, true);
551576
$orderExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class, [], null);
@@ -570,6 +595,8 @@ public function testPropertyNotFoundException()
570595
$queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
571596
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
572597
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
598+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
599+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(1);
573600

574601
$orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, true, null, null, true);
575602
$orderExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class, []);
@@ -599,6 +626,8 @@ public function testResourceClassNotFoundExceptionPropertyNameCollection()
599626
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
600627
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
601628
$queryBuilderProphecy->innerJoin('o.relation', 'relation_a1')->shouldBeCalled(1);
629+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
630+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(1);
602631

603632
$orderExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, true, null, null, true);
604633
$orderExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class, []);
@@ -654,6 +683,8 @@ public function testApplyToCollectionWithSerializerContextBuilder()
654683

655684
$queryBuilderProphecy->leftJoin('o.relatedDummy', 'relatedDummy_a1')->shouldBeCalled(1);
656685
$queryBuilderProphecy->addSelect('partial relatedDummy_a1.{id,name}')->shouldBeCalled(1);
686+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
687+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(2);
657688

658689
$request = Request::create('/api/dummies', 'GET', []);
659690

@@ -718,6 +749,8 @@ public function testAttributes()
718749

719750
$queryBuilderProphecy->leftJoin('o.relatedDummy', 'relatedDummy_a1')->shouldBeCalled(1);
720751
$queryBuilderProphecy->addSelect('partial relatedDummy_a1.{id,name}')->shouldBeCalled(1);
752+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
753+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(2);
721754

722755
$request = Request::create('/api/dummies', 'GET', []);
723756

@@ -759,6 +792,8 @@ public function testNotInAttributes()
759792

760793
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
761794
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
795+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
796+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(1);
762797

763798
$request = Request::create('/api/dummies', 'GET', []);
764799

@@ -808,6 +843,8 @@ public function testApplyToCollectionNoPartial()
808843
$queryBuilderProphecy->innerJoin('o.relatedDummy2', 'relatedDummy2_a2')->shouldBeCalled(1);
809844
$queryBuilderProphecy->addSelect('relatedDummy_a1')->shouldBeCalled(1);
810845
$queryBuilderProphecy->addSelect('relatedDummy2_a2')->shouldBeCalled(1);
846+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
847+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(3);
811848

812849
$queryBuilder = $queryBuilderProphecy->reveal();
813850
$eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30);
@@ -864,6 +901,8 @@ private function doTestApplyToCollectionWithANonRedableButFetchEagerProperty(boo
864901
$queryBuilderProphecy->innerJoin('o.relatedDummy2', 'relatedDummy2_a2')->shouldBeCalled(1);
865902
$queryBuilderProphecy->addSelect('relatedDummy_a1')->shouldBeCalled(1);
866903
$queryBuilderProphecy->addSelect('relatedDummy2_a2')->shouldBeCalled(1);
904+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
905+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(3);
867906

868907
$queryBuilder = $queryBuilderProphecy->reveal();
869908
$eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30);
@@ -918,6 +957,8 @@ private function doTestApplyToCollectionWithARedableButNotFetchEagerProperty(boo
918957
$queryBuilderProphecy->innerJoin('o.relatedDummy2', 'relatedDummy2_a2')->shouldNotBeCalled();
919958
$queryBuilderProphecy->addSelect('relatedDummy_a1')->shouldNotBeCalled();
920959
$queryBuilderProphecy->addSelect('relatedDummy2_a2')->shouldNotBeCalled();
960+
$queryAbstractProphecy = $this->prophesize(AbstractQuery::class);
961+
$queryBuilderProphecy->getQuery()->willReturn($queryAbstractProphecy)->shouldBeCalledTimes(1);
921962

922963
$queryBuilder = $queryBuilderProphecy->reveal();
923964
$eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30);

0 commit comments

Comments
 (0)