Completed
Pull Request — master (#294)
by Christoffer
02:23
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
    /**
17
     * @param Schema        $schema
18
     * @param DocumentNode  $documentNode
19
     * @param mixed         $rootValue
20
     * @param mixed         $contextValue
21
     * @param array         $variableValues
22
     * @param null|string   $operationName
23
     * @param callable|null $fieldResolver
24
     * @return ExecutionResult
25
     * @throws \Throwable
26
     */
27
    public function execute(
28
        Schema $schema,
29
        DocumentNode $documentNode,
30
        $rootValue = null,
31
        $contextValue = null,
32
        array $variableValues = [],
33
        ?string $operationName = null,
34
        ?callable $fieldResolver = null,
35
        ?ErrorHandlerInterface $errorHandler = null
36
    ): ExecutionResult {
37
        try {
38
            $context = $this->createContext(
39
                $schema,
40
                $documentNode,
41
                $rootValue,
42
                $contextValue,
43
                $variableValues,
44
                $operationName,
45
                $fieldResolver
46
            );
47
48
            // Return early errors if execution context failed.
49
            if (!empty($context->getErrors())) {
50
                return new ExecutionResult(null, $context->getErrors());
51
            }
52
        } catch (ExecutionException $error) {
53
            return new ExecutionResult(null, [$error]);
54
        }
55
56
        $data   = $this->createExecutor($context, $errorHandler)->execute();
57
        $errors = $context->getErrors();
58
59
        return new ExecutionResult($data, $errors);
60
    }
61
62
    /**
63
     * @param Schema        $schema
64
     * @param DocumentNode  $documentNode
65
     * @param mixed         $rootValue
66
     * @param mixed         $contextValue
67
     * @param mixed         $rawVariableValues
68
     * @param null|string   $operationName
69
     * @param callable|null $fieldResolver
70
     * @return ExecutionContext
71
     * @throws ExecutionException
72
     * @throws \Exception
73
     */
74
    protected function createContext(
75
        Schema $schema,
76
        DocumentNode $documentNode,
77
        $rootValue,
78
        $contextValue,
79
        $rawVariableValues,
80
        ?string $operationName = null,
81
        ?callable $fieldResolver = null
82
    ): ExecutionContext {
83
        $errors    = [];
84
        $fragments = [];
85
        $operation = null;
86
87
        foreach ($documentNode->getDefinitions() as $definition) {
88
            if ($definition instanceof OperationDefinitionNode) {
89
                if (null === $operationName && $operation) {
90
                    throw new ExecutionException(
91
                        'Must provide operation name if query contains multiple operations.'
92
                    );
93
                }
94
95
                if (null === $operationName || $definition->getNameValue() === $operationName) {
96
                    $operation = $definition;
97
                }
98
99
                continue;
100
            }
101
102
            if ($definition instanceof FragmentDefinitionNode || $definition instanceof FragmentSpreadNode) {
103
                $fragments[$definition->getNameValue()] = $definition;
104
105
                continue;
106
            }
107
        }
108
109
        if (null === $operation) {
110
            if (null !== $operationName) {
111
                throw new ExecutionException(sprintf('Unknown operation named "%s".', $operationName));
112
            }
113
114
            throw new ExecutionException('Must provide an operation.');
115
        }
116
117
        $coercedVariableValues = coerceVariableValues(
118
            $schema,
119
            $operation->getVariableDefinitions(),
120
            $rawVariableValues
121
        );
122
123
        $variableValues = $coercedVariableValues->getValue();
124
125
        if ($coercedVariableValues->hasErrors()) {
126
            $errors = $coercedVariableValues->getErrors();
127
        }
128
129
        return new ExecutionContext(
130
            $schema,
131
            $fragments,
132
            $rootValue,
133
            $contextValue,
134
            $variableValues,
135
            $fieldResolver,
136
            $operation,
137
            $errors
138
        );
139
    }
140
141
    /**
142
     * @param ExecutionContext           $context
143
     * @param ErrorHandlerInterface|null $errorHandler
144
     * @return Executor
145
     */
146
    protected function createExecutor(ExecutionContext $context, ?ErrorHandlerInterface $errorHandler = null): Executor
147
    {
148
        return new Executor($context, new FieldCollector($context), $errorHandler);
149
    }
150
}
151