Completed
Push — master ( b1f2d3...564d61 )
by Portey
03:39
created

Processor::processQuery()   C

Complexity

Conditions 8
Paths 55

Size

Total Lines 29
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 10.0619

Importance

Changes 9
Bugs 2 Features 3
Metric Value
c 9
b 2
f 3
dl 0
loc 29
ccs 15
cts 22
cp 0.6818
rs 5.3846
cc 8
eloc 16
nc 55
nop 2
crap 10.0619
1
<?php
2
/*
3
* This file is a part of graphql-youshido project.
4
*
5
* @author Portey Vasil <[email protected]>
6
* @author Alexandr Viniychuk <[email protected]>
7
* created: 11/28/15 1:05 AM
8
*/
9
10
namespace Youshido\GraphQL;
11
12
use Symfony\Component\PropertyAccess\PropertyAccess;
13
use Symfony\Component\PropertyAccess\PropertyAccessor;
14
use Youshido\GraphQL\Introspection\SchemaType;
15
use Youshido\GraphQL\Introspection\TypeDefinitionType;
16
use Youshido\GraphQL\Parser\Ast\FragmentReference;
17
use Youshido\GraphQL\Parser\Ast\Mutation;
18
use Youshido\GraphQL\Parser\Ast\Query;
19
use Youshido\GraphQL\Parser\Ast\TypedFragmentReference;
20
use Youshido\GraphQL\Parser\Parser;
21
use Youshido\GraphQL\Type\Field\Field;
22
use Youshido\GraphQL\Type\Object\AbstractEnumType;
23
use Youshido\GraphQL\Type\Object\InputObjectType;
24
use Youshido\GraphQL\Type\Object\ObjectType;
25
use Youshido\GraphQL\Type\Scalar\AbstractScalarType;
26
use Youshido\GraphQL\Type\TypeInterface;
27
use Youshido\GraphQL\Type\TypeMap;
28
use Youshido\GraphQL\Parser\Ast\Field as QueryField;
29
use Youshido\GraphQL\Validator\Exception\ResolveException;
30
use Youshido\GraphQL\Validator\ResolveValidator\ResolveValidatorInterface;
31
32
class Processor
33
{
34
35
    const TYPE_NAME_QUERY = '__typename';
36
37
    /** @var  array */
38
    protected $data;
39
40
    /** @var ResolveValidatorInterface */
41
    protected $resolveValidator;
42
43
    /** @var Schema */
44
    protected $schema;
45
46
    /** @var PropertyAccessor */
47
    protected $propertyAccessor;
48
49
    /** @var Request */
50
    protected $request;
51
52 19
    public function __construct(ResolveValidatorInterface $validator)
53
    {
54 19
        $this->resolveValidator = $validator;
55
56 19
        $this->propertyAccessor = PropertyAccess::createPropertyAccessor();
57 19
    }
58
59 19
    public function processQuery($queryString, $variables = [])
60
    {
61 19
        $this->resolveValidator->clearErrors();
62 19
        $this->data = [];
63
64
        try {
65 19
            $this->parseAndCreateRequest($queryString, $variables);
66
67 19
            if ($this->request->hasQueries()) {
68 19
                foreach ($this->request->getQueries() as $query) {
69 19
                    if ($queryResult = $this->executeQuery($query, $this->getSchema()->getQueryType())) {
70 17
                        $this->data = array_merge($this->data, $queryResult);
71 17
                    };
72 19
                }
73 19
            }
74
75 19
            if ($this->request->hasMutations()) {
76
                foreach ($this->request->getMutations() as $mutation) {
77
                    if ($mutationResult = $this->executeMutation($mutation, $this->getSchema()->getMutationType())) {
78
                        $this->data = array_merge($this->data, $mutationResult);
79
                    }
80
                }
81 1
            }
82 19
        } catch (\Exception $e) {
83
            $this->resolveValidator->clearErrors();
84
85
            $this->resolveValidator->addError($e);
86
        }
87 19
    }
88
89
    /**
90
     * @param Mutation        $mutation
91
     * @param InputObjectType $objectType
92
     *
93
     * @return array|bool|mixed
94
     */
95 1
    protected function executeMutation($mutation, $objectType)
96
    {
97
        if (!$this->checkFieldExist($objectType, $mutation)) {
98
99
            return null;
100
        }
101
102
        /** @var Field $field */
103
        $field = $objectType->getConfig()->getField($mutation->getName());
104
105
        if (!$this->resolveValidator->validateArguments($field, $mutation, $this->request)) {
106
            return null;
107
        }
108
109
        $alias         = $mutation->hasAlias() ? $mutation->getAlias() : $mutation->getName();
110
        $resolvedValue = $this->resolveValue($field, null, $mutation);
111
112
        if (!$this->resolveValidator->validateResolvedValue($resolvedValue, $field->getType()->getKind())) {
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...
113
            $this->resolveValidator->addError(new ResolveException(sprintf('Not valid resolved value for mutation "%s"', $field->getType()->getName())));
114
115
            return [$alias => null];
116
        }
117
118
        $value = null;
119
        if ($mutation->hasFields()) {
120
            $outputType = $field->getType()->getOutputType();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Youshido\GraphQL\Type\TypeInterface as the method getOutputType() does only exist in the following implementations of said interface: Youshido\GraphQL\Type\Object\AbstractMutationType.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
121
122
            if ($outputType && in_array($outputType->getKind(), [TypeMap::KIND_INTERFACE, TypeMap::KIND_UNION])) {
123
                $outputType = $outputType->getConfig()->resolveType($resolvedValue);
124
            }
125
126
            if ($outputType->getKind() == TypeMap::KIND_LIST) {
127
                foreach ($resolvedValue as $resolvedValueItem) {
128
                    $value[] = [];
129
                    $index   = count($value) - 1;
130
131 View Code Duplication
                    if (in_array($outputType->getConfig()->getItem()->getKind(), [TypeMap::KIND_UNION, TypeMap::KIND_INTERFACE])) {
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...
132
                        $type = $outputType->getConfig()->getItemConfig()->resolveType($resolvedValueItem);
133
                    } else {
134
                        $type = $outputType;
135
                    }
136
137
                    $value[$index] = $this->processQueryFields($mutation, $type, $resolvedValueItem, $value[$index]);
138
                }
139
            } else {
140
                $value = $this->processQueryFields($mutation, $outputType, $resolvedValue, []);
141 1
            }
142
        }
143
144
        return [$alias => $value];
145
    }
146
147 19
    protected function parseAndCreateRequest($query, $variables = [])
148
    {
149 19
        $parser = new Parser();
150
151 19
        $parser->setSource($query);
152 19
        $data = $parser->parse();
153
154 19
        $this->request = new Request($data);
155 19
        $this->request->setVariables($variables);
156 19
    }
157
158
    /**
159
     * @param Query|Field $query
160
     * @param ObjectType  $currentLevelSchema
161
     * @param null        $contextValue
162
     * @return array|bool|mixed
163
     */
164 19
    protected function executeQuery($query, $currentLevelSchema, $contextValue = null)
165
    {
166 19
        if (!$this->checkFieldExist($currentLevelSchema, $query)) {
167
            return null;
168
        }
169
170
        /** @var Field $field */
171 19
        $field = $currentLevelSchema->getConfig()->getField($query->getName());
172 19
        if ($query instanceof QueryField) {
173 16
            $alias            = $query->getAlias() ?: $query->getName();
174 16
            $preResolvedValue = $this->getPreResolvedValue($contextValue, $query, $field);
175
176 16
            if ($field->getConfig()->getType()->getKind() == TypeMap::KIND_LIST) {
177 1
                if (!is_array($preResolvedValue)) {
178
                    $value = null;
0 ignored issues
show
Unused Code introduced by
$value is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
179
                    $this->resolveValidator->addError(new ResolveException('Not valid resolve value for list type'));
180
                }
181
182 1
                $listValue = [];
183 1
                foreach ($preResolvedValue as $resolvedValueItem) {
0 ignored issues
show
Bug introduced by
The expression $preResolvedValue of type object|integer|double|string|null|boolean|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
184
                    /** @var TypeInterface $type */
185 1
                    $type = $field->getType()->getConfig()->getItem();
186
187 1
                    if ($type->getKind() == TypeMap::KIND_ENUM) {
188
                        /** @var $type AbstractEnumType */
189 1
                        if (!$type->isValidValue($resolvedValueItem)) {
190
                            $this->resolveValidator->addError(new ResolveException('Not valid value for enum type'));
191
192
                            $listValue = null;
193
                            break;
194
                        }
195
196 1
                        $listValue[] = $type->resolve($resolvedValueItem);
197 1
                    } else {
198
                        /** @var AbstractScalarType $type */
199
                        $listValue[] = $type->serialize($preResolvedValue);
200
                    }
201 1
                }
202
203 1
                $value = $listValue;
204 1
            } else {
205 16 View Code Duplication
                if ($field->getType()->getKind() == TypeMap::KIND_ENUM) {
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...
206
                    if (!$field->getType()->isValidValue($preResolvedValue)) {
207
                        $this->resolveValidator->addError(new ResolveException('Not valid value for enum type'));
208
                        $value = null;
209
                    } else {
210
                        $value = $field->getType()->resolve($preResolvedValue);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Youshido\GraphQL\Type\TypeInterface as the method resolve() does only exist in the following implementations of said interface: Youshido\GraphQL\Introspection\DirectiveListType, Youshido\GraphQL\Introspection\DirectiveType, Youshido\GraphQL\Introspection\EnumValueListType, Youshido\GraphQL\Introspection\EnumValueType, Youshido\GraphQL\Introspection\FieldListType, Youshido\GraphQL\Introspection\FieldType, Youshido\GraphQL\Introspection\InputValueListType, Youshido\GraphQL\Introspection\InputValueType, Youshido\GraphQL\Introspection\InterfaceListType, Youshido\GraphQL\Introspection\MutationType, Youshido\GraphQL\Introspection\QueryListType, Youshido\GraphQL\Introspection\QueryType, Youshido\GraphQL\Introspection\SchemaType, Youshido\GraphQL\Introspection\TypeDefinitionType, Youshido\GraphQL\Type\ListType\AbstractListType, Youshido\GraphQL\Type\ListType\ListType, Youshido\GraphQL\Type\Object\AbstractEnumType, Youshido\GraphQL\Type\Ob...AbstractInputObjectType, Youshido\GraphQL\Type\Object\AbstractMutationType, Youshido\GraphQL\Type\Object\AbstractObjectType, Youshido\GraphQL\Type\Object\AbstractUnionType, Youshido\GraphQL\Type\Object\EnumType, Youshido\GraphQL\Type\Object\InputObjectType, Youshido\GraphQL\Type\Object\ObjectType, Youshido\Tests\DataProvider\UserType, Youshido\Tests\StarWars\Schema\DroidType, Youshido\Tests\StarWars\Schema\EpisodeEnum, Youshido\Tests\StarWars\Schema\HumanType, Youshido\Tests\StarWars\Schema\QueryType, Youshido\Tests\Type\Union\Schema\FirstType, Youshido\Tests\Type\Union\Schema\QueryType, Youshido\Tests\Type\Union\Schema\SecondType, Youshido\Tests\Type\Union\Schema\TestUnionType.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
211
                    }
212
                } else {
213 16
                    $value = $field->getType()->serialize($preResolvedValue);
214
                }
215
            }
216 16
        } else {
217 19
            if (!$this->resolveValidator->validateArguments($field, $query, $this->request)) {
218 2
                return null;
219
            }
220
221 17
            $resolvedValue = $this->resolveValue($field, $contextValue, $query);
222 17
            $alias         = $query->hasAlias() ? $query->getAlias() : $query->getName();
0 ignored issues
show
Bug introduced by
The method hasAlias does only exist in Youshido\GraphQL\Parser\Ast\Query, but not in Youshido\GraphQL\Type\Field\Field.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
Bug introduced by
The method getAlias does only exist in Youshido\GraphQL\Parser\Ast\Query, but not in Youshido\GraphQL\Type\Field\Field.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
223
224 17
            if (!$this->resolveValidator->validateResolvedValue($resolvedValue, $field->getType()->getKind())) {
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...
225
                $this->resolveValidator->addError(new ResolveException(sprintf('Not valid resolved value for query "%s"', $field->getType()->getName())));
226
227
                return [$alias => null];
228
            }
229
230 17
            $value = [];
231 17
            if ($resolvedValue) {
232 16
                if ($field->getType()->getKind() == TypeMap::KIND_LIST) {
233 7
                    foreach ($resolvedValue as $resolvedValueItem) {
234 7
                        $value[] = [];
235 7
                        $index   = count($value) - 1;
236
237 7
                        if (in_array($field->getConfig()->getType()->getConfig()->getItem()->getKind(), [TypeMap::KIND_UNION, TypeMap::KIND_INTERFACE])) {
238 4
                            $type = $field->getConfig()->getType()->getConfig()->getItemConfig()->resolveType($resolvedValueItem);
239 4
                        } else {
240 3
                            $type = $field->getType();
241
                        }
242
243 7
                        $value[$index] = $this->processQueryFields($query, $type, $resolvedValueItem, $value[$index]);
244 7
                    }
245 7
                } else {
246 14
                    $value = $this->processQueryFields($query, $field->getType(), $resolvedValue, $value);
247
                }
248 16
            } else {
249 4
                $value = $resolvedValue;
250
            }
251
        }
252
253 17
        return [$alias => $value];
254
    }
255
256
    /**
257
     * @param $objectType InputObjectType|ObjectType
258
     * @param $query      Mutation|Query
259
     * @return null
260
     */
261 19
    private function checkFieldExist($objectType, $query)
262
    {
263 19 View Code Duplication
        if (!$objectType->getConfig()->hasField($query->getName())) {
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...
264
            if ($objectType->getKind() == TypeMap::KIND_LIST) {
265
                $name = $objectType->getConfig()->getItem()->getName();
266
            } else {
267
                $name = $objectType->getName();
268
            }
269
270
            $this->resolveValidator->addError(new ResolveException(sprintf('Field "%s" not found in type "%s"', $query->getName(), $name)));
271
272
            return false;
273
        }
274
275 19
        return true;
276
    }
277
278
    /**
279
     * @param $value
280
     * @param $query QueryField
281
     * @param $field Field
282
     *
283
     * @throws \Exception
284
     *
285
     * @return mixed
286
     */
287 16
    protected function getPreResolvedValue($value, $query, $field)
288
    {
289 16
        $resolved      = false;
290 16
        $resolverValue = null;
291
292 16
        if (is_array($value) && array_key_exists($query->getName(), $value)) {
293 11
            $resolverValue = $value[$query->getName()];
294 11
            $resolved      = true;
295 16
        } elseif (is_object($value)) {
296
            try {
297 5
                $resolverValue = $this->propertyAccessor->getValue($value, $query->getName());
298 5
                $resolved      = true;
299 5
            } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
300
            }
301 5
        }
302
303 16
        if ($resolved) {
304 16
            if ($field->getConfig()->issetResolve()) {
305
                $resolverFunc = $field->getConfig()->getResolveFunction();
306
                $resolverValue = $resolverFunc($resolverValue, []);
307
            }
308
309 16
            return $resolverValue;
310
        }
311
312
        throw new \Exception(sprintf('Property "%s" not found in resolve result', $query->getName()));
313
    }
