Completed
Push — master ( 686b71...786636 )
by Alexandr
03:06
created

Processor::collectResult()   C

Complexity

Conditions 10
Paths 10

Size

Total Lines 55
Code Lines 30

Duplication

Lines 23
Ratio 41.82 %

Code Coverage

Tests 27
CRAP Score 10.0045

Importance

Changes 0
Metric Value
dl 23
loc 55
ccs 27
cts 28
cp 0.9643
rs 6.8372
c 0
b 0
f 0
cc 10
eloc 30
nc 10
nop 4
crap 10.0045

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
 * Date: 03.11.16
4
 *
5
 * @author Portey Vasil <[email protected]>
6
 */
7
8
namespace Youshido\GraphQL\Execution;
9
10
11
use Youshido\GraphQL\Exception\ResolveException;
12
use Youshido\GraphQL\Execution\Container\Container;
13
use Youshido\GraphQL\Execution\Context\ExecutionContext;
14
use Youshido\GraphQL\Execution\Visitor\MaxComplexityQueryVisitor;
15
use Youshido\GraphQL\Field\Field;
16
use Youshido\GraphQL\Field\FieldInterface;
17
use Youshido\GraphQL\Field\InputField;
18
use Youshido\GraphQL\Parser\Ast\ArgumentValue\InputList as AstInputList;
19
use Youshido\GraphQL\Parser\Ast\ArgumentValue\InputObject as AstInputObject;
20
use Youshido\GraphQL\Parser\Ast\ArgumentValue\Literal as AstLiteral;
21
use Youshido\GraphQL\Parser\Ast\ArgumentValue\VariableReference;
22
use Youshido\GraphQL\Parser\Ast\Field as AstField;
23
use Youshido\GraphQL\Parser\Ast\FragmentReference;
24
use Youshido\GraphQL\Parser\Ast\Interfaces\FieldInterface as AstFieldInterface;
25
use Youshido\GraphQL\Parser\Ast\Mutation as AstMutation;
26
use Youshido\GraphQL\Parser\Ast\Query as AstQuery;
27
use Youshido\GraphQL\Parser\Ast\Query;
28
use Youshido\GraphQL\Parser\Ast\TypedFragmentReference;
29
use Youshido\GraphQL\Parser\Parser;
30
use Youshido\GraphQL\Schema\AbstractSchema;
31
use Youshido\GraphQL\Type\AbstractType;
32
use Youshido\GraphQL\Type\InputObject\AbstractInputObjectType;
33
use Youshido\GraphQL\Type\InterfaceType\AbstractInterfaceType;
34
use Youshido\GraphQL\Type\ListType\AbstractListType;
35
use Youshido\GraphQL\Type\Object\AbstractObjectType;
36
use Youshido\GraphQL\Type\Scalar\AbstractScalarType;
37
use Youshido\GraphQL\Type\TypeMap;
38
use Youshido\GraphQL\Type\Union\AbstractUnionType;
39
use Youshido\GraphQL\Validator\RequestValidator\RequestValidator;
40
use Youshido\GraphQL\Validator\ResolveValidator\ResolveValidator;
41
use Youshido\GraphQL\Validator\ResolveValidator\ResolveValidatorInterface;
42
43
class Processor
44
{
45
46
    const TYPE_NAME_QUERY = '__typename';
47
48
    /** @var ExecutionContext */
49
    protected $executionContext;
50
51
    /** @var ResolveValidatorInterface */
52
    protected $resolveValidator;
53
54
    /** @var  array */
55
    protected $data;
56
57
    /** @var int */
58
    protected $maxComplexity;
59
60 57
    public function __construct(AbstractSchema $schema)
61
    {
62 57
        if (empty($this->executionContext)) {
63 57
            $this->executionContext = new ExecutionContext($schema);
64 57
            $this->executionContext->setContainer(new Container());
65
        }
66
67 57
        $this->resolveValidator = new ResolveValidator($this->executionContext);
0 ignored issues
show
Unused Code introduced by
The call to ResolveValidator::__construct() has too many arguments starting with $this->executionContext.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
68 57
    }
69
70 55
    public function processPayload($payload, $variables = [], $reducers = [])
71
    {
72 55
        $this->data = [];
73
74
        try {
75 55
            $this->parseAndCreateRequest($payload, $variables);
76
77 54
            if ($this->maxComplexity) {
78 1
                $reducers[] = new MaxComplexityQueryVisitor($this->maxComplexity);
79
            }
80
81 54
            if ($reducers) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $reducers of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
82 2
                $reducer = new Reducer();
83 2
                $reducer->reduceQuery($this->executionContext, $reducers);
84
            }
85
86 54
            foreach ($this->executionContext->getRequest()->getAllOperations() as $query) {
87 54
                if ($operationResult = $this->resolveQuery($query)) {
88 54
                    $this->data = array_merge($this->data, $operationResult);
89
                };
90
            }
91 5
        } catch (\Exception $e) {
92 5
            $this->executionContext->addError($e);
93
        }
94
95 55
        return $this;
96
    }
