mirror of
https://github.com/retailcrm/graphql-php.git
synced 2025-02-14 11:33:13 +03:00
Execution: moved then
method to promise adapter
This commit is contained in:
parent
77244d3aab
commit
418ee48b20
@ -63,6 +63,14 @@ class Executor
|
|||||||
self::$promiseAdapter = $promiseAdapter;
|
self::$promiseAdapter = $promiseAdapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return PromiseAdapter
|
||||||
|
*/
|
||||||
|
public static function getPromiseAdapter()
|
||||||
|
{
|
||||||
|
return self::$promiseAdapter ?: (self::$promiseAdapter = new GenericPromiseAdapter());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom default resolve function
|
* Custom default resolve function
|
||||||
*
|
*
|
||||||
@ -85,10 +93,6 @@ class Executor
|
|||||||
*/
|
*/
|
||||||
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)
|
||||||
{
|
{
|
||||||
if (!self::$UNDEFINED) {
|
|
||||||
self::$UNDEFINED = new \stdClass();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null !== $variableValues) {
|
if (null !== $variableValues) {
|
||||||
Utils::invariant(
|
Utils::invariant(
|
||||||
is_array($variableValues) || $variableValues instanceof \ArrayAccess,
|
is_array($variableValues) || $variableValues instanceof \ArrayAccess,
|
||||||
@ -103,9 +107,7 @@ class Executor
|
|||||||
}
|
}
|
||||||
|
|
||||||
$exeContext = self::buildExecutionContext($schema, $ast, $rootValue, $contextValue, $variableValues, $operationName);
|
$exeContext = self::buildExecutionContext($schema, $ast, $rootValue, $contextValue, $variableValues, $operationName);
|
||||||
$promiseAdapter = self::$promiseAdapter ?: new GenericPromiseAdapter();
|
$executor = new self($exeContext, self::getPromiseAdapter());
|
||||||
|
|
||||||
$executor = new self($exeContext, $promiseAdapter);
|
|
||||||
return $executor->executeQuery();
|
return $executor->executeQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,6 +197,10 @@ class Executor
|
|||||||
*/
|
*/
|
||||||
private function __construct(ExecutionContext $context, PromiseAdapter $promiseAdapter)
|
private function __construct(ExecutionContext $context, PromiseAdapter $promiseAdapter)
|
||||||
{
|
{
|
||||||
|
if (!self::$UNDEFINED) {
|
||||||
|
self::$UNDEFINED = Utils::undefined();
|
||||||
|
}
|
||||||
|
|
||||||
$this->exeContext = $context;
|
$this->exeContext = $context;
|
||||||
$this->promises = $promiseAdapter;
|
$this->promises = $promiseAdapter;
|
||||||
}
|
}
|
||||||
@ -202,29 +208,28 @@ class Executor
|
|||||||
private function executeQuery()
|
private function executeQuery()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$data = $this->promises->createPromise(function (callable $resolve) {
|
// Return a Promise that will eventually resolve to the data described by
|
||||||
|
// The "Response" section of the GraphQL specification.
|
||||||
|
//
|
||||||
|
// If errors are encountered while executing a GraphQL field, only that
|
||||||
|
// field and its descendants will be omitted, and sibling fields will still
|
||||||
|
// be executed. An execution which encounters errors will still result in a
|
||||||
|
// resolved Promise.
|
||||||
|
$result = $this->promises->createPromise(function (callable $resolve) {
|
||||||
return $resolve($this->executeOperation($this->exeContext->operation, $this->exeContext->rootValue));
|
return $resolve($this->executeOperation($this->exeContext->operation, $this->exeContext->rootValue));
|
||||||
});
|
});
|
||||||
|
$result = $this->promises->then($result, null, function ($error) {
|
||||||
|
// Errors from sub-fields of a NonNull type may propagate to the top level,
|
||||||
|
// at which point we still log the error and null the parent field, which
|
||||||
|
// in this case is the entire response.
|
||||||
|
$this->exeContext->addError($error);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
$result = $this->promises->then($result, function ($data) {
|
||||||
|
return new ExecutionResult((array) $data, $this->exeContext->errors);
|
||||||
|
});
|
||||||
|
|
||||||
if ($this->promises->isPromise($data)) {
|
return $result;
|
||||||
// Return a Promise that will eventually resolve to the data described by
|
|
||||||
// The "Response" section of the GraphQL specification.
|
|
||||||
//
|
|
||||||
// If errors are encountered while executing a GraphQL field, only that
|
|
||||||
// field and its descendants will be omitted, and sibling fields will still
|
|
||||||
// be executed. An execution which encounters errors will still result in a
|
|
||||||
// resolved Promise.
|
|
||||||
return $data
|
|
||||||
->then(null, function ($error) {
|
|
||||||
// Errors from sub-fields of a NonNull type may propagate to the top level,
|
|
||||||
// at which point we still log the error and null the parent field, which
|
|
||||||
// in this case is the entire response.
|
|
||||||
$this->exeContext->addError($error);
|
|
||||||
return null;
|
|
||||||
})->then(function ($data) {
|
|
||||||
return new ExecutionResult((array) $data, $this->exeContext->errors);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (Error $e) {
|
} catch (Error $e) {
|
||||||
$this->exeContext->addError($e);
|
$this->exeContext->addError($e);
|
||||||
$data = null;
|
$data = null;
|
||||||
@ -315,7 +320,7 @@ class Executor
|
|||||||
return $results;
|
return $results;
|
||||||
}
|
}
|
||||||
if ($this->promises->isPromise($result)) {
|
if ($this->promises->isPromise($result)) {
|
||||||
return $result->then(function ($resolvedResult) use ($responseName, $results) {
|
return $this->promises->then($result, function ($resolvedResult) use ($responseName, $results) {
|
||||||
$results[$responseName] = $resolvedResult;
|
$results[$responseName] = $resolvedResult;
|
||||||
return $results;
|
return $results;
|
||||||
});
|
});
|
||||||
@ -326,7 +331,7 @@ class Executor
|
|||||||
|
|
||||||
foreach ($fields as $responseName => $fieldNodes) {
|
foreach ($fields as $responseName => $fieldNodes) {
|
||||||
if ($this->promises->isPromise($results)) {
|
if ($this->promises->isPromise($results)) {
|
||||||
$results = $results->then(function ($resolvedResults) use ($process, $responseName, $path, $parentType, $sourceValue, $fieldNodes) {
|
$results = $this->promises->then($results, function ($resolvedResults) use ($process, $responseName, $path, $parentType, $sourceValue, $fieldNodes) {
|
||||||
return $process($resolvedResults, $responseName, $path, $parentType, $sourceValue, $fieldNodes);
|
return $process($resolvedResults, $responseName, $path, $parentType, $sourceValue, $fieldNodes);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -335,7 +340,7 @@ class Executor
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($this->promises->isPromise($results)) {
|
if ($this->promises->isPromise($results)) {
|
||||||
return $results->then(function ($resolvedResults) {
|
return $this->promises->then($results, function ($resolvedResults) {
|
||||||
return self::fixResultsIfEmptyArray($resolvedResults);
|
return self::fixResultsIfEmptyArray($resolvedResults);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -380,7 +385,9 @@ class Executor
|
|||||||
// of resolving that field, which is possibly a promise. Return
|
// of resolving that field, which is possibly a promise. Return
|
||||||
// a promise that will return this same map, but with any
|
// a promise that will return this same map, but with any
|
||||||
// promises replaced with the values they resolved to.
|
// promises replaced with the values they resolved to.
|
||||||
return $this->promises->createPromiseAll($finalResults)->then(function ($resolvedResults) {
|
$promise = $this->promises->createPromiseAll($finalResults);
|
||||||
|
|
||||||
|
return $this->promises->then($promise, function ($resolvedResults) {
|
||||||
return self::fixResultsIfEmptyArray($resolvedResults);
|
return self::fixResultsIfEmptyArray($resolvedResults);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -703,7 +710,7 @@ class Executor
|
|||||||
$result
|
$result
|
||||||
);
|
);
|
||||||
if ($this->promises->isPromise($completed)) {
|
if ($this->promises->isPromise($completed)) {
|
||||||
return $completed->then(null, function ($error) use ($exeContext) {
|
return $this->promises->then($completed, null, function ($error) use ($exeContext) {
|
||||||
$exeContext->addError($error);
|
$exeContext->addError($error);
|
||||||
return $this->promises->createResolvedPromise(null);
|
return $this->promises->createResolvedPromise(null);
|
||||||
});
|
});
|
||||||
@ -747,7 +754,7 @@ class Executor
|
|||||||
$result
|
$result
|
||||||
);
|
);
|
||||||
if ($this->promises->isPromise($completed)) {
|
if ($this->promises->isPromise($completed)) {
|
||||||
return $completed->then(null, function ($error) use ($fieldNodes, $path) {
|
return $this->promises->then($completed, null, function ($error) use ($fieldNodes, $path) {
|
||||||
return $this->promises->createRejectedPromise(Error::createLocatedError($error, $fieldNodes, $path));
|
return $this->promises->createRejectedPromise(Error::createLocatedError($error, $fieldNodes, $path));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -795,11 +802,9 @@ class Executor
|
|||||||
&$result
|
&$result
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
$exeContext = $this->exeContext;
|
|
||||||
|
|
||||||
// If result is a Promise, apply-lift over completeValue.
|
// If result is a Promise, apply-lift over completeValue.
|
||||||
if ($this->promises->isPromise($result)) {
|
if ($this->promises->isPromise($result)) {
|
||||||
return $result->then(function (&$resolved) use ($returnType, $fieldNodes, $info, $path) {
|
return $this->promises->then($result, function (&$resolved) use ($returnType, $fieldNodes, $info, $path) {
|
||||||
return $this->completeValue($returnType, $fieldNodes, $info, $path, $resolved);
|
return $this->completeValue($returnType, $fieldNodes, $info, $path, $resolved);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,30 @@ class GenericPromiseAdapter implements PromiseAdapter
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts value qualified by `isPromise` and returns other promise.
|
||||||
|
*
|
||||||
|
* @param $promise
|
||||||
|
* @param callable|null $onFullFilled
|
||||||
|
* @param callable|null $onRejected
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function then($promise, callable $onFullFilled = null, callable $onRejected = null)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (null !== $onFullFilled) {
|
||||||
|
$promise = $onFullFilled($promise);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->createResolvedPromise($promise);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
if (null !== $onRejected) {
|
||||||
|
$onRejected($e);
|
||||||
|
}
|
||||||
|
return $this->createRejectedPromise($e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function createPromise(callable $resolver)
|
public function createPromise(callable $resolver)
|
||||||
{
|
{
|
||||||
return $resolver(function ($value) {
|
return $resolver(function ($value) {
|
||||||
|
@ -21,6 +21,19 @@ class ReactPromiseAdapter implements PromiseAdapter
|
|||||||
return $value instanceof PromiseInterface;
|
return $value instanceof PromiseInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts value qualified by `isPromise` and returns other promise.
|
||||||
|
*
|
||||||
|
* @param Promise $promise
|
||||||
|
* @param callable|null $onFullFilled
|
||||||
|
* @param callable|null $onRejected
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function then($promise, callable $onFullFilled = null, callable $onRejected = null)
|
||||||
|
{
|
||||||
|
return $promise->then($onFullFilled, $onRejected);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*
|
*
|
||||||
|
@ -13,6 +13,17 @@ interface PromiseAdapter
|
|||||||
*/
|
*/
|
||||||
public function isPromise($value);
|
public function isPromise($value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts value qualified by `isPromise` and returns other promise.
|
||||||
|
* Underlying mechanics of this process must match Promises/A+ specs
|
||||||
|
*
|
||||||
|
* @param $promise
|
||||||
|
* @param callable|null $onFullFilled
|
||||||
|
* @param callable|null $onRejected
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function then($promise, callable $onFullFilled = null, callable $onRejected = null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a Promise
|
* Creates a Promise
|
||||||
*
|
*
|
||||||
|
@ -19,7 +19,7 @@ class GraphQL
|
|||||||
* @param Schema $schema
|
* @param Schema $schema
|
||||||
* @param $requestString
|
* @param $requestString
|
||||||
* @param mixed $rootValue
|
* @param mixed $rootValue
|
||||||
* @param array <string, string>|null $variableValues
|
* @param array|null $variableValues
|
||||||
* @param string|null $operationName
|
* @param string|null $operationName
|
||||||
* @return Promise|array
|
* @return Promise|array
|
||||||
*/
|
*/
|
||||||
@ -27,7 +27,16 @@ class GraphQL
|
|||||||
{
|
{
|
||||||
$result = self::executeAndReturnResult($schema, $requestString, $rootValue, $contextValue, $variableValues, $operationName);
|
$result = self::executeAndReturnResult($schema, $requestString, $rootValue, $contextValue, $variableValues, $operationName);
|
||||||
|
|
||||||
return $result instanceof ExecutionResult ? $result->toArray() : $result->then(function(ExecutionResult $executionResult) { return $executionResult->toArray(); });
|
if ($result instanceof ExecutionResult) {
|
||||||
|
return $result->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Executor::getPromiseAdapter()->then(
|
||||||
|
$result,
|
||||||
|
function(ExecutionResult $executionResult) {
|
||||||
|
return $executionResult->toArray();
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user