314
315
    /**
316
     * @param $field        Field
317
     * @param $contextValue mixed
318
     * @param $query        Query
319
     *
320
     * @return mixed
321
     */
322 17
    protected function resolveValue($field, $contextValue, $query)
323
    {
324 17
        $resolvedValue = $field->getConfig()->resolve($contextValue, $this->parseArgumentsValues($field, $query));
325
326 17 View Code Duplication
        if (in_array($field->getType()->getKind(), [TypeMap::KIND_UNION, TypeMap::KIND_INTERFACE])) {
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...
327 6
            $resolvedType = $field->getType()->resolveType($resolvedValue);
328 6
            $field->setType($resolvedType);
329 6
        }
330
331 17
        return $resolvedValue;
332
    }
333
334
    /**
335
     * @param $field     Field
336
     * @param $query     Query
337
     *
338
     * @return array
339
     */
340 17
    public function parseArgumentsValues($field, $query)
341
    {
342 17
        if ($query instanceof \Youshido\GraphQL\Parser\Ast\Field) {
343
            return [];
344
        }
345
346 17
        $args = [];
347 17
        foreach ($query->getArguments() as $argument) {
348 5
            $args[$argument->getName()] = $field->getConfig()->getArgument($argument->getName())->getType()->parseValue($argument->getValue()->getValue());
349 17
        }
350
351 17
        return $args;
352
    }
