Provide a path with a correct list index to resolveType callback of the union and interface types (fixes #396)

This commit is contained in:
Vladimir Razuvaev 2019-06-19 17:11:24 +07:00
parent 261f8f5ebd
commit 84a52c6c76
3 changed files with 160 additions and 2 deletions

View File

@ -949,6 +949,7 @@ class ReferenceExecutor implements ExecutorImplementation
foreach ($result as $item) {
$fieldPath = $path;
$fieldPath[] = $i++;
$info->path = $fieldPath;
$completedItem = $this->completeValueCatchingError($itemType, $fieldNodes, $info, $fieldPath, $item);
if (! $containsPromise && $this->getPromise($completedItem)) {
$containsPromise = true;

View File

@ -620,8 +620,9 @@ class CoroutineExecutor implements Runtime, ExecutorImplementation
foreach ($value as $itemValue) {
++$index;
$itemPath = $path;
$itemPath[] = $index; // !!! use arrays COW semantics
$itemPath = $path;
$itemPath[] = $index; // !!! use arrays COW semantics
$ctx->resolveInfo->path = $itemPath;
try {
if (! $this->completeValueFast($ctx, $itemType, $itemValue, $itemPath, $itemReturnValue)) {

View File

@ -0,0 +1,156 @@
<?php
declare(strict_types=1);
namespace GraphQL\Tests\Regression;
use GraphQL\GraphQL;
use GraphQL\Type\Definition\InterfaceType;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\UnionType;
use GraphQL\Type\Schema;
use PHPUnit\Framework\TestCase;
use function stristr;
/**
* @see https://github.com/webonyx/graphql-php/issues/396
*/
class Issue396Test extends TestCase
{
public function testUnionResolveType()
{
$a = new ObjectType(['name' => 'A', 'fields' => ['name' => Type::string()]]);
$b = new ObjectType(['name' => 'B', 'fields' => ['name' => Type::string()]]);
$c = new ObjectType(['name' => 'C', 'fields' => ['name' => Type::string()]]);
$log = [];
$unionResult = new UnionType([
'name' => 'UnionResult',
'types' => [$a, $b, $c],
'resolveType' => static function ($result, $root, ResolveInfo $info) use ($a, $b, $c, &$log) : Type {
$log[] = [$result, $info->path];
if (stristr($result['name'], 'A')) {
return $a;
}
if (stristr($result['name'], 'B')) {
return $b;
}
if (stristr($result['name'], 'C')) {
return $c;
}
},
]);
$exampleType = new ObjectType([
'name' => 'Example',
'fields' => [
'field' => [
'type' => Type::nonNull(Type::listOf(Type::nonNull($unionResult))),
'resolve' => static function () : array {
return [
['name' => 'A 1'],
['name' => 'B 2'],
['name' => 'C 3'],
];
},
],
],
]);
$schema = new Schema(['query' => $exampleType]);
$query = '
query {
field {
... on A {
name
}
... on B {
name
}
... on C {
name
}
}
}
';
GraphQL::executeQuery($schema, $query);
$expected = [
[['name' => 'A 1'], ['field', 0]],
[['name' => 'B 2'], ['field', 1]],
[['name' => 'C 3'], ['field', 2]],
];
self::assertEquals($expected, $log);
}
public function testInterfaceResolveType()
{
$log = [];
$interfaceResult = new InterfaceType([
'name' => 'InterfaceResult',
'fields' => [
'name' => Type::string(),
],
'resolveType' => static function ($result, $root, ResolveInfo $info) use (&$a, &$b, &$c, &$log) : Type {
$log[] = [$result, $info->path];
if (stristr($result['name'], 'A')) {
return $a;
}
if (stristr($result['name'], 'B')) {
return $b;
}
if (stristr($result['name'], 'C')) {
return $c;
}
},
]);
$a = new ObjectType(['name' => 'A', 'fields' => ['name' => Type::string()], 'interfaces' => [$interfaceResult]]);
$b = new ObjectType(['name' => 'B', 'fields' => ['name' => Type::string()], 'interfaces' => [$interfaceResult]]);
$c = new ObjectType(['name' => 'C', 'fields' => ['name' => Type::string()], 'interfaces' => [$interfaceResult]]);
$exampleType = new ObjectType([
'name' => 'Example',
'fields' => [
'field' => [
'type' => Type::nonNull(Type::listOf(Type::nonNull($interfaceResult))),
'resolve' => static function () : array {
return [
['name' => 'A 1'],
['name' => 'B 2'],
['name' => 'C 3'],
];
},
],
],
]);
$schema = new Schema([
'query' => $exampleType,
'types' => [$a, $b, $c],
]);
$query = '
query {
field {
name
}
}
';
GraphQL::executeQuery($schema, $query);
$expected = [
[['name' => 'A 1'], ['field', 0]],
[['name' => 'B 2'], ['field', 1]],
[['name' => 'C 3'], ['field', 2]],
];
self::assertEquals($expected, $log);
}
}