97
98 54
    protected function resolveQuery(AstQuery $query)
99
    {
100 54
        $schema = $this->executionContext->getSchema();
101 54
        $type   = $query instanceof AstMutation ? $schema->getMutationType() : $schema->getQueryType();
102 54
        $field  = new Field([
103 54
            'name' => $query instanceof AstMutation ? 'mutation' : 'query',
104 54
            'type' => $type
105
        ]);
106
107 54
        if (self::TYPE_NAME_QUERY == $query->getName()) {
108 1
            return [$this->getAlias($query) => $type->getName()];
109
        }
110
111 54
        $this->resolveValidator->assetTypeHasField($type, $query);
112 54
        $value = $this->resolveField($field, $query);
113
114 54
        return [$this->getAlias($query) => $value];
115
    }
116
117 54
    protected function resolveField(FieldInterface $field, AstFieldInterface $ast, $parentValue = null, $fromObject = false)
118
    {
119
        try {
120
            /** @var AbstractObjectType $type */
121 54
            $type        = $field->getType();
122 54
            $nonNullType = $type->getNullableType();
123
124 54
            if (self::TYPE_NAME_QUERY == $ast->getName()) {
125 2
                return $nonNullType->getName();
126
            }
127
128 54
            $this->resolveValidator->assetTypeHasField($nonNullType, $ast);
129
130 54
            $targetField = $nonNullType->getField($ast->getName());
131
132 54
            $this->prepareAstArguments($targetField, $ast, $this->executionContext->getRequest());
133 53
            $this->resolveValidator->assertValidArguments($targetField, $ast, $this->executionContext->getRequest());
134
135 49
            switch ($kind = $targetField->getType()->getNullableType()->getKind()) {
136 49
                case TypeMap::KIND_ENUM:
137 49
                case TypeMap::KIND_SCALAR:
138 43
                    if ($ast instanceof AstQuery && $ast->hasFields()) {
139 2
                        throw new ResolveException(sprintf('You can\'t specify fields for scalar type "%s"', $targetField->getType()->getNullableType()->getName()), $ast->getLocation());
140
                    }
141
142 43
                    return $this->resolveScalar($targetField, $ast, $parentValue);
143
144 33 View Code Duplication
                case TypeMap::KIND_OBJECT:
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...
145
                    /** @var $type AbstractObjectType */
146 25
                    if (!$ast instanceof AstQuery) {
147 1
                        throw new ResolveException(sprintf('You have to specify fields for "%s"', $ast->getName()), $ast->getLocation());
148
                    }
149
150 25
                    return $this->resolveObject($targetField, $ast, $parentValue);
151
152 20
                case TypeMap::KIND_LIST:
153 17
                    return $this->resolveList($targetField, $ast, $parentValue);
154
155 6
                case TypeMap::KIND_UNION:
156 5 View Code Duplication
                case 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...
157 6
                    if (!$ast instanceof AstQuery) {
158
                        throw new ResolveException(sprintf('You have to specify fields for "%s"', $ast->getName()), $ast->getLocation());
159
                    }
160
161 6
                    return $this->resolveComposite($targetField, $ast, $parentValue);
162
163
                default:
164
                    throw new ResolveException(sprintf('Resolving type with kind "%s" not supported', $kind));
165
            }
166 16
        } catch (\Exception $e) {
167 16
            $this->executionContext->addError($e);
168
169 16
            if ($fromObject) {
170 4
                throw $e;
171
            }
172
173 14
            return null;
174
        }
175
    }
