Completed
Pull Request — master (#104)
by Quang
02:20
created

ExecutionStrategy::completeValue()   C

Complexity

Conditions 11
Paths 9

Size

Total Lines 60
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 60
rs 6.2926
c 0
b 0
f 0
cc 11
eloc 26
nc 9
nop 5

How to fix   Long Method    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
namespace Digia\GraphQL\Execution;
4
5
use Digia\GraphQL\Error\ExecutionException;
6
use Digia\GraphQL\Error\InvalidTypeException;
7
use Digia\GraphQL\Execution\Resolver\ResolveInfo;
8
use Digia\GraphQL\Language\Node\FieldNode;
9
use Digia\GraphQL\Language\Node\FragmentDefinitionNode;
10
use Digia\GraphQL\Language\Node\InlineFragmentNode;
11
use Digia\GraphQL\Language\Node\NodeInterface;
12
use Digia\GraphQL\Language\Node\NodeKindEnum;
13
use Digia\GraphQL\Language\Node\OperationDefinitionNode;
14
use Digia\GraphQL\Language\Node\SelectionSetNode;
15
use Digia\GraphQL\Type\Definition\AbstractTypeInterface;
16
use Digia\GraphQL\Type\Definition\Field;
17
use Digia\GraphQL\Type\Definition\InterfaceType;
18
use Digia\GraphQL\Type\Definition\LeafTypeInterface;
19
use Digia\GraphQL\Type\Definition\ListType;
20
use Digia\GraphQL\Type\Definition\NonNullType;
21
use Digia\GraphQL\Type\Definition\ObjectType;
22
use Digia\GraphQL\Type\Definition\TypeInterface;
23
use Digia\GraphQL\Type\Definition\UnionType;
24
use Digia\GraphQL\Type\Schema;
25
use function Digia\GraphQL\Type\SchemaMetaFieldDefinition;
26
use function Digia\GraphQL\Type\TypeMetaFieldDefinition;
27
use function Digia\GraphQL\Type\TypeNameMetaFieldDefinition;
28
use function Digia\GraphQL\Util\toString;
29
use function Digia\GraphQL\Util\typeFromAST;
30
31
/**
32
 * Class AbstractStrategy
33
 * @package Digia\GraphQL\Execution\Strategies
34
 */
35
abstract class ExecutionStrategy
36
{
37
    /**
38
     * @var ExecutionContext
39
     */
40
    protected $context;
41
42
    /**
43
     * @var OperationDefinitionNode
44
     */
45
    protected $operation;
46
47
    /**
48
     * @var mixed
49
     */
50
    protected $rootValue;
51
52
53
    /**
54
     * @var ValuesResolver
55
     */
56
    protected $valuesResolver;
57
58
    /**
59
     * @var array
60
     */
61
    protected $finalResult;
62
63
    /**
64
     * AbstractStrategy constructor.
65
     * @param ExecutionContext        $context
66
     *
67
     * @param OperationDefinitionNode $operation
68
     */
69
    public function __construct(
70
        ExecutionContext $context,
71
        OperationDefinitionNode $operation,
72
        $rootValue,
73
        $valueResolver
74
    ) {
75
        $this->context        = $context;
76
        $this->operation      = $operation;
77
        $this->rootValue      = $rootValue;
78
        $this->valuesResolver = $valueResolver;
79
    }
80
81
    /**
82
     * @return array|null
83
     */
84
    abstract function execute(): ?array;
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
85
86
    /**
87
     * @param ObjectType       $runtimeType
88
     * @param SelectionSetNode $selectionSet
89
     * @param                  $fields
90
     * @param                  $visitedFragmentNames
91
     * @return mixed
92
     * @throws InvalidTypeException
93
     * @throws \Digia\GraphQL\Error\ExecutionException
94
     * @throws \Digia\GraphQL\Error\InvariantException
95
     */
96
    protected function collectFields(
97
        ObjectType $runtimeType,
98
        SelectionSetNode $selectionSet,
99
        $fields,
100
        $visitedFragmentNames
101
    ) {
102
        foreach ($selectionSet->getSelections() as $selection) {
103
            switch ($selection->getKind()) {
104
                case NodeKindEnum::FIELD:
105
                    /** @var FieldNode $selection */
106
                    $fieldName = $this->getFieldNameKey($selection);
107
                    if (!isset($runtimeType->getFields()[$selection->getNameValue()])) {
108
                        continue 2;
109
                    }
110
                    if (!isset($fields[$fieldName])) {
111
                        $fields[$fieldName] = new \ArrayObject();
112
                    }
113
                    $fields[$fieldName][] = $selection;
114
                    break;
115
                case NodeKindEnum::INLINE_FRAGMENT:
116
                    /** @var FragmentDefinitionNode $selection */
117
                    if (!$this->shouldIncludeNode($selection) ||
118
                        !$this->doesFragmentConditionMatch($selection, $runtimeType)
119
                    ) {
120
                        continue 2;
121
                    }
122
                    $this->collectFields(
123
                        $runtimeType,
124
                        $selection->getSelectionSet(),
125
                        $fields,
126
                        $visitedFragmentNames
127
                    );
128
                    break;
129
                case NodeKindEnum::FRAGMENT_SPREAD:
130
                    $fragmentName = $selection->getNameValue();
131
                    if (!empty($visitedFragmentNames[$fragmentName]) || !$this->shouldIncludeNode($selection)) {
132
                        continue 2;
133
                    }
134
                    $visitedFragmentNames[$fragmentName] = true;
135
                    /** @var FragmentDefinitionNode $fragment */
136
                    $fragment = $this->context->getFragments()[$fragmentName];
137
                    $this->collectFields(
138
                        $runtimeType,
139
                        $fragment->getSelectionSet(),
140
                        $fields,
141
                        $visitedFragmentNames
142
                    );
143
                    break;
144
            }
145
        }
146
147
        return $fields;
148
    }
149
150
151
    /**
152
     * @param $node
153
     * @return bool
154
     * @throws InvalidTypeException
155
     * @throws \Digia\GraphQL\Error\ExecutionException
156
     * @throws \Digia\GraphQL\Error\InvariantException
157
     */
158
    private function shouldIncludeNode(NodeInterface $node)
159
    {
160
        $skip = $this->valuesResolver->getDirectiveValues(GraphQLSkipDirective(), $node,
161
            $this->context->getVariableValues());
162
163
        if ($skip && $skip['if'] === true) {
164
            return false;
165
        }
166
167
        $include = $this->valuesResolver->getDirectiveValues(GraphQLSkipDirective(), $node,
168
            $this->context->getVariableValues());
169
170
        if ($include && $include['if'] === false) {
171
            return false;
172
        }
173
174
        return true;
175
    }
176
177
    /**
178
     * @param FragmentDefinitionNode|InlineFragmentNode $fragment
179
     * @param ObjectType                                $type
180
     * @return bool
181
     * @throws InvalidTypeException
182
     */
183
    private function doesFragmentConditionMatch(NodeInterface $fragment, ObjectType $type)
184
    {
185
        $typeConditionNode = $fragment->getTypeCondition();
0 ignored issues
show
Bug introduced by
The method getTypeCondition() does not exist on Digia\GraphQL\Language\Node\NodeInterface. It seems like you code against a sub-type of Digia\GraphQL\Language\Node\NodeInterface such as Digia\GraphQL\Language\Node\InlineFragmentNode or Digia\GraphQL\Language\Node\FragmentDefinitionNode. ( Ignorable by Annotation )

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

185
        /** @scrutinizer ignore-call */ 
186
        $typeConditionNode = $fragment->getTypeCondition();
Loading history...
186
187
        if (!$typeConditionNode) {
188
            return true;
189
        }
190
191
        $conditionalType = typeFromAST($this->context->getSchema(), $typeConditionNode);
192
193
        if ($conditionalType === $type) {
194
            return true;
195
        }
196
197
        if ($conditionalType instanceof AbstractTypeInterface) {
198
            return $this->context->getSchema()->isPossibleType($conditionalType, $type);
199
        }
200
201
        return false;
202
    }
203
204
    /**
205
     * @TODO: consider to move this to FieldNode
206
     * @param FieldNode $node
207
     * @return string
208
     */
209
    private function getFieldNameKey(FieldNode $node)
210
    {
211
        return $node->getAlias() ? $node->getAlias()->getValue() : $node->getNameValue();
212
    }
213
214
    /**
215
     * Implements the "Evaluating selection sets" section of the spec for "read" mode.
216
     * @param ObjectType $objectType
217
     * @param            $rootValue
218
     * @param            $path
219
     * @param            $fields
220
     * @return array
221
     * @throws InvalidTypeException
222
     * @throws \Digia\GraphQL\Error\ExecutionException
223
     * @throws \Digia\GraphQL\Error\InvariantException
224
     * @throws \Throwable
225
     */
226
    protected function executeFields(
227
        ObjectType $objectType,
228
        $rootValue,
229
        $path,
230
        $fields
231
    ): array {
232
        $finalResults = [];
233
234
        foreach ($fields as $fieldName => $fieldNodes) {
235
            $fieldPath   = $path;
236
            $fieldPath[] = $fieldName;
237
238
            $result = $this->resolveField(
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $result is correct as $this->resolveField($obj...fieldNodes, $fieldPath) targeting Digia\GraphQL\Execution\...trategy::resolveField() 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...
239
                $objectType,
240
                $rootValue,
241
                $fieldNodes,
242
                $fieldPath
243
            );
244
245
            $finalResults[$fieldName] = $result;
246
        }
247
248
        return $finalResults;
249
    }
250
251
    /**
252
     * Implements the "Evaluating selection sets" section of the spec for "write" mode.
253
     *
254
     * @param ObjectType $objectType
255
     * @param            $rootValue
256
     * @param            $path
257
     * @param            $fields
258
     * @return array
259
     * @throws InvalidTypeException
260
     * @throws \Digia\GraphQL\Error\ExecutionException
261
     * @throws \Digia\GraphQL\Error\InvariantException
262
     * @throws \Throwable
263
     */
264
    public function executeFieldsSerially(ObjectType $objectType, $rootValue, $path, $fields)
265
    {
266
        //@TODO execute fields serially
267
        $finalResults = [];
268
269
        foreach ($fields as $fieldName => $fieldNodes) {
270
            $fieldPath   = $path;
271
            $fieldPath[] = $fieldName;
272
273
            $result = $this->resolveField($objectType,
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $result is correct as $this->resolveField($obj...fieldNodes, $fieldPath) targeting Digia\GraphQL\Execution\...trategy::resolveField() 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...
274
                $rootValue,
275
                $fieldNodes,
276
                $fieldPath
277
            );
278
279
            $finalResults[$fieldName] = $result;
280
        }
281
282
        return $finalResults;
283
    }
284
285
    /**
286
     * @param Schema     $schema
287
     * @param ObjectType $parentType
288
     * @param string     $fieldName
289
     * @return \Digia\GraphQL\Type\Definition\Field|null
290
     * @throws InvalidTypeException
291
     */
292
    public function getFieldDefinition(Schema $schema, ObjectType $parentType, string $fieldName)
293
    {
294
        $schemaMetaFieldDefinition   = SchemaMetaFieldDefinition();
295
        $typeMetaFieldDefinition     = TypeMetaFieldDefinition();
296
        $typeNameMetaFieldDefinition = TypeNameMetaFieldDefinition();
297
298
        if ($fieldName === $schemaMetaFieldDefinition->getName() && $schema->getQuery() === $parentType) {
299
            return $schemaMetaFieldDefinition;
300
        }
301
302
        if ($fieldName === $typeMetaFieldDefinition->getName() && $schema->getQuery() === $parentType) {
303
            return $typeMetaFieldDefinition;
304
        }
305
306
        if ($fieldName === $typeNameMetaFieldDefinition->getName()) {
307
            return $typeNameMetaFieldDefinition;
308
        }
309
310
        $fields = $parentType->getFields();
311
312
        return $fields[$fieldName] ?? null;
313
    }
314
315
316
    /**
317
     * @param ObjectType $parentType
318
     * @param            $rootValue
319
     * @param            $fieldNodes
320
     * @param            $path
321
     * @return array|null|\Throwable
322
     * @throws InvalidTypeException
323
     * @throws \Digia\GraphQL\Error\ExecutionException
324
     * @throws \Digia\GraphQL\Error\InvariantException
325
     * @throws \Throwable
326
     */
327
    protected function resolveField(
328
        ObjectType $parentType,
329
        $rootValue,
330
        $fieldNodes,
331
        $path
332
    ) {
333
        /** @var FieldNode $fieldNode */
334
        $fieldNode = $fieldNodes[0];
335
336
        $field = $this->getFieldDefinition($this->context->getSchema(), $parentType, $fieldNode->getNameValue());
337
338
        if (!$field) {
339
            return null;
340
        }
341
342
        $info = $this->buildResolveInfo($fieldNodes, $fieldNode, $field, $parentType, $path, $this->context);
343
344
        $resolveFunction = $this->determineResolveFunction($field, $parentType, $this->context);
345
346
        $result = $this->resolveFieldValueOrError(
347
            $field,
348
            $fieldNode,
349
            $resolveFunction,
350
            $rootValue,
351
            $this->context,
352
            $info
353
        );
354
355
        $result = $this->completeValueCatchingError(
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $result is correct as $this->completeValueCatc... $info, $path, $result) targeting Digia\GraphQL\Execution\...eteValueCatchingError() 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...
356
            $field->getType(),
357
            $fieldNodes,
358
            $info,
359
            $path,
360
            $result// $result is passed as $source
361
        );
362
363
        return $result;
364
    }
365
366
    /**
367
     * @param array            $fieldNodes
368
     * @param FieldNode        $fieldNode
369
     * @param Field            $field
370
     * @param ObjectType       $parentType
371
     * @param                  $path
372
     * @param ExecutionContext $context
373
     * @return ResolveInfo
374
     */
375
    private function buildResolveInfo(
376
        \ArrayAccess $fieldNodes,
377
        FieldNode $fieldNode,
378
        Field $field,
379
        ObjectType $parentType,
380
        $path,
381
        ExecutionContext $context
382
    ) {
383
        return new ResolveInfo([
384
            'fieldName'      => $fieldNode->getNameValue(),
385
            'fieldNodes'     => $fieldNodes,
386
            'returnType'     => $field->getType(),
387
            'parentType'     => $parentType,
388
            'path'           => $path,
389
            'schema'         => $context->getSchema(),
390
            'fragments'      => $context->getFragments(),
391
            'rootValue'      => $context->getRootValue(),
392
            'operation'      => $context->getOperation(),
393
            'variableValues' => $context->getVariableValues(),
394
        ]);
395
    }
396
397
    /**
398
     * @param Field            $field
399
     * @param ObjectType       $objectType
400
     * @param ExecutionContext $context
401
     * @return callable|mixed|null
402
     */
403
    private function determineResolveFunction(Field $field, ObjectType $objectType, ExecutionContext $context)
0 ignored issues
show
Unused Code introduced by
The parameter $context is not used and could be removed. ( Ignorable by Annotation )

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

403
    private function determineResolveFunction(Field $field, ObjectType $objectType, /** @scrutinizer ignore-unused */ ExecutionContext $context)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
404
    {
405
406
        if ($field->hasResolve()) {
407
            return $field->getResolve();
408
        }
409
410
        if ($objectType->hasResolve()) {
411
            return $objectType->getResolve();
412
        }
413
414
        return $this->context->getFieldResolver();
415
    }
416
417
    /**
418
     * @param TypeInterface $fieldType
419
     * @param               $fieldNodes
420
     * @param ResolveInfo   $info
421
     * @param               $path
422
     * @param               $result
423
     * @return null
424
     * @throws \Throwable
425
     */
426
    public function completeValueCatchingError(
427
        TypeInterface $fieldType,
428
        $fieldNodes,
429
        ResolveInfo $info,
430
        $path,
431
        &$result
432
    ) {
433
        if ($fieldType instanceof NonNullType) {
434
            return $this->completeValueWithLocatedError(
435
                $fieldType,
436
                $fieldNodes,
437
                $info,
438
                $path,
439
                $result
440
            );
441
        }
442
443
        try {
444
            $completed = $this->completeValueWithLocatedError(
445
                $fieldType,
446
                $fieldNodes,
447
                $info,
448
                $path,
449
                $result
450
            );
451
452
            return $completed;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $completed also could return the type array which is incompatible with the documented return type null.
Loading history...
453
        } catch (\Exception $ex) {
454
            $this->context->addError(new ExecutionException($ex->getMessage()));
455
            return null;
456
        }
457
    }
458
459
    /**
460
     * @param TypeInterface $fieldType
461
     * @param               $fieldNodes
462
     * @param ResolveInfo   $info
463
     * @param               $path
464
     * @param               $result
465
     * @throws \Throwable
466
     */
467
    public function completeValueWithLocatedError(
468
        TypeInterface $fieldType,
469
        $fieldNodes,
470
        ResolveInfo $info,
471
        $path,
472
        $result
473
    ) {
474
        try {
475
            $completed = $this->completeValue(
476
                $fieldType,
477
                $fieldNodes,
478
                $info,
479
                $path,
480
                $result
481
            );
482
            return $completed;
483
        } catch (\Exception $ex) {
484
            //@TODO throw located error
485
            throw $ex;
486
        } catch (\Throwable $ex) {
487
            //@TODO throw located error
488
            throw $ex;
489
        }
490
    }
491
492
    /**
493
     * @param TypeInterface $returnType
494
     * @param               $fieldNodes
495
     * @param ResolveInfo   $info
496
     * @param               $path
497
     * @param               $result
498
     * @return array|mixed
499
     * @throws ExecutionException
500
     * @throws \Throwable
501
     */
502
    private function completeValue(
503
        TypeInterface $returnType,
504
        $fieldNodes,
505
        ResolveInfo $info,
506
        $path,
507
        &$result
508
    ) {
509
        if ($result instanceof \Exception || $result instanceof \Throwable) {
510
            throw $result;
511
        }
512
513
        // If result is null-like, return null.
514
        if (null === $result) {
515
            return null;
516
        }
517
518
        if ($returnType instanceof NonNullType) {
519
            $completed = $this->completeValue(
520
                $returnType->getOfType(),
521
                $fieldNodes,
522
                $info,
523
                $path,
524
                $result
525
            );
526
527
            if ($completed === null) {
528
                throw new ExecutionException(
529
                    sprintf(
530
                        'Cannot return null for non-nullable field %s.%s.',
531
                        $info->getParentType(), $info->getFieldName()
532
                    )
533
                );
534
            }
535
536
            return $completed;
537
        }
538
539
        // If field type is List, complete each item in the list with the inner type
540
        if ($returnType instanceof ListType) {
541
            return $this->completeListValue($returnType, $fieldNodes, $info, $path, $result);
542
        }
543
544
545
        // If field type is Scalar or Enum, serialize to a valid value, returning
546
        // null if serialization is not possible.
547
        if ($returnType instanceof LeafTypeInterface) {
548
            return $this->completeLeafValue($returnType, $result);
549
        }
550
551
        //@TODO Make a funnction for checking abstract type?
552
        if ($returnType instanceof InterfaceType || $returnType instanceof UnionType) {
553
            return $this->completeAbstractValue($returnType, $fieldNodes, $info, $path, $result);
554
        }
555
556
        // Field type must be Object, Interface or Union and expect sub-selections.
557
        if ($returnType instanceof ObjectType) {
558
            return $this->completeObjectValue($returnType, $fieldNodes, $info, $path, $result);
559
        }
560
561
        throw new ExecutionException("Cannot complete value of unexpected type \"{$returnType}\".");
562
    }
563
564
    /**
565
     * @param AbstractTypeInterface $returnType
566
     * @param                       $fieldNodes
567
     * @param ResolveInfo           $info
568
     * @param                       $path
569
     * @param                       $result
570
     * @return array
571
     * @throws ExecutionException
572
     * @throws InvalidTypeException
573
     * @throws \Digia\GraphQL\Error\InvariantException
574
     * @throws \Throwable
575
     */
576
    private function completeAbstractValue(
577
        AbstractTypeInterface $returnType,
578
        $fieldNodes,
579
        ResolveInfo $info,
580
        $path,
581
        &$result
582
    ) {
583
        $runtimeType = $returnType->resolveType($result, $this->context, $info);
584
585
        if (null === $runtimeType) {
586
            throw new ExecutionException(
587
                sprintf(
588
                    "GraphQL Interface Type `%s` returned `null` from it`s `resolveType` function for value: %s",
589
                    $returnType->getName(), toString($result)
590
                )
591
            );
592
        }
593
594
        //@TODO Check if $runtimeType is a valid runtime type
595
        return $this->completeObjectValue(
596
            $runtimeType,
597
            $fieldNodes,
598
            $info,
599
            $path,
600
            $result
601
        );
602
    }
603
604
    /**
605
     * @param ListType    $returnType
606
     * @param             $fieldNodes
607
     * @param ResolveInfo $info
608
     * @param             $path
609
     * @param             $result
610
     * @return array
611
     * @throws \Throwable
612
     */
613
    private function completeListValue(ListType $returnType, $fieldNodes, ResolveInfo $info, $path, &$result)
614
    {
615
        $itemType = $returnType->getOfType();
616
617
        $completedItems = [];
618
619
        foreach ($result as $key => $item) {
620
            $fieldPath        = $path;
621
            $fieldPath[]      = $key;
622
            $completedItem    = $this->completeValueCatchingError($itemType, $fieldNodes, $info, $fieldPath, $item);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $completedItem is correct as $this->completeValueCatc...nfo, $fieldPath, $item) targeting Digia\GraphQL\Execution\...eteValueCatchingError() 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...
623
            $completedItems[] = $completedItem;
624
        }
625
626
        return $completedItems;
627
    }
