Completed
Pull Request — master (#217)
by Christoffer
02:30
created

FieldCollector::collectFields()   C

Complexity

Conditions 9
Paths 9

Size

Total Lines 52
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 23
nc 9
nop 4
dl 0
loc 52
rs 6.5703
c 0
b 0
f 0

How to fix   Long Method   

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\Error\InvariantException;
8
use Digia\GraphQL\Language\Node\FieldNode;
9
use Digia\GraphQL\Language\Node\FragmentDefinitionNode;
10
use Digia\GraphQL\Language\Node\FragmentSpreadNode;
11
use Digia\GraphQL\Language\Node\InlineFragmentNode;
12
use Digia\GraphQL\Language\Node\NodeInterface;
13
use Digia\GraphQL\Language\Node\SelectionSetNode;
14
use Digia\GraphQL\Type\Definition\AbstractTypeInterface;
15
use Digia\GraphQL\Type\Definition\ObjectType;
16
use function Digia\GraphQL\Util\typeFromAST;
17
18
class FieldCollector
19
{
20
    /**
21
     * @var ExecutionContext
22
     */
23
    protected $context;
24
25
    /**
26
     * FieldCollector constructor.
27
     * @param ExecutionContext $context
28
     */
29
    public function __construct(ExecutionContext $context)
30
    {
31
        $this->context = $context;
32
    }
33
34
    /**
35
     * @param ObjectType       $runtimeType
36
     * @param SelectionSetNode $selectionSet
37
     * @param array            $fields
38
     * @param array            $visitedFragmentNames
39
     * @return array
40
     * @throws InvalidTypeException
41
     * @throws ExecutionException
42
     * @throws InvariantException
43
     */
44
    public function collectFields(
45
        ObjectType $runtimeType,
46
        SelectionSetNode $selectionSet,
47
        array &$fields,
48
        array &$visitedFragmentNames
49
    ): array {
50
        foreach ($selectionSet->getSelections() as $selection) {
51
            // Check if this Node should be included first
52
            if (!$this->shouldIncludeNode($selection)) {
53
                continue;
54
            }
55
56
            // Collect fields
57
            if ($selection instanceof FieldNode) {
58
                $fieldName = $selection->getAliasOrNameValue();
59
60
                if (!isset($fields[$fieldName])) {
61
                    $fields[$fieldName] = [];
62
                }
63
64
                $fields[$fieldName][] = $selection;
65
66
                continue;
67
            }
68
69
            if ($selection instanceof InlineFragmentNode) {
70
                if (!$this->doesFragmentConditionMatch($selection, $runtimeType)) {
71
                    continue;
72
                }
73
74
                $this->collectFields($runtimeType, $selection->getSelectionSet(), $fields, $visitedFragmentNames);
75
76
                continue;
77
            }
78
79
            if ($selection instanceof FragmentSpreadNode) {
80
                $fragmentName = $selection->getNameValue();
81
82
                if (!empty($visitedFragmentNames[$fragmentName])) {
83
                    continue;
84
                }
85
86
                $visitedFragmentNames[$fragmentName] = true;
87
                /** @var FragmentDefinitionNode $fragment */
88
                $fragment = $this->context->getFragments()[$fragmentName];
89
                $this->collectFields($runtimeType, $fragment->getSelectionSet(), $fields, $visitedFragmentNames);
90
91
                continue;
92
            }
93
        }
94
95
        return $fields;
96
    }
97
98
    /**
99
     * @param $node
100
     * @return bool
101
     */
102
    protected function shouldIncludeNode(NodeInterface $node): bool
103
    {
104
105
        $contextVariables = $this->context->getVariableValues();
106
107
        $skip = coerceDirectiveValues(SkipDirective(), $node, $contextVariables);
108
109
        if ($skip && $skip['if'] === true) {
110
            return false;
111
        }
112
113
        $include = coerceDirectiveValues(IncludeDirective(), $node, $contextVariables);
114
115
        /** @noinspection IfReturnReturnSimplificationInspection */
116
        if ($include && $include['if'] === false) {
117
            return false;
118
        }
119
120
        return true;
121
    }
122
123
    /**
124
     * @param FragmentDefinitionNode|InlineFragmentNode|NodeInterface $fragment
125
     * @param ObjectType                                              $type
126
     * @return bool
127
     */
128
    protected function doesFragmentConditionMatch(NodeInterface $fragment, ObjectType $type): bool
129
    {
130
        $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\FragmentDefinitionNode or Digia\GraphQL\Language\Node\InlineFragmentNode. ( Ignorable by Annotation )

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

130
        /** @scrutinizer ignore-call */ 
131
        $typeConditionNode = $fragment->getTypeCondition();
Loading history...
131
132
        if (null === $typeConditionNode) {
133
            return true;
134
        }
135
136
        $conditionalType = typeFromAST($this->context->getSchema(), $typeConditionNode);
137
138
        if ($type === $conditionalType) {
0 ignored issues
show
introduced by
The condition $type === $conditionalType is always false.
Loading history...
139
            return true;
140
        }
141
142
        if ($conditionalType instanceof AbstractTypeInterface) {
143
            return $this->context->getSchema()->isPossibleType($conditionalType, $type);
144
        }
145
146
        return false;
147
    }
148
149
}
150