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
Branch master (08dc62)
by Anderson
04:35 queued 02:10
created

ElasticConnection::getElasticsearchVersion()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 8
nc 3
nop 0
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?refresh=true", $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?refresh=true";
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
        if (!$this->indexExists($index)) {
154
            trigger_error("$index index does not exists at insert attempt");
155
            return false;
156
        }
157
158
        if (!$this->typeExists($index, $type)) {
159
            trigger_error("$type type does not exists at insert attempt");
160
            return false;
161
        }
162
163
        $url = "$index/$type";
164
        if (isset($body['_id'])) {
165
            $url .= '/' . $body['_id'];
166
            unset($body['_id']);
167
        }
168
169
        $url = "$url?" . http_build_query(array_merge(['refresh' => true], $queryParams));
170
171
        $response = $this->curlRequest->request($url, $body, 'POST');
172
173
        $this->throwExceptionFromResponse($response);
174
        $return = $response['content'];
175
176
        if (isset($return['created'])) {
177
            return $return['created'];
178
        }
179
180
        $this->setErrorFromElasticReturn($return);
181
182
        return false;
183
    }
184
185
    /**
186
     * @param string $index
187
     * @param string $type
188
     * @param string $_id
189
     * @param array $body
190
     * @param array $queryParams
191
     * @param array|null $return
192
     *
193
     * @return bool
194
     */
195
    public function update($index, $type, $_id, array $body = [], array $queryParams = [], array &$return = null) {
196
        if (!$this->indexExists($index)) {
197
            return false;
198
        }
199
200
        if (array_key_exists('doc', $body)) {
201
            $params = $body;
202
        } else {
203
            $params = ['doc' => $body];
204
        }
205
206
        $url = "$index/$type/$_id/_update?" . http_build_query(array_merge(['refresh' => true], $queryParams));
207
        $response = $this->curlRequest->request($url, $params, 'POST');
208
        $this->throwExceptionFromResponse($response);
209
210
        $return = $response['content'];
211
212
        if (isset($return['_id'])) {
213
            return true;
214
        }
215
216
        $this->setErrorFromElasticReturn($return);
217
218
        return false;
219
    }
220
221
    /**
222
     * @param string $index
223
     * @param string $type
224
     * @param string $_id
225
     * @param array $queryParams
226
     * @param array|null $return
227
     * @return bool
228
     */
229
    public function delete($index, $type, $_id, array $queryParams = [], array &$return = null) {
230
        if (!$this->indexExists($index)) {
231
            return false;
232
        }
233
234
        $url = "$index/$type/$_id?" . http_build_query(array_merge(['refresh' => true], $queryParams));
235
        $response = $this->curlRequest->request($url, [], 'DELETE');
236
        $this->throwExceptionFromResponse($response);
237
        $return = $response['content'];
238
239
        if (isset($return['found']) && !$return['found']) {
240
            error_log("Doc with _id '$_id' was not found for delete. Index: '$index', Type: '$type' ");
241
        }
242
243
        if (isset($return['_id'])) {
244
            return true;
245
        }
246
247
        $this->setErrorFromElasticReturn($return);
248
249
        return false;
250
    }
251
252
    public function updateWhere($index, $type, array $where, array &$return = null) {
253
        // TODO
254
    }
255
256
    public function deleteWhere($index, $type, array $where, array &$return = null) {
257
        // TODO
258
    }
259
260
    /**
261
     *
262
     * @param string $index
263
     * @param string $type
264
     * @param string $_id
265
     * @param array $queryParams
266
     * @param array|null $return
267
     * @return array|null
268
     */
269
    public function get($index, $type, $_id, array $queryParams = [], array &$return = null) {
270
        if (!$this->indexExists($index)) {
271
            return null;
272
        }
273
274
        $url = "$index/$type/$_id?" . http_build_query(array_merge(['refresh' => true], $queryParams));
275
        $response = $this->curlRequest->request($url, [], 'GET');
276
        $return = $response['content'];
277
278
        if ($response['status'] == 404) {
279
            return null;
280
        }
281
282
        if (isset($return['found']) && boolval($return['found'])) {
283
            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...
284
        }
285
286
        return null;
287
    }
288
289
    /**
290
     * Returns the [hits][hits] array from query
291
     *
292
     * @param string $index
293
     * @param string $type
294
     * @param array $body
295
     * @param array $queryParams
296
     * @param array|null $return
297
     * @return array
298
     */
299
    public function search($index, $type, array $body = [], array $queryParams = [], array &$return = null) {
300
        if (!$this->indexExists($index)) {
301
            return [];
302
        }
303
304
        $this->unsetEmpties($body);
305
306
        if (isset($body['query']) && empty($body['query'])) {
307
            unset($body['query']);
308
        }
309
310
        $url = "$index/$type/_search?" . http_build_query(array_merge(['refresh' => true], $queryParams));
311
        $response = $this->curlRequest->request($url, $body, 'POST');
312
        $this->throwExceptionFromResponse($response);
313
        $return = $response['content'];
314
315
        if (isset($return['hits']['hits'])) {
316
            return $return['hits']['hits'];
317
        }
318
319
        return [];
320
    }
321
322
    private function unsetEmpties(array &$array, array &$parent = null) {
323
        if (!is_array($array)) {
324
            return null;
325
        }
326
327
        for ($count = 2; $count > 0; $count--) {
328
            foreach ($array as $key => $item) {
0 ignored issues
show
Bug introduced by
The expression $array of type null|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
329
                if (is_array($item) && empty($item)) {
330
                    unset($array[$key]);
331
332
                    if (is_array($parent)) {
333
                        $this->unsetEmpties($parent);
334
                    }
335
                } else if (is_array($item)) {
336
                    $this->unsetEmpties($array[$key], $array);
337
                }
338
            }
339
        }
340
    }
341
342
    /**
343
     * @param string $index
344
     * @return bool
345
     */
346
    public function indexExists($index) {
347
        $response = $this->curlRequest->request($index, [], 'HEAD');
348
349
        return $response['status'] === 200;
350
    }
351
352
    /**
353
     * @param string $index
354
     * @param string $type
355
     * @return bool
356
     */
357
    public function typeExists($index, $type) {
358
        $response = $this->curlRequest->request("$index/$type", [], 'HEAD');
359
360
        return $response['status'] === 200;
361
    }
362
363
    private function throwExceptionFromResponse($response, $appendPrefix = '') {
364
        if (isset($response['content']['error']['reason'])) {
365
            if (!empty($appendPrefix)) {
366
                $appendPrefix .= ': ';
367
            }
368
369
            throw new ElasticOperationException($appendPrefix . $response['content']['error']['reason']);
370
        }
371
    }
372
373
    public function hasConnection() {
374
        $response = $this->curlRequest->request('', [], 'HEAD');
375
376
        return $response['status'] == 200;
377
    }
378
379
    private function setErrorFromElasticReturn($return) {
380
        if (isset($return['error']['root_cause'][0]['reason'])) {
381
            $this->setError($return['error']['root_cause'][0]['reason']);
382
        } else if (isset($return['error']['reason'])) {
383
            $this->setError($return['error']['reason']);
384
        }
385
    }
386
387
    public function getElasticsearchVersion() {
388
        if (is_null($this->esVersion)) {
389
            $response = $this->curlRequest->request('', [], 'GET');
390
391
            if (isset($response['content']['version']['number'])) {
392
                $this->esVersion = floatval($response['content']['version']['number']);
393
            } else {
394
                throw new ConnectionException('Unable to fetch elasticsearch version. ');
395
            }
396
        }
397
398
        return $this->esVersion;
399
    }
400
}
401