xref: /plugin/elasticsearch/vendor/ruflin/elastica/src/Response.php (revision d832d53af2a0f84c34c8d5f17c93ffaa85869e5d)
1<?php
2
3namespace Elastica;
4
5use Elastica\Exception\NotFoundException;
6
7/**
8 * Elastica Response object.
9 *
10 * Stores query time, and result array -> is given to result set, returned by ...
11 *
12 * @author Nicolas Ruflin <spam@ruflin.com>
13 */
14class Response
15{
16    /**
17     * Query time.
18     *
19     * @var float Query time
20     */
21    protected $_queryTime;
22
23    /**
24     * Response string (json).
25     *
26     * @var string Response
27     */
28    protected $_responseString = '';
29
30    /**
31     * Transfer info.
32     *
33     * @var array transfer info
34     */
35    protected $_transferInfo = [];
36
37    /**
38     * Response.
39     *
40     * @var array|null
41     */
42    protected $_response;
43
44    /**
45     * HTTP response status code.
46     *
47     * @var int
48     */
49    protected $_status;
50
51    /**
52     * Whether or not to convert bigint results to string (see issue #717).
53     *
54     * @var bool
55     */
56    protected $_jsonBigintConversion = false;
57
58    /**
59     * Construct.
60     *
61     * @param array|string $responseString Response string (json)
62     * @param int          $responseStatus http status code
63     */
64    public function __construct($responseString, $responseStatus = null)
65    {
66        if (\is_array($responseString)) {
67            $this->_response = $responseString;
68        } else {
69            $this->_responseString = $responseString;
70        }
71        $this->_status = $responseStatus;
72    }
73
74    /**
75     * Error message.
76     *
77     * @return string Error message
78     */
79    public function getError()
80    {
81        $error = $this->getFullError();
82
83        if (!$error) {
84            return '';
85        }
86
87        if (\is_string($error)) {
88            return $error;
89        }
90
91        $rootError = $error['root_cause'][0] ?? $error;
92
93        $message = $rootError['reason'];
94        if (isset($rootError['index'])) {
95            $message .= ' [index: '.$rootError['index'].']';
96        }
97
98        if (isset($error['reason']) && $rootError['reason'] !== $error['reason']) {
99            $message .= ' [reason: '.$error['reason'].']';
100        }
101
102        return $message;
103    }
104
105    /**
106     * A keyed array representing any errors that occurred.
107     *
108     * In case of http://localhost:9200/_alias/test the error is a string
109     *
110     * @return array|string|null Error data or null if there is no error
111     */
112    public function getFullError()
113    {
114        $response = $this->getData();
115
116        return $response['error'] ?? null;
117    }
118
119    /**
120     * @return string Error string based on the error object
121     */
122    public function getErrorMessage()
123    {
124        return $this->getError();
125    }
126
127    /**
128     * True if response has error.
129     *
130     * @return bool True if response has error
131     */
132    public function hasError()
133    {
134        $response = $this->getData();
135
136        return isset($response['error']);
137    }
138
139    /**
140     * True if response has failed shards.
141     *
142     * @return bool True if response has failed shards
143     */
144    public function hasFailedShards()
145    {
146        try {
147            $shardsStatistics = $this->getShardsStatistics();
148        } catch (NotFoundException $e) {
149            return false;
150        }
151
152        return \array_key_exists('failures', $shardsStatistics);
153    }
154
155    /**
156     * Checks if the query returned ok.
157     *
158     * @return bool True if ok
159     */
160    public function isOk()
161    {
162        $data = $this->getData();
163
164        // Bulk insert checks. Check every item
165        if (isset($data['status'])) {
166            return $data['status'] >= 200 && $data['status'] <= 300;
167        }
168
169        if (isset($data['items'])) {
170            if (isset($data['errors']) && true === $data['errors']) {
171                return false;
172            }
173
174            foreach ($data['items'] as $item) {
175                if (isset($item['index']['ok']) && false == $item['index']['ok']) {
176                    return false;
177                }
178
179                if (isset($item['index']['status']) && ($item['index']['status'] < 200 || $item['index']['status'] >= 300)) {
180                    return false;
181                }
182            }
183
184            return true;
185        }
186
187        if ($this->_status >= 200 && $this->_status <= 300) {
188            // http status is ok
189            return true;
190        }
191
192        return isset($data['ok']) && $data['ok'];
193    }
194
195    /**
196     * @return int
197     */
198    public function getStatus()
199    {
200        return $this->_status;
201    }
202
203    /**
204     * Response data array.
205     *
206     * @return array<string, mixed> Response data array
207     */
208    public function getData()
209    {
210        if (null == $this->_response) {
211            $response = $this->_responseString;
212
213            try {
214                if ($this->getJsonBigintConversion()) {
215                    $response = JSON::parse($response, true, 512, \JSON_BIGINT_AS_STRING);
216                } else {
217                    $response = JSON::parse($response);
218                }
219            } catch (\JsonException $e) {
220                // leave response as is if parse fails
221            }
222
223            if (empty($response)) {
224                $response = [];
225            }
226
227            if (\is_string($response)) {
228                $response = ['message' => $response];
229            }
230
231            $this->_response = $response;
232            $this->_responseString = '';
233        }
234
235        return $this->_response;
236    }
237
238    /**
239     * Gets the transfer information.
240     *
241     * @return array information about the curl request
242     */
243    public function getTransferInfo()
244    {
245        return $this->_transferInfo;
246    }
247
248    /**
249     * Sets the transfer info of the curl request. This function is called
250     * from the \Elastica\Client::_callService .
251     *
252     * @param array $transferInfo the curl transfer information
253     *
254     * @return $this
255     */
256    public function setTransferInfo(array $transferInfo)
257    {
258        $this->_transferInfo = $transferInfo;
259
260        return $this;
261    }
262
263    /**
264     * Returns query execution time.
265     *
266     * @return float Query time
267     */
268    public function getQueryTime()
269    {
270        return $this->_queryTime;
271    }
272
273    /**
274     * Sets the query time.
275     *
276     * @param float $queryTime Query time
277     *
278     * @return $this
279     */
280    public function setQueryTime($queryTime)
281    {
282        $this->_queryTime = $queryTime;
283
284        return $this;
285    }
286
287    /**
288     * Time request took.
289     *
290     * @throws NotFoundException
291     *
292     * @return int Time request took
293     */
294    public function getEngineTime()
295    {
296        $data = $this->getData();
297
298        if (!isset($data['took'])) {
299            throw new NotFoundException('Unable to find the field [took]from the response');
300        }
301
302        return $data['took'];
303    }
304
305    /**
306     * Get the _shard statistics for the response.
307     *
308     * @throws NotFoundException
309     *
310     * @return array
311     */
312    public function getShardsStatistics()
313    {
314        $data = $this->getData();
315
316        if (!isset($data['_shards'])) {
317            throw new NotFoundException('Unable to find the field [_shards] from the response');
318        }
319
320        return $data['_shards'];
321    }
322
323    /**
324     * Get the _scroll value for the response.
325     *
326     * @throws NotFoundException
327     *
328     * @return string
329     */
330    public function getScrollId()
331    {
332        $data = $this->getData();
333
334        if (!isset($data['_scroll_id'])) {
335            throw new NotFoundException('Unable to find the field [_scroll_id] from the response');
336        }
337
338        return $data['_scroll_id'];
339    }
340
341    /**
342     * Sets whether or not to apply bigint conversion on the JSON result.
343     *
344     * @param bool $jsonBigintConversion
345     */
346    public function setJsonBigintConversion($jsonBigintConversion): void
347    {
348        $this->_jsonBigintConversion = $jsonBigintConversion;
349    }
350
351    /**
352     * Gets whether or not to apply bigint conversion on the JSON result.
353     *
354     * @return bool
355     */
356    public function getJsonBigintConversion()
357    {
358        return $this->_jsonBigintConversion;
359    }
360}
361