Completed
Push — master ( 00caed...6e7cf2 )
by Vladimir
03:44
created

AST::fromArray()   B

Complexity

Conditions 10
Paths 11

Size

Total Lines 29
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 10.0203

Importance

Changes 0
Metric Value
eloc 17
dl 0
loc 29
rs 7.6666
c 0
b 0
f 0
ccs 16
cts 17
cp 0.9412
cc 10
nc 11
nop 1
crap 10.0203

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Utils;
6
7
use GraphQL\Error\Error;
8
use GraphQL\Error\InvariantViolation;
9
use GraphQL\Language\AST\BooleanValueNode;
10
use GraphQL\Language\AST\DocumentNode;
11
use GraphQL\Language\AST\EnumValueNode;
12
use GraphQL\Language\AST\FloatValueNode;
13
use GraphQL\Language\AST\IntValueNode;
14
use GraphQL\Language\AST\ListTypeNode;
15
use GraphQL\Language\AST\ListValueNode;
16
use GraphQL\Language\AST\Location;
17
use GraphQL\Language\AST\NamedTypeNode;
18
use GraphQL\Language\AST\NameNode;
19
use GraphQL\Language\AST\Node;
20
use GraphQL\Language\AST\NodeKind;
21
use GraphQL\Language\AST\NodeList;
22
use GraphQL\Language\AST\NonNullTypeNode;
23
use GraphQL\Language\AST\NullValueNode;
24
use GraphQL\Language\AST\ObjectFieldNode;
25
use GraphQL\Language\AST\ObjectValueNode;
26
use GraphQL\Language\AST\OperationDefinitionNode;
27
use GraphQL\Language\AST\StringValueNode;
28
use GraphQL\Language\AST\ValueNode;
29
use GraphQL\Language\AST\VariableNode;
30
use GraphQL\Type\Definition\EnumType;
31
use GraphQL\Type\Definition\IDType;
32
use GraphQL\Type\Definition\InputObjectType;
33
use GraphQL\Type\Definition\InputType;
34
use GraphQL\Type\Definition\ListOfType;
35
use GraphQL\Type\Definition\NonNull;
36
use GraphQL\Type\Definition\ScalarType;
37
use GraphQL\Type\Definition\Type;
38
use GraphQL\Type\Schema;
39
use function array_combine;
40
use function array_key_exists;
41
use function array_map;
42
use function count;
43
use function floatval;
44
use function intval;
45
use function is_array;
46
use function is_bool;
47
use function is_float;
48
use function is_int;
49
use function is_object;
50
use function is_string;
51
use function iterator_to_array;
52
use function property_exists;
53
54
/**
55
 * Various utilities dealing with AST
56
 */
