Completed
Push — master ( 8b906b...982da4 )
by Alexandr
02:54
created

Processor::getMaxComplexity()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
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 59
    public function __construct(AbstractSchema $schema)
61
    {
62 59
        if (empty($this->executionContext)) {
63 59
            $this->executionContext = new ExecutionContext($schema);
64 59
            $this->executionContext->setContainer(new Container());
65 59
        }
66
67 59
        $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 59
    }
69
70 57
    public function processPayload($payload, $variables = [], $reducers = [])
71
    {
72 57
        $this->data = [];
73
74
        try {
75 57
            $this->parseAndCreateRequest($payload, $variables);
76
77 56
            if ($this->maxComplexity) {
78 1
                $reducers[] = new MaxComplexityQueryVisitor($this->maxComplexity);
79 1
            }
80
81 56
            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 2
            }
85
86 56
            foreach ($this->executionContext->getRequest()->getAllOperations() as $query) {
87 56
                if ($operationResult = $this->resolveQuery($query)) {
88 56
                    $this->data = array_merge($this->data, $operationResult);
89 56
                };
90 56
            }
91 57
        } catch (\Exception $e) {
92 5
            $this->executionContext->addError($e);
93
        }
94
95 57
        return $this;
96
    }
97
98 56
    protected function resolveQuery(AstQuery $query)
99
    {
100 56
        $schema = $this->executionContext->getSchema();
101 56
        $type   = $query instanceof AstMutation ? $schema->getMutationType() : $schema->getQueryType();
102 56
        $field  = new Field([
103 56
            'name' => $query instanceof AstMutation ? 'mutation' : 'query',
104
            'type' => $type
105 56
        ]);
106
107 56
        if (self::TYPE_NAME_QUERY == $query->getName()) {
108 1
            return [$this->getAlias($query) => $type->getName()];
109
        }
110
111 56
        $this->resolveValidator->assetTypeHasField($type, $query);
112 56
        $value = $this->resolveField($field, $query);
113
114 56
        return [$this->getAlias($query) => $value];
115
    }
116
117 56
    protected function resolveField(FieldInterface $field, AstFieldInterface $ast, $parentValue = null, $fromObject = false)
