Completed
Pull Request — master (#217)
by Christoffer
10:41 queued 08:05
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\ExecutionException;
6
use Digia\GraphQL\Language\Node\DocumentNode;
7
use Digia\GraphQL\Language\Node\FragmentDefinitionNode;
8
use Digia\GraphQL\Language\Node\FragmentSpreadNode;
9
use Digia\GraphQL\Language\Node\OperationDefinitionNode;
10
use Digia\GraphQL\Schema\Schema;
11
12
class Execution implements ExecutionInterface
13
{
14
    /**
15
     * @param Schema        $schema
16
     * @param DocumentNode  $documentNode
17
     * @param mixed|null    $rootValue
18
     * @param mixed|null    $contextValue
19
     * @param array         $variableValues
20
     * @param null|string   $operationName
21
     * @param callable|null $fieldResolver
22
     * @return ExecutionResult
23
     * @throws \Throwable
24
     */
25
    public function execute(
26
        Schema $schema,
27
        DocumentNode $documentNode,
28
        $rootValue = null,
29
        $contextValue = null,
30
        array $variableValues = [],
31
        string $operationName = null,
32
        callable $fieldResolver = null
33
    ): ExecutionResult {
34
        try {
35
            $context = $this->createContext(
36
                $schema,
37
                $documentNode,
38
                $rootValue,
39
                $contextValue,
40
                $variableValues,
41
                $operationName,
0 ignored issues
show
Bug introduced by
It seems like $operationName can also be of type string; however, parameter $operationName of Digia\GraphQL\Execution\Execution::createContext() does only seem to accept null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

41
                /** @scrutinizer ignore-type */ $operationName,
Loading history...
42
                $fieldResolver
43
            );
44
45
            // Return early errors if execution context failed.
46
            if (!empty($context->getErrors())) {
47
                return new ExecutionResult(null, $context->getErrors());
48
            }
49
        } catch (ExecutionException $error) {
50
            return new ExecutionResult(null, [$error]);
51
        }
52
53
        $data   = $this->createExecutor($context)->execute();
54
        $errors = $context->getErrors();
55
56
        return new ExecutionResult($data, $errors);
57
    }
58
59
    /**
60
     * @param Schema        $schema
61
     * @param DocumentNode  $documentNode
62
     * @param mixed         $rootValue
63
     * @param mixed         $contextValue
64
     * @param mixed         $rawVariableValues
65
     * @param null          $operationName
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $operationName is correct as it would always require null to be passed?
Loading history...
66
     * @param callable|null $fieldResolver
67
     * @return ExecutionContext
68
     * @throws ExecutionException
69
     * @throws \Exception
70
     */
71
    protected function createContext(
72
        Schema $schema,
73
        DocumentNode $documentNode,
74
        $rootValue,
75
        $contextValue,
76
        $rawVariableValues,
77
        $operationName = null,
78
        callable $fieldResolver = null
79
    ): ExecutionContext {
80
        $errors    = [];
81
        $fragments = [];
82
        $operation = null;
83
84
        foreach ($documentNode->getDefinitions() as $definition) {
85
            if ($definition instanceof OperationDefinitionNode) {
86
                if (!$operationName && $operation) {
87
                    throw new ExecutionException(
88
                        'Must provide operation name if query contains multiple operations.'
89
                    );
90
                }
91
92
                if (!$operationName || $definition->getNameValue() === $operationName) {
93
                    $operation = $definition;
94
                }
95
96
                continue;
97
            }
98
99
            if ($definition instanceof FragmentDefinitionNode || $definition instanceof FragmentSpreadNode) {
100
                $fragments[$definition->getNameValue()] = $definition;
101
102
                continue;
103
            }
104
        }
105
106
        if (null === $operation) {
107
            if (null !== $operationName) {
108
                throw new ExecutionException(sprintf('Unknown operation named "%s".', $operationName));
109
            }
110
111
            throw new ExecutionException('Must provide an operation.');
112
        }
113
114
        $variableValues = [];
115
116
        /** @var OperationDefinitionNode $operation */
117
        if (null !== $operation) {
118
            $coercedVariableValues = coerceVariableValues(
119
                $schema,
120
                $operation->getVariableDefinitions(),
121
                $rawVariableValues
122
            );
123
124
            $variableValues = $coercedVariableValues->getValue();
125
126
            if ($coercedVariableValues->hasErrors()) {
127
                $errors = $coercedVariableValues->getErrors();
128
            }
129
        }
130
131
        return new ExecutionContext(
132
            $schema,
133
            $fragments,
134
            $rootValue,
135
            $contextValue,
136
            $variableValues,
137
            $fieldResolver,
138
            $operation,
139
            $errors
140
        );
141
    }
142
143
    /**
144
     * @param ExecutionContext $context
145
     * @return Executor
146
     */
147
    protected function createExecutor(ExecutionContext $context): Executor
148
    {
149
        return new Executor($context, new FieldCollector($context));
150
    }
151
}
152