From 3d8371a56f12468df7b0fa8974a9babe35578b26 Mon Sep 17 00:00:00 2001 From: Nico Haase Date: Thu, 12 Jan 2023 15:47:06 +0100 Subject: [PATCH] fix(graphql): use depth for nested resource class operation (#5314) * test: add reproducer for bug 5310 * fix(graphql): use depth for nested resource class operation Co-authored-by: Alan Poulain --- features/graphql/query.feature | 27 ++++++++ src/GraphQl/Type/FieldsBuilder.php | 2 +- tests/Behat/DoctrineContext.php | 17 +++++ .../Fixtures/TestBundle/Entity/TreeDummy.php | 63 +++++++++++++++++++ 4 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 tests/Fixtures/TestBundle/Entity/TreeDummy.php diff --git a/features/graphql/query.feature b/features/graphql/query.feature index 4463a717b87..ce4c7c2b0e5 100644 --- a/features/graphql/query.feature +++ b/features/graphql/query.feature @@ -68,6 +68,33 @@ Feature: GraphQL query support And the JSON node "data.multiRelationsDummy.oneToManyRelations.edges[0].node.name" should be equal to "RelatedOneToManyDummy12" And the JSON node "data.multiRelationsDummy.oneToManyRelations.edges[2].node.name" should be equal to "RelatedOneToManyDummy32" + @createSchema @!mongodb + Scenario: Retrieve an item with child relation to the same resource + Given there are tree dummies + When I send the following GraphQL request: + """ + { + treeDummies { + edges { + node { + id + children { + totalCount + } + } + } + } + } + """ + Then the response status code should be 200 + And the response should be in JSON + And the header "Content-Type" should be equal to "application/json" + And the JSON node "errors" should not exist + And the JSON node "data.treeDummies.edges[0].node.id" should be equal to "/tree_dummies/1" + And the JSON node "data.treeDummies.edges[0].node.children.totalCount" should be equal to "1" + And the JSON node "data.treeDummies.edges[1].node.id" should be equal to "/tree_dummies/2" + And the JSON node "data.treeDummies.edges[1].node.children.totalCount" should be equal to "0" + @createSchema Scenario: Retrieve a Relay Node Given there are 2 dummy objects with relatedDummy diff --git a/src/GraphQl/Type/FieldsBuilder.php b/src/GraphQl/Type/FieldsBuilder.php index 26a9c7d42c3..c6bc5bc14a8 100644 --- a/src/GraphQl/Type/FieldsBuilder.php +++ b/src/GraphQl/Type/FieldsBuilder.php @@ -262,7 +262,7 @@ private function getResourceFieldConfiguration(?string $property, ?string $field } $resourceOperation = $rootOperation; - if ($resourceClass && $rootOperation->getClass() && $this->resourceClassResolver->isResourceClass($resourceClass) && $rootOperation->getClass() !== $resourceClass) { + if ($resourceClass && $depth >= 1 && $this->resourceClassResolver->isResourceClass($resourceClass)) { $resourceMetadataCollection = $this->resourceMetadataCollectionFactory->create($resourceClass); $resourceOperation = $resourceMetadataCollection->getOperation($isCollectionType ? 'collection_query' : 'item_query'); } diff --git a/tests/Behat/DoctrineContext.php b/tests/Behat/DoctrineContext.php index 7237a47359e..0cf1a057471 100644 --- a/tests/Behat/DoctrineContext.php +++ b/tests/Behat/DoctrineContext.php @@ -167,6 +167,7 @@ use ApiPlatform\Tests\Fixtures\TestBundle\Entity\SymfonyUuidDummy; use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Taxon; use ApiPlatform\Tests\Fixtures\TestBundle\Entity\ThirdLevel; +use ApiPlatform\Tests\Fixtures\TestBundle\Entity\TreeDummy; use ApiPlatform\Tests\Fixtures\TestBundle\Entity\UrlEncodedId; use ApiPlatform\Tests\Fixtures\TestBundle\Entity\User; use ApiPlatform\Tests\Fixtures\TestBundle\Entity\UuidIdentifierDummy; @@ -799,6 +800,22 @@ public function thereAreMultiRelationsDummyObjectsHavingEachAManyToOneRelationMa $this->manager->flush(); } + /** + * @Given there are tree dummies + */ + public function thereAreTreeDummies(): void + { + $parentDummy = new TreeDummy(); + $this->manager->persist($parentDummy); + + $childDummy = new TreeDummy(); + $childDummy->setParent($parentDummy); + + $this->manager->persist($childDummy); + + $this->manager->flush(); + } + /** * @Given there are :nb dummy objects with dummyDate * @Given there is :nb dummy object with dummyDate diff --git a/tests/Fixtures/TestBundle/Entity/TreeDummy.php b/tests/Fixtures/TestBundle/Entity/TreeDummy.php new file mode 100644 index 00000000000..ae5a44713c3 --- /dev/null +++ b/tests/Fixtures/TestBundle/Entity/TreeDummy.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity; + +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\GraphQl\Query; +use ApiPlatform\Metadata\GraphQl\QueryCollection; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; + +#[ApiResource(graphQlOperations: [new Query(), new QueryCollection()])] +#[ORM\Entity] +class TreeDummy +{ + #[ORM\Column(type: 'integer', nullable: true)] + #[ORM\Id] + #[ORM\GeneratedValue(strategy: 'AUTO')] + private ?int $id = null; + + #[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'children')] + public ?TreeDummy $parent = null; + + /** @var Collection */ + #[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')] + public Collection $children; + + public function __construct() + { + $this->children = new ArrayCollection(); + } + + public function getId(): ?int + { + return $this->id; + } + + public function getParent(): ?self + { + return $this->parent; + } + + public function setParent(?self $parent): void + { + $this->parent = $parent; + } + + public function getChildren(): Collection + { + return $this->children; + } +}