diff --git a/src/Doctrine/Common/State/LinksHandlerTrait.php b/src/Doctrine/Common/State/LinksHandlerTrait.php index 2033ac76241..aced9536f14 100644 --- a/src/Doctrine/Common/State/LinksHandlerTrait.php +++ b/src/Doctrine/Common/State/LinksHandlerTrait.php @@ -34,11 +34,13 @@ private function getLinks(string $resourceClass, Operation $operation, array $co return $links; } - $newLinks = []; + $newLink = null; + $linkProperty = $context['linkProperty']; foreach ($links as $link) { - if ($linkClass === $link->getFromClass()) { - $newLinks[] = $link; + if (($linkClass === $link->getFromClass()) && ($linkProperty === $link->getFromProperty())) { + $newLink = $link; + break; } } @@ -62,16 +64,17 @@ private function getLinks(string $resourceClass, Operation $operation, array $co } foreach ($this->getOperationLinks($linkedOperation ?? null) as $link) { - if ($resourceClass === $link->getToClass()) { - $newLinks[] = $link; + if (($resourceClass === $link->getToClass()) && ($linkProperty === $link->getFromProperty())) { + $newLink = $link; + break; } } - if (!$newLinks) { + if (null === $newLink) { throw new RuntimeException(sprintf('The class "%s" cannot be retrieved from "%s".', $resourceClass, $linkClass)); } - return $newLinks; + return [$newLink]; } private function getIdentifierValue(array &$identifiers, string $name = null) diff --git a/src/GraphQl/Resolver/Stage/ReadStage.php b/src/GraphQl/Resolver/Stage/ReadStage.php index 139c211454e..a13b21b2da7 100644 --- a/src/GraphQl/Resolver/Stage/ReadStage.php +++ b/src/GraphQl/Resolver/Stage/ReadStage.php @@ -92,6 +92,7 @@ public function __invoke(?string $resourceClass, ?string $rootClass, Operation $ if (isset($source[$info->fieldName], $source[ItemNormalizer::ITEM_IDENTIFIERS_KEY], $source[ItemNormalizer::ITEM_RESOURCE_CLASS_KEY])) { $uriVariables = $source[ItemNormalizer::ITEM_IDENTIFIERS_KEY]; $normalizationContext['linkClass'] = $source[ItemNormalizer::ITEM_RESOURCE_CLASS_KEY]; + $normalizationContext['linkProperty'] = $info->fieldName; } return $this->provider->provide($operation, $uriVariables, $normalizationContext); diff --git a/src/Metadata/Resource/Factory/LinkResourceMetadataCollectionFactory.php b/src/Metadata/Resource/Factory/LinkResourceMetadataCollectionFactory.php index befcd6d5bd4..2b2fc536e85 100644 --- a/src/Metadata/Resource/Factory/LinkResourceMetadataCollectionFactory.php +++ b/src/Metadata/Resource/Factory/LinkResourceMetadataCollectionFactory.php @@ -71,18 +71,22 @@ private function mergeLinks(array $links, array $toMergeLinks): array { $classLinks = []; foreach ($links as $link) { - $classLinks[$link->getToClass()] = $link; + $classLinks[$link->getToClass()][$link->getFromProperty()] = $link; } foreach ($toMergeLinks as $link) { - if (isset($classLinks[$link->getToClass()])) { - $classLinks[$link->getToClass()] = $classLinks[$link->getToClass()]->withLink($link); + if (null !== $prevLink = $classLinks[$link->getToClass()][$link->getFromProperty()] ?? null) { + $classLinks[$link->getToClass()][$link->getFromProperty()] = $prevLink->withLink($link); continue; } - $classLinks[$link->getToClass()] = $link; + $classLinks[$link->getToClass()][$link->getFromProperty()] = $link; } - return array_values($classLinks); + // return array_values(array_merge(...array_values($classLinks))); (branch 3.0) + + return array_reduce($classLinks, function (array $carry, array $item) { + return array_merge($carry, array_values($item)); + }, []); } } diff --git a/tests/GraphQl/Resolver/Stage/ReadStageTest.php b/tests/GraphQl/Resolver/Stage/ReadStageTest.php index b90f3ee131d..d0d3fa89741 100644 --- a/tests/GraphQl/Resolver/Stage/ReadStageTest.php +++ b/tests/GraphQl/Resolver/Stage/ReadStageTest.php @@ -210,7 +210,7 @@ public function testApplyCollection(array $args, ?string $rootClass, ?array $sou $this->serializerContextBuilderProphecy->create($resourceClass, $operation, $context, true)->shouldBeCalled()->willReturn($normalizationContext); $this->providerProphecy->provide($operation, [], $normalizationContext + ['filters' => $expectedFilters])->willReturn([]); - $this->providerProphecy->provide($operation, ['id' => 3], $normalizationContext + ['filters' => $expectedFilters, 'linkClass' => 'myResource'])->willReturn(['subresource']); + $this->providerProphecy->provide($operation, ['id' => 3], $normalizationContext + ['filters' => $expectedFilters, 'linkClass' => 'myResource', 'linkProperty' => 'subresource'])->willReturn(['subresource']); $result = ($this->readStage)($resourceClass, $rootClass, $operation, $context); diff --git a/tests/Metadata/Resource/Factory/LinkResourceMetadataCollectionFactoryTest.php b/tests/Metadata/Resource/Factory/LinkResourceMetadataCollectionFactoryTest.php index 0b28987a8e3..b6ac53677af 100644 --- a/tests/Metadata/Resource/Factory/LinkResourceMetadataCollectionFactoryTest.php +++ b/tests/Metadata/Resource/Factory/LinkResourceMetadataCollectionFactoryTest.php @@ -84,6 +84,7 @@ class: AttributeResource::class, class: AttributeResource::class, graphQlOperations: [ 'item_query' => (new Query(shortName: 'AttributeResource', class: AttributeResource::class))->withLinks([ + (new Link())->withFromProperty('foo')->withFromClass(AttributeResource::class)->withToClass(Dummy::class)->withIdentifiers(['id']), (new Link())->withFromProperty('foo2')->withFromClass(AttributeResource::class)->withToClass(Dummy::class)->withIdentifiers(['id']), (new Link())->withFromProperty('bar')->withFromClass(AttributeResource::class)->withToClass(RelatedDummy::class)->withIdentifiers(['id']), ]),