Skip to content

Commit 4c80a41

Browse files
authored
Merge pull request #110 from mcg-web/fix-resolve-field-bug
Fix resolve field bug
2 parents 1802903 + 4ce05de commit 4c80a41

File tree

6 files changed

+77
-43
lines changed

6 files changed

+77
-43
lines changed

Config/ObjectTypeDefinition.php

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Overblog\GraphQLBundle\Config;
1313

14+
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
1415
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
1516

1617
class ObjectTypeDefinition extends TypeWithOutputFieldsDefinition
@@ -35,6 +36,19 @@ public function getDefinition()
3536
->end()
3637
->end();
3738

39+
$this->treatFieldsDefaultAccess($node);
40+
$this->treatResolveField($node);
41+
42+
return $node;
43+
}
44+
45+
/**
46+
* set empty fields.access with fieldsDefaultAccess values if is set?
47+
*
48+
* @param ArrayNodeDefinition $node
49+
*/
50+
private function treatFieldsDefaultAccess(ArrayNodeDefinition $node)
51+
{
3852
$node->validate()
3953
->ifTrue(function ($v) {
4054
return array_key_exists('fieldsDefaultAccess', $v) && null !== $v['fieldsDefaultAccess'];
@@ -50,8 +64,35 @@ public function getDefinition()
5064

5165
return $v;
5266
})
53-
->end();
67+
->end();
68+
}
5469

55-
return $node;
70+
/**
71+
* resolveField is set as fields default resolver if not set
72+
* then remove resolveField to keep "access" feature
73+
* TODO(mcg-web) : get a cleaner way to use resolveField combine with "access" feature.
74+
*
75+
* @param ArrayNodeDefinition $node
76+
*/
77+
private function treatResolveField(ArrayNodeDefinition $node)
78+
{
79+
$node->validate()
80+
->ifTrue(function ($v) {
81+
return array_key_exists('resolveField', $v) && null !== $v['resolveField'];
82+
})
83+
->then(function ($v) {
84+
$resolveField = $v['resolveField'];
85+
unset($v['resolveField']);
86+
foreach ($v['fields'] as &$field) {
87+
if (!empty($field['resolve'])) {
88+
continue;
89+
}
90+
91+
$field['resolve'] = $resolveField;
92+
}
93+
94+
return $v;
95+
})
96+
->end();
5697
}
5798
}

