Passed
Push — master ( d044ba...6d4515 )
by Christoffer
02:32
created

Execution::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 1
1
<?php
2
3
namespace Digia\GraphQL\Execution;
4
5
use Digia\GraphQL\Error\ErrorHandlerInterface;
6
use Digia\GraphQL\Error\ExecutionException;
7
use Digia\GraphQL\Language\Node\DocumentNode;
8
use Digia\GraphQL\Language\Node\FragmentDefinitionNode;
9
use Digia\GraphQL\Language\Node\FragmentSpreadNode;
10
use Digia\GraphQL\Language\Node\OperationDefinitionNode;
11
use Digia\GraphQL\Schema\Schema;
12
13
class Execution implements ExecutionInterface
14
{
15
    /**
16
     * @var ErrorHandlerInterface
17
     */
18
    private $errorHandler;
19
20
    /**
21
     * Execution constructor.
22
     * @param ErrorHandlerInterface $errorHandler
23
     */
24
    public function __construct(ErrorHandlerInterface $errorHandler)
25
    {
26
        $this->errorHandler = $errorHandler;
27
    }
28
29
    /**
30
     * @param Schema        $schema
31
     * @param DocumentNode  $documentNode
32
     * @param mixed         $rootValue
33
     * @param mixed         $contextValue
34
     * @param array         $variableValues
35
     * @param null|string   $operationName
36
     * @param callable|null $fieldResolver
37
     * @return ExecutionResult
38
     * @throws \Throwable
39
     */
40
    public function execute(
41
        Schema $schema,
42
        DocumentNode $documentNode,
43
        $rootValue = null,
44
        $contextValue = null,
45
        array $variableValues = [],
46
        ?string $operationName = null,
47
        ?callable $fieldResolver = null
48
    ): ExecutionResult {
49
        try {
50
            $context = $this->createContext(
51
                $schema,
52
                $documentNode,
53
                $rootValue,
54
                $contextValue,
55
                $variableValues,
56
                $operationName,
57
                $fieldResolver
58
            );
59
60
            // Return early errors if execution context failed.
61
            if (!empty($context->getErrors())) {
62
                return new ExecutionResult(null, $context->getErrors());
63
            }
64
        } catch (ExecutionException $error) {
65
            return new ExecutionResult(null, [$error]);
66
        }
67
68
        $data   = $this->createExecutor($context)->execute();
69
        $errors = $context->getErrors();
70
71
        return new ExecutionResult($data, $errors);
72
    }
73
74
    /**
75
     * @param Schema        $schema
76
     * @param DocumentNode  $documentNode
77
     * @param mixed         $rootValue
78
     * @param mixed         $contextValue
79
     * @param mixed         $rawVariableValues
80
     * @param null|string   $operationName
81
     * @param callable|null $fieldResolver
82
     * @return ExecutionContext
83
     * @throws ExecutionException
84
     * @throws \Exception
85
     */
86
    protected function createContext(
87
        Schema $schema,
88
        DocumentNode $documentNode,
89
        $rootValue,
90
        $contextValue,
91
        $rawVariableValues,
92
        ?string $operationName = null,
93
        ?callable $fieldResolver = null
94
    ): ExecutionContext {
95
        $errors    = [];
96
        $fragments = [];
97
        $operation = null;
98
99
        foreach ($documentNode->getDefinitions() as $definition) {
100
            if ($definition instanceof OperationDefinitionNode) {
101
                if (null === $operationName && $operation) {
102
                    throw new ExecutionException(
103
                        'Must provide operation name if query contains multiple operations.'
104
                    );
105
                }
106
107
                if (null === $operationName || $definition->getNameValue() === $operationName) {
108
                    $operation = $definition;
109
                }
110
111
                continue;
112
            }
113
114
            if ($definition instanceof FragmentDefinitionNode || $definition instanceof FragmentSpreadNode) {
115
                $fragments[$definition->getNameValue()] = $definition;
116
117
                continue;
118
            }
119
        }
120
121
        if (null === $operation) {
122
            if (null !== $operationName) {
123
                throw new ExecutionException(sprintf('Unknown operation named "%s".', $operationName));
124
            }
125
126
            throw new ExecutionException('Must provide an operation.');
127
        }
128
129
        $coercedVariableValues = coerceVariableValues(
130
            $schema,
131
            $operation->getVariableDefinitions(),
132
            $rawVariableValues
133
        );
134
135
        $variableValues = $coercedVariableValues->getValue();
136
137
        if ($coercedVariableValues->hasErrors()) {
138
            $errors = $coercedVariableValues->getErrors();
139
        }
140
141
        return new ExecutionContext(
142
            $schema,
143
            $fragments,
144
            $rootValue,
145
            $contextValue,
146
            $variableValues,
147
            $fieldResolver,
148
            $operation,
149
            $errors
150
        );
151
    }
152
153
    /**
154
     * @param ExecutionContext $context
155
     * @return Executor
156
     */
157
    protected function createExecutor(ExecutionContext $context): Executor
158
    {
159
        return new Executor($context, new FieldCollector($context), $this->errorHandler);
160
    }
161
}
162