176
177 54
    private function prepareAstArguments(FieldInterface $field, AstFieldInterface $query, Request $request)
178
    {
179 54
        foreach ($query->getArguments() as $astArgument) {
180 30
            if ($field->hasArgument($astArgument->getName())) {
181 30
                $argumentType = $field->getArgument($astArgument->getName())->getType()->getNullableType();
182
183 30
                $astArgument->setValue($this->prepareArgumentValue($astArgument->getValue(), $argumentType, $request));
184
            }
185
        }
186 53
    }
187
188 30
    private function prepareArgumentValue($argumentValue, AbstractType $argumentType, Request $request)
189
    {
190 30
        switch ($argumentType->getKind()) {
191 30
            case TypeMap::KIND_LIST:
192
                /** @var $argumentType AbstractListType */
193 6
                $result = [];
194 6
                if ($argumentValue instanceof AstInputList || is_array($argumentValue)) {
195 5
                    $list = is_array($argumentValue) ? $argumentValue : $argumentValue->getValue();
196 5
                    foreach ($list as $item) {
197 5
                        $result[] = $this->prepareArgumentValue($item, $argumentType->getItemType()->getNullableType(), $request);
198
                    }
199 1
                } else if ($argumentValue instanceof VariableReference) {
200 1
                    return $this->getVariableReferenceArgumentValue($argumentValue, $argumentType, $request);
201
                }
202
203 5
                return $result;
204
205 29
            case TypeMap::KIND_INPUT_OBJECT:
206
                /** @var $argumentType AbstractInputObjectType */
207 5
                $result = [];
208 5
                if ($argumentValue instanceof AstInputObject) {
209 4
                    foreach ($argumentType->getFields() as $field) {
210
                        /** @var $field Field */
211 4
                        if ($field->getConfig()->has('defaultValue')) {
212 4
                            $result[$field->getName()] = $field->getType()->getNullableType()->parseInputValue($field->getConfig()->get('defaultValue'));
213
                        }
214
                    }
215 4
                    foreach ($argumentValue->getValue() as $key => $item) {
216 4
                        if ($argumentType->hasField($key)) {
217 4
                            $result[$key] = $this->prepareArgumentValue($item, $argumentType->getField($key)->getType()->getNullableType(), $request);
218
                        } else {
219 4
                            $result[$key] = $item;
220
                        }
221
                    }
222 2
                } else if ($argumentValue instanceof VariableReference) {
223
                    return $this->getVariableReferenceArgumentValue($argumentValue, $argumentType, $request);
224 2
                } else if (is_array($argumentValue)) {
225 1
                    return $argumentValue;
226
                }
227
228 5
                return $result;
229
230 28
            case TypeMap::KIND_SCALAR:
231 3
            case TypeMap::KIND_ENUM:
232
                /** @var $argumentValue AstLiteral|VariableReference */
233 28
                if ($argumentValue instanceof VariableReference) {
234 5
                    return $this->getVariableReferenceArgumentValue($argumentValue, $argumentType, $request);
235 24
                } else if ($argumentValue instanceof AstLiteral) {
236 17
                    return $argumentValue->getValue();
237
                } else {
238 8
                    return $argumentValue;
239
                }
240
        }
241
242
        throw new ResolveException('Argument type not supported');
243
    }
244
245 6
    private function getVariableReferenceArgumentValue(VariableReference $variableReference, AbstractType $argumentType, Request $request)
