GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 98d33c...05e8ba )
by Anderson
04:55
created

ElasticConnection::unsetEmpties()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 9.2
c 0
b 0
f 0
cc 4
eloc 8
nc 5
nop 1
1
<?php
2
3
namespace DoctrineElastic\Connection;
4
5
use DoctrineElastic\Exception\ConnectionException;
6
use DoctrineElastic\Exception\ElasticOperationException;
7
use DoctrineElastic\Helper\MappingHelper;
8
use DoctrineElastic\Http\CurlRequest;
9
use DoctrineElastic\Traiting\ErrorGetterTrait;
10
11
/**
12
 * Default elastic connection class for general operations
13
 * Notice that the original elastic result of most of operations can be get by $return param
14
 *
15
 * @author Andsalves <[email protected]>
16
 */
17
class ElasticConnection implements ElasticConnectionInterface {
18
19
    use ErrorGetterTrait;
20
21
    /** Override default elastic limit size query */
22
    const DEFAULT_MAX_RESULTS = 10000;
23
24
    /** @var CurlRequest */
25
    protected $curlRequest;
26
27
    /** @var float */
28
    protected $esVersion;
29
30
    public function __construct(array $hosts) {
31
        $this->curlRequest = new CurlRequest();
32
        $baseHost = reset($hosts);
33
34
        if (empty($baseHost) || !is_string($baseHost) || !preg_match('/http/', $baseHost)) {
35
            throw new ConnectionException("Elasticsearch host is invalid. ");
36
        }
37
38
        $this->curlRequest->setBaseUrl($baseHost);
39
    }
40
41
    /**
42
     * @param string $index
43
     * @param array|null $mappings
44
     * @param array|null $settings
45
     * @param array|null $aliases
46
     * @param array|null $return
47
     * @return bool
48
     */
49
    public function createIndex(
50
        $index, array $mappings = null, array $settings = null, array $aliases = null, array &$return = null
51
    ) {
52
        if ($this->indexExists($index)) {
53
            throw new \InvalidArgumentException(sprintf("'%s' index already exists", $index));
54
        }
55
56
        $params = [];
57
58
        if (is_array($mappings) && !empty($mappings)) {
59
            $params['mappings'] = MappingHelper::patchMappings($mappings, floor($this->getElasticsearchVersion()));
60
        }
61
62
        if (is_array($settings) && !empty($settings)) {
63
            $params['settings'] = $settings;
64
        }
65
66
        if (is_array($aliases) && !empty($aliases)) {
67
            $params['aliases'] = $aliases;
68
        }
69
70
        $response = $this->curlRequest->request($index, $params, 'PUT');
71
        $return = $response['content'];
72
73
        if (isset($return['acknowledged']) && $return['acknowledged']) {
74
            return $return['acknowledged'];
75
        }
76
77
        $this->setErrorFromElasticReturn($return);
78
79
        return false;
80
    }
81
82
    /**
83
     * @param string $index
84
     * @param array|null $return
85
     * @return bool
86
     * @throws ElasticOperationException
87
     */
88
    public function deleteIndex($index, array &$return = null) {
89
        if (is_string($index) && !strstr('_all', $index) && !strstr('*', $index)) {
90
            $response = $this->curlRequest->request("$index?refresh=true", [], 'DELETE');
91
            $return = $response['content'];
92
93
            if ($response['status'] == 404) {
94
                throw new ElasticOperationException("Index '$index' doesn't exist so cannot be deleted. ");
95
            }
96
97
            if (isset($return['acknowledged'])) {
98
                return $return['acknowledged'];
99
            }
100
        } else {
101
            throw new ElasticOperationException('Index name is invalid for deletion. ');
102
        }
103
104
        $this->setErrorFromElasticReturn($return);
105
106
        return false;
107
    }
108
109
    /**
110
     * @param string $index
111
     * @param string $type
112
     * @param array $mappings
113
     * @param array|null $return
114
     * @return bool
115
     * @throws ElasticOperationException
116
     */
117
    public function createType($index, $type, array $mappings = [], array &$return = null) {
118
        if (!$this->indexExists($index)) {
119
            throw new \InvalidArgumentException(sprintf("%s' index does not exists", $index));
120
        }
121
122
        if ($this->typeExists($index, $type)) {
123
            throw new \InvalidArgumentException(sprintf("Type 's%' already exists on index %s", $type, $index));
124
        }
125
126
        $mappings = MappingHelper::patchMappings($mappings, floor($this->getElasticsearchVersion()));
127
128
        $url = "$index/_mapping/$type";
129
        $response = $this->curlRequest->request($url, $mappings, 'PUT');
130
131
        $this->throwExceptionFromResponse($response, "Error creating type '$type' in '$index' index");
132
133
        $return = $response['content'];
134
135
        if (isset($return['acknowledged'])) {
136
            return $return['acknowledged'];
137
        }
138
139
        $this->setErrorFromElasticReturn($return);
140
141
        return false;
142
    }
143
144
    /**
145
     * @param string $index
146
     * @param string $type
147
     * @param array $body
148
     * @param array $queryParams
149
     * @param array|null $return
150
     * @return bool
151
     */
152
    public function insert($index, $type, array $body, array $queryParams = [], array &$return = null) {
153
        $url = "$index/$type";
154
        if (isset($body['_id'])) {
155
            $url .= '/' . $body['_id'];
156
            unset($body['_id']);
157
        }
158
159
        $url = "$url?" . http_build_query(array_merge(['refresh' => "true"], $queryParams));
160
161
        $response = $this->curlRequest->request($url, $body, 'POST');
162
163
        $this->throwExceptionFromResponse($response);
164
        $return = $response['content'];
165
166
        if (isset($return['created'])) {
167
            return $return['created'];
168
        }
169
170
        $this->setErrorFromElasticReturn($return);
171
172
        return false;
173
    }
174
175
    /**
176
     * @param string $index
177
     * @param string $type
178
     * @param string $_id
179
     * @param array $body
180
     * @param array $queryParams
181
     * @param array|null $return
182
     *
183
     * @return bool
184
     */
185
    public function update($index, $type, $_id, array $body = [], array $queryParams = [], array &$return = null) {
186
        if (!$this->indexExists($index)) {
187
            return false;
188
        }
189
190
        if (array_key_exists('doc', $body)) {
191
            $params = $body;
192
        } else {
193
            $params = ['doc' => $body];
194
        }
195
196
        $url = "$index/$type/$_id/_update?" . http_build_query(array_merge(['refresh' => 'true'], $queryParams));
197
        $response = $this->curlRequest->request($url, $params, 'POST');
198
        $this->throwExceptionFromResponse($response);
199
200
        $return = $response['content'];
201
202
        if (isset($return['_id'])) {
203
            return true;
204
        }
205
206
        $this->setErrorFromElasticReturn($return);
207
208
        return false;
209
    }
210
211
    /**
212
     * @param string $index
213
     * @param string $type
214
     * @param string $_id
215
     * @param array $queryParams
216
     * @param array|null $return
217
     * @return bool
218
     */
219
    public function delete($index, $type, $_id, array $queryParams = [], array &$return = null) {
220
        if (!$this->indexExists($index)) {
221
            return false;
222
        }
223
224
        $url = "$index/$type/$_id?" . http_build_query(array_merge(['refresh' => 'true'], $queryParams));
225
        $response = $this->curlRequest->request($url, [], 'DELETE');
226
        $this->throwExceptionFromResponse($response);
227
        $return = $response['content'];
228
229
        if (isset($return['found']) && !$return['found']) {
230
            error_log("Doc with _id '$_id' was not found for delete. Index: '$index', Type: '$type' ");
231
        }
232
233
        if (isset($return['_id'])) {
234
            return true;
235
        }
236
237
        $this->setErrorFromElasticReturn($return);
238
239
        return false;
240
    }
241
242
    public function updateWhere($index, $type, array $where, array &$return = null) {
243
        // TODO
244
    }
245
246
    public function deleteWhere($index, $type, array $where, array &$return = null) {
247
        // TODO
248
    }
249
250
    /**
251
     *
252
     * @param string $index
253
     * @param string $type
254
     * @param string $_id
255
     * @param array $queryParams
256
     * @param array|null $return
257
     * @return array|null
258
     */
259
    public function get($index, $type, $_id, array $queryParams = [], array &$return = null) {
260
        if (!$this->indexExists($index)) {
261
            return null;
262
        }
263
264
        $url = "$index/$type/$_id";
265
        $response = $this->curlRequest->request($url, [], 'GET');
266
        $return = $response['content'];
267
268
        if ($response['status'] == 404) {
269
            return null;
270
        }
271
272
        if (isset($return['found']) && boolval($return['found'])) {
273
            return $return;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $return; (object|integer|double|string|array|boolean) is incompatible with the return type declared by the interface DoctrineElastic\Connecti...onnectionInterface::get of type array|null.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
274
        }
275
276
        return null;
277
    }
278
279
    /**
280
     * Returns the [hits][hits] array from query
281
     *
282
     * @param string $index
283
     * @param string $type
284
     * @param array $body
285
     * @param array $queryParams
286
     * @param array|null $return
287
     * @return array
288
     */
289
    public function search($index, $type, array $body = [], array $queryParams = [], array &$return = null) {
290
        if (!$this->indexExists($index)) {
291
            return [];
292
        }
293
294
        $body = $this->unsetEmpties($body);
295
296
        if (isset($body['query']) && empty($body['query'])) {
297
            unset($body['query']);
298
        }
299
300
        $url = "$index/$type/_search?" . http_build_query($queryParams);
301
302
        $cleanQuery = function ($queryPart, callable $recusiveFn) {
303
            if (!is_array($queryPart)) {
304
                return $queryPart;
305
            }
306
307
            foreach ($queryPart as $key => $item) {
308
                if ($key == 'query' && isset($queryPart['query']['bool'])) {
309
                    $queryPart['bool'] = $recusiveFn($queryPart['query']['bool'], $recusiveFn);
310
                    unset($queryPart['query']['bool']);
311
                }
312
313
                if (isset($item['query']['bool'])) {
314
                    $queryPart[$key]['bool'] = $recusiveFn($item['query']['bool'], $recusiveFn);
315
                    unset($queryPart[$key]['query']);
316
                } else if (is_array($item)) {
317
                    $queryPart[$key] = $recusiveFn($item, $recusiveFn);
318
                }
319
            }
320
321
            return $queryPart;
322
        };
323
324
        if (isset($body['query'])) {
325
            foreach ($body['query']['bool'] as $key => $item) {
326
                $body['query']['bool'][$key] = $cleanQuery($item, $cleanQuery);
327
            }
328
        }
329
330
        $response = $this->curlRequest->request($url, $body, 'POST');
331
        $this->throwExceptionFromResponse($response);
332
        $return = $response['content'];
333
334
        if (isset($return['hits']['hits'])) {
335
            return $return['hits']['hits'];
336
        }
337
338
        return [];
339
    }
340
341
    private function unsetEmpties(array $haystack) {
342
        $selfFn = __FUNCTION__;
343
344
        foreach ($haystack as $key => $value) {
345
            if (is_array($value)) {
346
                $haystack[$key] = $this->$selfFn($haystack[$key]);
347
            }
348
349
            if (empty($haystack[$key])) {
350
                unset($haystack[$key]);
351
            }
352
        }
353
354
        return $haystack;
355
    }
356
357
    /**
358
     * @param string $index
359
     * @return bool
360
     */
361
    public function indexExists($index) {
362
        $response = $this->curlRequest->request($index, [], 'HEAD');
363
364
        return $response['status'] === 200;
365
    }
366
367
    /**
368
     * @param string $index
369
     * @param string $type
370
     * @return bool
371
     */
372
    public function typeExists($index, $type) {
373
        $response = $this->curlRequest->request("$index/$type", [], 'HEAD');
374
375
        return $response['status'] === 200;
376
    }
377
378
    private function throwExceptionFromResponse($response, $appendPrefix = '') {
379
        if (isset($response['content']['error']['reason'])) {
380
            if (!empty($appendPrefix)) {
381
                $appendPrefix .= ': ';
382
            }
383
384
            throw new ElasticOperationException($appendPrefix . $response['content']['error']['reason']);
385
        }
386
    }
387
388
    public function hasConnection() {
389
        $response = $this->curlRequest->request('', [], 'HEAD');
390
391
        return $response['status'] == 200;
392
    }
393
394
    private function setErrorFromElasticReturn($return) {
395
        if (isset($return['error']['root_cause'][0]['reason'])) {
396
            $this->setError($return['error']['root_cause'][0]['reason']);
397
        } else if (isset($return['error']['reason'])) {
398
            $this->setError($return['error']['reason']);
399
        }
400
    }
401
402
    public function getElasticsearchVersion() {
403
        if (is_null($this->esVersion)) {
404
            $response = $this->curlRequest->request('', [], 'GET');
405
406
            if (isset($response['content']['version']['number'])) {
407
                $this->esVersion = floatval($response['content']['version']['number']);
408
            } else {
409
                throw new ConnectionException('Unable to fetch elasticsearch version. ');
410
            }
411
        }
412
413
        return $this->esVersion;
414
    }
415
}
416