Skip to content

Commit 353bdf3

Browse files
authored
Merge pull request #73 from mcg-web/promise
Promise
2 parents eed88d8 + a39d080 commit 353bdf3

32 files changed

+575
-167
lines changed

.travis.yml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ matrix:
1919
- php: 7.1
2020
env: SYMFONY_VERSION=3.2.*
2121
- php: hhvm
22-
- php: nightly
23-
allow_failures:
24-
- php: nightly
22+
# TODO(mcg-web): uncomment after fixing this bug https://github.com/travis-ci/travis-ci/issues/7124
23+
# - php: nightly
24+
# allow_failures:
25+
# - php: nightly
2526

2627
cache:
2728
directories:
@@ -35,8 +36,9 @@ before_install:
3536
install: composer update --prefer-dist --no-interaction
3637

3738
script:
38-
- if [ "$TRAVIS_PHP_VERSION" == "5.6" ]; then bin/phpunit -d xdebug.max_nesting_level=1000 --debug --coverage-clover=coverage.clover; else bin/phpunit --debug; fi
39+
- if [ "$TRAVIS_PHP_VERSION" == "5.6" ]; then bin/phpunit -d xdebug.max_nesting_level=1000 --debug --coverage-clover=build/logs/clover.xml; else bin/phpunit --debug; fi
3940
- if [ "$TRAVIS_PHP_VERSION" == "7.0" ]; then bin/php-cs-fixer fix --diff --dry-run -v; fi;
4041

4142
after_script:
42-
- if [ "$TRAVIS_PHP_VERSION" == "5.6" ]; then wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover coverage.clover; fi
43+
- if [ "$TRAVIS_PHP_VERSION" == "5.6" ]; then wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml; fi
44+
- if [ "$TRAVIS_PHP_VERSION" == "5.6" ]; then composer require "satooshi/php-coveralls:^1.0" && travis_retry php bin/coveralls -v; fi

DependencyInjection/Configuration.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ public function getConfigTreeBuilder()
142142
->arrayNode('services')
143143
->addDefaultsIfNotSet()
144144
->children()
145+
->scalarNode('executor')
146+
->defaultValue('overblog_graphql.executor.default')
147+
->end()
148+
->scalarNode('promise_adapter')
149+
->defaultValue('overblog_graphql.promise_adapter.default')
150+
->end()
145151
->scalarNode('expression_language')
146152
->defaultValue('overblog_graphql.expression_language.default')
147153
->end()

DependencyInjection/OverblogGraphQLExtension.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ public function load(array $configs, ContainerBuilder $container)
3939
$this->setSecurity($config, $container);
4040
$this->setConfigBuilders($config);
4141
$this->setVersions($config, $container);
42+
$this->setShowDebug($config, $container);
4243

43-
$container->getDefinition('overblog_graphql.request_executor')->replaceArgument(3, $config['definitions']['show_debug_info']);
4444
$container->setParameter($this->getAlias().'.resources_dir', realpath(__DIR__.'/../Resources'));
4545
}
4646

@@ -55,6 +55,11 @@ public function prepend(ContainerBuilder $container)
5555
$typesExtension->containerPrependExtensionConfig($config, $container);
5656
}
5757

58+
private function setShowDebug(array $config, ContainerBuilder $container)
59+
{
60+
$container->getDefinition($this->getAlias().'.request_executor')->replaceArgument(4, $config['definitions']['show_debug_info']);
61+
}
62+
5863
private function setVersions(array $config, ContainerBuilder $container)
5964
{
6065
$container->setParameter($this->getAlias().'.versions.graphiql', $config['versions']['graphiql']);

Error/ErrorHandler.php

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace Overblog\GraphQLBundle\Error;
1313

14-
use GraphQL\Error;
14+
use GraphQL\Error\Error as GraphQLError;
1515
use GraphQL\Executor\ExecutionResult;
1616
use Psr\Log\LoggerInterface;
1717
use Psr\Log\LogLevel;
@@ -63,8 +63,8 @@ public function setUserErrorClass($userErrorClass)
6363
}
6464

