Parser   F
last analyzed

Complexity

Total Complexity 73

Size/Duplication

Total Lines 438
Duplicated Lines 36.99 %

Coupling/Cohesion

Components 1
Dependencies 33

Test Coverage

Coverage 87.5%

Importance

Changes 0
Metric Value
wmc 73
lcom 1
cbo 33
dl 162
loc 438
ccs 217
cts 248
cp 0.875
rs 1.3043
c 0
b 0
f 0

22 Methods

Rating   Name   Duplication   Size   Complexity  
A getNameFor() 0 4 1
B parseObject() 22 22 4
A parseList() 20 20 4
A parseVariable() 0 7 1
C parseValue() 0 51 12
A parseArgument() 0 8 1
B parseArgumentList() 25 25 5
A parseField() 0 23 3
A parseFragment() 0 16 2
A parseSelection() 19 19 4
A parseSelectionSet() 20 20 4
A parseTypeCondition() 0 13 2
A parseListType() 0 8 1
A parseNamedType() 0 7 1
B parseType() 0 25 6
A parseDirective() 0 8 1
A parseDirectiveList() 0 9 2
A parseVariableDefinition() 13 13 2
B parseVariableDefinitionList() 25 25 5
C parseDefinition() 18 67 9
A parseDocument() 0 10 2
A parse() 0 9 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Parser often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Parser, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace HansOtt\GraphQL\Query;
4
5
use HansOtt\GraphQL\Shared\ScannerTokens;
6
use HansOtt\GraphQL\Shared\ScannerGeneric;
7
use HansOtt\GraphQL\Shared\Parser as ParserShared;
8
9
final class Parser extends ParserShared
10
{
11 6
    protected function getNameFor($tokenType)
12
    {
13 6
        return Token::getNameFor($tokenType);
14
    }
15
16 6 View Code Duplication
    private function parseObject()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
17
    {
18 3
        $location = $this->expect(Token::T_BRACE_LEFT)->location;
19 3
        $fields = array();
20
21 3
        while (true) {
22 3
            if ($this->scanner->eof()) {
23
                throw $this->getParseError('Unclosed brace of object value');
24
            }
25
26 3
            if ($this->accept(Token::T_BRACE_RIGHT)) {
27 6
                break;
28
            }
29
30 3
            $nameToken = $this->expect(Token::T_NAME);
31 3
            $this->expect(Token::T_COLON);
32 3
            $fields[] = new ValueObjectField($nameToken->value, $this->parseValue(), $nameToken->location);
0 ignored issues
show
Documentation introduced by
$nameToken->location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
33 3
            $this->accept(Token::T_COMMA);
34 3
        }
35
36 3
        return new ValueObject($fields, $location);
0 ignored issues
show
Documentation introduced by
$location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
37
    }
38
39 6 View Code Duplication
    private function parseList()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
40
    {
41 6
        $location = $this->expect(Token::T_BRACKET_LEFT)->location;
42 6
        $items = array();
43
44 6
        while (true) {
45 6
            if ($this->scanner->eof()) {
46
                throw $this->getParseError('Unclosed bracket of list');
47
            }
48
49 6
            if ($this->accept(Token::T_BRACKET_RIGHT)) {
50 3
                break;
51
            }
52
53 6
            $items[] = $this->parseValue();
54 3
            $this->accept(Token::T_COMMA);
55 3
        }
56
57 3
        return new ValueList($items, $location);
0 ignored issues
show
Documentation introduced by
$location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
58
    }
59
60 15
    private function parseVariable()
61
    {
62 15
        $location = $this->expect(Token::T_DOLLAR)->location;
63 15
        $name = $this->expect(Token::T_NAME)->value;
64
65 15
        return new ValueVariable($name, $location);
0 ignored issues
show
Documentation introduced by
$location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
66
    }
67
68 30
    private function parseValue()
69
    {
70 30
        if ($this->is(Token::T_DOLLAR)) {
71 12
            return $this->parseVariable();
72
        }
73
74 24
        if ($string = $this->accept(Token::T_STRING)) {
75 18
            return new ValueString($string->value, $string->location);
0 ignored issues
show
Documentation introduced by
$string->location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
76
        }
77
78 21
        if ($true = $this->accept(Token::T_TRUE)) {
79 3
            return new ValueBoolean(true, $true->location);
80
        }
81
82 21
        if ($false = $this->accept(Token::T_FALSE)) {
83 3
            return new ValueBoolean(false, $false->location);
84
        }
85
86 21
        if ($null = $this->accept(Token::T_NULL)) {
87 3
            return new ValueNull($null->location);
88
        }
89
90 21
        if ($int = $this->accept(Token::T_INT)) {
91 18
            return new ValueInt($int->value, $int->location);
92
        }
93
94 6
        if ($float = $this->accept(Token::T_FLOAT)) {
95 3
            return new ValueFloat($float->value, $float->location);
96
        }
97
98 6
        if ($name = $this->accept(Token::T_NAME)) {
99 3
            return new ValueEnum($name->value, $name->location);
100
        }
101
102 6
        if ($this->is(Token::T_BRACKET_LEFT)) {
103 6
            return $this->parseList();
104
        }
105
106 6
        if ($this->is(Token::T_BRACE_LEFT)) {
107 3
            return $this->parseObject();
108
        }
109
110 3
        $message = 'Expected a value';
111
112 3
        if ($this->scanner->eof()) {
113
            throw $this->getParseError($message . ' but instead reached end');
114
        }
115
116 3
        $token = $this->scanner->peek();
117 3
        throw $this->getParseError($message . " but instead found \"{$token->getName()}\" with value \"{$token->value}\"");
118
    }
119
120 36
    private function parseArgument()
121
    {
122 36
        $nameToken = $this->expect(Token::T_NAME);
123 30
        $this->expect(Token::T_COLON);
124 30
        $value = $this->parseValue();
125
126 27
        return new Argument($nameToken->value, $value, $nameToken->location);
0 ignored issues
show
Documentation introduced by
$nameToken->location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
127
    }
128
129 60 View Code Duplication
    private function parseArgumentList()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
130
    {
131 60
        $arguments = array();
132
133 60
        if ($this->is(Token::T_PAREN_LEFT) === false) {
134 30
            return $arguments;
135
        }
136
137 39
        $this->expect(Token::T_PAREN_LEFT);
138
139 39
        while (true) {
140 39
            if ($this->scanner->eof()) {
141
                throw $this->getParseError('Unclosed brace of argument list');
142
            }
143
144 39
            if ($this->accept(Token::T_PAREN_RIGHT)) {
145 30
                break;
146
            }
147
148 36
            $arguments[] = $this->parseArgument();
149 27
            $this->accept(Token::T_COMMA);
150 27
        }
151
152 30
        return $arguments;
153
    }
154
155 60
    private function parseField()
156
    {
157 60
        $nameToken = $this->expect(Token::T_NAME);
158 60
        $name = $nameToken->value;
159
160 60
        $alias = null;
161 60
        if ($this->is(Token::T_COLON)) {
162 3
            $this->expect(Token::T_COLON);
163 3
            $aliasToken = $this->expect(Token::T_NAME);
164 3
            $alias = $name;
165 3
            $name = $aliasToken->value;
166 3
        }
167
168 60
        $arguments = $this->parseArgumentList();
169 51
        $directives = $this->parseDirectiveList();
170
171 51
        $selectionSet = null;
172 51
        if ($this->is(Token::T_BRACE_LEFT)) {
173 21
            $selectionSet = $this->parseSelectionSet();
174 18
        }
175
176 48
        return new SelectionField($alias, $name, $arguments, $directives, $selectionSet, $nameToken->location);
0 ignored issues
show
Documentation introduced by
$nameToken->location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
177
    }
178
179 6
    private function parseFragment()
180
    {
181 6
        $location = $this->expect(Token::T_SPREAD)->location;
182 6
        $fragmentName = $this->expect(Token::T_NAME)->value;
183
184 6
        if ($fragmentName !== 'on') {
185 3
            return new SelectionFragmentSpread($fragmentName, $location);
0 ignored issues
show
Documentation introduced by
$location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
186
        }
187
188 3
        $this->scanner->back();
189 3
        $typeCondition = $this->parseTypeCondition();
190 3
        $directives = $this->parseDirectiveList();
191 3
        $selectionSet = $this->parseSelectionSet();
192
193 3
        return new SelectionInlineFragment($typeCondition, $directives, $selectionSet, $location);
0 ignored issues
show
Documentation introduced by
$location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
194
    }
195
196 63 View Code Duplication
    private function parseSelection()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
197
    {
198 63
        if ($this->is(Token::T_SPREAD)) {
199 6
            return $this->parseFragment();
200
        }
201
202 63
        if ($this->is(Token::T_NAME)) {
203 60
            return $this->parseField();
204
        }
205
206 3
        $message = 'Expected a field, a fragment spread or an inline fragment';
207
208 3
        if ($this->scanner->eof()) {
209
            throw $this->getParseError($message . ' but instead reached end');
210
        }
211
212 3
        $token = $this->scanner->peek();
213 3
        throw $this->getParseError($message . " but instead found \"{$token->getName()}\" with value \"{$token->value}\"");
214
    }
215
216 66 View Code Duplication
    private function parseSelectionSet()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
217
    {
218 66
        $location = $this->expect(Token::T_BRACE_LEFT)->location;
219
220
        /** @var Selection[] $selections */
221 66
        $selections = array();
222 66
        while (true) {
223 66
            if ($this->scanner->eof()) {
224 9
                throw $this->getParseError('Unclosed brace of selection set');
225
            }
226
227 63
            if ($this->accept(Token::T_BRACE_RIGHT)) {
228 45
                break;
229
            }
230
231 63
            $selections[] = $this->parseSelection();
232 48
        }
233
234 45
        return new SelectionSet($selections, $location);
0 ignored issues
show
Documentation introduced by
$location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
235
    }
236
237 9
    private function parseTypeCondition()
238
    {
239 6
        $nameToken = $this->expect(Token::T_NAME);
240 6
        $on = $nameToken->value;
241 6
        if ($on !== 'on') {
242
            $tokenNameName = Token::getNameFor(Token::T_NAME);
243
            throw $this->getParseError("Expected a type condition but instead found \"{$tokenNameName}\" with value \"{$on}\"");
244
        }
245
246 6
        $type = $this->parseNamedType();
247
248 9
        return new TypeCondition($type, $nameToken->location);
0 ignored issues
show
Documentation introduced by
$nameToken->location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
249 3
    }
250
251 3
    private function parseListType()
252 3
    {
253 3
        $location = $this->expect(Token::T_BRACKET_LEFT)->location;
254 3
        $type = $this->parseType();
255 3
        $this->accept(Token::T_BRACKET_RIGHT);
256
257 3
        return new TypeList($type, $location);
0 ignored issues
show
Documentation introduced by
$location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
258
    }
259
260 18
    private function parseNamedType()
261
    {
262 18
        $nameToken = $this->expect(Token::T_NAME);
263 18
        $type = new TypeNamed($nameToken->value, $nameToken->location);
0 ignored issues
show
Documentation introduced by
$nameToken->location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
264
265 18
        return $type;
266
    }
267
268 12
    private function parseType()
269
    {
270 12
        $type = null;
271 12
        if ($this->is(Token::T_BRACKET_LEFT)) {
272 3
            $type = $this->parseListType();
273 12
        } elseif ($this->is(Token::T_NAME)) {
274 12
            $type = $this->parseNamedType();
275 12
        }
276
277 12
        if ($type !== null) {
278 12
            if ($this->accept(Token::T_EXCLAMATION)) {
279 6
                return new TypeNonNull($type, $type->location);
280
            }
281 9
            return $type;
282
        }
283
284
        $message = 'Expected a type';
285
286
        if ($this->scanner->eof()) {
287
            throw $this->getParseError($message . ' but instead reached end');
288
        }
289
290
        $token = $this->scanner->peek();
291
        throw $this->getParseError($message . " but instead found \"{$token->getName()}\" with value \"{$token->value}\"");
292
    }
293
294 6
    private function parseDirective()
295
    {
296 6
        $location = $this->expect(Token::T_AT)->location;
297 6
        $name = $this->expect(Token::T_NAME)->value;
298 6
        $arguments = $this->parseArgumentList();
299
300 6
        return new Directive($name, $arguments, $location);
0 ignored issues
show
Documentation introduced by
$location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
301
    }
302
303 51
    private function parseDirectiveList()
304
    {
305 51
        $directives = array();
306 51
        while ($this->is(Token::T_AT)) {
307 6
            $directives[] = $this->parseDirective();
308 6
        }
309
310 51
        return $directives;
311
    }
312
313 12 View Code Duplication
    private function parseVariableDefinition()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
314
    {
315 12
        $variable = $this->parseVariable();
316 12
        $this->expect(Token::T_COLON);
317 12
        $type = $this->parseType();
318 12
        $defaultValue = null;
319
320 12
        if ($this->accept(Token::T_EQUAL)) {
321 3
            $defaultValue = $this->parseValue();
322 3
        }
323
324 12
        return new VariableDefinition($variable, $type, $defaultValue, $variable->location);
0 ignored issues
show
Bug introduced by
It seems like $variable->location can also be of type object<HansOtt\GraphQL\Shared\Location>; however, HansOtt\GraphQL\Query\Va...finition::__construct() does only seem to accept null|object<HansOtt\GraphQL\Query\Location>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
325
    }
326
327 18 View Code Duplication
    private function parseVariableDefinitionList()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
328
    {
329 18
        $definitions = array();
330
331 18
        if ($this->is(Token::T_PAREN_LEFT) === false) {
332 6
            return $definitions;
333
        }
334
335 12
        $this->expect(Token::T_PAREN_LEFT);
336
337 12
        while (true) {
338 12
            if ($this->scanner->eof()) {
339
                throw $this->getParseError('Unclosed parenthesis of variable definition list');
340
            }
341
342 12
            if ($this->accept(Token::T_PAREN_RIGHT)) {
343 12
                break;
344
            }
345
346 12
            $definitions[] = $this->parseVariableDefinition();
347 12
            $this->accept(Token::T_COMMA);
348 12
        }
349
350 12
        return $definitions;
351
    }
352
353 66
    private function parseDefinition()
354
    {
355 66
        if ($this->is(Token::T_FRAGMENT)) {
356 3
            $location = $this->expect(Token::T_FRAGMENT)->location;
357
358 3
            $name = $this->expect(Token::T_NAME)->value;
359 3
            if ($name === 'on') {
360
                throw $this->getParseError('A fragment cannot be named "on"');
361
            }
362
363 3
            $typeCondition = $this->parseTypeCondition();
364 3
            $directives = $this->parseDirectiveList();
365 3
            $selectionSet = $this->parseSelectionSet();
366
367 3
            return new Fragment($name, $typeCondition, $directives, $selectionSet, $location);
0 ignored issues
show
Documentation introduced by
$location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
368
        }
369
370 66 View Code Duplication
        if ($this->is(Token::T_MUTATION)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
371
            $location = $this->expect(Token::T_MUTATION)->location;
372
            $name = $this->expect(Token::T_NAME)->value;
373
            $variables = $this->parseVariableDefinitionList();
374
            $directives = $this->parseDirectiveList();
375
            $selectionSet = $this->parseSelectionSet();
376
377
            return new OperationMutation($name, $variables, $directives, $selectionSet, $location);
0 ignored issues
show
Documentation introduced by
$location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
378
        }
379
380 66 View Code Duplication
        if ($this->is(Token::T_SUBSCRIPTION)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
381
            $location = $this->expect(Token::T_SUBSCRIPTION)->location;
382
            $name = $this->expect(Token::T_NAME)->value;
383
            $variables = $this->parseVariableDefinitionList();
384
            $directives = $this->parseDirectiveList();
385
            $selectionSet = $this->parseSelectionSet();
386
387
            return new OperationSubscription($name, $variables, $directives, $selectionSet, $location);
0 ignored issues
show
Documentation introduced by
$location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
388
        }
389
390 66
        if ($this->is(Token::T_QUERY)) {
391 18
            $location = $this->expect(Token::T_QUERY)->location;
392
393 18
            $name = null;
394 18
            if ($this->is(Token::T_NAME)) {
395 15
                $name = $this->expect(Token::T_NAME)->value;
396 15
            }
397
398 18
            $variables = $this->parseVariableDefinitionList();
399 18
            $directives = $this->parseDirectiveList();
400 18
            $selectionSet = $this->parseSelectionSet();
401
402 18
            return new OperationQuery($name, $variables, $directives, $selectionSet, $location);
0 ignored issues
show
Documentation introduced by
$location is of type object<HansOtt\GraphQL\Shared\Location>, but the function expects a null|object<HansOtt\GraphQL\Query\Location>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
403
        }
404
405 48
        if ($this->is(Token::T_BRACE_LEFT)) {
406 48
            $selectionSet = $this->parseSelectionSet();
407
408 27
            return new OperationQuery(null, array(), array(), $selectionSet, $selectionSet->location);
0 ignored issues
show
Bug introduced by
It seems like $selectionSet->location can also be of type object<HansOtt\GraphQL\Shared\Location>; however, HansOtt\GraphQL\Query\OperationBase::__construct() does only seem to accept null|object<HansOtt\GraphQL\Query\Location>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
409
        }
410
411
        $message = 'Expected a query, a query shorthand, a mutation or a subscription operation';
412
413
        if ($this->scanner->eof()) {
414
            throw $this->getParseError($message . ' but instead reached end');
415
        }
416
417
        $token = $this->scanner->peek();
418
        throw $this->getParseError($message . " but instead found \"{$token->getName()}\" with value \"{$token->value}\"");
419
    }
420
421 69
    private function parseDocument()
422
    {
423
        /** @var Definition[] $definitions */
424 69
        $definitions = array();
425 69
        while ($this->scanner->eof() === false) {
426 66
            $definitions[] = $this->parseDefinition();
427 45
        }
428
429 48
        return new Document($definitions);
430
    }
431
432
    /**
433
     * @param string $query
434
     *
435
     * @return Document
436
     */
437 96
    public function parse($query)
438
    {
439 96
        $tokens = $this->lexer->lex($query);
440 69
        $scanner = new ScannerGeneric($tokens);
441 69
        $this->scanner = new ScannerTokens($scanner);
442 69
        $document = $this->parseDocument();
443
444 48
        return $document;
445
    }
446
}
447