Config/TypeWithOutputFieldsDefinition.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ protected function getBuilder($name, $type)
106106
$newName = 'Relay::'.rtrim($name, 'Args');
107107
if (isset($builderClassMap[$newName])) {
108108
@trigger_error(
109-
sprintf('The "%s" %s builder is deprecated as of 0.7 and will be removed in 0.8. Use "%s" instead.', $name, $type, $newName),
109+
sprintf('The "%s" %s builder is deprecated as of 0.7 and will be removed in 1.0. Use "%s" instead.', $name, $type, $newName),
110110
E_USER_DEPRECATED
111111
);
112112

@@ -162,7 +162,7 @@ protected function outputFieldsSelection($name)
162162
unset($field['builder']);
163163
} elseif (is_string($field)) {
164164
@trigger_error(
165-
'The builder short syntax (Field: Builder => Field: {builder: Builder}) is deprecated as of 0.7 and will be removed in 0.8. '.
165+
'The builder short syntax (Field: Builder => Field: {builder: Builder}) is deprecated as of 0.7 and will be removed in 0.9. '.
166166
'It will be replaced by the field type short syntax (Field: Type => Field: {type: Type})',
167167
E_USER_DEPRECATED
168168
);

Generator/TypeGenerator.php

Lines changed: 13 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
namespace Overblog\GraphQLBundle\Generator;
1313

14-
use Overblog\GraphQLBundle\Request\Executor;
1514
use Overblog\GraphQLGenerator\Generator\TypeGenerator as BaseTypeGenerator;
1615
use Symfony\Component\ClassLoader\MapClassLoader;
1716
use Symfony\Component\Filesystem\Filesystem;
@@ -77,10 +76,12 @@ protected function generateResolve(array $value)
7776
{
7877
$accessIsSet = $this->arrayKeyExistsAndIsNotNull($value, 'access');
7978
$fieldOptions = $value;
80-
$fieldOptions['resolve'] = $this->arrayKeyExistsAndIsNotNull($fieldOptions, 'resolve') ? $fieldOptions['resolve'] : $this->defaultResolver;
79+
if (!$this->arrayKeyExistsAndIsNotNull($fieldOptions, 'resolve')) {
80+
$fieldOptions['resolve'] = $this->defaultResolver;
81+
}
82+
$resolveCallback = parent::generateResolve($fieldOptions);
8183

8284
if (!$accessIsSet || true === $fieldOptions['access']) { // access granted to this field
83-
$resolveCallback = parent::generateResolve($fieldOptions);
8485
if ('null' === $resolveCallback) {
8586
return $resolveCallback;
8687
}
@@ -90,60 +91,37 @@ protected function generateResolve(array $value)
9091

9192
$code = <<<'CODE'
9293
function ($value, $args, $context, %s $info) <closureUseStatements> {
93-
<spaces><spaces>$onFulFilled = function ($value) use (%s, $args, $context, $info) {
94-
<spaces><spaces><spaces>$resolverCallback = %s;
95-
96-
<spaces><spaces><spaces>return call_user_func_array($resolverCallback, [$value, new %s($args), $context, $info]);
97-
<spaces><spaces>};
98-
99-
%s
94+
<spaces><spaces>$resolverCallback = %s;
95+
<spaces><spaces>return call_user_func_array($resolverCallback, [$value, new %s($args), $context, $info]);
10096
<spaces>}
10197
CODE;
10298

103-
return sprintf($code, $resolveInfoClass, static::USE_FOR_CLOSURES, $resolveCallback, $argumentClass, $this->promiseAdapter());
99+
return sprintf($code, $resolveInfoClass, $resolveCallback, $argumentClass);
104100
} elseif ($accessIsSet && false === $fieldOptions['access']) { // access deny to this field
105101
$exceptionClass = $this->shortenClassName('\\Overblog\\GraphQLBundle\\Error\\UserWarning');
106102

107103
return sprintf('function () { throw new %s(\'Access denied to this field.\'); }', $exceptionClass);
108104
} else { // wrap resolver with access
109-
$resolveCallback = parent::generateResolve($fieldOptions);
105+
110106
$accessChecker = $this->callableCallbackFromArrayValue($fieldOptions, 'access', '$value, $args, $context, \\GraphQL\\Type\\Definition\\ResolveInfo $info, $object');
111107
$resolveInfoClass = $this->shortenClassName('\\GraphQL\\Type\\Definition\\ResolveInfo');
112108
$argumentClass = $this->shortenClassName('\\Overblog\\GraphQLBundle\\Definition\\Argument');
113109

114110
$code = <<<'CODE'
115111
function ($value, $args, $context, %s $info) <closureUseStatements> {
116-
<spaces><spaces>$onFulFilled = function ($value) use (%s, $args, $context, $info) {
117-
<spaces><spaces><spaces>$resolverCallback = %s;
118-
<spaces><spaces><spaces>$accessChecker = %s;
119-
<spaces><spaces><spaces>$isMutation = $info instanceof ResolveInfo && 'mutation' === $info->operation->operation && $info->parentType === $info->schema->getMutationType();
120-
<spaces><spaces><spaces>return $container->get('overblog_graphql.access_resolver')->resolve($accessChecker, $resolverCallback, [$value, new %s($args), $context, $info], $isMutation);
121-
<spaces><spaces>};
122-
123-
%s
112+
<spaces><spaces>$resolverCallback = %s;
113+
<spaces><spaces>$accessChecker = %s;
114+
<spaces><spaces>$isMutation = $info instanceof ResolveInfo && 'mutation' === $info->operation->operation && $info->parentType === $info->schema->getMutationType();
115+
<spaces><spaces>return $container->get('overblog_graphql.access_resolver')->resolve($accessChecker, $resolverCallback, [$value, new %s($args), $context, $info], $isMutation);
124116
<spaces>}
125117
CODE;
126118

127-
$code = sprintf($code, $resolveInfoClass, static::USE_FOR_CLOSURES, $resolveCallback, $accessChecker, $argumentClass, $this->promiseAdapter());
119+
$code = sprintf($code, $resolveInfoClass, $resolveCallback, $accessChecker, $argumentClass);
128120

129121
return $code;
130122
}
131123
}
132124

133-
private function promiseAdapter()
134-
{
135-
$code = <<<'CODE'
136-
<spaces><spaces>$promiseAdapter = $container->get('%s');
137-
<spaces><spaces>if ($promiseAdapter->isThenable($value)) {
138-
<spaces><spaces><spaces>return $promiseAdapter->isThenable($value, $onFulFilled);
139-
<spaces><spaces>}
140-
<spaces><spaces>return $onFulFilled($value);
141-
CODE;
142-
$code = sprintf($code, Executor::PROMISE_ADAPTER_SERVICE_ID);
143-
144-
return $code;
145-
}
146-
147125
/**
148126
* @param array $value
149127
*

Tests/Functional/app/Resolver/NodeResolver.php

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Overblog\GraphQLBundle\Tests\Functional\app\Resolver;
1313

14+
use GraphQL\Type\Definition\ResolveInfo;
1415
use Overblog\GraphQLBundle\Resolver\TypeResolver;
1516

1617
class NodeResolver
@@ -31,12 +32,12 @@ class NodeResolver
3132

3233
private $photoData = [
3334
'3' => [
34-
'id' => 3,
35-
'width' => 300,
35+
'photoID' => 3,
36+
'photoWidth' => 300,
3637
],
3738
'4' => [
38-
'id' => 4,
39-
'width' => 400,
39+
'photoID' => 4,
40+
'photoWidth' => 400,
4041
],
4142
];
4243

@@ -45,6 +46,18 @@ public function __construct(TypeResolver $typeResolver)
4546
$this->typeResolver = $typeResolver;
4647
}
4748

49+
public function resolvePhotoField($value, ResolveInfo $info)
50+
{
51+
switch ($info->fieldName) {
52+
case 'id':
53+
return $value['photoID'];
54+
case 'width':
55+
return $value['photoWidth'];
56+
default:
57+
return null;
58+
}
59+
}
60+
4861
public function idFetcher($id)
4962
{
5063
if (isset($this->userData[$id])) {

Tests/Functional/app/config/node/config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ services:
1212
tags:
1313
- { name: "overblog_graphql.resolver", alias: "node_type", method: "typeResolver" }
1414
- { name: "overblog_graphql.resolver", alias: "node_id_fetcher", method: "idFetcher" }
15+
- { name: "overblog_graphql.resolver", alias: "resolve_photo_field", method: "resolvePhotoField" }
1516

1617
overblog_graphql:
1718
definitions:

Tests/Functional/app/config/node/mapping/Photo.types.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ Photo:
66
type: ID!
77
width:
88
type: Int
9+
resolveField: "@=resolver('resolve_photo_field', [value, info])"
910
interfaces: [Node]

0 commit comments

Comments
 (0)