246
    {
247 6
        $variable = $variableReference->getVariable();
248 6
        if ($argumentType->getKind() === TypeMap::KIND_LIST) {
249
            if (
250 1
                !$variable->isArray() ||
251 1
                ($variable->getTypeName() !== $argumentType->getNamedType()->getNullableType()->getName()) ||
252 1
                ($argumentType->getNamedType()->getKind() === TypeMap::KIND_NON_NULL && $variable->isArrayElementNullable())
253
            ) {
254 1
                throw new ResolveException(sprintf('Invalid variable "%s" type, allowed type is "%s"', $variable->getName(), $argumentType->getNamedType()->getNullableType()->getName()), $variable->getLocation());
255
            }
256
        } else {
257 5
            if ($variable->getTypeName() !== $argumentType->getName()) {
258 1
                throw new ResolveException(sprintf('Invalid variable "%s" type, allowed type is "%s"', $variable->getName(), $argumentType->getName()), $variable->getLocation());
259
            }
260
        }
261
262 5
        $requestValue = $request->getVariable($variable->getName());
263 5
        if ((null === $requestValue && $variable->isNullable()) && !$request->hasVariable($variable->getName())) {
264
            throw new ResolveException(sprintf('Variable "%s" does not exist in request', $variable->getName()), $variable->getLocation());
265
        }
266
267 5
        return $requestValue;
268
    }
269
270 30
    protected function resolveObject(FieldInterface $field, AstFieldInterface $ast, $parentValue, $fromUnion = false)
271
    {
272 30
        $resolvedValue = $parentValue;
273 30
        if (!$fromUnion) {
274 25
            $resolvedValue = $this->doResolve($field, $ast, $parentValue);
275
        }
276
277 30
        $this->resolveValidator->assertValidResolvedValueForField($field, $resolvedValue);
278
279 30
        if (null === $resolvedValue) {
280 5
            return null;
281
        }
282
        /** @var AbstractObjectType $type */
283 29
        $type = $field->getType()->getNullableType();
284
285
        try {
286 29
            return $this->collectResult($field, $type, $ast, $resolvedValue);
287 4
        } catch (\Exception $e) {
288 4
            return null;
289
        }
290
    }
291
292
    /**
293
     * @param FieldInterface     $field
294
     * @param AbstractObjectType $type
295
     * @param AstFieldInterface $ast
296
     * @param                    $resolvedValue
297
     * @return array
298
     */
299 29
    private function collectResult(FieldInterface $field, AbstractObjectType $type, $ast, $resolvedValue)
300
    {
301 29
        $result = [];
302
303 29
        foreach ($ast->getFields() as $astField) {
304
            switch (true) {
305 29
                case $astField instanceof TypedFragmentReference:
306 2
                    $astName  = $astField->getTypeName();
307 2
                    $typeName = $type->getName();
308
309 2 View Code Duplication
                    if ($typeName !== $astName) {
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...
310 2
                        foreach ($type->getInterfaces() as $interface) {
311 1
                            if ($interface->getName() === $astName) {
312
                                $result = array_merge($result, $this->collectResult($field, $type, $astField, $resolvedValue));
0 ignored issues
show
Documentation introduced by
$astField is of type object<Youshido\GraphQL\...TypedFragmentReference>, but the function expects a object<Youshido\GraphQL\...erfaces\FieldInterface>.

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...
313
314 1
                                break;
315
                            }
316
                        }
317
318 2
                        continue;
319
                    }
320
321 2
                    $result = array_merge($result, $this->collectResult($field, $type, $astField, $resolvedValue));
0 ignored issues
show
Documentation introduced by
$astField is of type object<Youshido\GraphQL\...TypedFragmentReference>, but the function expects a object<Youshido\GraphQL\...erfaces\FieldInterface>.

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...
322
323 2
                    break;
324
325 29
                case $astField instanceof FragmentReference:
326 4
                    $astFragment      = $this->executionContext->getRequest()->getFragment($astField->getName());
327 4
                    $astFragmentModel = $astFragment->getModel();
328 4
                    $typeName         = $type->getName();
329
330 4 View Code Duplication
                    if ($typeName !== $astFragmentModel) {
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...
331 1
                        foreach ($type->getInterfaces() as $interface) {
332 1
                            if ($interface->getName() === $astFragmentModel) {
333 1
                                $result = array_merge($result, $this->collectResult($field, $type, $astFragment, $resolvedValue));
0 ignored issues
show
Documentation introduced by
$astFragment is of type object<Youshido\GraphQL\Parser\Ast\Fragment>|null, but the function expects a object<Youshido\GraphQL\...erfaces\FieldInterface>.

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...
334
335 1
                                break;
336
                            }
337
338
                        }
339
340 1
                        continue;
341
                    }
342
343 4
                    $result = array_merge($result, $this->collectResult($field, $type, $astFragment, $resolvedValue));
0 ignored issues
show
Documentation introduced by
$astFragment is of type object<Youshido\GraphQL\Parser\Ast\Fragment>|null, but the function expects a object<Youshido\GraphQL\...erfaces\FieldInterface>.

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...
344
345 4
                    break;
346
347
                default:
348 29
                    $result[$this->getAlias($astField)] = $this->resolveField($field, $astField, $resolvedValue, true);
349
            }
350
        }
351
352 29
        return $result;
353
    }