628
629
    /**
630
     * @param LeafTypeInterface $returnType
631
     * @param                   $result
632
     * @return mixed
633
     * @throws ExecutionException
634
     */
635
    private function completeLeafValue(LeafTypeInterface $returnType, &$result)
636
    {
637
        $serializedResult = $returnType->serialize($result);
0 ignored issues
show
Bug introduced by
The method serialize() does not exist on Digia\GraphQL\Type\Definition\LeafTypeInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Digia\GraphQL\Type\Definition\LeafTypeInterface. ( Ignorable by Annotation )

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

637
        /** @scrutinizer ignore-call */ 
638
        $serializedResult = $returnType->serialize($result);
Loading history...
638
639
        if ($serializedResult === null) {
640
            throw new ExecutionException(
641
                'Expected a value of type "' . toString($returnType) . '" but received: ' . toString($result)
642
            );
643
        }
644
645
        return $serializedResult;
646
    }
647
648
    /**
649
     * @param ObjectType  $returnType
650
     * @param             $fieldNodes
651
     * @param ResolveInfo $info
652
     * @param             $path
653
     * @param             $result
654
     * @return array
655
     * @throws ExecutionException
656
     * @throws InvalidTypeException
657
     * @throws \Digia\GraphQL\Error\InvariantException
658
     * @throws \Throwable
659
     */
