Skip to content

Commit 78d9ba0

Browse files
committed
Allow providing default field resolver for execution call
1 parent 9f4980c commit 78d9ba0

File tree

4 files changed

+147
-10
lines changed

4 files changed

+147
-10
lines changed

src/Executor/ExecutionContext.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,17 @@ class ExecutionContext
4444
*/
4545
public $variableValues;
4646

47+
/**
48+
* @var callable
49+
*/
50+
public $fieldResolver;
51+
4752
/**
4853
* @var array
4954
*/
5055
public $errors;
5156

52-
public function __construct($schema, $fragments, $root, $contextValue, $operation, $variables, $errors)
57+
public function __construct($schema, $fragments, $root, $contextValue, $operation, $variables, $errors, $fieldResolver)
5358
{
5459
$this->schema = $schema;
5560
$this->fragments = $fragments;
@@ -58,6 +63,7 @@ public function __construct($schema, $fragments, $root, $contextValue, $operatio
5863
$this->operation = $operation;
5964
$this->variableValues = $variables;
6065
$this->errors = $errors ?: [];
66+
$this->fieldResolver = $fieldResolver;
6167
}
6268

6369
public function addError(Error $error)

src/Executor/Executor.php

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,18 @@ public static function setDefaultFieldResolver(callable $fn)
8989
* @param $contextValue
9090
* @param array|\ArrayAccess $variableValues
9191
* @param null $operationName
92+
* @param callable $fieldResolver
9293
* @return ExecutionResult|Promise
9394
*/
94-
public static function execute(Schema $schema, DocumentNode $ast, $rootValue = null, $contextValue = null, $variableValues = null, $operationName = null)
95+
public static function execute(
96+
Schema $schema,
97+
DocumentNode $ast,
98+
$rootValue = null,
99+
$contextValue = null,
100+
$variableValues = null,
101+
$operationName = null,
102+
$fieldResolver = null
103+
)
95104
{
96105
if (null !== $variableValues) {
97106
Utils::invariant(
@@ -106,7 +115,15 @@ public static function execute(Schema $schema, DocumentNode $ast, $rootValue = n
106115
);
107116
}
108117

109-
$exeContext = self::buildExecutionContext($schema, $ast, $rootValue, $contextValue, $variableValues, $operationName);
118+
$exeContext = self::buildExecutionContext(
119+
$schema,
120+
$ast,
121+
$rootValue,
122+
$contextValue,
123+
$variableValues,
124+
$operationName,
125+
$fieldResolver
126+
);
110127
$promiseAdapter = self::getPromiseAdapter();
111128

112129
$executor = new self($exeContext, $promiseAdapter);
@@ -129,6 +146,8 @@ public static function execute(Schema $schema, DocumentNode $ast, $rootValue = n
129146
* @param $contextValue
130147
* @param $rawVariableValues
131148
* @param string $operationName
149+
* @param callable $fieldResolver
150+
*
132151
* @return ExecutionContext
133152
* @throws Error
134153
*/
@@ -138,7 +157,8 @@ private static function buildExecutionContext(
138157
$rootValue,
139158
$contextValue,
140159
$rawVariableValues,
141-
$operationName = null
160+
$operationName = null,
161+
$fieldResolver = null
142162
)
143163
{
144164
$errors = [];
@@ -183,7 +203,16 @@ private static function buildExecutionContext(
183203
$rawVariableValues ?: []
184204
);
185205

186-
$exeContext = new ExecutionContext($schema, $fragments, $rootValue, $contextValue, $operation, $variableValues, $errors);
206+
$exeContext = new ExecutionContext(
207+
$schema,
208+
$fragments,
209+
$rootValue,
210+
$contextValue,
211+
$operation,
212+
$variableValues,
213+
$errors,
214+
$fieldResolver ?: self::$defaultFieldResolver
215+
);
187216
return $exeContext;
188217
}
189218

@@ -625,7 +654,7 @@ private function resolveField(ObjectType $parentType, $source, $fieldNodes, $pat
625654
} else if (isset($parentType->resolveFieldFn)) {
626655
$resolveFn = $parentType->resolveFieldFn;
627656
} else {
628-
$resolveFn = self::$defaultFieldResolver;
657+
$resolveFn = $this->exeContext->fieldResolver;
629658
}
630659

631660
// The resolve function's optional third argument is a context value that

src/GraphQL.php

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,60 @@
1717
class GraphQL
1818
{
1919
/**
20+
* This is the primary entry point function for fulfilling GraphQL operations
21+
* by parsing, validating, and executing a GraphQL document along side a
22+
* GraphQL schema.
23+
*
24+
* More sophisticated GraphQL servers, such as those which persist queries,
25+
* may wish to separate the validation and execution phases to a static time
26+
* tooling step, and a server runtime step.
27+
*
28+
* schema:
29+
* The GraphQL type system to use when validating and executing a query.
30+
* requestString:
31+
* A GraphQL language formatted string representing the requested operation.
32+
* rootValue:
33+
* The value provided as the first argument to resolver functions on the top
34+
* level type (e.g. the query object type).
35+
* variableValues:
36+
* A mapping of variable name to runtime value to use for all variables
37+
* defined in the requestString.
38+
* operationName:
39+
* The name of the operation to use if requestString contains multiple
40+
* possible operations. Can be omitted if requestString contains only
41+
* one operation.
42+
* fieldResolver:
43+
* A resolver function to use when one is not provided by the schema.
44+
* If not provided, the default field resolver is used (which looks for a
45+
* value or method on the source value with the field's name).
46+
*
2047
* @param Schema $schema
2148
* @param string|DocumentNode $requestString
2249
* @param mixed $rootValue
2350
* @param array|null $variableValues
2451
* @param string|null $operationName
52+
* @param callable $fieldResolver
2553
* @return Promise|array
2654
*/
27-
public static function execute(Schema $schema, $requestString, $rootValue = null, $contextValue = null, $variableValues = null, $operationName = null)
55+
public static function execute(
56+
Schema $schema,
57+
$requestString,
58+
$rootValue = null,
59+
$contextValue = null,
60+
$variableValues = null,
61+
$operationName = null,
62+
$fieldResolver = null
63+
)
2864
{
29-
$result = self::executeAndReturnResult($schema, $requestString, $rootValue, $contextValue, $variableValues, $operationName);
65+
$result = self::executeAndReturnResult(
66+
$schema,
67+
$requestString,
68+
$rootValue,
69+
$contextValue,
70+
$variableValues,
71+
$operationName,
72+
$fieldResolver
73+
);
3074

3175
if ($result instanceof ExecutionResult) {
3276
return $result->toArray();
@@ -40,14 +84,26 @@ public static function execute(Schema $schema, $requestString, $rootValue = null
4084
}
4185

4286
/**
87+
* Same as `execute`, but returns instance of ExecutionResult instead of array,
88+
* which can be used for custom error formatting or adding extensions to response
89+
*
4390
* @param Schema $schema
4491
* @param string|DocumentNode $requestString
4592
* @param mixed $rootValue
4693
* @param array|null $variableValues
4794
* @param string|null $operationName
95+
* @param callable $fieldResolver
4896
* @return ExecutionResult|Promise
4997
*/
50-
public static function executeAndReturnResult(Schema $schema, $requestString, $rootValue = null, $contextValue = null, $variableValues = null, $operationName = null)
98+
public static function executeAndReturnResult(
99+
Schema $schema,
100+
$requestString,
101+
$rootValue = null,
102+
$contextValue = null,
103+
$variableValues = null,
104+
$operationName = null,
105+
$fieldResolver = null
106+
)
51107
{
52108
try {
53109
if ($requestString instanceof DocumentNode) {
@@ -66,7 +122,15 @@ public static function executeAndReturnResult(Schema $schema, $requestString, $r
66122
if (!empty($validationErrors)) {
67123
return new ExecutionResult(null, $validationErrors);
68124
} else {
69-
return Executor::execute($schema, $documentNode, $rootValue, $contextValue, $variableValues, $operationName);
125+
return Executor::execute(
126+
$schema,
127+
$documentNode,
128+
$rootValue,
129+
$contextValue,
130+
$variableValues,
131+
$operationName,
132+
$fieldResolver
133+
);
70134
}
71135
} catch (Error $e) {
72136
return new ExecutionResult(null, [$e]);

tests/Executor/ExecutorTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,44 @@ public function testFailsToExecuteQueryContainingTypeDefinition()
972972
}
973973
}
974974

975+
/**
976+
* @it uses a custom field resolver
977+
*/
978+
public function testUsesACustomFieldResolver()
979+
{
980+
$query = Parser::parse('{ foo }');
981+
982+
$schema = new Schema([
983+
'query' => new ObjectType([
984+
'name' => 'Query',
985+
'fields' => [
986+
'foo' => ['type' => Type::string()]
987+
]
988+
])
989+
]);
990+
991+
// For the purposes of test, just return the name of the field!
992+
$customResolver = function ($source, $args, $context, ResolveInfo $info) {
993+
return $info->fieldName;
994+
};
995+
996+
$result = Executor::execute(
997+
$schema,
998+
$query,
999+
null,
1000+
null,
1001+
null,
1002+
null,
1003+
$customResolver
1004+
);
1005+
1006+
$expected = [
1007+
'data' => ['foo' => 'foo']
1008+
];
1009+
1010+
$this->assertEquals($expected, $result->toArray());
1011+
}
1012+
9751013
public function testSubstitutesArgumentWithDefaultValue()
9761014
{
9771015
$schema = new Schema([

0 commit comments

Comments
 (0)