353
354
    /**
355
     * @param $query         Query
356
     * @param $queryType     ObjectType|TypeInterface|Field
357
     * @param $resolvedValue mixed
358
     * @param $value         array
359
     *
360
     * @throws \Exception
361
     *
362
     * @return array
363
     */
364 16
    protected function processQueryFields($query, $queryType, $resolvedValue, $value)
365
    {
366 16
        foreach ($query->getFields() as $field) {
367 16
            if ($field instanceof FragmentReference) {
368 1
                if (!$fragment = $this->request->getFragment($field->getName())) {
369
                    throw new \Exception(sprintf('Fragment reference "%s" not found', $field->getName()));
370
                }
371
372 1
                if ($fragment->getModel() !== $queryType->getName()) {
373
                    throw new \Exception(sprintf('Fragment reference "%s" not found on model "%s"', $field->getName(), $queryType->getName()));
374
                }
375
376 1
                foreach ($fragment->getFields() as $fragmentField) {
377 1
                    $value = $this->collectValue($value, $this->executeQuery($fragmentField, $queryType, $resolvedValue));
378 1
                }
379 16
            } elseif ($field instanceof TypedFragmentReference) {
380 2
                if ($field->getTypeName() !== $queryType->getName()) {
381 1
                    continue;
382
                }
383
384 2
                foreach ($field->getFields() as $fragmentField) {
385 2
                    $value = $this->collectValue($value, $this->executeQuery($fragmentField, $queryType, $resolvedValue));
0 ignored issues
show
Documentation introduced by
$fragmentField is of type object<Youshido\GraphQL\Parser\Ast\Field>, but the function expects a object<Youshido\GraphQL\...aphQL\Type\Field\Field>.

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...
386 2
                }
387 16
            } elseif ($field->getName() == self::TYPE_NAME_QUERY) {
388 1
                $value = $this->collectValue($value, [$field->getAlias() ?: $field->getName() => $queryType->getName()]);
389 1
            } else {
390 16
                $value = $this->collectValue($value, $this->executeQuery($field, $queryType, $resolvedValue));
391
            }
392 16
        }
393
394 16
        return $value;
395
    }