660
    private function completeObjectValue(ObjectType $returnType, $fieldNodes, ResolveInfo $info, $path, &$result)
661
    {
662
        return $this->collectAndExecuteSubFields(
663
            $returnType,
664
            $fieldNodes,
665
            $info,
666
            $path,
667
            $result
668
        );
669
    }
670
671
    /**
672
     * @param Field            $field
673
     * @param FieldNode        $fieldNode
674
     * @param callable         $resolveFunction
675
     * @param                  $rootValue
676
     * @param ExecutionContext $context
677
     * @param ResolveInfo      $info
678
     * @return array|\Throwable
679
     */
680
    private function resolveFieldValueOrError(
681
        Field $field,
682
        FieldNode $fieldNode,
683
        callable $resolveFunction,
684
        $rootValue,
685
        ExecutionContext $context,
686
        ResolveInfo $info
687
    ) {
688
        try {
689
            $args = $this->valuesResolver->coerceArgumentValues($field, $fieldNode, $context->getVariableValues());
690
691
            return $resolveFunction($rootValue, $args, $context->getContextValue(), $info);
692
        } catch (\Throwable $error) {
693
            return $error;
694
        }
695
    }
696
697
    /**
698
     * @param ObjectType  $returnType
699
     * @param             $fieldNodes
700
     * @param ResolveInfo $info
701
     * @param             $path
702
     * @param             $result
703
     * @return array
704
     * @throws InvalidTypeException
705
     * @throws \Digia\GraphQL\Error\ExecutionException
706
     * @throws \Digia\GraphQL\Error\InvariantException
707
     * @throws \Throwable
708
     */
709
    private function collectAndExecuteSubFields(
710
        ObjectType $returnType,
711
        $fieldNodes,
712
        ResolveInfo $info,
0 ignored issues
show
Unused Code introduced by
The parameter $info is not used and could be removed. ( Ignorable by Annotation )

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

712
        /** @scrutinizer ignore-unused */ ResolveInfo $info,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
713
        $path,
714
        &$result
715
    ) {
716
        $subFields = new \ArrayObject();
717
718
        foreach ($fieldNodes as $fieldNode) {
719
            /** @var FieldNode $fieldNode */
720
            if ($fieldNode->getSelectionSet() !== null) {
721
                $subFields = $this->collectFields(
722
                    $returnType,
723
                    $fieldNode->getSelectionSet(),
724
                    $subFields,
725
                    new \ArrayObject()
726
                );
727
            }
728
        }
729
730
        if ($subFields->count()) {
731
            return $this->executeFields($returnType, $result, $path, $subFields);
732
        }
733
734
        return $result;
735
    }
736
}
737