6565
/**
66-
* @param Error[] $errors
67-
* @param bool $throwRawException
66+
* @param GraphQLError[] $errors
67+
* @param bool $throwRawException
6868
*
6969
* @return array
7070
*
@@ -79,7 +79,7 @@ protected function treatExceptions(array $errors, $throwRawException)
7979
],
8080
];
8181

82-
/** @var Error $error */
82+
/** @var GraphQLError $error */
8383
foreach ($errors as $error) {
8484
$rawException = $this->convertException($error->getPrevious());
8585

@@ -111,7 +111,7 @@ protected function treatExceptions(array $errors, $throwRawException)
111111
if ($rawException instanceof UserErrors) {
112112
$rawExceptions = $rawException;
113113
foreach ($rawExceptions->getErrors() as $rawException) {
114-
$treatedExceptions['errors'][] = Error::createLocatedError($rawException, $error->nodes);
114+
$treatedExceptions['errors'][] = GraphQLError::createLocatedError($rawException, $error->nodes);
115115
}
116116
continue;
117117
}
@@ -123,19 +123,24 @@ protected function treatExceptions(array $errors, $throwRawException)
123123

124124
$this->logException($rawException, LogLevel::CRITICAL);
125125

126-
$treatedExceptions['errors'][] = new Error(
126+
$treatedExceptions['errors'][] = new GraphQLError(
127127
$this->internalErrorMessage,
128128
$error->nodes,
129-
$rawException,
130129
$error->getSource(),
131-
$error->getPositions()
130+
$error->getPositions(),
131+
$error->path,
132+
$rawException
132133
);
133134
}
134135

135136
return $treatedExceptions;
136137
}
137138

