GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Collector::collectFields()   B
last analyzed

Complexity

Conditions 9
Paths 5

Size

Total Lines 28
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 9

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 16
dl 0
loc 28
ccs 17
cts 17
cp 1
rs 8.0555
c 1
b 0
f 0
cc 9
nc 5
nop 2
crap 9
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Experimental\Executor;
6
7
use Generator;
8
use GraphQL\Error\Error;
9
use GraphQL\Language\AST\BooleanValueNode;
10
use GraphQL\Language\AST\DefinitionNode;
11
use GraphQL\Language\AST\DocumentNode;
12
use GraphQL\Language\AST\EnumValueNode;
13
use GraphQL\Language\AST\FieldNode;
14
use GraphQL\Language\AST\FloatValueNode;
15
use GraphQL\Language\AST\FragmentDefinitionNode;
16
use GraphQL\Language\AST\FragmentSpreadNode;
17
use GraphQL\Language\AST\InlineFragmentNode;
18
use GraphQL\Language\AST\IntValueNode;
19
use GraphQL\Language\AST\ListValueNode;
20
use GraphQL\Language\AST\Node;
21
use GraphQL\Language\AST\NullValueNode;
22
use GraphQL\Language\AST\ObjectValueNode;
23
use GraphQL\Language\AST\OperationDefinitionNode;
24
use GraphQL\Language\AST\SelectionSetNode;
25
use GraphQL\Language\AST\StringValueNode;
26
use GraphQL\Language\AST\VariableNode;
27
use GraphQL\Type\Definition\AbstractType;
28
use GraphQL\Type\Definition\Directive;
29
use GraphQL\Type\Definition\ObjectType;
30
use GraphQL\Type\Definition\Type;
31
use GraphQL\Type\Introspection;
32
use GraphQL\Type\Schema;
33
use function sprintf;
34
35
/**
36
 * @internal
37
 */
