Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Executor/Executor.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

use GraphQL\Executor\ExecutionResult;
use GraphQL\Executor\Promise\Promise;
use GraphQL\Executor\Promise\PromiseAdapter;
use GraphQL\Schema;
use Overblog\GraphQLBundle\Executor\Promise\PromiseAdapterInterface;

class Executor implements ExecutorInterface
{
Expand All @@ -34,9 +34,9 @@ public function execute(Schema $schema, $requestString, $rootValue = null, $cont
}

/**
* @param PromiseAdapterInterface|null $promiseAdapter
* @param PromiseAdapter|null $promiseAdapter
*/
public function setPromiseAdapter(PromiseAdapterInterface $promiseAdapter = null)
public function setPromiseAdapter(PromiseAdapter $promiseAdapter = null)
{
call_user_func_array('GraphQL\GraphQL::setPromiseAdapter', func_get_args());
}
Expand Down
6 changes: 3 additions & 3 deletions Executor/ExecutorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

use GraphQL\Executor\ExecutionResult;
use GraphQL\Executor\Promise\Promise;
use GraphQL\Executor\Promise\PromiseAdapter;
use GraphQL\Schema;
use Overblog\GraphQLBundle\Executor\Promise\PromiseAdapterInterface;

interface ExecutorInterface
{
Expand All @@ -31,7 +31,7 @@ interface ExecutorInterface
public function execute(Schema $schema, $requestString, $rootValue = null, $contextValue = null, $variableValues = null, $operationName = null);

/**
* @param PromiseAdapterInterface|null $promiseAdapter
* @param PromiseAdapter|null $promiseAdapter
*/
public function setPromiseAdapter(PromiseAdapterInterface $promiseAdapter = null);
public function setPromiseAdapter(PromiseAdapter $promiseAdapter = null);
}
42 changes: 0 additions & 42 deletions Executor/Promise/Adapter/GraphQLPromiseAdapter.php

This file was deleted.

40 changes: 29 additions & 11 deletions Request/Executor.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
namespace Overblog\GraphQLBundle\Request;

use GraphQL\Executor\ExecutionResult;
use GraphQL\Executor\Promise\Promise;
use GraphQL\Executor\Promise\PromiseAdapter;
use GraphQL\Schema;
use GraphQL\Validator\DocumentValidator;
use GraphQL\Validator\Rules\QueryComplexity;
Expand Down Expand Up @@ -54,7 +54,7 @@ class Executor
private $executor;

/**
* @var PromiseAdapterInterface
* @var PromiseAdapter
*/
private $promiseAdapter;

Expand All @@ -64,7 +64,7 @@ public function __construct(
$throwException = false,
ErrorHandler $errorHandler = null,
$hasDebugInfo = false,
PromiseAdapterInterface $promiseAdapter = null
PromiseAdapter $promiseAdapter = null
) {
$this->executor = $executor;
$this->dispatcher = $dispatcher;
Expand All @@ -81,6 +81,13 @@ public function setExecutor(ExecutorInterface $executor)
return $this;
}

public function setPromiseAdapter(PromiseAdapter $promiseAdapter = null)
{
$this->promiseAdapter = $promiseAdapter;

return $this;
}

public function addSchema($name, Schema $schema)
{
$this->schemas[$name] = $schema;
Expand Down Expand Up @@ -141,6 +148,18 @@ public function execute(array $data, array $context = [], $schemaName = null)
$context = $event->getExecutorContext();
}

if ($this->promiseAdapter) {
if (!$this->promiseAdapter instanceof PromiseAdapterInterface && !is_callable([$this->promiseAdapter, 'wait'])) {
throw new \RuntimeException(
sprintf(
'PromiseAdapter should be an object instantiating "%s" or "%s" with a "wait" method.',
'Overblog\\GraphQLBundle\\Executor\\Promise\\PromiseAdapterInterface',
'GraphQL\\Executor\\Promise\\PromiseAdapter'
)
);
}
}

$schema = $this->getSchema($schemaName);

$startTime = microtime(true);
Expand All @@ -157,20 +176,19 @@ public function execute(array $data, array $context = [], $schemaName = null)
isset($data[ParserInterface::PARAM_OPERATION_NAME]) ? $data[ParserInterface::PARAM_OPERATION_NAME] : null
);

