Skip to content

Commit 202aabc

Browse files
authored
Merge pull request #850 from teohhanhui/refactor-eagerloadingextension
Refactor EagerLoadingExtension to use QueryNameGenerator
2 parents c395e18 + 9c278ac commit 202aabc

File tree

2 files changed

+65
-60
lines changed

2 files changed

+65
-60
lines changed

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

Lines changed: 41 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -41,34 +41,6 @@ public function __construct(PropertyMetadataFactoryInterface $propertyMetadataFa
4141
$this->forceEager = $forceEager;
4242
}
4343

44-
/**
45-
* Gets serializer groups once if available, if not it returns the $options array.
46-
*
47-
* @param array $options represents the operation name so that groups are the one of the specific operation
48-
* @param string $resourceClass
49-
* @param string $context normalization_context or denormalization_context
50-
*
51-
* @return string[]
52-
*/
53-
private function getSerializerGroups(string $resourceClass, array $options, string $context): array
54-
{
55-
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
56-
57-
if (isset($options['collection_operation_name'])) {
58-
$context = $resourceMetadata->getCollectionOperationAttribute($options['collection_operation_name'], $context, null, true);
59-
} elseif (isset($options['item_operation_name'])) {
60-
$context = $resourceMetadata->getItemOperationAttribute($options['item_operation_name'], $context, null, true);
61-
} else {
62-
$context = $resourceMetadata->getAttribute($context);
63-
}
64-
65-
if (empty($context['groups'])) {
66-
return $options;
67-
}
68-
69-
return ['serializer_groups' => $context['groups']];
70-
}
71-
7244
/**
7345
* {@inheritdoc}
7446
*/
@@ -83,7 +55,7 @@ public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGenerator
8355
$forceEager = $this->isForceEager($resourceClass, $options);
8456
$groups = $this->getSerializerGroups($resourceClass, $options, 'normalization_context');
8557

86-
$this->joinRelations($queryBuilder, $resourceClass, $forceEager, $groups);
58+
$this->joinRelations($queryBuilder, $queryNameGenerator, $resourceClass, $forceEager, $queryBuilder->getRootAliases()[0], $groups);
8759
}
8860

8961
/**
@@ -108,32 +80,31 @@ public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterf
10880
$groups = $this->getSerializerGroups($resourceClass, $options, 'normalization_context');
10981
}
11082

111-
$this->joinRelations($queryBuilder, $resourceClass, $forceEager, $groups);
83+
$this->joinRelations($queryBuilder, $queryNameGenerator, $resourceClass, $forceEager, $queryBuilder->getRootAliases()[0], $groups);
11284
}
11385

11486
/**
11587
* Joins relations to eager load.
11688
*
117-
* @param QueryBuilder $queryBuilder
118-
* @param string $resourceClass
119-
* @param bool $forceEager
120-
* @param array $propertyMetadataOptions
121-
* @param string $originAlias the current entity alias (first o, then a1, a2 etc.)
122-
* @param string $relationAlias the previous relation alias to keep it unique
123-
* @param bool $wasLeftJoin if the relation containing the new one had a left join, we have to force the new one to left join too
124-
* @param int $joinCount the number of joins
89+
* @param QueryBuilder $queryBuilder
90+
* @param QueryNameGeneratorInterface $queryNameGenerator
91+
* @param string $resourceClass
92+
* @param bool $forceEager
93+
* @param string $parentAlias
94+
* @param array $propertyMetadataOptions
95+
* @param bool $wasLeftJoin if the relation containing the new one had a left join, we have to force the new one to left join too
96+
* @param int $joinCount the number of joins
12597
*
12698
* @throws RuntimeException when the max number of joins has been reached
12799
*/
128-
private function joinRelations(QueryBuilder $queryBuilder, string $resourceClass, bool $forceEager, array $propertyMetadataOptions = [], string $originAlias = 'o', string &$relationAlias = 'a', bool $wasLeftJoin = false, int &$joinCount = 0)
100+
private function joinRelations(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, bool $forceEager, string $parentAlias, array $propertyMetadataOptions = [], bool $wasLeftJoin = false, int &$joinCount = 0)
129101
{
130102
if ($joinCount > $this->maxJoins) {
131103
throw new RuntimeException('The total number of joined relations has exceeded the specified maximum. Raise the limit if necessary.');
132104
}
133105

134106
$entityManager = $queryBuilder->getEntityManager();
135107
$classMetadata = $entityManager->getClassMetadata($resourceClass);
136-
$i = $j = 0;
137108

138109
foreach ($classMetadata->associationMappings as $association => $mapping) {
139110
$propertyMetadata = $this->propertyMetadataFactory->create($resourceClass, $association, $propertyMetadataOptions);
@@ -153,14 +124,40 @@ private function joinRelations(QueryBuilder $queryBuilder, string $resourceClass
153124
$method = 'innerJoin';
154125
}
155126

156-
$associationAlias = $relationAlias.$i++;
157-
$queryBuilder->{$method}($originAlias.'.'.$association, $associationAlias);
127+
$associationAlias = $queryNameGenerator->generateJoinAlias($association);
128+
$queryBuilder->{$method}(sprintf('%s.%s', $parentAlias, $association), $associationAlias);
158129
++$joinCount;
159130

160-
$relationAlias .= ++$j;
131+
$this->joinRelations($queryBuilder, $queryNameGenerator, $mapping['targetEntity'], $forceEager, $associationAlias, $propertyMetadataOptions, $method === 'leftJoin', $joinCount);
132+
}
133+
}
134+
135+
/**
136+
* Gets serializer groups if available, if not it returns the $options array.
137+
*
138+
* @param string $resourceClass
139+
* @param array $options represents the operation name so that groups are the one of the specific operation
140+
* @param string $context normalization_context or denormalization_context
141+
*
142+
* @return array
143+
*/
144+
private function getSerializerGroups(string $resourceClass, array $options, string $context): array
145+
{
146+
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
161147

162-
$this->joinRelations($queryBuilder, $mapping['targetEntity'], $forceEager, $propertyMetadataOptions, $associationAlias, $relationAlias, $method === 'leftJoin', $joinCount);
148+
if (isset($options['collection_operation_name'])) {
149+
$context = $resourceMetadata->getCollectionOperationAttribute($options['collection_operation_name'], $context, null, true);
150+
} elseif (isset($options['item_operation_name'])) {
151+
$context = $resourceMetadata->getItemOperationAttribute($options['item_operation_name'], $context, null, true);
152+
} else {
153+
$context = $resourceMetadata->getAttribute($context);
163154
}
155+
156+
if (empty($context['groups'])) {
157+
return $options;
158+
}
159+
160+
return ['serializer_groups' => $context['groups']];
164161
}
165162

