Passed
Push — master ( 7cc72b...baad32 )
by Vladimir
10:39
created

GraphQL::getStandardDirectives()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 0
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL;
6
7
use GraphQL\Error\Error;
8
use GraphQL\Executor\ExecutionResult;
9
use GraphQL\Executor\Executor;
10
use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter;
11
use GraphQL\Executor\Promise\Promise;
12
use GraphQL\Executor\Promise\PromiseAdapter;
13
use GraphQL\Executor\ReferenceExecutor;
14
use GraphQL\Experimental\Executor\CoroutineExecutor;
15
use GraphQL\Language\AST\DocumentNode;
16
use GraphQL\Language\Parser;
17
use GraphQL\Language\Source;
18
use GraphQL\Type\Definition\Directive;
19
use GraphQL\Type\Definition\ScalarType;
20
use GraphQL\Type\Definition\Type;
21
use GraphQL\Type\Schema as SchemaType;
22
use GraphQL\Validator\DocumentValidator;
23
use GraphQL\Validator\Rules\QueryComplexity;
24
use GraphQL\Validator\Rules\ValidationRule;
25
use function array_values;
26
use function trigger_error;
27
use const E_USER_DEPRECATED;
28
29
/**
30
 * This is the primary facade for fulfilling GraphQL operations.
31
 * See [related documentation](executing-queries.md).
32
 */