if (!is_object($result) || (!$result instanceof ExecutionResult && !$result instanceof Promise)) {
if ($this->promiseAdapter && $this->promiseAdapter->isThenable($result)) {
$result = $this->promiseAdapter->wait($result);
}

if (!is_object($result) || !$result instanceof ExecutionResult) {
throw new \RuntimeException(
sprintf(
'Execution result should be an object instantiating "%s" or "%s".',
'GraphQL\\Executor\\ExecutionResult',
'GraphQL\\Executor\\Promise\\Promise'
'Execution result should be an object instantiating "%s".',
'GraphQL\\Executor\\ExecutionResult'
)
);
}

if ($this->promiseAdapter && $this->promiseAdapter->isThenable($result)) {
$result = $this->promiseAdapter->wait($result);
}

return $this->prepareResult($result, $startTime, $startMemoryUsage);
}

Expand Down
25 changes: 14 additions & 11 deletions Resolver/AccessResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,20 @@

namespace Overblog\GraphQLBundle\Resolver;

use GraphQL\Executor\Promise\Adapter\SyncPromise;
use GraphQL\Executor\Promise\Promise;
use GraphQL\Executor\Promise\PromiseAdapter as PromiseAdapterInterface;
use GraphQL\Executor\Promise\PromiseAdapter;
use Overblog\GraphQLBundle\Error\UserError;
use Overblog\GraphQLBundle\Error\UserWarning;
use Overblog\GraphQLBundle\Relay\Connection\Output\Connection;
use Overblog\GraphQLBundle\Relay\Connection\Output\Edge;

