Completed
Pull Request — master (#106)
by Christoffer
02:31
created

GraphQLException::getExtensions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Digia\GraphQL\Error;
4
5
use Digia\GraphQL\Language\Node\NodeInterface;
6
use Digia\GraphQL\Language\Location;
7
use Digia\GraphQL\Language\Source;
8
use Digia\GraphQL\Language\SourceLocation;
9
10
/**
11
 * An GraphQLException describes an exception thrown during the execute
12
 * phase of performing a GraphQL operation. In addition to a message
13
 * and stack trace, it also includes information about the locations in a
14
 * GraphQL document and/or execution result that correspond to the Error.
15
 */
16
class GraphQLException extends AbstractException
17
{
18
19
    /**
20
     * An array of { line, column } locations within the source GraphQL document
21
     * which correspond to this error.
22
     *
23
     * Errors during validation often contain multiple locations, for example to
24
     * point out two things with the same name. Errors during execution include a
25
     * single location, the field which produced the error.
26
     *
27
     * @var array|null
28
     */
29
    protected $locations;
30
31
    /**
32
     * An array describing the JSON-path into the execution response which
33
     * corresponds to this error. Only included for errors during execution.
34
     *
35
     * @var string[]|null
36
     */
37
    protected $path;
38
39
    /**
40
     * An array of GraphQL AST Nodes corresponding to this error.
41
     *
42
     * @var NodeInterface[]|null
43
     */
44
    protected $nodes;
45
46
    /**
47
     * The source GraphQL document for the first location of this error.
48
     *
49
     * Note that if this Error represents more than one node, the source may not
50
     * represent nodes after the first node.
51
     *
52
     * @var Source|null
53
     */
54
    protected $source;
55
56
    /**
57
     * An array of character offsets within the source GraphQL document
58
     * which correspond to this error.
59
     *
60
     * @var int[]|null
61
     */
62
    protected $positions;
63
64
    /**
65
     * Extension fields to add to the formatted error.
66
     *
67
     * @var \Exception|null
68
     */
69
    protected $originalException;
70
71
    /**
72
     * ExecutionException constructor.
73
     *
74
     * @param string      $message
75
     * @param array|null  $nodes
76
     * @param Source|null $source
77
     * @param array|null  $positions
78
     * @param array|null  $path
79
     * @param array|null  $originalException
80
     */
81
    public function __construct(
82
        string $message,
83
        ?array $nodes = null,
84
        ?Source $source = null,
85
        ?array $positions = null,
86
        ?array $path = null,
87
        ?\Exception $originalException = null
88
    ) {
89
        parent::__construct($message);
90
91
        $this->resolveNodes($nodes);
92
        $this->resolveSource($source);
93
        $this->resolvePositions($positions);
94
        $this->resolveLocations($positions, $source);
95
96
        $this->path              = $path;
97
        $this->originalException = $originalException;
98
    }
99
100
    /**
101
     * @return NodeInterface[]
102
     */
103
    public function getNodes(): ?array
104
    {
105
        return $this->nodes;
106
    }
107
108
    /**
109
     * @return bool
110
     */
111
    public function hasSource(): bool
112
    {
113
        return null !== $this->source;
114
    }
115
116
    /**
117
     * @return Source|null
118
     */
119
    public function getSource(): ?Source
120
    {
121
        return $this->source;
122
    }
123
124
    /**
125
     * @return int[]|null
126
     */
127
    public function getPositions(): ?array
128
    {
129
        return $this->positions;
130
    }
131
132
    /**
133
     * @return bool
134
     */
135
    public function hasLocations(): bool
136
    {
137
        return !empty($this->locations);
138
    }
139
140
    /**
141
     * @return array|null
142
     */
143
    public function getLocations(): ?array
144
    {
145
        return $this->locations;
146
    }
147
148
    /**
149
     * @return array|null
150
     */
151
    public function getLocationsAsArray(): ?array
152
    {
153
        return !empty($this->locations) ? array_map(function (SourceLocation $location) {
154
            return $location->toArray();
155
        }, $this->locations) : null;
156
    }
157
158
    /**
159
     * @return array|null
160
     */
161
    public function getPath(): ?array
162
    {
163
        return $this->path;
164
    }
165
166
    /**
167
     * @return \Exception|null
168
     */
169
    public function getOriginalException(): ?\Exception
170
    {
171
        return $this->originalException;
172
    }
173
174
    /**
175
     * @return null|string
176
     */
177
    public function getOriginalError(): ?string
178
    {
179
        return null !== $this->originalException ? $this->originalException->getMessage() : null;
180
    }
181
182
    /**
183
     * @param array|null $nodes
184
     * @return $this
185
     */
186
    protected function resolveNodes(?array $nodes)
187
    {
188
        $this->nodes = is_array($nodes)
189
            ? (!empty($nodes) ? $nodes : null)
190
            : (null !== $nodes ? [$nodes] : null);
0 ignored issues
show
introduced by
The condition null !== $nodes is always false.
Loading history...
191
192
        return $this;
193
    }
194
195
    /**
196
     * @param Source|null $source
197
     * @return $this
198
     */
199
    protected function resolveSource(?Source $source)
200
    {
201
        if (null === $source && !empty($this->nodes)) {
202
            $firstNode    = $this->nodes[0];
203
            $location     = null !== $firstNode ? $firstNode->getLocation() : null;
204
            $source = null !== $location ? $location->getSource() : null;
205
        }
206
207
        $this->source = $source;
208
209
        return $this;
210
    }
211
212
    /**
213
     * @param array|null $positions
214
     * @return $this
215
     */
216
    protected function resolvePositions(?array $positions)
217
    {
218
        if (null === $positions && !empty($this->nodes)) {
219
            $positions = array_reduce($this->nodes, function (array $list, NodeInterface $node) {
220
                $location = $node->getLocation();
221
                if (null !== $location) {
222
                    $list[] = $location->getStart();
223
                }
224
                return $list;
225
            }, []);
226
        }
227
228
        if (null !== $positions && empty($positions)) {
229
            $positions = null;
230
        }
231
232
        $this->positions = $positions;
233
234
        return $this;
235
    }
236
237
    /**
238
     * @param array|null  $positions
239
     * @param Source|null $source
240
     * @return $this
241
     */
242
    protected function resolveLocations(?array $positions, ?Source $source)
243
    {
244
        if (null !== $positions && null !== $source) {
245
            $locations = array_map(function ($position) use ($source) {
246
                return SourceLocation::fromSource($source, $position);
247
            }, $positions);
248
        } elseif (!empty($this->nodes)) {
249
            $locations = array_reduce($this->nodes, function (array $list, NodeInterface $node) {
250
                $location = $node->getLocation();
251
                if (null !== $location) {
252
                    $list[] = SourceLocation::fromSource($location->getSource(), $location->getStart());
253
                }
254
                return $list;
255
            }, []);
256
        }
257
258
        if (isset($locations)) {
259
            $this->locations = $locations;
260
        }
261
262
        return $this;
263
    }
264
265
    /**
266
     * @inheritdoc
267
     */
268
    public function __toString(): string
269
    {
270
        return printError($this);
271
    }
272
}
273