33
class GraphQL
34
{
35
    /**
36
     * Executes graphql query.
37
     *
38
     * More sophisticated GraphQL servers, such as those which persist queries,
39
     * may wish to separate the validation and execution phases to a static time
40
     * tooling step, and a server runtime step.
41
     *
42
     * Available options:
43
     *
44
     * schema:
45
     *    The GraphQL type system to use when validating and executing a query.
46
     * source:
47
     *    A GraphQL language formatted string representing the requested operation.
48
     * rootValue:
49
     *    The value provided as the first argument to resolver functions on the top
50
     *    level type (e.g. the query object type).
51
     * contextValue:
52
     *    The context value is provided as an argument to resolver functions after
53
     *    field arguments. It is used to pass shared information useful at any point
54
     *    during executing this query, for example the currently logged in user and
55
     *    connections to databases or other services.
56
     * variableValues:
57
     *    A mapping of variable name to runtime value to use for all variables
58
     *    defined in the requestString.
59
     * operationName:
60
     *    The name of the operation to use if requestString contains multiple
61
     *    possible operations. Can be omitted if requestString contains only
62
     *    one operation.
63
     * fieldResolver:
64
     *    A resolver function to use when one is not provided by the schema.
65
     *    If not provided, the default field resolver is used (which looks for a
66
     *    value on the source value with the field's name).
67
     * validationRules:
68
     *    A set of rules for query validation step. Default value is all available rules.
69
     *    Empty array would allow to skip query validation (may be convenient for persisted
70
     *    queries which are validated before persisting and assumed valid during execution)
71
     *
72
     * @param string|DocumentNode $source
73
     * @param mixed               $rootValue
74
     * @param mixed               $contextValue
75
     * @param mixed[]|null        $variableValues
76
     * @param ValidationRule[]    $validationRules
77
     *
78
     * @api
79
     */
80 86
    public static function executeQuery(
81
        SchemaType $schema,
82
        $source,
83
        $rootValue = null,
84
        $contextValue = null,
85
        $variableValues = null,
86
        ?string $operationName = null,
87
        ?callable $fieldResolver = null,
88
        ?array $validationRules = null
89
    ) : ExecutionResult {
90 86
        $promiseAdapter = new SyncPromiseAdapter();
91
92 86
        $promise = self::promiseToExecute(
93 86
            $promiseAdapter,
94 86
            $schema,
95 86
            $source,
96 86
            $rootValue,
97 86
            $contextValue,
98 86
            $variableValues,
99 86
            $operationName,
100 86
            $fieldResolver,
101 86
            $validationRules
102
        );
103
104 86
        return $promiseAdapter->wait($promise);
105
    }
106
107
    /**
108
     * Same as executeQuery(), but requires PromiseAdapter and always returns a Promise.
109
     * Useful for Async PHP platforms.
110
     *
111
     * @param string|DocumentNode   $source
112
     * @param mixed                 $rootValue
113
     * @param mixed                 $context
114
     * @param mixed[]|null          $variableValues
115
     * @param ValidationRule[]|null $validationRules
116
     *
117
     * @api
118
     */
119 111
    public static function promiseToExecute(
120
        PromiseAdapter $promiseAdapter,
121
        SchemaType $schema,
122
        $source,
123
        $rootValue = null,
124
        $context = null,
125
        $variableValues = null,
126
        ?string $operationName = null,
127
        ?callable $fieldResolver = null,
128
        ?array $validationRules = null
129
    ) : Promise {
130
        try {
131 111
            if ($source instanceof DocumentNode) {
132 22
                $documentNode = $source;
133
            } else {
134 89
                $documentNode = Parser::parse(new Source($source ?: '', 'GraphQL'));
135
            }
136
137
            // FIXME
138 110
            if (empty($validationRules)) {
139
                /** @var QueryComplexity $queryComplexity */
140 109
                $queryComplexity = DocumentValidator::getRule(QueryComplexity::class);
141 109
                $queryComplexity->setRawVariableValues($variableValues);
142
            } else {
143 3
                foreach ($validationRules as $rule) {
144 3
                    if (! ($rule instanceof QueryComplexity)) {
145 3
                        continue;
146
                    }
147
148 2
                    $rule->setRawVariableValues($variableValues);
149
                }
150
            }
151
152 110
            $validationErrors = DocumentValidator::validate($schema, $documentNode, $validationRules);
153
154 110
            if (! empty($validationErrors)) {
155 14
                return $promiseAdapter->createFulfilled(
156 14
                    new ExecutionResult(null, $validationErrors)
157
                );
158
            }
159
160 100
            return Executor::promiseToExecute(
161 100
                $promiseAdapter,
162 100
                $schema,
163 100
                $documentNode,
164 100
                $rootValue,
165 100
                $context,
166 100
                $variableValues,
167 100
                $operationName,
168 100
                $fieldResolver
169
            );
170 1
        } catch (Error $e) {
171 1
            return $promiseAdapter->createFulfilled(
172 1
                new ExecutionResult(null, [$e])
173
            );
174
        }
175
    }
176
177
    /**
178
     * @deprecated Use executeQuery()->toArray() instead
179
     *
180
     * @param string|DocumentNode $source
181
     * @param mixed               $rootValue
182
     * @param mixed               $contextValue
183
     * @param mixed[]|null        $variableValues
184
     *
185
     * @return Promise|mixed[]
186
     *
187
     * @codeCoverageIgnore
188
     */
189
    public static function execute(
190
        SchemaType $schema,
191
        $source,
192
        $rootValue = null,
193
        $contextValue = null,
194
        $variableValues = null,
195
        ?string $operationName = null
196
    ) {
197
        trigger_error(
198
            __METHOD__ . ' is deprecated, use GraphQL::executeQuery()->toArray() as a quick replacement',
199
            E_USER_DEPRECATED
200
        );
201
202
        $promiseAdapter = Executor::getPromiseAdapter();
203
        $result         = self::promiseToExecute(
204
            $promiseAdapter,
205
            $schema,
206
            $source,
207
            $rootValue,
208
            $contextValue,
209
            $variableValues,
210
            $operationName
211
        );
212
213
        if ($promiseAdapter instanceof SyncPromiseAdapter) {
214
            $result = $promiseAdapter->wait($result)->toArray();
215
        } else {
216
            $result = $result->then(static function (ExecutionResult $r) {
217
                return $r->toArray();
218
            });
219
        }
220
221
        return $result;
222
    }
223
224
    /**
225
     * @deprecated renamed to executeQuery()
226
     *
227
     * @param string|DocumentNode $source
228
     * @param mixed               $rootValue
229
     * @param mixed               $contextValue
230
     * @param mixed[]|null        $variableValues
231
     *
232
     * @return ExecutionResult|Promise
233
     *
234
     * @codeCoverageIgnore
235
     */
236
    public static function executeAndReturnResult(
237
        SchemaType $schema,
238
        $source,
239
        $rootValue = null,
240
        $contextValue = null,
241
        $variableValues = null,
242
        ?string $operationName = null
243
    ) {
244
        trigger_error(
245
            __METHOD__ . ' is deprecated, use GraphQL::executeQuery() as a quick replacement',
246
            E_USER_DEPRECATED
247
        );
248
249
        $promiseAdapter = Executor::getPromiseAdapter();
250
        $result         = self::promiseToExecute(
251
            $promiseAdapter,
252
            $schema,
253
            $source,
254
            $rootValue,
255
            $contextValue,
256
            $variableValues,
257
            $operationName
258
        );
259
260
        if ($promiseAdapter instanceof SyncPromiseAdapter) {
261
            $result = $promiseAdapter->wait($result);
262
        }
263
264
        return $result;
265
    }
266
267
    /**
268
     * Returns directives defined in GraphQL spec
269
     *
270
     * @return Directive[]
271
     *
272
     * @api
273
     */
274 407
    public static function getStandardDirectives() : array
275
    {
276 407
        return array_values(Directive::getInternalDirectives());
277
    }
278
279
    /**
280
     * Returns types defined in GraphQL spec
281
     *
282
     * @return Type[]
283
     *
284
     * @api
285
     */
286
    public static function getStandardTypes() : array
287
    {
288
        return array_values(Type::getStandardTypes());
289
    }
290
291
    /**
292
     * Replaces standard types with types from this list (matching by name)
293
     * Standard types not listed here remain untouched.
294
     *
295
     * @param array<string, ScalarType> $types
296
     *
297
     * @api
298
     */
299
    public static function overrideStandardTypes(array $types)
300
    {
301
        Type::overrideStandardTypes($types);
302
    }
303
304
    /**
305
     * Returns standard validation rules implementing GraphQL spec
306
     *
307
     * @return ValidationRule[]
308
     *
309
     * @api
310
     */
311
    public static function getStandardValidationRules() : array
312
    {
313
        return array_values(DocumentValidator::defaultRules());
314
    }
315
316
    /**
317
     * Set default resolver implementation
318
     *
319
     * @api
320
     */
321
    public static function setDefaultFieldResolver(callable $fn) : void
322
    {
323
        Executor::setDefaultFieldResolver($fn);
324
    }
325
326
    public static function setPromiseAdapter(?PromiseAdapter $promiseAdapter = null) : void
327
    {
328
        Executor::setPromiseAdapter($promiseAdapter);
329
    }
330
331
    /**
332
     * Experimental: Switch to the new executor
333
     */
334
    public static function useExperimentalExecutor()
335
    {
336
        Executor::setImplementationFactory([CoroutineExecutor::class, 'create']);
337
    }
338
339
    /**
340
     * Experimental: Switch back to the default executor
341
     */
342
    public static function useReferenceExecutor()
343
    {
344
        Executor::setImplementationFactory([ReferenceExecutor::class, 'create']);
345
    }
346
347
    /**
348
     * Returns directives defined in GraphQL spec
349
     *
350
     * @deprecated Renamed to getStandardDirectives
351
     *
352
     * @return Directive[]
353
     *
354
     * @codeCoverageIgnore
355
     */
356
    public static function getInternalDirectives() : array
357
    {
358
        return self::getStandardDirectives();
359
    }
360
}
361