118
    {
119
        try {
120
            /** @var AbstractObjectType $type */
121 56
            $type        = $field->getType();
122 56
            $nonNullType = $type->getNullableType();
123
124 56
            if (self::TYPE_NAME_QUERY == $ast->getName()) {
125 2
                return $nonNullType->getName();
126
            }
127
128 56
            $this->resolveValidator->assetTypeHasField($nonNullType, $ast);
129
130 56
            $targetField = $nonNullType->getField($ast->getName());
131
132 56
            $this->prepareAstArguments($targetField, $ast, $this->executionContext->getRequest());
133 55
            $this->resolveValidator->assertValidArguments($targetField, $ast, $this->executionContext->getRequest());
134
135 51
            switch ($kind = $targetField->getType()->getNullableType()->getKind()) {
136 51
                case TypeMap::KIND_ENUM:
137 51
                case TypeMap::KIND_SCALAR:
138 44
                    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 44
                    return $this->resolveScalar($targetField, $ast, $parentValue);
143
144 35 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 26
                    if (!$ast instanceof AstQuery) {
147 1
                        throw new ResolveException(sprintf('You have to specify fields for "%s"', $ast->getName()), $ast->getLocation());
148
                    }
149
150 26
                    return $this->resolveObject($targetField, $ast, $parentValue);
151
152 22
                case TypeMap::KIND_LIST:
153 19
                    return $this->resolveList($targetField, $ast, $parentValue);
154
155 6
                case TypeMap::KIND_UNION:
156 6 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 56
    private function prepareAstArguments(FieldInterface $field, AstFieldInterface $query, Request $request)
178
    {
179 56
        foreach ($query->getArguments() as $astArgument) {
180 31
            if ($field->hasArgument($astArgument->getName())) {
181 31
                $argumentType = $field->getArgument($astArgument->getName())->getType()->getNullableType();
182
183 31
                $astArgument->setValue($this->prepareArgumentValue($astArgument->getValue(), $argumentType, $request));
184 30
            }
185 55
        }
186 55
    }
187
188 31
    private function prepareArgumentValue($argumentValue, AbstractType $argumentType, Request $request)
189
    {
190 31
        switch ($argumentType->getKind()) {
191 31
            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 5
                    }
199 5
                } else {
200 1
                    if ($argumentValue instanceof VariableReference) {
201 1
                        return $this->getVariableReferenceArgumentValue($argumentValue, $argumentType, $request);
202
                    }
203
                }
204
205 5
                return $result;
206
207 30
            case TypeMap::KIND_INPUT_OBJECT:
208
                /** @var $argumentType AbstractInputObjectType */
209 5
                $result = [];
210 5
                if ($argumentValue instanceof AstInputObject) {
211 4
                    foreach ($argumentType->getFields() as $field) {
212
                        /** @var $field Field */
213 4
                        if ($field->getConfig()->has('defaultValue')) {
214 1
                            $result[$field->getName()] = $field->getType()->getNullableType()->parseInputValue($field->getConfig()->get('defaultValue'));
215 1
                        }
216 4
                    }
217 4
                    foreach ($argumentValue->getValue() as $key => $item) {
218 4
                        if ($argumentType->hasField($key)) {
219 4
                            $result[$key] = $this->prepareArgumentValue($item, $argumentType->getField($key)->getType()->getNullableType(), $request);
220 4
                        } else {
221
                            $result[$key] = $item;
222
                        }
223 4
                    }
224 4
                } else {
225 2
                    if ($argumentValue instanceof VariableReference) {
226
                        return $this->getVariableReferenceArgumentValue($argumentValue, $argumentType, $request);
227
                    } else {
228 2
                        if (is_array($argumentValue)) {
229 1
                            return $argumentValue;
230
                        }
231
                    }
232
                }
233
234 5
                return $result;
235
236 29
            case TypeMap::KIND_SCALAR:
237 29
            case TypeMap::KIND_ENUM:
238
                /** @var $argumentValue AstLiteral|VariableReference */
239 29
                if ($argumentValue instanceof VariableReference) {
240 6
                    return $this->getVariableReferenceArgumentValue($argumentValue, $argumentType, $request);
241
                } else {
242 25
                    if ($argumentValue instanceof AstLiteral) {
243 18
                        return $argumentValue->getValue();
244
                    } else {
245 8
                        return $argumentValue;
246
                    }
247
                }
248
        }
249
250
        throw new ResolveException('Argument type not supported');
251
    }
252
253 7
    private function getVariableReferenceArgumentValue(VariableReference $variableReference, AbstractType $argumentType, Request $request)
254
    {
255 7
        $variable = $variableReference->getVariable();
256 7
        if ($argumentType->getKind() === TypeMap::KIND_LIST) {
257
            if (
258 1
                !$variable->isArray() ||
259 1
                ($variable->getTypeName() !== $argumentType->getNamedType()->getNullableType()->getName()) ||
260 1
                ($argumentType->getNamedType()->getKind() === TypeMap::KIND_NON_NULL && $variable->isArrayElementNullable())
261 1
            ) {
262 1
                throw new ResolveException(sprintf('Invalid variable "%s" type, allowed type is "%s"', $variable->getName(), $argumentType->getNamedType()->getNullableType()->getName()), $variable->getLocation());
263
            }
264 1
        } else {
265 6
            if ($variable->getTypeName() !== $argumentType->getName()) {
266 1
                throw new ResolveException(sprintf('Invalid variable "%s" type, allowed type is "%s"', $variable->getName(), $argumentType->getName()), $variable->getLocation());
267
            }
268
        }
269
270 6
        $requestValue = $request->getVariable($variable->getName());
271 6
        if ((null === $requestValue && $variable->isNullable()) && !$request->hasVariable($variable->getName())) {
272
            throw new ResolveException(sprintf('Variable "%s" does not exist in request', $variable->getName()), $variable->getLocation());
273
        }
274
275 6
        return $requestValue;
276
    }
277
278 31
    protected function resolveObject(FieldInterface $field, AstFieldInterface $ast, $parentValue, $fromUnion = false)
279
    {
280 31
        $resolvedValue = $parentValue;
281 31
        if (!$fromUnion) {
282 26
            $resolvedValue = $this->doResolve($field, $ast, $parentValue);
283 26
        }
284
285 31
        $this->resolveValidator->assertValidResolvedValueForField($field, $resolvedValue);
286
287 31
        if (null === $resolvedValue) {
288 5
            return null;
289
        }
290
        /** @var AbstractObjectType $type */
291 30
        $type = $field->getType()->getNullableType();
292
293
        try {
294 30
            return $this->collectResult($field, $type, $ast, $resolvedValue);
295 4
        } catch (\Exception $e) {
296 4
            return null;
297
        }
298
    }
299
300
    /**
301
     * @param FieldInterface     $field
302
     * @param AbstractObjectType $type
303
     * @param AstFieldInterface  $ast
304
     * @param                    $resolvedValue
305
     * @return array
306
     */
307 30
    private function collectResult(FieldInterface $field, AbstractObjectType $type, $ast, $resolvedValue)
308
    {
309 30
        $result = [];
310
311 30
        foreach ($ast->getFields() as $astField) {
312 30
            switch (true) {
313 30
                case $astField instanceof TypedFragmentReference:
314 2
                    $astName  = $astField->getTypeName();
315 2
                    $typeName = $type->getName();
316
317 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...
318 2
                        foreach ($type->getInterfaces() as $interface) {
319 1
                            if ($interface->getName() === $astName) {
320
                                $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...
321
322
                                break;
323
                            }
324 2
                        }
325
326 2
                        continue;
327
                    }
328
329 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...
330
331 2
                    break;
332
333 30
                case $astField instanceof FragmentReference:
334 4
                    $astFragment      = $this->executionContext->getRequest()->getFragment($astField->getName());
335 4
                    $astFragmentModel = $astFragment->getModel();
336 4
                    $typeName         = $type->getName();
337
338 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...
339 1
                        foreach ($type->getInterfaces() as $interface) {
340 1
                            if ($interface->getName() === $astFragmentModel) {
341 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...
342
343 1
                                break;
344
                            }
345
346 1
                        }
347
348 1
                        continue;
349
                    }
350
351 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...
352
353 4
                    break;
354
355 30
                default:
356 30
                    $result[$this->getAlias($astField)] = $this->resolveField($field, $astField, $resolvedValue, true);
357 30
            }
358 30
        }
