Skip to content

Commit 4630af7

Browse files
authored
fix: null iterable field should be resolved directly (#4092)
1 parent ff248ae commit 4630af7

File tree

7 files changed

+141
-1
lines changed

7 files changed

+141
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* OpenAPI: Fix error when schema is empty (#4051)
1414
* OpenAPI: Do not set scheme to oauth2 when generating securitySchemes (#4073)
1515
* OpenAPI: Fix missing `$ref` when no `type` is used in context (#4076)
16+
* GraphQL: Fix "Resource class cannot be determined." error when a null iterable field is returned (#4092)
1617

1718
## 2.6.2
1819

features/graphql/query.feature

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,23 @@ Feature: GraphQL query support
5959
And the JSON node "data.dummy.jsonData.bar" should be equal to 5
6060
And the JSON node "data.dummy.arrayData[2]" should be equal to baz
6161

62+
Scenario: Retrieve an item with an iterable null field
63+
Given there are 2 dummy with null JSON objects
64+
When I send the following GraphQL request:
65+
"""
66+
{
67+
withJsonDummy(id: "/with_json_dummies/2") {
68+
id
69+
json
70+
}
71+
}
72+
"""
73+
Then the response status code should be 200
74+
And the response should be in JSON
75+
And the header "Content-Type" should be equal to "application/json"
76+
And the JSON node "data.withJsonDummy.id" should be equal to "/with_json_dummies/2"
77+
And the JSON node "data.withJsonDummy.json" should be null
78+
6279
Scenario: Retrieve an item through a GraphQL query with variables
6380
When I have the following GraphQL request:
6481
"""

src/GraphQl/Resolver/Factory/ItemResolverFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public function __invoke(?string $resourceClass = null, ?string $rootClass = nul
5959
{
6060
return function (?array $source, array $args, $context, ResolveInfo $info) use ($resourceClass, $rootClass, $operationName) {
6161
// Data already fetched and normalized (field or nested resource)
62-
if (isset($source[$info->fieldName])) {
62+
if ($source && \array_key_exists($info->fieldName, $source)) {
6363
return $source[$info->fieldName];
6464
}
6565

tests/Behat/DoctrineContext.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\ThirdLevel as ThirdLevelDocument;
8181
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\UrlEncodedId as UrlEncodedIdDocument;
8282
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\User as UserDocument;
83+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\WithJsonDummy as WithJsonDummyDocument;
8384
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\AbsoluteUrlDummy;
8485
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\AbsoluteUrlRelationDummy;
8586
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Address;
@@ -154,6 +155,7 @@
154155
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\UrlEncodedId;
155156
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\User;
156157
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\UuidIdentifierDummy;
158+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\WithJsonDummy;
157159
use Behat\Behat\Context\Context;
158160
use Behat\Gherkin\Node\PyStringNode;
159161
use Doctrine\ODM\MongoDB\DocumentManager;
@@ -573,6 +575,21 @@ public function thereAreDummyObjectsWithJsonData(int $nb)
573575
$this->manager->flush();
574576
}
575577

578+
/**
579+
* @Given there are :nb dummy with null JSON objects
580+
*/
581+
public function thereAreDummyWithNullJsonObjects(int $nb)
582+
{
583+
for ($i = 1; $i <= $nb; ++$i) {
584+
$dummy = $this->buildWithJsonDummy();
585+
$dummy->json = null;
586+
587+
$this->manager->persist($dummy);
588+
}
589+
590+
$this->manager->flush();
591+
}
592+
576593
/**
577594
* @Given there are :nb dummy objects with relatedDummy and its thirdLevel
578595
* @Given there is :nb dummy object with relatedDummy and its thirdLevel
@@ -2190,4 +2207,12 @@ private function buildCustomMultipleIdentifierDummy()
21902207
{
21912208
return $this->isOrm() ? new CustomMultipleIdentifierDummy() : new CustomMultipleIdentifierDummyDocument();
21922209
}
2210+
2211+
/**
2212+
* @return WithJsonDummy|WithJsonDummyDocument
2213+
*/
2214+
private function buildWithJsonDummy()
2215+
{
2216+
return $this->isOrm() ? new WithJsonDummy() : new WithJsonDummyDocument();
2217+
}
21932218
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\Document;
15+
16+
use ApiPlatform\Core\Annotation\ApiResource;
17+
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
18+
19+
/**
20+
* @ApiResource
21+
* @ODM\Document
22+
*/
23+
class WithJsonDummy
24+
{
25+
/**
26+
* @var int
27+
*
28+
* @ODM\Id(strategy="INCREMENT", type="int", nullable=true)
29+
*/
30+
private $id;
31+
32+
/**
33+
* @var array|null
34+
*
35+
* @ODM\Field(type="hash", nullable=true)
36+
*/
37+
public $json;
38+
39+
public function getId(): int
40+
{
41+
return $this->id;
42+
}
43+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity;
15+
16+
use ApiPlatform\Core\Annotation\ApiResource;
17+
use Doctrine\ORM\Mapping as ORM;
18+
19+
/**
20+
* @ApiResource
21+
* @ORM\Entity
22+
*/
23+
class WithJsonDummy
24+
{
25+
/**
26+
* @var int
27+
*
28+
* @ORM\Column(type="integer", nullable=true)
29+
* @ORM\Id
30+
* @ORM\GeneratedValue(strategy="AUTO")
31+
*/
32+
private $id;
33+
34+
/**
35+
* @var array|null
36+
*
37+
* @ORM\Column(type="json", nullable=true)
38+
*/
39+
public $json;
40+
41+
public function getId(): int
42+
{
43+
return $this->id;
44+
}
45+
}

tests/GraphQl/Resolver/Factory/ItemResolverFactoryTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,15 @@ public function testResolveNested(): void
118118
$this->assertSame(['already_serialized'], ($this->itemResolverFactory)('resourceClass')($source, [], null, $info));
119119
}
120120

121+
public function testResolveNestedNullValue(): void
122+
{
123+
$source = ['nestedNullValue' => null];
124+
$info = $this->prophesize(ResolveInfo::class)->reveal();
125+
$info->fieldName = 'nestedNullValue';
126+
127+
$this->assertNull(($this->itemResolverFactory)('resourceClass')($source, [], null, $info));
128+
}
129+
121130
public function testResolveBadReadStageItem(): void
122131
{
123132
$resourceClass = 'stdClass';

0 commit comments

Comments
 (0)