57
class AST
58
{
59
    /**
60
     * Convert representation of AST as an associative array to instance of GraphQL\Language\AST\Node.
61
     *
62
     * For example:
63
     *
64
     * ```php
65
     * AST::fromArray([
66
     *     'kind' => 'ListValue',
67
     *     'values' => [
68
     *         ['kind' => 'StringValue', 'value' => 'my str'],
69
     *         ['kind' => 'StringValue', 'value' => 'my other str']
70
     *     ],
71
     *     'loc' => ['start' => 21, 'end' => 25]
72
     * ]);
73
     * ```
74
     *
75
     * Will produce instance of `ListValueNode` where `values` prop is a lazily-evaluated `NodeList`
76
     * returning instances of `StringValueNode` on access.
77
     *
78
     * This is a reverse operation for AST::toArray($node)
79
     *
80
     * @api
81
     * @param mixed[] $node
82
     */
83 2
    public static function fromArray(array $node) : Node
84
    {
85 2
        if (! isset($node['kind']) || ! isset(NodeKind::$classMap[$node['kind']])) {
86
            throw new InvariantViolation('Unexpected node structure: ' . Utils::printSafeJson($node));
87
        }
88
89 2
        $kind     = $node['kind'] ?? null;
90 2
        $class    = NodeKind::$classMap[$kind];
91 2
        $instance = new $class([]);
92
93 2
        if (isset($node['loc'], $node['loc']['start'], $node['loc']['end'])) {
94 1
            $instance->loc = Location::create($node['loc']['start'], $node['loc']['end']);
95
        }
96
97 2
        foreach ($node as $key => $value) {
98 2
            if ($key === 'loc' || $key === 'kind') {
99 2
                continue;
100
            }
101 2
            if (is_array($value)) {
102 2
                if (isset($value[0]) || empty($value)) {
103 2
                    $value = new NodeList($value);
104
                } else {
105 2
                    $value = self::fromArray($value);
106
                }
107
            }
108 2
            $instance->{$key} = $value;
109
        }
110
111 2
        return $instance;
112
    }
113
114
    /**
115
     * Convert AST node to serializable array
116
     *
117
     * @api
118
     * @return mixed[]
119
     */
120
    public static function toArray(Node $node)
121
    {
122
        return $node->toArray(true);
123
    }
124
125
    /**
126
     * Produces a GraphQL Value AST given a PHP value.
127
     *
128
     * Optionally, a GraphQL type may be provided, which will be used to
129
     * disambiguate between value primitives.
130
     *
131
     * | PHP Value     | GraphQL Value        |
132
     * | ------------- | -------------------- |
133
     * | Object        | Input Object         |
134
     * | Assoc Array   | Input Object         |
135
     * | Array         | List                 |
136
     * | Boolean       | Boolean              |
137
     * | String        | String / Enum Value  |
138
     * | Int           | Int                  |
139
     * | Float         | Int / Float          |
140
     * | Mixed         | Enum Value           |
141
     * | null          | NullValue            |
142
     *
143
     * @api
144
     * @param Type|mixed|null $value
145
     * @return ObjectValueNode|ListValueNode|BooleanValueNode|IntValueNode|FloatValueNode|EnumValueNode|StringValueNode|NullValueNode
146
     */
147 27
    public static function astFromValue($value, InputType $type)
148
    {
149 27
        if ($type instanceof NonNull) {
150 4
            $astValue = self::astFromValue($value, $type->getWrappedType());
0 ignored issues
show
Bug introduced by
It seems like $type->getWrappedType() can also be of type GraphQL\Type\Definition\UnionType and GraphQL\Type\Definition\ObjectType and GraphQL\Type\Definition\InterfaceType; however, parameter $type of GraphQL\Utils\AST::astFromValue() does only seem to accept GraphQL\Type\Definition\InputType, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

150
            $astValue = self::astFromValue($value, /** @scrutinizer ignore-type */ $type->getWrappedType());
Loading history...
151 4
            if ($astValue instanceof NullValueNode) {
152 4
                return null;
153
            }
154
155 1
            return $astValue;
156
        }
157
158 27
        if ($value === null) {
159 7
            return new NullValueNode([]);
160
        }
161
162
        // Convert PHP array to GraphQL list. If the GraphQLType is a list, but
163
        // the value is not an array, convert the value using the list's item type.
164 25
        if ($type instanceof ListOfType) {
165 2
            $itemType = $type->getWrappedType();
166 2
            if (is_array($value) || ($value instanceof \Traversable)) {
167 1
                $valuesNodes = [];
168 1
                foreach ($value as $item) {
169 1
                    $itemNode = self::astFromValue($item, $itemType);
170 1
                    if (! $itemNode) {
171
                        continue;
172
                    }
173
174 1
                    $valuesNodes[] = $itemNode;
175
                }
176
177 1
                return new ListValueNode(['values' => $valuesNodes]);
178
            }
179
180 1
            return self::astFromValue($value, $itemType);
181
        }
182
183
        // Populate the fields of the input object by creating ASTs from each value
184
        // in the PHP object according to the fields in the input type.
185 25
        if ($type instanceof InputObjectType) {
186 2
            $isArray     = is_array($value);
187 2
            $isArrayLike = $isArray || $value instanceof \ArrayAccess;
188 2
            if ($value === null || (! $isArrayLike && ! is_object($value))) {
189
                return null;
190
            }
191 2
            $fields     = $type->getFields();
192 2
            $fieldNodes = [];
193 2
            foreach ($fields as $fieldName => $field) {
194 2
                if ($isArrayLike) {
195 2
                    $fieldValue = $value[$fieldName] ?? null;
196
                } else {
197 1
                    $fieldValue = $value->{$fieldName} ?? null;
198
                }
199
200
                // Have to check additionally if key exists, since we differentiate between
201
                // "no key" and "value is null":
202 2
                if ($fieldValue !== null) {
203 1
                    $fieldExists = true;
204 1
                } elseif ($isArray) {
205 1
                    $fieldExists = array_key_exists($fieldName, $value);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type ArrayAccess and GraphQL\Type\Definition\Type and GraphQL\Type\Definition\Type&ArrayAccess; however, parameter $search of array_key_exists() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

205
                    $fieldExists = array_key_exists($fieldName, /** @scrutinizer ignore-type */ $value);
Loading history...
206
                } elseif ($isArrayLike) {
207
                    /** @var \ArrayAccess $value */
208
                    $fieldExists = $value->offsetExists($fieldName);
209
                } else {
210
                    $fieldExists = property_exists($value, $fieldName);
211
                }
212
213 2
                if (! $fieldExists) {
214 1
                    continue;
215
                }
216
217 2
                $fieldNode = self::astFromValue($fieldValue, $field->getType());
0 ignored issues
show
Bug introduced by
It seems like $field->getType() can also be of type callable; however, parameter $type of GraphQL\Utils\AST::astFromValue() does only seem to accept GraphQL\Type\Definition\InputType, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

217
                $fieldNode = self::astFromValue($fieldValue, /** @scrutinizer ignore-type */ $field->getType());
Loading history...
218
219 2
                if (! $fieldNode) {
220
                    continue;
221
                }
222
223 2
                $fieldNodes[] = new ObjectFieldNode([
224 2
                    'name'  => new NameNode(['value' => $fieldName]),
225 2
                    'value' => $fieldNode,
226
                ]);
227
            }
228
229 2
            return new ObjectValueNode(['fields' => $fieldNodes]);
230
        }
231
232 24
        if ($type instanceof ScalarType || $type instanceof EnumType) {
233
            // Since value is an internally represented value, it must be serialized
234
            // to an externally represented value before converting into an AST.
235
            try {
236 24
                $serialized = $type->serialize($value);
237 3
            } catch (\Exception $error) {
238 3
                if ($error instanceof Error && $type instanceof EnumType) {
239 1
                    return null;
240
                }
241 2
                throw $error;
242
            } catch (\Throwable $error) {
243
                if ($error instanceof Error && $type instanceof EnumType) {
244
                    return null;
245
                }
246
                throw $error;
247
            }
248
249
            // Others serialize based on their corresponding PHP scalar types.
250 22
            if (is_bool($serialized)) {
251 6
                return new BooleanValueNode(['value' => $serialized]);
252
            }
253 20
            if (is_int($serialized)) {
254 5
                return new IntValueNode(['value' => $serialized]);
255
            }
256 15
            if (is_float($serialized)) {
257
                // int cast with == used for performance reasons
258
                // @codingStandardsIgnoreLine
259 2
                if ((int) $serialized == $serialized) {
260 2
                    return new IntValueNode(['value' => $serialized]);
261
                }
262
263 1
                return new FloatValueNode(['value' => $serialized]);
264
            }
265 14
            if (is_string($serialized)) {
266
                // Enum types use Enum literals.
267 14
                if ($type instanceof EnumType) {
268 4
                    return new EnumValueNode(['value' => $serialized]);
269
                }
270
271
                // ID types can use Int literals.
272 12
                $asInt = (int) $serialized;
273 12
                if ($type instanceof IDType && (string) $asInt === $serialized) {
274 1
                    return new IntValueNode(['value' => $serialized]);
275
                }
276
277
                // Use json_encode, which uses the same string encoding as GraphQL,
278
                // then remove the quotes.
279 12
                return new StringValueNode(['value' => $serialized]);
280
            }
281
282
            throw new InvariantViolation('Cannot convert value to AST: ' . Utils::printSafe($serialized));
283
        }
284
285
        throw new Error('Unknown type: ' . Utils::printSafe($type) . '.');
286
    }
287
288
    /**
289
     * Produces a PHP value given a GraphQL Value AST.
290
     *
291
     * A GraphQL type must be provided, which will be used to interpret different
292
     * GraphQL Value literals.
293
     *
294
     * Returns `null` when the value could not be validly coerced according to
295
     * the provided type.
296
     *
297
     * | GraphQL Value        | PHP Value     |
298
     * | -------------------- | ------------- |
299
     * | Input Object         | Assoc Array   |
300
     * | List                 | Array         |
301
     * | Boolean              | Boolean       |
302
     * | String               | String        |
303
     * | Int / Float          | Int / Float   |
304
     * | Enum Value           | Mixed         |
305
     * | Null Value           | null          |
306
     *
307
     * @api
308
     * @param ValueNode|null $valueNode
309
     * @param mixed[]|null   $variables
310
     * @return mixed[]|null|\stdClass
311
     * @throws \Exception
312
     */
313 80
    public static function valueFromAST($valueNode, InputType $type, $variables = null)
314
    {
315 80
        $undefined = Utils::undefined();
316
317 80
        if ($valueNode === null) {
318
            // When there is no AST, then there is also no value.
319
            // Importantly, this is different from returning the GraphQL null value.
320 1
            return $undefined;
321
        }
322
323 79
        if ($type instanceof NonNull) {
324 37
            if ($valueNode instanceof NullValueNode) {
325
                // Invalid: intentionally return no value.
326 5
                return $undefined;
327
            }
328
329 36
            return self::valueFromAST($valueNode, $type->getWrappedType(), $variables);
0 ignored issues
show
Bug introduced by
It seems like $type->getWrappedType() can also be of type GraphQL\Type\Definition\UnionType and GraphQL\Type\Definition\ObjectType and GraphQL\Type\Definition\InterfaceType; however, parameter $type of GraphQL\Utils\AST::valueFromAST() does only seem to accept GraphQL\Type\Definition\InputType, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

329
            return self::valueFromAST($valueNode, /** @scrutinizer ignore-type */ $type->getWrappedType(), $variables);
Loading history...
330
        }
331
332 79
        if ($valueNode instanceof NullValueNode) {
333
            // This is explicitly returning the value null.
334 8
            return null;
335
        }
336
337 77
        if ($valueNode instanceof VariableNode) {
338 3
            $variableName = $valueNode->name->value;
339
340 3
            if (! $variables || ! array_key_exists($variableName, $variables)) {
341
                // No valid return value.
342 1
                return $undefined;
343
            }
344
            // Note: we're not doing any checking that this variable is correct. We're
345
            // assuming that this query has been validated and the variable usage here
346
            // is of the correct type.
347 3
            return $variables[$variableName];
348
        }
349
350 76
        if ($type instanceof ListOfType) {
351 7
            $itemType = $type->getWrappedType();
352
353 7
            if ($valueNode instanceof ListValueNode) {
354 7
                $coercedValues = [];
355 7
                $itemNodes     = $valueNode->values;
356 7
                foreach ($itemNodes as $itemNode) {
357 7
                    if (self::isMissingVariable($itemNode, $variables)) {
358
                        // If an array contains a missing variable, it is either coerced to
359
                        // null or if the item type is non-null, it considered invalid.
360 1
                        if ($itemType instanceof NonNull) {
361
                            // Invalid: intentionally return no value.
362 1
                            return $undefined;
363
                        }
364 1
                        $coercedValues[] = null;
365
                    } else {
366 7
                        $itemValue = self::valueFromAST($itemNode, $itemType, $variables);
367 7
                        if ($undefined === $itemValue) {
368
                            // Invalid: intentionally return no value.
369 4
                            return $undefined;
370
                        }
371 7
                        $coercedValues[] = $itemValue;
372
                    }
373
                }
374
375 7
                return $coercedValues;
376
            }
377 5
            $coercedValue = self::valueFromAST($valueNode, $itemType, $variables);
378 5
            if ($undefined === $coercedValue) {
379
                // Invalid: intentionally return no value.
380 4
                return $undefined;
381
            }
382
383 5
            return [$coercedValue];
384
        }
385
386 75
        if ($type instanceof InputObjectType) {
387 4
            if (! $valueNode instanceof ObjectValueNode) {
388
                // Invalid: intentionally return no value.
389 2
                return $undefined;
390
            }
391
392 4
            $coercedObj = [];
393 4
            $fields     = $type->getFields();
394 4
            $fieldNodes = Utils::keyMap(
395 4
                $valueNode->fields,
396
                function ($field) {
397 4
                    return $field->name->value;
398 4
                }
399
            );
400 4
            foreach ($fields as $field) {
401
                /** @var ValueNode $fieldNode */
402 4
                $fieldName = $field->name;
403 4
                $fieldNode = $fieldNodes[$fieldName] ?? null;
404
405 4
                if (! $fieldNode || self::isMissingVariable($fieldNode->value, $variables)) {
406 4
                    if ($field->defaultValueExists()) {
407 2
                        $coercedObj[$fieldName] = $field->defaultValue;
408 4
                    } elseif ($field->getType() instanceof NonNull) {
409
                        // Invalid: intentionally return no value.
410 2
                        return $undefined;
411
                    }
412 4
                    continue;
413
                }
414
415 4
                $fieldValue = self::valueFromAST($fieldNode ? $fieldNode->value : null, $field->getType(), $variables);
0 ignored issues
show
Bug introduced by
It seems like $field->getType() can also be of type callable; however, parameter $type of GraphQL\Utils\AST::valueFromAST() does only seem to accept GraphQL\Type\Definition\InputType, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

415
                $fieldValue = self::valueFromAST($fieldNode ? $fieldNode->value : null, /** @scrutinizer ignore-type */ $field->getType(), $variables);
Loading history...
416
417 4
                if ($undefined === $fieldValue) {
418
                    // Invalid: intentionally return no value.
419 1
                    return $undefined;
420
                }
421 4
                $coercedObj[$fieldName] = $fieldValue;
422
            }
423
424 4
            return $coercedObj;
425
        }
426
427 75
        if ($type instanceof EnumType) {
428 6
            if (! $valueNode instanceof EnumValueNode) {
429 1
                return $undefined;
430
            }
431 6
            $enumValue = $type->getValue($valueNode->value);
432 6
            if (! $enumValue) {
433
                return $undefined;
434
            }
435
436 6
            return $enumValue->value;
437
        }
438
439 70
        if ($type instanceof ScalarType) {
440
            // Scalars fulfill parsing a literal value via parseLiteral().
441
            // Invalid values represent a failure to parse correctly, in which case
442
            // no value is returned.
443
            try {
444 70
                return $type->parseLiteral($valueNode, $variables);
445 8
            } catch (\Exception $error) {
446 8
                return $undefined;
447
            } catch (\Throwable $error) {
448
                return $undefined;
449
            }
450
        }
451
452
        throw new Error('Unknown type: ' . Utils::printSafe($type) . '.');
453
    }
454
455
    /**
456
     * Returns true if the provided valueNode is a variable which is not defined
457
     * in the set of variables.
458
     * @param ValueNode $valueNode
459
     * @param mixed[]   $variables
460
     * @return bool
461
     */
462 9
    private static function isMissingVariable($valueNode, $variables)
463
    {
464 9
        return $valueNode instanceof VariableNode &&
465 9
            (count($variables) === 0 || ! array_key_exists($valueNode->name->value, $variables));
466
    }
467
468
    /**
469
     * Produces a PHP value given a GraphQL Value AST.
470
     *
471
     * Unlike `valueFromAST()`, no type is provided. The resulting PHP value
472
     * will reflect the provided GraphQL value AST.
473
     *
474
     * | GraphQL Value        | PHP Value     |
475
     * | -------------------- | ------------- |
476
     * | Input Object         | Assoc Array   |
477
     * | List                 | Array         |
478
     * | Boolean              | Boolean       |
479
     * | String               | String        |
480
     * | Int / Float          | Int / Float   |
481
     * | Enum                 | Mixed         |
482
     * | Null                 | null          |
483
     *
484
     * @api
485
     * @param Node         $valueNode
486
     * @param mixed[]|null $variables
487
     * @return mixed
488
     * @throws \Exception
489
     */
490 6
    public static function valueFromASTUntyped($valueNode, ?array $variables = null)
491
    {
492
        switch (true) {
493 6
            case $valueNode instanceof NullValueNode:
494 2
                return null;
495 6
            case $valueNode instanceof IntValueNode:
496 3
                return intval($valueNode->value, 10);
497 5
            case $valueNode instanceof FloatValueNode:
498 2
                return floatval($valueNode->value);
499 5
            case $valueNode instanceof StringValueNode:
500 5
            case $valueNode instanceof EnumValueNode:
501 5
            case $valueNode instanceof BooleanValueNode:
502 4
                return $valueNode->value;
503 4
            case $valueNode instanceof ListValueNode:
504 4
                return array_map(
505
                    function ($node) use ($variables) {
506 4
                        return self::valueFromASTUntyped($node, $variables);
507 4
                    },
508 4
                    iterator_to_array($valueNode->values)
509
                );
510 2
            case $valueNode instanceof ObjectValueNode:
511 2
                return array_combine(
512 2
                    array_map(
513
                        function ($field) {
514 2
                            return $field->name->value;
515 2
                        },
516 2
                        iterator_to_array($valueNode->fields)
517
                    ),
518 2
                    array_map(
519
                        function ($field) use ($variables) {
520 2
                            return self::valueFromASTUntyped($field->value, $variables);
521 2
                        },
522 2
                        iterator_to_array($valueNode->fields)
523
                    )
524
                );
525 1
            case $valueNode instanceof VariableNode:
526 1
                $variableName = $valueNode->name->value;
527
528 1
                return ($variables && isset($variables[$variableName]))
529 1
                    ? $variables[$variableName]
530 1
                    : null;
531
        }
532
533
        throw new Error('Unexpected value kind: ' . $valueNode->kind . '.');
534
    }
535
536
    /**
537
     * Returns type definition for given AST Type node
538
     *
539
     * @api
540
     * @param NamedTypeNode|ListTypeNode|NonNullTypeNode $inputTypeNode
541
     * @return Type|null
542
     * @throws \Exception
543
     */
544 331
    public static function typeFromAST(Schema $schema, $inputTypeNode)
545
    {
546 331
        if ($inputTypeNode instanceof ListTypeNode) {
547 18
            $innerType = self::typeFromAST($schema, $inputTypeNode->type);
548
549 18
            return $innerType ? new ListOfType($innerType) : null;
550
        }
551 331
        if ($inputTypeNode instanceof NonNullTypeNode) {
552 44
            $innerType = self::typeFromAST($schema, $inputTypeNode->type);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $innerType is correct as self::typeFromAST($schema, $inputTypeNode->type) targeting GraphQL\Utils\AST::typeFromAST() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
It seems like $inputTypeNode->type can also be of type GraphQL\Language\AST\NameNode; however, parameter $inputTypeNode of GraphQL\Utils\AST::typeFromAST() does only seem to accept GraphQL\Language\AST\Lis...guage\AST\NamedTypeNode, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

552
            $innerType = self::typeFromAST($schema, /** @scrutinizer ignore-type */ $inputTypeNode->type);
Loading history...
553
554 44
            return $innerType ? new NonNull($innerType) : null;
0 ignored issues
show
introduced by
$innerType is of type null, thus it always evaluated to false.
Loading history...
555
        }
556 331
        if ($inputTypeNode instanceof NamedTypeNode) {
0 ignored issues
show
introduced by
$inputTypeNode is always a sub-type of GraphQL\Language\AST\NamedTypeNode.
Loading history...
557 331
            return $schema->getType($inputTypeNode->name->value);
558
        }
559
560
        throw new Error('Unexpected type kind: ' . $inputTypeNode->kind . '.');
561
    }
562
563
    /**
564
     * Returns operation type ("query", "mutation" or "subscription") given a document and operation name
565
     *
566
     * @api
567
     * @param string $operationName
568
     * @return bool
569
     */
570 22
    public static function getOperation(DocumentNode $document, $operationName = null)
571
    {
572 22
        if ($document->definitions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $document->definitions of type GraphQL\Language\AST\DefinitionNode[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
573 22
            foreach ($document->definitions as $def) {
574 22
                if (! ($def instanceof OperationDefinitionNode)) {
575
                    continue;
576
                }
577
578 22
                if (! $operationName || (isset($def->name->value) && $def->name->value === $operationName)) {
579 22
                    return $def->operation;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $def->operation returns the type string which is incompatible with the documented return type boolean.
Loading history...
580
                }
581
            }
582
        }
583
584
        return false;
585
    }
586
}
587