38
class Collector
39
{
40
    /** @var Schema */
41
    private $schema;
42
43
    /** @var Runtime */
44
    private $runtime;
45
46
    /** @var OperationDefinitionNode|null */
47
    public $operation = null;
48
49
    /** @var FragmentDefinitionNode[] */
50
    public $fragments = [];
51
52
    /** @var ObjectType|null */
53
    public $rootType;
54
55
    /** @var FieldNode[][] */
56
    private $fields;
57
58
    /** @var array<string, bool> */
59
    private $visitedFragments;
60
61 253
    public function __construct(Schema $schema, Runtime $runtime)
62
    {
63 253
        $this->schema  = $schema;
64 253
        $this->runtime = $runtime;
65 253
    }
66
67 253
    public function initialize(DocumentNode $documentNode, ?string $operationName = null)
68
    {
69 253
        $hasMultipleAssumedOperations = false;
70
71 253
        foreach ($documentNode->definitions as $definitionNode) {
72
            /** @var DefinitionNode|Node $definitionNode */
73
74 253
            if ($definitionNode instanceof OperationDefinitionNode) {
75 251
                if ($operationName === null && $this->operation !== null) {
76 1
                    $hasMultipleAssumedOperations = true;
77
                }
78 251
                if ($operationName === null ||
79 251
                    (isset($definitionNode->name) && $definitionNode->name->value === $operationName)
80
                ) {
81 251
                    $this->operation = $definitionNode;
82
                }
83 26
            } elseif ($definitionNode instanceof FragmentDefinitionNode) {
84 253
                $this->fragments[$definitionNode->name->value] = $definitionNode;
85
            }
86
        }
87
88 253
        if ($this->operation === null) {
89 3
            if ($operationName !== null) {
90 1
                $this->runtime->addError(new Error(sprintf('Unknown operation named "%s".', $operationName)));
91
            } else {
92 2
                $this->runtime->addError(new Error('Must provide an operation.'));
93
            }
94
95 3
            return;
96
        }
97
98 250
        if ($hasMultipleAssumedOperations) {
99 1
            $this->runtime->addError(new Error('Must provide operation name if query contains multiple operations.'));
100
101 1
            return;
102
        }
103
104 249
        if ($this->operation->operation === 'query') {
105 241
            $this->rootType = $this->schema->getQueryType();
106 8
        } elseif ($this->operation->operation === 'mutation') {
107 6
            $this->rootType = $this->schema->getMutationType();
108 2
        } elseif ($this->operation->operation === 'subscription') {
109 2
            $this->rootType = $this->schema->getSubscriptionType();
110
        } else {
111
            $this->runtime->addError(new Error(sprintf('Cannot initialize collector with operation type "%s".', $this->operation->operation)));
112
        }
113 249
    }
114
115
    /**
116
     * @return Generator
117
     */
118 238
    public function collectFields(ObjectType $runtimeType, ?SelectionSetNode $selectionSet)
119
    {
120 238
        $this->fields           = [];
121 238
        $this->visitedFragments = [];
122
123 238
        $this->doCollectFields($runtimeType, $selectionSet);
124
125 238
        foreach ($this->fields as $resultName => $fieldNodes) {
126 229
            $fieldNode = $fieldNodes[0];
127 229
            $fieldName = $fieldNode->name->value;
128
129 229
            $argumentValueMap = null;
130 229
            if (! empty($fieldNode->arguments)) {
131 229
                foreach ($fieldNode->arguments as $argumentNode) {
132 91
                    $argumentValueMap                             = $argumentValueMap ?? [];
133 91
                    $argumentValueMap[$argumentNode->name->value] = $argumentNode->value;
134
                }
135
            }
136
137 229
            if ($fieldName !== Introspection::TYPE_NAME_FIELD_NAME &&
138 229
                ! ($runtimeType === $this->schema->getQueryType() && ($fieldName === Introspection::SCHEMA_FIELD_NAME || $fieldName === Introspection::TYPE_FIELD_NAME)) &&
139 229
                ! $runtimeType->hasField($fieldName)
140
            ) {
141
                // do not emit error
142 7
                continue;
143
            }
144
145 225
            yield new CoroutineContextShared($fieldNodes, $fieldName, $resultName, $argumentValueMap);
146
        }
147 238
    }
148
149 238
    private function doCollectFields(ObjectType $runtimeType, ?SelectionSetNode $selectionSet)
150
    {
151 238
        if ($selectionSet === null) {
152
            return;
153
        }
154
155 238
        foreach ($selectionSet->selections as $selection) {
156
            /** @var FieldNode|FragmentSpreadNode|InlineFragmentNode $selection */
157 238
            if (! empty($selection->directives)) {
158 238
                foreach ($selection->directives as $directiveNode) {
159 21
                    if ($directiveNode->name->value === Directive::SKIP_NAME) {
160
                        /** @var VariableNode|NullValueNode|IntValueNode|FloatValueNode|StringValueNode|BooleanValueNode|EnumValueNode|ListValueNode|ObjectValueNode|null $condition */
161 13
                        $condition = null;
162 13
                        foreach ($directiveNode->arguments as $argumentNode) {
163 13
                            if ($argumentNode->name->value === Directive::IF_ARGUMENT_NAME) {
164 13
                                $condition = $argumentNode->value;
165 13
                                break;
166
                            }
167
                        }
168
169 13
                        if ($condition === null) {
170
                            $this->runtime->addError(new Error(
171
                                sprintf('@%s directive is missing "%s" argument.', Directive::SKIP_NAME, Directive::IF_ARGUMENT_NAME),
172
                                $selection
173
                            ));
174
                        } else {
175 13
                            if ($this->runtime->evaluate($condition, Type::boolean()) === true) {
176 13
                                continue 2; // !!! advances outer loop
177
                            }
178
                        }
179 15
                    } elseif ($directiveNode->name->value === Directive::INCLUDE_NAME) {
180
                        /** @var VariableNode|NullValueNode|IntValueNode|FloatValueNode|StringValueNode|BooleanValueNode|EnumValueNode|ListValueNode|ObjectValueNode|null $condition */
181 15
                        $condition = null;
182 15
                        foreach ($directiveNode->arguments as $argumentNode) {
183 15
                            if ($argumentNode->name->value === Directive::IF_ARGUMENT_NAME) {
184 15
                                $condition = $argumentNode->value;
185 15
                                break;
186
                            }
187
                        }
188
189 15
                        if ($condition === null) {
190
                            $this->runtime->addError(new Error(
191
                                sprintf('@%s directive is missing "%s" argument.', Directive::INCLUDE_NAME, Directive::IF_ARGUMENT_NAME),
192
                                $selection
193
                            ));
194
                        } else {
195 15
                            if ($this->runtime->evaluate($condition, Type::boolean()) !== true) {
196 18
                                continue 2; // !!! advances outer loop
197
                            }
198
                        }
199
                    }
200
                }
201
            }
202
203 229
            if ($selection instanceof FieldNode) {
204 229
                $resultName = $selection->alias === null ? $selection->name->value : $selection->alias->value;
205
206 229
                if (! isset($this->fields[$resultName])) {
207 229
                    $this->fields[$resultName] = [];
208
                }
209
210 229
                $this->fields[$resultName][] = $selection;
211 36
            } elseif ($selection instanceof FragmentSpreadNode) {
212 14
                $fragmentName = $selection->name->value;
213
214 14
                if (isset($this->visitedFragments[$fragmentName])) {
215 1
                    continue;
216
                }
217
218 14
                if (! isset($this->fragments[$fragmentName])) {
219
                    $this->runtime->addError(new Error(
220
                        sprintf('Fragment "%s" does not exist.', $fragmentName),
221
                        $selection
222
                    ));
223
                    continue;
224
                }
225
226 14
                $this->visitedFragments[$fragmentName] = true;
227
228 14
                $fragmentDefinition = $this->fragments[$fragmentName];
229 14
                $conditionTypeName  = $fragmentDefinition->typeCondition->name->value;
230
231 14
                if (! $this->schema->hasType($conditionTypeName)) {
232
                    $this->runtime->addError(new Error(
233
                        sprintf('Cannot spread fragment "%s", type "%s" does not exist.', $fragmentName, $conditionTypeName),
234
                        $selection
235
                    ));
236
                    continue;
237
                }
238
239 14
                $conditionType = $this->schema->getType($conditionTypeName);
240
241 14
                if ($conditionType instanceof ObjectType) {
242 13
                    if ($runtimeType->name !== $conditionType->name) {
243 13
                        continue;
244
                    }
245 1
                } elseif ($conditionType instanceof AbstractType) {
246 1
                    if (! $this->schema->isPossibleType($conditionType, $runtimeType)) {
247
                        continue;
248
                    }
249
                }
250
251 14
                $this->doCollectFields($runtimeType, $fragmentDefinition->selectionSet);
252 24
            } elseif ($selection instanceof InlineFragmentNode) {
253 24
                if ($selection->typeCondition !== null) {
254 23
                    $conditionTypeName = $selection->typeCondition->name->value;
255
256 23
                    if (! $this->schema->hasType($conditionTypeName)) {
257
                        $this->runtime->addError(new Error(
258
                            sprintf('Cannot spread inline fragment, type "%s" does not exist.', $conditionTypeName),
259
                            $selection
260
                        ));
261
                        continue;
262
                    }
263
264 23
                    $conditionType = $this->schema->getType($conditionTypeName);
265
266 23
                    if ($conditionType instanceof ObjectType) {
267 23
                        if ($runtimeType->name !== $conditionType->name) {
268 23
                            continue;
269
                        }
270
                    } elseif ($conditionType instanceof AbstractType) {
271
                        if (! $this->schema->isPossibleType($conditionType, $runtimeType)) {
272
                            continue;
273
                        }
274
                    }
275
                }
276
277 229
                $this->doCollectFields($runtimeType, $selection->selectionSet);
278
            }
279
        }
280 238
    }
281
}
282