166163
/**

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

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,10 @@ public function testApplyToCollection()
5757
$emProphecy->getClassMetadata(RelatedDummy::class)->shouldBeCalled()->willReturn($relatedClassMetadataProphecy->reveal());
5858

5959
$queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
60-
$queryBuilderProphecy->leftJoin('o.relatedDummy', 'a0')->shouldBeCalled(1);
61-
$queryBuilderProphecy->innerJoin('o.relatedDummy2', 'a11')->shouldBeCalled(1);
62-
$queryBuilderProphecy->getEntityManager()->shouldBeCalled(2)->willReturn($emProphecy->reveal());
60+
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
61+
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
62+
$queryBuilderProphecy->leftJoin('o.relatedDummy', 'relatedDummy_a1')->shouldBeCalled(1);
63+
$queryBuilderProphecy->innerJoin('o.relatedDummy2', 'relatedDummy2_a2')->shouldBeCalled(1);
6364

6465
$eagerExtensionTest = new EagerLoadingExtension($propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false);
6566
$eagerExtensionTest->applyToCollection($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class);
@@ -104,12 +105,13 @@ public function testApplyToItem()
104105
$emProphecy->getClassMetadata(UnknownDummy::class)->shouldBeCalled()->willReturn($unknownClassMetadataProphecy->reveal());
105106

106107
$queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
107-
$queryBuilderProphecy->leftJoin('o.relatedDummy', 'a0')->shouldBeCalled(1);
108-
$queryBuilderProphecy->leftJoin('a0.relation', 'a10')->shouldBeCalled(1);
109-
$queryBuilderProphecy->innerJoin('o.relatedDummy2', 'a111')->shouldBeCalled(1);
110-
$queryBuilderProphecy->innerJoin('o.relatedDummy3', 'a1122')->shouldBeCalled(1);
111-
$queryBuilderProphecy->leftJoin('o.relatedDummy4', 'a11233')->shouldBeCalled(1);
112-
$queryBuilderProphecy->getEntityManager()->shouldBeCalled(2)->willReturn($emProphecy->reveal());
108+
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
109+
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
110+
$queryBuilderProphecy->leftJoin('o.relatedDummy', 'relatedDummy_a1')->shouldBeCalled(1);
111+
$queryBuilderProphecy->leftJoin('relatedDummy_a1.relation', 'relation_a2')->shouldBeCalled(1);
112+
$queryBuilderProphecy->innerJoin('o.relatedDummy2', 'relatedDummy2_a3')->shouldBeCalled(1);
113+
$queryBuilderProphecy->innerJoin('o.relatedDummy3', 'relatedDummy3_a4')->shouldBeCalled(1);
114+
$queryBuilderProphecy->leftJoin('o.relatedDummy4', 'relatedDummy4_a5')->shouldBeCalled(1);
113115

114116
$orderExtensionTest = new EagerLoadingExtension($propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false);
115117
$orderExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class, []);
@@ -132,7 +134,8 @@ public function testCreateItemWithOperationName()
132134
$emProphecy->getClassMetadata(Dummy::class)->shouldBeCalled()->willReturn($classMetadataProphecy->reveal());
133135

134136
$queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
135-
$queryBuilderProphecy->getEntityManager()->shouldBeCalled()->willReturn($emProphecy);
137+
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
138+
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
136139

137140
$orderExtensionTest = new EagerLoadingExtension($propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false);
138141
$orderExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class, [], 'item_operation');
@@ -155,7 +158,8 @@ public function testCreateCollectionWithOperationName()
155158
$emProphecy->getClassMetadata(Dummy::class)->shouldBeCalled()->willReturn($classMetadataProphecy->reveal());
156159

157160
$queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
158-
$queryBuilderProphecy->getEntityManager()->shouldBeCalled()->willReturn($emProphecy);
161+
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
162+
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
159163

160164
$eagerExtensionTest = new EagerLoadingExtension($propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false);
161165
$eagerExtensionTest->applyToCollection($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class, 'collection_operation');
@@ -177,7 +181,8 @@ public function testDenormalizeItemWithCorrectResourceClass()
177181
$emProphecy->getClassMetadata(RelatedDummy::class)->shouldBeCalled()->willReturn($classMetadataProphecy->reveal());
178182

179183
$queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
180-
$queryBuilderProphecy->getEntityManager()->shouldBeCalled()->willReturn($emProphecy);
184+
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
185+
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
181186

182187
$eagerExtensionTest = new EagerLoadingExtension($propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false);
183188
$eagerExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), RelatedDummy::class, ['id' => 1], 'item_operation', ['resource_class' => Dummy::class]);
@@ -199,7 +204,8 @@ public function testDenormalizeItemWithExistingGroups()
199204
$emProphecy->getClassMetadata(RelatedDummy::class)->shouldBeCalled()->willReturn($classMetadataProphecy->reveal());
200205

201206
$queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
202-
$queryBuilderProphecy->getEntityManager()->shouldBeCalled()->willReturn($emProphecy);
207+
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
208+
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
203209

204210
$eagerExtensionTest = new EagerLoadingExtension($propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false);
205211
$eagerExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), RelatedDummy::class, ['id' => 1], 'item_operation', ['groups' => 'some_groups']);
@@ -239,7 +245,8 @@ public function testMaxDepthReached()
239245
$emProphecy->getClassMetadata(RelatedDummy::class)->shouldBeCalled()->willReturn($relatedClassMetadataProphecy->reveal());
240246

241247
$queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
242-
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy->reveal());
248+
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
249+
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
243250
$queryBuilderProphecy->innerJoin(Argument::type('string'), Argument::type('string'))->shouldBeCalled();
244251

245252
$eagerExtensionTest = new EagerLoadingExtension($propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false);
@@ -270,8 +277,9 @@ public function testForceEager()
270277
$emProphecy->getClassMetadata(UnknownDummy::class)->shouldBeCalled()->willReturn($unknownClassMetadataProphecy->reveal());
271278

272279
$queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
273-
$queryBuilderProphecy->innerJoin('o.relation', 'a0')->shouldBeCalled(1);
274-
$queryBuilderProphecy->getEntityManager()->shouldBeCalled(2)->willReturn($emProphecy->reveal());
280+
$queryBuilderProphecy->getRootAliases()->willReturn(['o']);
281+
$queryBuilderProphecy->getEntityManager()->willReturn($emProphecy);
282+
$queryBuilderProphecy->innerJoin('o.relation', 'relation_a1')->shouldBeCalled(1);
275283

276284
$orderExtensionTest = new EagerLoadingExtension($propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, true);
277285
$orderExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), Dummy::class, []);

0 commit comments

Comments
 (0)