354
355 43
    protected function resolveScalar(FieldInterface $field, AstFieldInterface $ast, $parentValue)
356
    {
357 43
        $resolvedValue = $this->doResolve($field, $ast, $parentValue);
358
359 43
        $this->resolveValidator->assertValidResolvedValueForField($field, $resolvedValue);
360
361
        /** @var AbstractScalarType $type */
362 42
        $type = $field->getType()->getNullableType();
363
364 42
        return $type->serialize($resolvedValue);
365
    }
366
367 17
    protected function resolveList(FieldInterface $field, AstFieldInterface $ast, $parentValue)
368
    {
369
        /** @var AstQuery $ast */
370 17
        $resolvedValue = $this->doResolve($field, $ast, $parentValue);
371
372 17
        $this->resolveValidator->assertValidResolvedValueForField($field, $resolvedValue);
373
374 15
        if (null === $resolvedValue) {
375 5
            return null;
376
        }
377
378
        /** @var AbstractListType $type */
379 14
        $type     = $field->getType()->getNullableType();
380 14
        $itemType = $type->getNamedType();
381
382 14
        $fakeAst = clone $ast;
383 14
        if ($fakeAst instanceof AstQuery) {
384 14
            $fakeAst->setArguments([]);
385
        }
386
387 14
        $fakeField = new Field([
388 14
            'name' => $field->getName(),
389 14
            'type' => $itemType,
390
        ]);
391
392 14
        $result = [];
393 14
        foreach ($resolvedValue as $resolvedValueItem) {
394
            try {
395 13
                $fakeField->getConfig()->set('resolve', function () use ($resolvedValueItem) {
396 13
                    return $resolvedValueItem;
397 13
                });
398
399 13
                switch ($itemType->getNullableType()->getKind()) {
400 13
                    case TypeMap::KIND_ENUM:
401 12
                    case TypeMap::KIND_SCALAR:
402 3
                        $value = $this->resolveScalar($fakeField, $fakeAst, $resolvedValueItem);
403
404 2
                        break;
405
406
407 11
                    case TypeMap::KIND_OBJECT:
408 9
                        $value = $this->resolveObject($fakeField, $fakeAst, $resolvedValueItem);
409
410 9
                        break;
411
412 3
                    case TypeMap::KIND_UNION:
413 3
                    case TypeMap::KIND_INTERFACE:
414 3
                        $value = $this->resolveComposite($fakeField, $fakeAst, $resolvedValueItem);
415
416 3
                        break;
417
418
                    default:
419 12
                        $value = null;
420
                }
421 1
            } catch (\Exception $e) {
422 1
                $this->executionContext->addError($e);
423
424 1
                $value = null;
425
            }
426
427 13
            $result[] = $value;
428
        }
429
430 14
        return $result;
431
    }
432
433 7
    protected function resolveComposite(FieldInterface $field, AstFieldInterface $ast, $parentValue)