138-
public function logException(\Exception $exception, $errorLevel = LogLevel::ERROR)
139+
/**
140+
* @param \Exception|\Error $exception
141+
* @param string $errorLevel
142+
*/
143+
public function logException($exception, $errorLevel = LogLevel::ERROR)
139144
{
140145
$message = sprintf(
141146
'%s: %s[%d] (caught exception) at %s line %s.',
@@ -154,15 +159,15 @@ public function handleErrors(ExecutionResult $executionResult, $throwRawExceptio
154159
$exceptions = $this->treatExceptions($executionResult->errors, $throwRawException);
155160
$executionResult->errors = $exceptions['errors'];
156161
if (!empty($exceptions['extensions']['warnings'])) {
157-
$executionResult->extensions['warnings'] = array_map(['GraphQL\Error', 'formatError'], $exceptions['extensions']['warnings']);
162+
$executionResult->extensions['warnings'] = array_map(['GraphQL\Error\Error', 'formatError'], $exceptions['extensions']['warnings']);
158163
}
159164
}
160165

161166
/**
162167
* Tries to convert a raw exception into a user warning or error
163168
* that is displayed to the user.
164169
*
165-
* @param \Exception $rawException
170+
* @param \Exception|\Error $rawException
166171
*
167172
* @return \Exception|\Error
168173
*/
@@ -172,8 +177,9 @@ protected function convertException($rawException = null)
172177
return;
173178
}
174179

175-
if (!empty($this->exceptionMap[get_class($rawException)])) {
176-
$errorClass = $this->exceptionMap[get_class($rawException)];
180+
$rawExceptionClass = get_class($rawException);
181+
if (isset($this->exceptionMap[$rawExceptionClass])) {
182+
$errorClass = $this->exceptionMap[$rawExceptionClass];
177183

178184
return new $errorClass($rawException->getMessage(), $rawException->getCode(), $rawException);
179185
}

Executor/Executor.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the OverblogGraphQLBundle package.
5+
*
6+
* (c) Overblog <http://github.com/overblog/>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Overblog\GraphQLBundle\Executor;
13+
14+
use GraphQL\Executor\ExecutionResult;
15+
use GraphQL\Executor\Promise\Promise;
16+
use GraphQL\Schema;
17+
use Overblog\GraphQLBundle\Executor\Promise\PromiseAdapterInterface;
18+
19+
class Executor implements ExecutorInterface
20+
{
21+
/**
22+
* @param Schema $schema
23+
* @param string $requestString
24+
* @param null|array $rootValue
25+
* @param null|array $contextValue
26+
* @param null|array $variableValues
27+
* @param null|string $operationName
28+
*
29+
* @return ExecutionResult|Promise
30+
*/
31+
public function execute(Schema $schema, $requestString, $rootValue = null, $contextValue = null, $variableValues = null, $operationName = null)
32+
{
33+
return call_user_func_array('GraphQL\GraphQL::executeAndReturnResult', func_get_args());
34+
}
35+
36+
/**
37+
* @param PromiseAdapterInterface|null $promiseAdapter
38+
*/
39+
public function setPromiseAdapter(PromiseAdapterInterface $promiseAdapter = null)
40+
{
41+
call_user_func_array('GraphQL\GraphQL::setPromiseAdapter', func_get_args());
42+
}
43+
}

Executor/ExecutorInterface.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the OverblogGraphQLBundle package.
5+
*
6+
* (c) Overblog <http://github.com/overblog/>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Overblog\GraphQLBundle\Executor;
13+
14+
use GraphQL\Executor\ExecutionResult;
15+
use GraphQL\Executor\Promise\Promise;
16+
use GraphQL\Schema;
17+
use Overblog\GraphQLBundle\Executor\Promise\PromiseAdapterInterface;
18+
19+
interface ExecutorInterface
20+
{
21+
/**
22+
* @param Schema $schema
23+
* @param string $requestString
24+
* @param null|array $rootValue
25+
* @param null|array $contextValue
26+
* @param null|array $variableValues
27+
* @param null|string $operationName
28+
*
29+
* @return ExecutionResult|Promise
30+
*/
31+
public function execute(Schema $schema, $requestString, $rootValue = null, $contextValue = null, $variableValues = null, $operationName = null);
32+
33+
/**
34+
* @param PromiseAdapterInterface|null $promiseAdapter
35+
*/
36+
public function setPromiseAdapter(PromiseAdapterInterface $promiseAdapter = null);
37+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the OverblogGraphQLBundle package.
5+
*
6+
* (c) Overblog <http://github.com/overblog/>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Overblog\GraphQLBundle\Executor\Promise\Adapter;
13+
14+
use GraphQL\Executor\Promise\Adapter\SyncPromise;
15+
use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter as BaseSyncPromiseAdapter;
16+
use GraphQL\Executor\Promise\Promise;
17+
use Overblog\GraphQLBundle\Executor\Promise\PromiseAdapterInterface;
18+
19+
class GraphQLPromiseAdapter extends BaseSyncPromiseAdapter implements PromiseAdapterInterface
20+
{
21+
/**
22+
* {@inheritdoc}
23+
*/
24+
public function isThenable($value)
25+
{
26+
$valueOrPromise = $value instanceof Promise ? $value->adoptedPromise : $value;
27+
28+
return parent::isThenable($valueOrPromise) || $valueOrPromise instanceof SyncPromise;
29+
}
30+
31+
/**
32+
* {@inheritdoc}
33+
*/
34+
public function convertThenable($thenable)
35+
{
36+
if ($thenable instanceof Promise) {
37+
return $thenable;
38+
}
39+
40+
return parent::convertThenable($thenable);
41+
}
42+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the OverblogGraphQLBundle package.
5+
*
6+
* (c) Overblog <http://github.com/overblog/>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Overblog\GraphQLBundle\Executor\Promise\Adapter;
13+
14+
use GraphQL\Executor\ExecutionResult;
15+
use GraphQL\Executor\Promise\Adapter\ReactPromiseAdapter as BaseReactPromiseAdapter;
16+
use GraphQL\Executor\Promise\Promise;
17+
use Overblog\GraphQLBundle\Executor\Promise\PromiseAdapterInterface;
18+
19+
class ReactPromiseAdapter extends BaseReactPromiseAdapter implements PromiseAdapterInterface
20+
{
21+
/**
22+
* {@inheritdoc}
23+
*/
24+
public function isThenable($value)
25+
{
26+
return parent::isThenable($value instanceof Promise ? $value->adoptedPromise : $value);
27+
}
28+
29+
/**
30+
* {@inheritdoc}
31+
*/
32+
public function convertThenable($thenable)
33+
{
34+
if ($thenable instanceof Promise) {
35+
return $thenable;
36+
}
37+
38+
return parent::convertThenable($thenable);
39+
}
40+
41+
/**
42+
* Synchronously wait when promise completes.
43+
*
44+
* @param Promise $promise
45+
*
46+
* @return ExecutionResult
47+
*
48+
* @throws \Exception
49+
*/
50+
public function wait(Promise $promise)
51+
{
52+
if (!$this->isThenable($promise)) {
53+
return;
54+
}
55+
$wait = true;
56+
$resolvedValue = null;
57+
$exception = null;
58+
/** @var \React\Promise\PromiseInterface $reactPromise */
59+
$reactPromise = $promise->adoptedPromise;
60+
61+
while ($wait) {
62+
$reactPromise->then(function ($values) use (&$resolvedValue, &$wait) {
63+
$resolvedValue = $values;
64+
$wait = false;
65+
}, function ($reason) use (&$exception, &$wait) {
66+
$exception = $reason;
67+
$wait = false;
68+
});
69+
}
70+
71+
if ($exception instanceof \Exception) {
72+
throw $exception;
73+
}
74+
75+
return $resolvedValue;
76+
}
77+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the OverblogGraphQLBundle package.
5+
*
6+
* (c) Overblog <http://github.com/overblog/>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Overblog\GraphQLBundle\Executor\Promise;
13+
14+
use GraphQL\Executor\ExecutionResult;
15+
use GraphQL\Executor\Promise\Promise;
16+
use GraphQL\Executor\Promise\PromiseAdapter;
17+
18+
interface PromiseAdapterInterface extends PromiseAdapter
19+
{
20+
/**
21+
* Synchronously wait when promise completes.
22+
*
23+
* @param Promise $promise
24+
*
25+
* @return ExecutionResult
26+
*/
27+
public function wait(Promise $promise);
28+
}

0 commit comments

Comments
 (0)