359
360 30
        return $result;
361
    }
362
363 45
    protected function resolveScalar(FieldInterface $field, AstFieldInterface $ast, $parentValue)
364
    {
365 45
        $resolvedValue = $this->doResolve($field, $ast, $parentValue);
366
367 45
        $this->resolveValidator->assertValidResolvedValueForField($field, $resolvedValue);
368
369
        /** @var AbstractScalarType $type */
370 44
        $type = $field->getType()->getNullableType();
371
372 44
        return $type->serialize($resolvedValue);
373
    }
374
375 19
    protected function resolveList(FieldInterface $field, AstFieldInterface $ast, $parentValue)
376
    {
377
        /** @var AstQuery $ast */
378 19
        $resolvedValue = $this->doResolve($field, $ast, $parentValue);
379
380 19
        $this->resolveValidator->assertValidResolvedValueForField($field, $resolvedValue);
381
382 17
        if (null === $resolvedValue) {
383 5
            return null;
384
        }
385
386
        /** @var AbstractListType $type */
387 16
        $type     = $field->getType()->getNullableType();
388 16
        $itemType = $type->getNamedType();
389
390 16
        $fakeAst = clone $ast;
391 16
        if ($fakeAst instanceof AstQuery) {
392 15
            $fakeAst->setArguments([]);
393 15
        }
394
395 16
        $fakeField = new Field([
396 16
            'name' => $field->getName(),
397 16
            'type' => $itemType,
398 16
            'args' => $field->getArguments(),
399 16
        ]);
400
401 16
        $result = [];
402 16
        foreach ($resolvedValue as $resolvedValueItem) {
403
            try {
404 15
                $fakeField->getConfig()->set('resolve', function () use ($resolvedValueItem) {
405 15
                    return $resolvedValueItem;
406 15
                });
407
408 15
                switch ($itemType->getNullableType()->getKind()) {
409 15
                    case TypeMap::KIND_ENUM:
410 15
                    case TypeMap::KIND_SCALAR:
411 5
                        $value = $this->resolveScalar($fakeField, $fakeAst, $resolvedValueItem);
412
413 4
                        break;
414
415
416 11
                    case TypeMap::KIND_OBJECT:
417 9
                        $value = $this->resolveObject($fakeField, $fakeAst, $resolvedValueItem);
418
419 9
                        break;
420
421 3
                    case TypeMap::KIND_UNION:
422 3
                    case TypeMap::KIND_INTERFACE:
423 3
                        $value = $this->resolveComposite($fakeField, $fakeAst, $resolvedValueItem);
424
425 3
                        break;
426
427
                    default:
428
                        $value = null;
429 14
                }
430 15
            } catch (\Exception $e) {
431 1
                $this->executionContext->addError($e);
432
433 1
                $value = null;
434
            }
435
436 15
            $result[] = $value;
437 16
        }
438
439 16
        return $result;
440
    }
