mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-22 12:56:05 +03:00
Allow providing default field resolver for execution call
This commit is contained in:
parent
9f4980ce49
commit
78d9ba0d5e
@ -44,12 +44,17 @@ class ExecutionContext
|
|||||||
*/
|
*/
|
||||||
public $variableValues;
|
public $variableValues;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var callable
|
||||||
|
*/
|
||||||
|
public $fieldResolver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
public $errors;
|
public $errors;
|
||||||
|
|
||||||
public function __construct($schema, $fragments, $root, $contextValue, $operation, $variables, $errors)
|
public function __construct($schema, $fragments, $root, $contextValue, $operation, $variables, $errors, $fieldResolver)
|
||||||
{
|
{
|
||||||
$this->schema = $schema;
|
$this->schema = $schema;
|
||||||
$this->fragments = $fragments;
|
$this->fragments = $fragments;
|
||||||
@ -58,6 +63,7 @@ class ExecutionContext
|
|||||||
$this->operation = $operation;
|
$this->operation = $operation;
|
||||||
$this->variableValues = $variables;
|
$this->variableValues = $variables;
|
||||||
$this->errors = $errors ?: [];
|
$this->errors = $errors ?: [];
|
||||||
|
$this->fieldResolver = $fieldResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addError(Error $error)
|
public function addError(Error $error)
|
||||||
|
@ -89,9 +89,18 @@ class Executor
|
|||||||
* @param $contextValue
|
* @param $contextValue
|
||||||
* @param array|\ArrayAccess $variableValues
|
* @param array|\ArrayAccess $variableValues
|
||||||
* @param null $operationName
|
* @param null $operationName
|
||||||
|
* @param callable $fieldResolver
|
||||||
* @return ExecutionResult|Promise
|
* @return ExecutionResult|Promise
|
||||||
*/
|
*/
|
||||||
public static function execute(Schema $schema, DocumentNode $ast, $rootValue = null, $contextValue = null, $variableValues = null, $operationName = null)
|
public static function execute(
|
||||||
|
Schema $schema,
|
||||||
|
DocumentNode $ast,
|
||||||
|
$rootValue = null,
|
||||||
|
$contextValue = null,
|
||||||
|
$variableValues = null,
|
||||||
|
$operationName = null,
|
||||||
|
$fieldResolver = null
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (null !== $variableValues) {
|
if (null !== $variableValues) {
|
||||||
Utils::invariant(
|
Utils::invariant(
|
||||||
@ -106,7 +115,15 @@ class Executor
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$exeContext = self::buildExecutionContext($schema, $ast, $rootValue, $contextValue, $variableValues, $operationName);
|
$exeContext = self::buildExecutionContext(
|
||||||
|
$schema,
|
||||||
|
$ast,
|
||||||
|
$rootValue,
|
||||||
|
$contextValue,
|
||||||
|
$variableValues,
|
||||||
|
$operationName,
|
||||||
|
$fieldResolver
|
||||||
|
);
|
||||||
$promiseAdapter = self::getPromiseAdapter();
|
$promiseAdapter = self::getPromiseAdapter();
|
||||||
|
|
||||||
$executor = new self($exeContext, $promiseAdapter);
|
$executor = new self($exeContext, $promiseAdapter);
|
||||||
@ -129,6 +146,8 @@ class Executor
|
|||||||
* @param $contextValue
|
* @param $contextValue
|
||||||
* @param $rawVariableValues
|
* @param $rawVariableValues
|
||||||
* @param string $operationName
|
* @param string $operationName
|
||||||
|
* @param callable $fieldResolver
|
||||||
|
*
|
||||||
* @return ExecutionContext
|
* @return ExecutionContext
|
||||||
* @throws Error
|
* @throws Error
|
||||||
*/
|
*/
|
||||||
@ -138,7 +157,8 @@ class Executor
|
|||||||
$rootValue,
|
$rootValue,
|
||||||
$contextValue,
|
$contextValue,
|
||||||
$rawVariableValues,
|
$rawVariableValues,
|
||||||
$operationName = null
|
$operationName = null,
|
||||||
|
$fieldResolver = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
$errors = [];
|
$errors = [];
|
||||||
@ -183,7 +203,16 @@ class Executor
|
|||||||
$rawVariableValues ?: []
|
$rawVariableValues ?: []
|
||||||
);
|
);
|
||||||
|
|
||||||
$exeContext = new ExecutionContext($schema, $fragments, $rootValue, $contextValue, $operation, $variableValues, $errors);
|
$exeContext = new ExecutionContext(
|
||||||
|
$schema,
|
||||||
|
$fragments,
|
||||||
|
$rootValue,
|
||||||
|
$contextValue,
|
||||||
|
$operation,
|
||||||
|
$variableValues,
|
||||||
|
$errors,
|
||||||
|
$fieldResolver ?: self::$defaultFieldResolver
|
||||||
|
);
|
||||||
return $exeContext;
|
return $exeContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -625,7 +654,7 @@ class Executor
|
|||||||
} else if (isset($parentType->resolveFieldFn)) {
|
} else if (isset($parentType->resolveFieldFn)) {
|
||||||
$resolveFn = $parentType->resolveFieldFn;
|
$resolveFn = $parentType->resolveFieldFn;
|
||||||
} else {
|
} else {
|
||||||
$resolveFn = self::$defaultFieldResolver;
|
$resolveFn = $this->exeContext->fieldResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The resolve function's optional third argument is a context value that
|
// The resolve function's optional third argument is a context value that
|
||||||
|
@ -17,16 +17,60 @@ use GraphQL\Validator\Rules\QueryComplexity;
|
|||||||
class GraphQL
|
class GraphQL
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
* This is the primary entry point function for fulfilling GraphQL operations
|
||||||
|
* by parsing, validating, and executing a GraphQL document along side a
|
||||||
|
* GraphQL schema.
|
||||||
|
*
|
||||||
|
* More sophisticated GraphQL servers, such as those which persist queries,
|
||||||
|
* may wish to separate the validation and execution phases to a static time
|
||||||
|
* tooling step, and a server runtime step.
|
||||||
|
*
|
||||||
|
* schema:
|
||||||
|
* The GraphQL type system to use when validating and executing a query.
|
||||||
|
* requestString:
|
||||||
|
* A GraphQL language formatted string representing the requested operation.
|
||||||
|
* rootValue:
|
||||||
|
* The value provided as the first argument to resolver functions on the top
|
||||||
|
* level type (e.g. the query object type).
|
||||||
|
* variableValues:
|
||||||
|
* A mapping of variable name to runtime value to use for all variables
|
||||||
|
* defined in the requestString.
|
||||||
|
* operationName:
|
||||||
|
* The name of the operation to use if requestString contains multiple
|
||||||
|
* possible operations. Can be omitted if requestString contains only
|
||||||
|
* one operation.
|
||||||
|
* fieldResolver:
|
||||||
|
* A resolver function to use when one is not provided by the schema.
|
||||||
|
* If not provided, the default field resolver is used (which looks for a
|
||||||
|
* value or method on the source value with the field's name).
|
||||||
|
*
|
||||||
* @param Schema $schema
|
* @param Schema $schema
|
||||||
* @param string|DocumentNode $requestString
|
* @param string|DocumentNode $requestString
|
||||||
* @param mixed $rootValue
|
* @param mixed $rootValue
|
||||||
* @param array|null $variableValues
|
* @param array|null $variableValues
|
||||||
* @param string|null $operationName
|
* @param string|null $operationName
|
||||||
|
* @param callable $fieldResolver
|
||||||
* @return Promise|array
|
* @return Promise|array
|
||||||
*/
|
*/
|
||||||
public static function execute(Schema $schema, $requestString, $rootValue = null, $contextValue = null, $variableValues = null, $operationName = null)
|
public static function execute(
|
||||||
|
Schema $schema,
|
||||||
|
$requestString,
|
||||||
|
$rootValue = null,
|
||||||
|
$contextValue = null,
|
||||||
|
$variableValues = null,
|
||||||
|
$operationName = null,
|
||||||
|
$fieldResolver = null
|
||||||
|
)
|
||||||
{
|
{
|
||||||
$result = self::executeAndReturnResult($schema, $requestString, $rootValue, $contextValue, $variableValues, $operationName);
|
$result = self::executeAndReturnResult(
|
||||||
|
$schema,
|
||||||
|
$requestString,
|
||||||
|
$rootValue,
|
||||||
|
$contextValue,
|
||||||
|
$variableValues,
|
||||||
|
$operationName,
|
||||||
|
$fieldResolver
|
||||||
|
);
|
||||||
|
|
||||||
if ($result instanceof ExecutionResult) {
|
if ($result instanceof ExecutionResult) {
|
||||||
return $result->toArray();
|
return $result->toArray();
|
||||||
@ -40,14 +84,26 @@ class GraphQL
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Same as `execute`, but returns instance of ExecutionResult instead of array,
|
||||||
|
* which can be used for custom error formatting or adding extensions to response
|
||||||
|
*
|
||||||
* @param Schema $schema
|
* @param Schema $schema
|
||||||
* @param string|DocumentNode $requestString
|
* @param string|DocumentNode $requestString
|
||||||
* @param mixed $rootValue
|
* @param mixed $rootValue
|
||||||
* @param array|null $variableValues
|
* @param array|null $variableValues
|
||||||
* @param string|null $operationName
|
* @param string|null $operationName
|
||||||
|
* @param callable $fieldResolver
|
||||||
* @return ExecutionResult|Promise
|
* @return ExecutionResult|Promise
|
||||||
*/
|
*/
|
||||||
public static function executeAndReturnResult(Schema $schema, $requestString, $rootValue = null, $contextValue = null, $variableValues = null, $operationName = null)
|
public static function executeAndReturnResult(
|
||||||
|
Schema $schema,
|
||||||
|
$requestString,
|
||||||
|
$rootValue = null,
|
||||||
|
$contextValue = null,
|
||||||
|
$variableValues = null,
|
||||||
|
$operationName = null,
|
||||||
|
$fieldResolver = null
|
||||||
|
)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if ($requestString instanceof DocumentNode) {
|
if ($requestString instanceof DocumentNode) {
|
||||||
@ -66,7 +122,15 @@ class GraphQL
|
|||||||
if (!empty($validationErrors)) {
|
if (!empty($validationErrors)) {
|
||||||
return new ExecutionResult(null, $validationErrors);
|
return new ExecutionResult(null, $validationErrors);
|
||||||
} else {
|
} else {
|
||||||
return Executor::execute($schema, $documentNode, $rootValue, $contextValue, $variableValues, $operationName);
|
return Executor::execute(
|
||||||
|
$schema,
|
||||||
|
$documentNode,
|
||||||
|
$rootValue,
|
||||||
|
$contextValue,
|
||||||
|
$variableValues,
|
||||||
|
$operationName,
|
||||||
|
$fieldResolver
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (Error $e) {
|
} catch (Error $e) {
|
||||||
return new ExecutionResult(null, [$e]);
|
return new ExecutionResult(null, [$e]);
|
||||||
|
@ -972,6 +972,44 @@ class ExecutorTest extends \PHPUnit_Framework_TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it uses a custom field resolver
|
||||||
|
*/
|
||||||
|
public function testUsesACustomFieldResolver()
|
||||||
|
{
|
||||||
|
$query = Parser::parse('{ foo }');
|
||||||
|
|
||||||
|
$schema = new Schema([
|
||||||
|
'query' => new ObjectType([
|
||||||
|
'name' => 'Query',
|
||||||
|
'fields' => [
|
||||||
|
'foo' => ['type' => Type::string()]
|
||||||
|
]
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
|
||||||
|
// For the purposes of test, just return the name of the field!
|
||||||
|
$customResolver = function ($source, $args, $context, ResolveInfo $info) {
|
||||||
|
return $info->fieldName;
|
||||||
|
};
|
||||||
|
|
||||||
|
$result = Executor::execute(
|
||||||
|
$schema,
|
||||||
|
$query,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
$customResolver
|
||||||
|
);
|
||||||
|
|
||||||
|
$expected = [
|
||||||
|
'data' => ['foo' => 'foo']
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
}
|
||||||
|
|
||||||
public function testSubstitutesArgumentWithDefaultValue()
|
public function testSubstitutesArgumentWithDefaultValue()
|
||||||
{
|
{
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
|
Loading…
Reference in New Issue
Block a user