434
    {
435
        /** @var AstQuery $ast */
436 7
        $resolvedValue = $this->doResolve($field, $ast, $parentValue);
437
438 7
        $this->resolveValidator->assertValidResolvedValueForField($field, $resolvedValue);
439
440
        /** @var AbstractUnionType $type */
441 7
        $type         = $field->getType()->getNullableType();
442 7
        $resolvedType = $type->resolveType($resolvedValue);
443
444 7
        if (!$resolvedType) {
445
            throw new ResolveException('Resolving function must return type');
446
        }
447
448 7
        if ($type instanceof AbstractInterfaceType) {
449 6
            $this->resolveValidator->assertTypeImplementsInterface($resolvedType, $type);
450
        } else {
451 1
            $this->resolveValidator->assertTypeInUnionTypes($resolvedType, $type);
452
        }
453
454 7
        $fakeField = new Field([
455 7
            'name' => $field->getName(),
456 7
            'type' => $resolvedType,
457
        ]);
458
459 7
        return $this->resolveObject($fakeField, $ast, $resolvedValue, true);
460
    }
461
462 55
    protected function parseAndCreateRequest($payload, $variables = [])
463
    {
464 55
        if (empty($payload)) {
465 1
            throw new \InvalidArgumentException('Must provide an operation.');
466
        }
467
468 55
        $parser  = new Parser();
469 55
        $request = new Request($parser->parse($payload), $variables);
470
471 55
        (new RequestValidator())->validate($request);
472
473 54
        $this->executionContext->setRequest($request);
474 54
    }
475
476 49
    protected function doResolve(FieldInterface $field, AstFieldInterface $ast, $parentValue = null)
477
    {
478
        /** @var AstQuery|AstField $ast */
479 49
        $arguments = $this->parseArgumentsValues($field, $ast);
480 49
        $astFields = $ast instanceof AstQuery ? $ast->getFields() : [];
481
482 49
        return $field->resolve($parentValue, $arguments, $this->createResolveInfo($field, $astFields));
483
    }
484
485 49
    protected function parseArgumentsValues(FieldInterface $field, AstFieldInterface $ast)
486
    {
487 49
        $values   = [];
488 49
        $defaults = [];
489
490 49
        foreach ($field->getArguments() as $argument) {
491
            /** @var $argument InputField */
492 34
            if ($argument->getConfig()->has('defaultValue')) {
493 34
                $defaults[$argument->getName()] = $argument->getConfig()->getDefaultValue();
494
            }
495
        }
496
497 49
        foreach ($ast->getArguments() as $astArgument) {
498 27
            $argument     = $field->getArgument($astArgument->getName());
499 27
            $argumentType = $argument->getType()->getNullableType();
500
501 27
            $values[$argument->getName()] = $argumentType->parseValue($astArgument->getValue());
502
503 27
            if (isset($defaults[$argument->getName()])) {
504 27
                unset($defaults[$argument->getName()]);
505
            }
506
        }
507
508 49
        return array_merge($values, $defaults);
509
    }
510
511 54
    private function getAlias(AstFieldInterface $ast)
512
    {
513 54
        return $ast->getAlias() ?: $ast->getName();
514
    }
515
516 49
    protected function createResolveInfo(FieldInterface $field, array $astFields)
517
    {
518 49
        return new ResolveInfo($field, $astFields, $this->executionContext);
519
    }
520
521
522
    /**
523
     * You can access ExecutionContext to check errors and inject dependencies
524
     *
525
     * @return ExecutionContext
526
     */
527 11
    public function getExecutionContext()
528
    {
529 11
        return $this->executionContext;
530
    }
531
532 55
    public function getResponseData()
533
    {
534 55
        $result = [];
535
536 55
        if (!empty($this->data)) {
537 54
            $result['data'] = $this->data;
538
        }
539
540 55
        if ($this->executionContext->hasErrors()) {
541 18
            $result['errors'] = $this->executionContext->getErrorsArray();
542
        }
543
544 55
        return $result;
545
    }
546
547
    /**
548
     * @return int
549
     */
550
    public function getMaxComplexity()
551
    {
552
        return $this->maxComplexity;
553
    }
554
555
    /**
556
     * @param int $maxComplexity
557
     */
558 1
    public function setMaxComplexity($maxComplexity)
559
    {
560 1
        $this->maxComplexity = $maxComplexity;
561 1
    }
562
563
}
564