class AccessResolver
{
/** @var PromiseAdapterInterface */
/** @var PromiseAdapter */
private $promiseAdapter;

public function __construct(PromiseAdapterInterface $promiseAdapter)
public function __construct(PromiseAdapter $promiseAdapter)
{
$this->promiseAdapter = $promiseAdapter;
}
Expand All @@ -47,15 +48,17 @@ public function resolve(callable $accessChecker, callable $resolveCallback, arra
private function filterResultUsingAccess(callable $accessChecker, callable $resolveCallback, array $resolveArgs = [])
{
$result = call_user_func_array($resolveCallback, $resolveArgs);
if ($result instanceof Promise) {
$result = $result->adoptedPromise;
}

if ($this->promiseAdapter->isThenable($result)) {
if (!$result instanceof Promise) {
$result = $this->promiseAdapter->convertThenable($result);
}

return $this->promiseAdapter->then($result, function ($result) use ($accessChecker, $resolveArgs) {
return $this->processFilter($result, $accessChecker, $resolveArgs);
});
if ($this->promiseAdapter->isThenable($result) || $result instanceof SyncPromise) {
return $this->promiseAdapter->then(
new Promise($result, $this->promiseAdapter),
function ($result) use ($accessChecker, $resolveArgs) {
return $this->processFilter($result, $accessChecker, $resolveArgs);
}
);
}

return $this->processFilter($result, $accessChecker, $resolveArgs);
Expand Down
2 changes: 1 addition & 1 deletion Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ services:
- { name: kernel.event_listener, event: graphql.executor.context, method: onExecutorContextEvent }

overblog_graphql.promise_adapter.default:
class: Overblog\GraphQLBundle\Executor\Promise\Adapter\GraphQLPromiseAdapter
class: GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter
public: false

overblog_graphql.react.promise_adapter:
Expand Down
11 changes: 7 additions & 4 deletions Resources/doc/data-fetching/promise.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
The bundle is totally "promise ready", by default it use **Webonyx/GraphQL-Php**
SyncPromise adapter (supporting the native deferred feature) and it also comes
with [ReactPHP/Promise](https://github.com/reactphp/promise) adapter.
To integrate an other promise implementation, you must create a new service that
implements `Overblog\GraphQLBundle\Executor\Promise\PromiseAdapterInterface`.
To integrate an other promise implementation, you must create a new service that
implements `Overblog\GraphQLBundle\Executor\Promise\PromiseAdapterInterface`
or `GraphQL\Executor\Promise\PromiseAdapter` with a `wait` method that accepts
a Promise like argument and returns the result of the promise resolved
or throw an exception otherwise.

Config bundle to use the new service:

Expand All @@ -23,11 +26,11 @@ in resolver like this:
```php
<?php

use Overblog\GraphQLBundle\Executor\Promise\PromiseAdapterInterface;
use GraphQL\Executor\Promise\PromiseAdapter;

class MyResolver
{
public function __construct(PromiseAdapterInterface $promiseAdapter)
public function __construct(PromiseAdapter $promiseAdapter)
{
$this->promiseAdapter = $promiseAdapter;
}
Expand Down
6 changes: 3 additions & 3 deletions Tests/Functional/app/Resolver/ConnectionResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
namespace Overblog\GraphQLBundle\Tests\Functional\app\Resolver;

use GraphQL\Deferred;
use GraphQL\Executor\Promise\PromiseAdapter;
use Overblog\GraphQLBundle\Executor\Promise\Adapter\GraphQLPromiseAdapter;
use Overblog\GraphQLBundle\Executor\Promise\Adapter\ReactPromiseAdapter;
use Overblog\GraphQLBundle\Executor\Promise\PromiseAdapterInterface;
use Overblog\GraphQLBundle\Relay\Connection\Output\ConnectionBuilder;
use Overblog\GraphQLBundle\Relay\Connection\Output\Edge;
use React\Promise\Promise;
Expand Down Expand Up @@ -45,11 +45,11 @@ class ConnectionResolver
];

/**
* @var PromiseAdapterInterface
* @var PromiseAdapter
*/
private $promiseAdapter;

public function __construct(PromiseAdapterInterface $promiseAdapter)
public function __construct(PromiseAdapter $promiseAdapter)
{
$this->promiseAdapter = $promiseAdapter;
}
Expand Down
15 changes: 13 additions & 2 deletions Tests/Request/ExecutorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Overblog\GraphQLBundle\Tests\Request;

use GraphQL\Executor\Promise\Adapter\ReactPromiseAdapter;
use GraphQL\Schema;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
Expand Down Expand Up @@ -43,7 +44,7 @@ public function setUp()

/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Execution result should be an object instantiating "GraphQL\Executor\ExecutionResult" or "GraphQL\Executor\Promise\Promise".
* @expectedExceptionMessage Execution result should be an object instantiating "GraphQL\Executor\ExecutionResult".
*/
public function testInvalidExecutorReturnNotObject()
{
Expand All @@ -53,14 +54,24 @@ public function testInvalidExecutorReturnNotObject()

/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Execution result should be an object instantiating "GraphQL\Executor\ExecutionResult" or "GraphQL\Executor\Promise\Promise".
* @expectedExceptionMessage Execution result should be an object instantiating "GraphQL\Executor\ExecutionResult".
*/
public function testInvalidExecutorReturnInvalidObject()
{
$this->executor->setExecutor($this->createExecutorExecuteMock(new \stdClass()));
$this->executor->execute($this->request);
}

/**
* @expectedException \RuntimeException
* @expectedExceptionMessage PromiseAdapter should be an object instantiating "Overblog\GraphQLBundle\Executor\Promise\PromiseAdapterInterface" or "GraphQL\Executor\Promise\PromiseAdapter" with a "wait" method.
*/
public function testInvalidExecutorAdapterPromise()
{
$this->executor->setPromiseAdapter(new ReactPromiseAdapter());
$this->executor->execute($this->request);
}

public function testDisabledDebugInfo()
{
$this->assertArrayNotHasKey('debug', $this->executor->disabledDebugInfo()->execute($this->request)->extensions);
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "0.7-dev"
"dev-master": "0.8-dev"
}
}
}