396
397 16
    protected function collectValue($value, $queryValue)
398
    {
399 16
        if ($queryValue && is_array($queryValue)) {
400 16
            $value = array_merge(is_array($value) ? $value : [], $queryValue);
401 16
        } else {
402
            $value = $queryValue;
403
        }
404
405 16
        return $value;
406
    }
407
408 19
    public function getSchema()
409
    {
410 19
        return $this->schema;
411
    }
412
413 19
    public function setSchema(Schema $schema)
414
    {
415 19
        $this->schema = $schema;
416
417 19
        $__schema = new SchemaType();
418 19
        $__schema->setSchema($schema);
419
420 19
        $__type = new TypeDefinitionType();
421
422 19
        $this->schema->addQuery('__schema', $__schema);
423 19
        $this->schema->addQuery('__type', $__type);
424 19
    }
425
426
    /**
427
     * @return ResolveValidatorInterface
428
     */
429
    public function getResolveValidator()
430
    {
431
        return $this->resolveValidator;
432
    }
433
434 19
    public function getResponseData()
435
    {
436 19
        $result = [];
437
438 19
        if (!empty($this->data)) {
439 17
            $result['data'] = $this->data;
440 17
        }
441
442 19
        if ($this->resolveValidator->hasErrors()) {
443 2
            $result['errors'] = $this->resolveValidator->getErrorsArray();
444 2
        }
445
446 19
        return $result;
447
    }
448
}
449