Skip to content

Commit

Permalink
Merge 62e807b into 5289a54
Browse files Browse the repository at this point in the history
  • Loading branch information
brunobg committed Jan 19, 2021
2 parents 5289a54 + 62e807b commit 0862376
Show file tree
Hide file tree
Showing 2 changed files with 195 additions and 1 deletion.
13 changes: 12 additions & 1 deletion src/Executor/Executor.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use GraphQL\Language\AST\DocumentNode;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQL\Type\Schema;
use Throwable;
use function is_array;
use function is_object;

Expand Down Expand Up @@ -173,10 +174,20 @@ public static function defaultFieldResolver($objectValue, $args, $contextValue,
$fieldName = $info->fieldName;
$property = null;

if (is_array($objectValue) || $objectValue instanceof ArrayAccess) {
if (is_array($objectValue)) {
if (isset($objectValue[$fieldName])) {
$property = $objectValue[$fieldName];
}
} elseif ($objectValue instanceof ArrayAccess) {
// handles #759: ArrayAccess::offsetExists() can call offsetGet() internally,
// which results in calling offsetGet() twice.
// This avoids the double call and handles Exceptions to have the same
// behavior as isset() in the pure array case.
try {
$property = $objectValue[$fieldName];
} catch (Throwable $e) {
// pass
}
} elseif (is_object($objectValue)) {
if (isset($objectValue->{$fieldName})) {
$property = $objectValue->{$fieldName};
Expand Down
183 changes: 183 additions & 0 deletions tests/Executor/ExecutorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace GraphQL\Tests\Executor;

use ArrayAccess;
use Exception;
use GraphQL\Deferred;
use GraphQL\Error\Error;
use GraphQL\Error\UserError;
Expand Down Expand Up @@ -1225,4 +1227,185 @@ public function testSerializesToEmptyObjectVsEmptyArray() : void
$result->toArray()
);
}

public function testDefaultResolverGrabsValuesOffOfCommonPhpDataStructures() : void
{
$Array = new ObjectType([
'name' => 'Array',
'fields' => [
'set' => Type::int(),
'unset' => Type::int(),
],
]);

$ArrayAccess = new ObjectType([
'name' => 'ArrayAccess',
'fields' => [
'set' => Type::int(),
'unsetNull' => Type::int(),
'unsetThrow' => Type::int(),
],
]);

$ObjectField = new ObjectType([
'name' => 'ObjectField',
'fields' => [
'set' => Type::int(),
'unset' => Type::int(),
'nonExistent' => Type::int(),
],
]);

$ObjectVirtual = new ObjectType([
'name' => 'ObjectVirtual',
'fields' => [
'set' => Type::int(),
'unsetNull' => Type::int(),
'unsetThrow' => Type::int(),
],
]);

$schema = new Schema([
'query' => new ObjectType([
'name' => 'Query',
'fields' => [
'array' => [
'type' => $Array,
'resolve' => static function () : array {
return ['set' => 1];
},
],
'arrayAccess' => [
'type' => $ArrayAccess,
'resolve' => static function () : ArrayAccess {
return new class implements ArrayAccess {
public function offsetExists($offset)
{
switch ($offset) {
case 'set':
return true;
default:
return false;
}
}

public function offsetGet($offset)
{
switch ($offset) {
case 'set':
return 1;
case 'unsetNull':
return null;
default:
throw new Exception('unsetThrow');
}
}

public function offsetSet($offset, $value)
{
}

public function offsetUnset($offset)
{
}
};
},
],
'objectField' => [
'type' => $ObjectField,
'resolve' => static function () : stdClass {
return new class extends stdClass {
/** @var int|null */
public $set = 1;

/** @var int|null */
public $unset;
};
},
],
'objectVirtual' => [
'type' => $ObjectVirtual,
'resolve' => static function () {
return new class {
public function __isset($name) : bool
{
switch ($name) {
case 'set':
return true;
default:
return false;
}
}

public function __get($name) : ?int
{
switch ($name) {
case 'set':
return 1;
case 'unsetNull':
return null;
default:
throw new Exception('unsetThrow');
}
}
};
},
],
],
]),
]);

$query = Parser::parse('
{
array {
set
unset
}
arrayAccess {
set
unsetNull
unsetThrow
}
objectField {
set
unset
nonExistent
}
objectVirtual {
set
unsetNull
unsetThrow
}
}
');

$result = Executor::execute($schema, $query);

self::assertEquals(
[
'data' => [
'array' => [
'set' => 1,
'unset' => null,
],
'arrayAccess' => [
'set' => 1,
'unsetNull' => null,
'unsetThrow' => null,
],
'objectField' => [
'set' => 1,
'unset' => null,
'nonExistent' => null,
],
'objectVirtual' => [
'set' => 1,
'unsetNull' => null,
'unsetThrow' => null,
],
],
],
$result->toArray()
);
}
}

0 comments on commit 0862376

Please sign in to comment.