1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Drupal\graphql\GraphQL\Execution; |
4
|
|
|
|
5
|
|
|
use Drupal\graphql\GraphQL\Execution\Visitor\VisitorInterface; |
6
|
|
|
use Youshido\GraphQL\Exception\ResolveException; |
7
|
|
|
use Youshido\GraphQL\Execution\DeferredResolverInterface; |
8
|
|
|
use Youshido\GraphQL\Execution\DeferredResult; |
9
|
|
|
use Youshido\GraphQL\Execution\Processor as BaseProcessor; |
10
|
|
|
use Youshido\GraphQL\Execution\Request; |
11
|
|
|
use Youshido\GraphQL\Field\FieldInterface; |
12
|
|
|
use Youshido\GraphQL\Parser\Parser; |
13
|
|
|
use Youshido\GraphQL\Schema\AbstractSchema; |
14
|
|
|
use Youshido\GraphQL\Type\Enum\AbstractEnumType; |
15
|
|
|
use Youshido\GraphQL\Type\Scalar\AbstractScalarType; |
16
|
|
|
use Youshido\GraphQL\Validator\RequestValidator\RequestValidator; |
17
|
|
|
|
18
|
|
|
class Processor extends BaseProcessor { |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* @var \Drupal\graphql\GraphQL\Execution\Reducer |
22
|
|
|
*/ |
23
|
|
|
protected $requestReducer; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Processor constructor. |
27
|
|
|
* |
28
|
|
|
* @param \Youshido\GraphQL\Schema\AbstractSchema $schema |
29
|
|
|
* @param $query |
30
|
|
|
* @param array $variables |
31
|
|
|
*/ |
32
|
|
|
public function __construct(AbstractSchema $schema, $query, array $variables = []) { |
33
|
|
|
parent::__construct($schema); |
34
|
|
|
|
35
|
|
|
$parser = new Parser(); |
36
|
|
|
$request = new Request($parser->parse($query), $variables); |
37
|
|
|
|
38
|
|
|
// Validation of the query payload. This does not take into consideration |
39
|
|
|
// any schema specifics and simply validations the structure of the query. |
40
|
|
|
$validator = new RequestValidator(); |
41
|
|
|
$validator->validate($request); |
42
|
|
|
|
43
|
|
|
// Set the request in the execution context. |
44
|
|
|
$this->executionContext->setRequest($request); |
45
|
|
|
|
46
|
|
|
// Create a request reducer for our query visitors. |
47
|
|
|
$this->requestReducer = new Reducer($this->executionContext); |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* @param \Drupal\graphql\GraphQL\Execution\Visitor\VisitorInterface $visitor |
52
|
|
|
* @param callable $callback |
53
|
|
|
* |
54
|
|
|
* @return null |
55
|
|
|
*/ |
56
|
|
|
public function reduceRequest(VisitorInterface $visitor, callable $callback) { |
57
|
|
|
try { |
58
|
|
|
$result = $this->requestReducer->reduceRequest($visitor); |
59
|
|
|
|
60
|
|
|
// Call the 'finish' callback. This is useful because that way the |
61
|
|
|
// exceptions are caught here and can be written into the execution |
62
|
|
|
// context. |
63
|
|
|
return $callback($result); |
64
|
|
|
} |
65
|
|
|
catch (ResolveException $exception) { |
66
|
|
|
$this->executionContext->addError($exception); |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
return NULL; |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* @return array|mixed |
74
|
|
|
*/ |
75
|
|
|
public function resolveRequest() { |
76
|
|
|
$output = []; |
77
|
|
|
|
78
|
|
|
// if (!$this->executionContext->hasErrors()) { |
|
|
|
|
79
|
|
|
try { |
80
|
|
|
$operations = $this->executionContext->getRequest()->getAllOperations(); |
81
|
|
|
|
82
|
|
|
foreach ($operations as $query) { |
83
|
|
|
if ($result = $this->resolveQuery($query)) { |
84
|
|
|
$output = array_replace_recursive($output, $result); |
85
|
|
|
}; |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
// If the processor found any deferred results, resolve them now. |
89
|
|
|
if (!empty($output) && (!empty($this->deferredResultsLeaf) || !empty($this->deferredResultsComplex))) { |
90
|
|
|
try { |
91
|
|
|
while ($resolver = array_shift($this->deferredResultsComplex)) { |
92
|
|
|
$resolver->resolve(); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
// Deferred scalar and enum fields should be resolved last to pick up |
96
|
|
|
// as many as possible for a single batch. |
97
|
|
|
while ($resolver = array_shift($this->deferredResultsLeaf)) { |
98
|
|
|
$resolver->resolve(); |
99
|
|
|
} |
100
|
|
|
} |
101
|
|
|
catch (ResolveException $exception) { |
102
|
|
|
$this->executionContext->addError($exception); |
103
|
|
|
} |
104
|
|
|
finally { |
105
|
|
|
$output = static::unpackDeferredResults($output); |
106
|
|
|
} |
107
|
|
|
} |
108
|
|
|
} |
109
|
|
|
catch (ResolveException $exception) { |
110
|
|
|
$this->executionContext->addError($exception); |
111
|
|
|
} |
112
|
|
|
// } |
113
|
|
|
|
114
|
|
|
return $output; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* {@inheritdoc} |
119
|
|
|
*/ |
120
|
|
|
protected function deferredResolve($resolvedValue, FieldInterface $field, callable $callback) { |
121
|
|
|
if ($resolvedValue instanceof DeferredResolverInterface) { |
122
|
|
|
$deferredResult = new DeferredResult($resolvedValue, function ($resolvedValue) use ($field, $callback) { |
123
|
|
|
// Allow nested deferred resolvers. |
124
|
|
|
return $this->deferredResolve($resolvedValue, $field, $callback); |
125
|
|
|
}); |
126
|
|
|
|
127
|
|
|
// Whenever we stumble upon a deferred resolver, add it to the queue to be |
128
|
|
|
// resolved later. |
129
|
|
|
$type = $field->getType()->getNamedType(); |
130
|
|
|
if ($type instanceof AbstractScalarType || $type instanceof AbstractEnumType) { |
131
|
|
|
array_push($this->deferredResultsLeaf, $deferredResult); |
132
|
|
|
} |
133
|
|
|
else { |
134
|
|
|
array_push($this->deferredResultsComplex, $deferredResult); |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
return $deferredResult; |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
// For simple values, invoke the callback immediately. |
141
|
|
|
return $callback($resolvedValue); |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
} |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.