Execution::execute()   B
last analyzed

Complexity

Conditions 6
Paths 7

Size

Total Lines 46
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 6
eloc 22
nc 7
nop 8
dl 0
loc 46
rs 8.9457
c 2
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace Digia\GraphQL\Execution;
4
5
use Digia\GraphQL\Error\Handler\ErrorHandlerInterface;
6
use Digia\GraphQL\Execution\Strategy\FieldCollector;
7
use Digia\GraphQL\Execution\Strategy\ParallelExecutionStrategy;
8
use Digia\GraphQL\Execution\Strategy\SerialExecutionStrategy;
9
use Digia\GraphQL\Language\Node\DocumentNode;
10
use Digia\GraphQL\Language\Node\FragmentDefinitionNode;
11
use Digia\GraphQL\Language\Node\FragmentSpreadNode;
12
use Digia\GraphQL\Language\Node\OperationDefinitionNode;
13
use Digia\GraphQL\Schema\Schema;
14
use React\Promise\PromiseInterface;
15
use function React\Promise\resolve;
16
17
class Execution implements ExecutionInterface
18
{
19
    /**
20
     * @inheritdoc
21
     */
22
    public function execute(
23
        Schema $schema,
24
        DocumentNode $documentNode,
25
        $rootValue = null,
26
        $contextValue = null,
27
        array $variableValues = [],
28
        ?string $operationName = null,
29
        ?callable $fieldResolver = null,
30
        ?ErrorHandlerInterface $errorHandler = null
31
    ): PromiseInterface {
32
        try {
33
            $context = $this->createContext(
34
                $schema,
35
                $documentNode,
36
                $rootValue,
37
                $contextValue,
38
                $variableValues,
39
                $operationName,
40
                $fieldResolver
41
            );
42
43
            // Return early errors if execution context failed.
44
            if (!empty($context->getErrors())) {
45
                return resolve(new ExecutionResult(null, $context->getErrors()));
46
            }
47
        } catch (ExecutionException $error) {
48
            return resolve(new ExecutionResult(null, [$error]));
49
        }
50
51
        $fieldCollector = new FieldCollector($context);
52
53
        $data = $this->executeOperation($operationName, $context, $fieldCollector);
54
55
        if ($data instanceof PromiseInterface) {
56
            return $data->then(function ($resolvedData) use ($context) {
57
                return new ExecutionResult($resolvedData, $context->getErrors());
58
            });
59
        }
60
61
        if (null !== $errorHandler) {
62
            foreach ($context->getErrors() as $error) {
63
                $errorHandler->handleExecutionError($error, $context);
64
            }
65
        }
66
67
        return resolve(new ExecutionResult($data, $context->getErrors()));
68
    }
69
70
    /**
71
     * @param null|string      $operationName
72
     * @param ExecutionContext $context
73
     * @param FieldCollector   $fieldCollector
74
     * @return array|mixed|null|PromiseInterface
75
     */
76
    protected function executeOperation(
77
        ?string $operationName,
78
        ExecutionContext $context,
79
        FieldCollector $fieldCollector
80
    ) {
81
        $strategy = $operationName === 'mutation'
82
            ? new SerialExecutionStrategy($context, $fieldCollector)
83
            : new ParallelExecutionStrategy($context, $fieldCollector);
84
85
        $result = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
86
87
        try {
88
            $result = $strategy->execute();
89
        } catch (ExecutionException $exception) {
90
            $context->addError($exception);
91
        } catch (\Throwable $exception) {
92
            $context->addError(
93
                new ExecutionException($exception->getMessage(), null, null, null, null, null, $exception)
94
            );
95
        }
96
97
        if ($result instanceof PromiseInterface) {
98
            return $result->then(null, function (ExecutionException $exception) use ($context) {
99
                $context->addError($exception);
100
                return resolve(null);
101
            });
102
        }
103
104
        return $result;
105
    }
106
107
    /**
108
     * @param Schema        $schema
109
     * @param DocumentNode  $documentNode
110
     * @param mixed         $rootValue
111
     * @param mixed         $contextValue
112
     * @param mixed         $rawVariableValues
113
     * @param null|string   $operationName
114
     * @param callable|null $fieldResolver
115
     * @return ExecutionContext
116
     * @throws ExecutionException
117
     */
118
    protected function createContext(
119
        Schema $schema,
120
        DocumentNode $documentNode,
121
        $rootValue,
122
        $contextValue,
123
        $rawVariableValues,
124
        ?string $operationName = null,
125
        ?callable $fieldResolver = null
126
    ): ExecutionContext {
127
        $errors    = [];
128
        $fragments = [];
129
        $operation = null;
130
131
        foreach ($documentNode->getDefinitions() as $definition) {
132
            if ($definition instanceof OperationDefinitionNode) {
133
                if (null === $operationName && null !== $operation) {
134
                    throw new ExecutionException(
135
                        'Must provide operation name if query contains multiple operations.'
136
                    );
137
                }
138
139
                if (null === $operationName || $definition->getNameValue() === $operationName) {
140
                    $operation = $definition;
141
                }
142
143
                continue;
144
            }
145
146
            if ($definition instanceof FragmentDefinitionNode || $definition instanceof FragmentSpreadNode) {
147
                $fragments[$definition->getNameValue()] = $definition;
148
149
                continue;
150
            }
151
        }
152
153
        if (null === $operation) {
154
            if (null !== $operationName) {
155
                throw new ExecutionException(sprintf('Unknown operation named "%s".', $operationName));
156
            }
157
158
            throw new ExecutionException('Must provide an operation.');
159
        }
160
161
        $coercedVariableValues = ValuesResolver::coerceVariableValues(
162
            $schema,
163
            $operation->getVariableDefinitions(),
164
            $rawVariableValues
165
        );
166
167
        $variableValues = $coercedVariableValues->getValue();
168
169
        if ($coercedVariableValues->hasErrors()) {
170
            $errors = $coercedVariableValues->getErrors();
171
        }
172
173
        return new ExecutionContext(
174
            $schema,
175
            $fragments,
176
            $rootValue,
177
            $contextValue,
178
            $variableValues,
179
            $fieldResolver,
180
            $operation,
181
            $errors
182
        );
183
    }
184
}
185