Skip to content

Commit

Permalink
fix: null iterable field should be resolved directly
Browse files Browse the repository at this point in the history
  • Loading branch information
alanpoulain committed Feb 23, 2021
1 parent ff248ae commit bc1b959
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -13,6 +13,7 @@
* OpenAPI: Fix error when schema is empty (#4051)
* OpenAPI: Do not set scheme to oauth2 when generating securitySchemes (#4073)
* OpenAPI: Fix missing `$ref` when no `type` is used in context (#4076)
* GraphQL: Fix "Resource class cannot be determined." error when a null iterable field is returned (#4092)

## 2.6.2

Expand Down
17 changes: 17 additions & 0 deletions features/graphql/query.feature
Expand Up @@ -59,6 +59,23 @@ Feature: GraphQL query support
And the JSON node "data.dummy.jsonData.bar" should be equal to 5
And the JSON node "data.dummy.arrayData[2]" should be equal to baz

Scenario: Retrieve an item with an iterable null field
Given there are 2 dummy with null JSON objects
When I send the following GraphQL request:
"""
{
withJsonDummy(id: "/with_json_dummies/2") {
id
json
}
}
"""
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 "data.withJsonDummy.id" should be equal to "/with_json_dummies/2"
And the JSON node "data.withJsonDummy.json" should be null

Scenario: Retrieve an item through a GraphQL query with variables
When I have the following GraphQL request:
"""
Expand Down
2 changes: 1 addition & 1 deletion src/GraphQl/Resolver/Factory/ItemResolverFactory.php
Expand Up @@ -59,7 +59,7 @@ public function __invoke(?string $resourceClass = null, ?string $rootClass = nul
{
return function (?array $source, array $args, $context, ResolveInfo $info) use ($resourceClass, $rootClass, $operationName) {
// Data already fetched and normalized (field or nested resource)
if (isset($source[$info->fieldName])) {
if ($source && array_key_exists($info->fieldName, $source)) {
return $source[$info->fieldName];
}

Expand Down
25 changes: 25 additions & 0 deletions tests/Behat/DoctrineContext.php
Expand Up @@ -80,6 +80,7 @@
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\ThirdLevel as ThirdLevelDocument;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\UrlEncodedId as UrlEncodedIdDocument;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\User as UserDocument;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\WithJsonDummy as WithJsonDummyDocument;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\AbsoluteUrlDummy;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\AbsoluteUrlRelationDummy;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Address;
Expand Down Expand Up @@ -154,6 +155,7 @@
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\UrlEncodedId;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\User;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\UuidIdentifierDummy;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\WithJsonDummy;
use Behat\Behat\Context\Context;
use Behat\Gherkin\Node\PyStringNode;
use Doctrine\ODM\MongoDB\DocumentManager;
Expand Down Expand Up @@ -573,6 +575,21 @@ public function thereAreDummyObjectsWithJsonData(int $nb)
$this->manager->flush();
}

/**
* @Given there are :nb dummy with null JSON objects
*/
public function thereAreDummyWithNullJsonObjects(int $nb)
{
for ($i = 1; $i <= $nb; ++$i) {
$dummy = $this->buildWithJsonDummy();
$dummy->json = null;

$this->manager->persist($dummy);
}

$this->manager->flush();
}

/**
* @Given there are :nb dummy objects with relatedDummy and its thirdLevel
* @Given there is :nb dummy object with relatedDummy and its thirdLevel
Expand Down Expand Up @@ -2190,4 +2207,12 @@ private function buildCustomMultipleIdentifierDummy()
{
return $this->isOrm() ? new CustomMultipleIdentifierDummy() : new CustomMultipleIdentifierDummyDocument();
}

/**
* @return WithJsonDummy|WithJsonDummyDocument
*/
private function buildWithJsonDummy()
{
return $this->isOrm() ? new WithJsonDummy() : new WithJsonDummyDocument();
}
}
43 changes: 43 additions & 0 deletions tests/Fixtures/TestBundle/Document/WithJsonDummy.php
@@ -0,0 +1,43 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* 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\Core\Tests\Fixtures\TestBundle\Document;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;

/**
* @ApiResource
* @ODM\Document
*/
class WithJsonDummy
{
/**
* @var int
*
* @ODM\Id(strategy="INCREMENT", type="int", nullable=true)
*/
private $id;

/**
* @var ?array
*
* @ODM\Field(type="hash", nullable=true)
*/
public $json;

public function getId(): int
{
return $this->id;
}
}
45 changes: 45 additions & 0 deletions tests/Fixtures/TestBundle/Entity/WithJsonDummy.php
@@ -0,0 +1,45 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* 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\Core\Tests\Fixtures\TestBundle\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;

/**
* @ApiResource
* @ORM\Entity
*/
class WithJsonDummy
{
/**
* @var int
*
* @ORM\Column(type="integer", nullable=true)
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;

/**
* @var ?array
*
* @ORM\Column(type="json", nullable=true)
*/
public $json;

public function getId(): int
{
return $this->id;
}
}
9 changes: 9 additions & 0 deletions tests/GraphQl/Resolver/Factory/ItemResolverFactoryTest.php
Expand Up @@ -118,6 +118,15 @@ public function testResolveNested(): void
$this->assertSame(['already_serialized'], ($this->itemResolverFactory)('resourceClass')($source, [], null, $info));
}

public function testResolveNestedNullValue(): void
{
$source = ['nestedNullValue' => null];
$info = $this->prophesize(ResolveInfo::class)->reveal();
$info->fieldName = 'nestedNullValue';

$this->assertNull(($this->itemResolverFactory)('resourceClass')($source, [], null, $info));
}

public function testResolveBadReadStageItem(): void
{
$resourceClass = 'stdClass';
Expand Down

0 comments on commit bc1b959

Please sign in to comment.