Skip to content

Commit 677d404

Browse files
authored
Merge pull request #1973 from soyuka/merge-2.2
Merge 2.2 (couple eager loading fixes + conflicts due to cs fixes)
2 parents bd114f5 + b00f00d commit 677d404

File tree

6 files changed

+67
-14
lines changed

6 files changed

+67
-14
lines changed

features/main/circular_reference.feature

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,29 @@ Feature: Circular references handling
6060
"@type": "CircularReference",
6161
"parent": "/circular_references/1",
6262
"children": [
63-
"/circular_references/1",
64-
"/circular_references/2"
63+
"/circular_references/1"
6564
]
6665
},
6766
"children": []
6867
}
6968
"""
69+
And I send a "GET" request to "/circular_references/1"
70+
Then the response status code should be 200
71+
And the JSON should be equal to:
72+
"""
73+
{
74+
"@context": "/contexts/CircularReference",
75+
"@id": "/circular_references/1",
76+
"@type": "CircularReference",
77+
"parent": "/circular_references/1",
78+
"children": [
79+
"/circular_references/1",
80+
{
81+
"@id": "/circular_references/2",
82+
"@type": "CircularReference",
83+
"parent": "/circular_references/1",
84+
"children": []
85+
}
86+
]
87+
}
88+
"""

features/main/operation.feature

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,24 @@ Feature: Operation support
1212
"""
1313
"This is a custom action for 42."
1414
"""
15+
16+
@createSchema
17+
@dropSchema
18+
Scenario: Select a resource and it's embedded data
19+
Given there are 1 embedded dummy objects
20+
When I send a "GET" request to "/embedded_dummies_groups/1"
21+
Then the response status code should be 200
22+
And the response should be in JSON
23+
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
24+
And the JSON should be equal to:
25+
"""
26+
{
27+
"@context": "/contexts/EmbeddedDummy",
28+
"@id": "/embedded_dummies/1",
29+
"@type": "EmbeddedDummy",
30+
"name": "Dummy #1",
31+
"embeddedDummy": {
32+
"dummyName": "Dummy #1"
33+
}
34+
}
35+
"""

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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,13 @@ private function joinRelations(QueryBuilder $queryBuilder, QueryNameGeneratorInt
207207
$queryBuilder->addSelect($associationAlias);
208208
}
209209

210-
// Avoid recursion
210+
// Avoid recursive joins
211211
if ($mapping['targetEntity'] === $resourceClass) {
212-
$queryBuilder->addSelect($associationAlias);
212+
// Avoid joining the same association twice (see #1959)
213+
if (!\in_array($associationAlias, $queryBuilder->getAllAliases(), true)) {
214+
$queryBuilder->addSelect($associationAlias);
215+
}
216+
213217
continue;
214218
}
215219

@@ -245,15 +249,17 @@ private function addSelect(QueryBuilder $queryBuilder, string $entity, string $a
245249
continue;
246250
}
247251

248-
//the field test allows to add methods to a Resource which do not reflect real database fields
249-
if ($targetClassMetadata->hasField($property) && (true === $propertyMetadata->getAttribute('fetchable') || $propertyMetadata->isReadable())) {
250-
$select[] = $property;
251-
}
252-
252+
// If it's an embedded property see below
253253
if (!array_key_exists($property, $targetClassMetadata->embeddedClasses)) {
254+
//the field test allows to add methods to a Resource which do not reflect real database fields
255+
if ($targetClassMetadata->hasField($property) && (true === $propertyMetadata->getAttribute('fetchable') || $propertyMetadata->isReadable())) {
256+
$select[] = $property;
257+
}
258+
254259
continue;
255260
}
256261

262+
// It's an embedded property, select relevent subfields
257263
foreach ($this->propertyNameCollectionFactory->create($targetClassMetadata->embeddedClasses[$property]['class']) as $embeddedProperty) {
258264
$propertyMetadata = $this->propertyMetadataFactory->create($entity, $property, $propertyMetadataOptions);
259265
$propertyName = "$property.$embeddedProperty";

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ public function testApplyToCollection()
9797
$relatedClassMetadataProphecy = $this->prophesize(ClassMetadata::class);
9898

9999
foreach ($relatedNameCollection as $property) {
100-
if ('id' !== $property) {
101-
$relatedClassMetadataProphecy->hasField($property)->willReturn(!\in_array($property, ['notindatabase', 'embeddedDummy'], true))->shouldBeCalled();
100+
if ('id' !== $property && 'embeddedDummy' !== $property) {
101+
$relatedClassMetadataProphecy->hasField($property)->willReturn(!\in_array($property, ['notindatabase'], true))->shouldBeCalled();
102102
}
103103
}
104104
$relatedClassMetadataProphecy->hasField('embeddedDummy.name')->willReturn(true)->shouldBeCalled();
@@ -183,8 +183,8 @@ public function testApplyToItem()
183183
$relatedClassMetadataProphecy = $this->prophesize(ClassMetadata::class);
184184

185185
foreach ($relatedNameCollection as $property) {
186-
if ('id' !== $property) {
187-
$relatedClassMetadataProphecy->hasField($property)->willReturn(!\in_array($property, ['notindatabase', 'embeddedDummy'], true))->shouldBeCalled();
186+
if ('id' !== $property && 'embeddedDummy' !== $property) {
187+
$relatedClassMetadataProphecy->hasField($property)->willReturn(!\in_array($property, ['notindatabase'], true))->shouldBeCalled();
188188
}
189189
}
190190
$relatedClassMetadataProphecy->hasField('embeddedDummy.name')->willReturn(true)->shouldBeCalled();

tests/Fixtures/TestBundle/Entity/EmbeddableDummy.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class EmbeddableDummy
3030
* @var string The dummy name
3131
*
3232
* @ORM\Column(nullable=true)
33+
* @Groups({"embed"})
3334
*/
3435
private $dummyName;
3536

tests/Fixtures/TestBundle/Entity/EmbeddedDummy.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,18 @@
1515

1616
use ApiPlatform\Core\Annotation\ApiResource;
1717
use Doctrine\ORM\Mapping as ORM;
18+
use Symfony\Component\Serializer\Annotation\Groups;
1819
use Symfony\Component\Validator\Constraints as Assert;
1920

2021
/**
2122
* Embedded Dummy.
2223
*
2324
* @author Jordan Samouh <[email protected]>
2425
*
25-
* @ApiResource(attributes={"filters"={"my_dummy.search", "my_dummy.order", "my_dummy.date", "my_dummy.range", "my_dummy.boolean", "my_dummy.numeric"}})
26+
* @ApiResource(
27+
* attributes={"filters"={"my_dummy.search", "my_dummy.order", "my_dummy.date", "my_dummy.range", "my_dummy.boolean", "my_dummy.numeric"}},
28+
* itemOperations={"get", "put", "delete", "groups"={"method"="GET", "path"="/embedded_dummies_groups/{id}", "normalization_context"={"groups"={"embed"}}}}
29+
* )
2630
* @ORM\Entity
2731
*/
2832
class EmbeddedDummy
@@ -40,6 +44,7 @@ class EmbeddedDummy
4044
* @var string The dummy name
4145
*
4246
* @ORM\Column(nullable=true)
47+
* @Groups({"embed"})
4348
*/
4449
private $name;
4550

@@ -55,6 +60,7 @@ class EmbeddedDummy
5560
* @var EmbeddableDummy
5661
*
5762
* @ORM\Embedded(class="EmbeddableDummy")
63+
* @Groups({"embed"})
5864
*/
5965
public $embeddedDummy;
6066

0 commit comments

Comments
 (0)