441
442 7
    protected function resolveComposite(FieldInterface $field, AstFieldInterface $ast, $parentValue)
443
    {
444
        /** @var AstQuery $ast */
445 7
        $resolvedValue = $this->doResolve($field, $ast, $parentValue);
446
447 7
        $this->resolveValidator->assertValidResolvedValueForField($field, $resolvedValue);
448
449
        /** @var AbstractUnionType $type */
450 7
        $type         = $field->getType()->getNullableType();
451 7
        $resolvedType = $type->resolveType($resolvedValue);
452
453 7
        if (!$resolvedType) {
454
            throw new ResolveException('Resolving function must return type');
455
        }
456
457 7
        if ($type instanceof AbstractInterfaceType) {
458 6
            $this->resolveValidator->assertTypeImplementsInterface($resolvedType, $type);
459 6
        } else {
460 1
            $this->resolveValidator->assertTypeInUnionTypes($resolvedType, $type);
461
        }
462
463 7
        $fakeField = new Field([
464 7
            'name' => $field->getName(),
465 7
            'type' => $resolvedType,
466 7
            'args' => $field->getArguments(),
467 7
        ]);
468
469 7
        return $this->resolveObject($fakeField, $ast, $resolvedValue, true);
470
    }
471
472 57
    protected function parseAndCreateRequest($payload, $variables = [])
473
    {
474 57
        if (empty($payload)) {
475 1
            throw new \InvalidArgumentException('Must provide an operation.');
476
        }
477
478 57
        $parser  = new Parser();
479 57
        $request = new Request($parser->parse($payload), $variables);
480
481 57
        (new RequestValidator())->validate($request);
482
483 56
        $this->executionContext->setRequest($request);
484 56
    }
485
486 51
    protected function doResolve(FieldInterface $field, AstFieldInterface $ast, $parentValue = null)
487
    {
488
        /** @var AstQuery|AstField $ast */
489 51
        $arguments = $this->parseArgumentsValues($field, $ast);
490 51
        $astFields = $ast instanceof AstQuery ? $ast->getFields() : [];
491
492 51
        return $field->resolve($parentValue, $arguments, $this->createResolveInfo($field, $astFields));
493
    }
494
495 51
    protected function parseArgumentsValues(FieldInterface $field, AstFieldInterface $ast)
496
    {
497 51
        $values   = [];
498 51
        $defaults = [];
499
500 51
        foreach ($field->getArguments() as $argument) {
501
            /** @var $argument InputField */
502 36
            if ($argument->getConfig()->has('defaultValue')) {
503 6
                $defaults[$argument->getName()] = $argument->getConfig()->getDefaultValue();
504 6
            }
505 51
        }
506
507 51
        foreach ($ast->getArguments() as $astArgument) {
508 28
            $argument     = $field->getArgument($astArgument->getName());
509 28
            $argumentType = $argument->getType()->getNullableType();
510
511 28
            $values[$argument->getName()] = $argumentType->parseValue($astArgument->getValue());
512
513 28
            if (isset($defaults[$argument->getName()])) {
514 3
                unset($defaults[$argument->getName()]);
515 3
            }
516 51
        }
517
518 51
        return array_merge($values, $defaults);
519
    }
520
521 56
    private function getAlias(AstFieldInterface $ast)
522
    {
523 56
        return $ast->getAlias() ?: $ast->getName();
524
    }
525
526 51
    protected function createResolveInfo(FieldInterface $field, array $astFields)
527
    {
528 51
        return new ResolveInfo($field, $astFields, $this->executionContext);
529
    }
530
531
532
    /**
533
     * You can access ExecutionContext to check errors and inject dependencies
534
     *
535
     * @return ExecutionContext
536
     */
537 11
    public function getExecutionContext()
538
    {
539 11
        return $this->executionContext;
540
    }
541
542 57
    public function getResponseData()
543
    {
544 57
        $result = [];
545
546 57
        if (!empty($this->data)) {
547 56
            $result['data'] = $this->data;
548 56
        }
549
550 57
        if ($this->executionContext->hasErrors()) {
551 18
            $result['errors'] = $this->executionContext->getErrorsArray();
552 18
        }
553
554 57
        return $result;
555
    }
556
557
    /**
558
     * @return int
559
     */
560
    public function getMaxComplexity()
561
    {
562
        return $this->maxComplexity;
563
    }
564
565
    /**
566
     * @param int $maxComplexity
567
     */
568 1
    public function setMaxComplexity($maxComplexity)
569
    {
570 1
        $this->maxComplexity = $maxComplexity;
571 1
    }
572
573
}
574