graphql-php/src/GraphQL.php

352 lines
10 KiB
PHP
Raw Normal View History

2015-07-15 23:05:46 +06:00
<?php
2018-09-02 10:17:27 +02:00
declare(strict_types=1);
2015-07-15 23:05:46 +06:00
namespace GraphQL;
use GraphQL\Error\Error;
use GraphQL\Executor\ExecutionResult;
2015-07-15 23:05:46 +06:00
use GraphQL\Executor\Executor;
2017-08-17 23:50:25 +07:00
use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter;
use GraphQL\Executor\Promise\Promise;
2018-09-02 10:17:27 +02:00
use GraphQL\Executor\Promise\PromiseAdapter;
use GraphQL\Executor\ReferenceExecutor;
use GraphQL\Experimental\Executor\CoroutineExecutor;
use GraphQL\Language\AST\DocumentNode;
2015-07-15 23:05:46 +06:00
use GraphQL\Language\Parser;
use GraphQL\Language\Source;
use GraphQL\Type\Definition\Directive;
2017-08-17 02:12:37 +07:00
use GraphQL\Type\Definition\Type;
2018-09-02 10:17:27 +02:00
use GraphQL\Type\Schema as SchemaType;
2015-07-15 23:05:46 +06:00
use GraphQL\Validator\DocumentValidator;
use GraphQL\Validator\Rules\QueryComplexity;
2018-09-02 10:17:27 +02:00
use GraphQL\Validator\Rules\ValidationRule;
use function array_values;
use function trigger_error;
use const E_USER_DEPRECATED;
2015-07-15 23:05:46 +06:00
/**
* This is the primary facade for fulfilling GraphQL operations.
* See [related documentation](executing-queries.md).
*/
2015-07-15 23:05:46 +06:00
class GraphQL
{
/**
* Executes graphql query.
*
* 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.
*
* Available options:
*
* schema:
* The GraphQL type system to use when validating and executing a query.
* source:
* 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).
* context:
* The value provided as the third argument to all resolvers.
* Use this to pass current session, user data, etc
* 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
2017-08-17 02:12:37 +07:00
* value on the source value with the field's name).
* validationRules:
* A set of rules for query validation step. Default value is all available rules.
* Empty array would allow to skip query validation (may be convenient for persisted
* queries which are validated before persisting and assumed valid during execution)
*
2017-07-05 16:26:02 +07:00
* @param string|DocumentNode $source
2018-09-02 10:17:27 +02:00
* @param mixed $rootValue
* @param mixed $context
* @param mixed[]|null $variableValues
* @param ValidationRule[] $validationRules
2018-09-26 11:03:10 +02:00
*
* @api
2017-08-17 02:12:37 +07:00
*/
public static function executeQuery(
2018-09-02 10:17:27 +02:00
SchemaType $schema,
2017-08-17 02:12:37 +07:00
$source,
$rootValue = null,
2017-08-17 23:50:25 +07:00
$context = null,
2017-08-17 02:12:37 +07:00
$variableValues = null,
2018-09-02 10:17:27 +02:00
?string $operationName = null,
?callable $fieldResolver = null,
?array $validationRules = null
) : ExecutionResult {
2017-08-17 23:50:25 +07:00
$promiseAdapter = new SyncPromiseAdapter();
2018-09-02 10:17:27 +02:00
$promise = self::promiseToExecute(
$promiseAdapter,
$schema,
$source,
$rootValue,
$context,
$variableValues,
$operationName,
$fieldResolver,
$validationRules
);
2017-08-17 23:50:25 +07:00
return $promiseAdapter->wait($promise);
}
/**
* Same as executeQuery(), but requires PromiseAdapter and always returns a Promise.
* Useful for Async PHP platforms.
2017-08-17 23:50:25 +07:00
*
2018-09-02 10:17:27 +02:00
* @param string|DocumentNode $source
* @param mixed $rootValue
* @param mixed $context
* @param mixed[]|null $variableValues
* @param ValidationRule[]|null $validationRules
2018-09-26 11:03:10 +02:00
*
* @api
2017-08-17 23:50:25 +07:00
*/
public static function promiseToExecute(
PromiseAdapter $promiseAdapter,
2018-09-02 10:17:27 +02:00
SchemaType $schema,
2017-08-17 23:50:25 +07:00
$source,
$rootValue = null,
$context = null,
$variableValues = null,
2018-09-02 10:17:27 +02:00
?string $operationName = null,
?callable $fieldResolver = null,
?array $validationRules = null
) : Promise {
2017-08-17 02:12:37 +07:00
try {
if ($source instanceof DocumentNode) {
$documentNode = $source;
} else {
$documentNode = Parser::parse(new Source($source ?: '', 'GraphQL'));
}
// FIXME
2018-09-02 10:17:27 +02:00
if (empty($validationRules)) {
/** @var QueryComplexity $queryComplexity */
$queryComplexity = DocumentValidator::getRule(QueryComplexity::class);
$queryComplexity->setRawVariableValues($variableValues);
2018-09-02 10:17:27 +02:00
} else {
foreach ($validationRules as $rule) {
if (! ($rule instanceof QueryComplexity)) {
continue;
}
$rule->setRawVariableValues($variableValues);
}
}
2017-08-17 02:12:37 +07:00
$validationErrors = DocumentValidator::validate($schema, $documentNode, $validationRules);
2018-09-02 10:17:27 +02:00
if (! empty($validationErrors)) {
2017-08-17 23:50:25 +07:00
return $promiseAdapter->createFulfilled(
new ExecutionResult(null, $validationErrors)
);
2017-08-17 02:12:37 +07:00
}
2018-09-02 10:17:27 +02:00
return Executor::promiseToExecute(
$promiseAdapter,
$schema,
$documentNode,
$rootValue,
$context,
$variableValues,
$operationName,
$fieldResolver
);
2017-08-17 02:12:37 +07:00
} catch (Error $e) {
2017-08-17 23:50:25 +07:00
return $promiseAdapter->createFulfilled(
new ExecutionResult(null, [$e])
);
2017-08-17 02:12:37 +07:00
}
}
/**
* @deprecated Use executeQuery()->toArray() instead
*
* @param string|DocumentNode $source
2018-09-02 10:17:27 +02:00
* @param mixed $rootValue
* @param mixed $contextValue
* @param mixed[]|null $variableValues
2018-09-26 11:03:10 +02:00
*
2018-09-02 10:17:27 +02:00
* @return Promise|mixed[]
2015-07-15 23:05:46 +06:00
*/
public static function execute(
2018-09-02 10:17:27 +02:00
SchemaType $schema,
2017-07-05 16:26:02 +07:00
$source,
$rootValue = null,
$contextValue = null,
$variableValues = null,
2018-09-02 10:17:27 +02:00
?string $operationName = null
) {
trigger_error(
__METHOD__ . ' is deprecated, use GraphQL::executeQuery()->toArray() as a quick replacement',
E_USER_DEPRECATED
);
2018-09-02 10:17:27 +02:00
$promiseAdapter = Executor::getPromiseAdapter();
$result = self::promiseToExecute(
$promiseAdapter,
$schema,
2017-07-05 16:26:02 +07:00
$source,
$rootValue,
$contextValue,
$variableValues,
2017-08-17 23:50:25 +07:00
$operationName
);
2017-08-17 23:50:25 +07:00
if ($promiseAdapter instanceof SyncPromiseAdapter) {
$result = $promiseAdapter->wait($result)->toArray();
} else {
2018-09-26 11:03:10 +02:00
$result = $result->then(static function (ExecutionResult $r) {
2017-08-17 23:50:25 +07:00
return $r->toArray();
2016-12-03 04:11:14 +07:00
});
}
2018-09-02 10:17:27 +02:00
2017-08-17 23:50:25 +07:00
return $result;
}
/**
2017-08-17 02:12:37 +07:00
* @deprecated renamed to executeQuery()
*
2017-07-05 16:26:02 +07:00
* @param string|DocumentNode $source
2018-09-02 10:17:27 +02:00
* @param mixed $rootValue
* @param mixed $contextValue
* @param mixed[]|null $variableValues
*
* @return ExecutionResult|Promise
*/
public static function executeAndReturnResult(
2018-09-02 10:17:27 +02:00
SchemaType $schema,
2017-07-05 16:26:02 +07:00
$source,
$rootValue = null,
$contextValue = null,
$variableValues = null,
2018-09-02 10:17:27 +02:00
?string $operationName = null
) {
trigger_error(
__METHOD__ . ' is deprecated, use GraphQL::executeQuery() as a quick replacement',
E_USER_DEPRECATED
);
2018-09-02 10:17:27 +02:00
$promiseAdapter = Executor::getPromiseAdapter();
$result = self::promiseToExecute(
$promiseAdapter,
2017-08-17 02:12:37 +07:00
$schema,
$source,
$rootValue,
$contextValue,
$variableValues,
2017-08-17 23:50:25 +07:00
$operationName
2017-08-17 02:12:37 +07:00
);
2018-09-02 10:17:27 +02:00
2017-08-17 23:50:25 +07:00
if ($promiseAdapter instanceof SyncPromiseAdapter) {
$result = $promiseAdapter->wait($result);
}
2018-09-02 10:17:27 +02:00
2017-08-17 23:50:25 +07:00
return $result;
2015-07-15 23:05:46 +06:00
}
/**
2017-08-17 02:12:37 +07:00
* Returns directives defined in GraphQL spec
*
* @return Directive[]
2018-09-26 11:03:10 +02:00
*
* @api
*/
2018-09-02 10:17:27 +02:00
public static function getStandardDirectives() : array
{
return array_values(Directive::getInternalDirectives());
}
2017-08-17 02:12:37 +07:00
/**
* Returns types defined in GraphQL spec
*
* @return Type[]
2018-09-26 11:03:10 +02:00
*
* @api
2017-08-17 02:12:37 +07:00
*/
2018-09-02 10:17:27 +02:00
public static function getStandardTypes() : array
2017-08-17 02:12:37 +07:00
{
return array_values(Type::getStandardTypes());
}
/**
* Replaces standard types with types from this list (matching by name)
* Standard types not listed here remain untouched.
*
* @param Type[] $types
*
* @api
*/
public static function overrideStandardTypes(array $types)
{
Type::overrideStandardTypes($types);
}
/**
* Returns standard validation rules implementing GraphQL spec
*
2018-08-07 00:35:37 +02:00
* @return ValidationRule[]
2018-09-26 11:03:10 +02:00
*
* @api
*/
2018-09-02 10:17:27 +02:00
public static function getStandardValidationRules() : array
{
return array_values(DocumentValidator::defaultRules());
2017-08-17 02:12:37 +07:00
}
/**
* Set default resolver implementation
*
* @api
*/
2018-09-02 10:17:27 +02:00
public static function setDefaultFieldResolver(callable $fn) : void
{
Executor::setDefaultFieldResolver($fn);
}
2018-09-02 10:17:27 +02:00
public static function setPromiseAdapter(?PromiseAdapter $promiseAdapter = null) : void
{
Executor::setPromiseAdapter($promiseAdapter);
}
/**
* Experimental: Switch to the new executor
*/
public static function useExperimentalExecutor()
{
Executor::setImplementationFactory([CoroutineExecutor::class, 'create']);
}
/**
* Experimental: Switch back to the default executor
*/
public static function useReferenceExecutor()
{
Executor::setImplementationFactory([ReferenceExecutor::class, 'create']);
}
/**
* Returns directives defined in GraphQL spec
*
* @deprecated Renamed to getStandardDirectives
2018-09-26 11:03:10 +02:00
*
* @return Directive[]
*/
2018-09-02 10:17:27 +02:00
public static function getInternalDirectives() : array
{
return self::getStandardDirectives();
}
2015-07-15 23:05:46 +06:00
}