Completed
Push — master ( cc9a05...c4b523 )
by Avtandil
03:36
created

ElasticSearchManager   B

Complexity

Total Complexity 53

Size/Duplication

Total Lines 371
Duplicated Lines 27.22 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 101
loc 371
ccs 0
cts 276
cp 0
rs 7.4757
c 0
b 0
f 0
wmc 53
lcom 1
cbo 2

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A setEnabled() 0 6 1
A setTimeout() 0 6 1
B createIndex() 0 26 4
B deleteIndexes() 0 24 5
A deleteIndexesByAlias() 0 18 3
B addDocumentsToIndex() 33 33 5
B updateDocumentsInIndex() 33 33 5
B addOrUpdateDocumentsInIndex() 0 33 5
A handleBulkError() 0 13 3
A refreshIndex() 18 18 3
A performSearch() 17 17 3
B switchIndexAlias() 0 54 6
B createTemplate() 0 23 4
A ping() 0 8 2
A getClient() 0 4 1
A isEnabled() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ElasticSearchManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ElasticSearchManager, and based on these observations, apply Extract Interface, too.

1
<?php
2
/*
3
 * This file is part of the Laravel Lodash package.
4
 *
5
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
declare(strict_types=1);
11
12
namespace Longman\LaravelLodash\ElasticSearch;
13
14
use ElasticSearch\Client;
15
use InvalidArgumentException;
16
17
class ElasticSearchManager implements ElasticSearchManagerContract
18
{
19
    /**
20
     * @var \ElasticSearch\Client
21
     */
22
    protected $client;
23
24
    /**
25
     * @var bool
26
     */
27
    protected $enabled;
28
29
    /**
30
     * @var int|null
31
     */
32
    protected $timeout;
33
34
    public function __construct(Client $client, bool $enabled = false)
35
    {
36
        $this->client = $client;
37
        $this->enabled = $enabled;
38
    }
39
40
    public function setEnabled(bool $enabled): ElasticSearchManagerContract
41
    {
42
        $this->enabled = $enabled;
43
44
        return $this;
45
    }
46
47
    public function setTimeout(int $timeout): ElasticSearchManagerContract
48
    {
49
        $this->timeout = $timeout;
50
51
        return $this;
52
    }
53
54
    public function createIndex(string $index_name, array $settings, array $mappings)
55
    {
56
        if (! $this->isEnabled()) {
57
            return;
58
        }
59
60
        $params = [
61
            'index' => $index_name,
62
            'body'  => [
63
                'settings' => $settings,
64
                'mappings' => $mappings,
65
            ],
66
        ];
67
68
        if (! empty($this->timeout)) {
69
            $params['client'] = [
70
                'timeout' => $this->timeout,
71
            ];
72
        }
73
74
        $response = $this->client->indices()->create($params);
75
76
        if ($response['acknowledged'] !== true) {
77
            throw new ElasticSearchException('Something went wrong during index creation');
78
        }
79
    }
80
81
    public function deleteIndexes(array $names)
82
    {
83
        if (! $this->isEnabled()) {
84
            return;
85
        }
86
        if (empty($names)) {
87
            throw new InvalidArgumentException('Index names can not be empty');
88
        }
89
90
        $params = [
91
            'index' => implode(',', $names),
92
        ];
93
94
        if (! empty($this->timeout)) {
95
            $params['client'] = [
96
                'timeout' => $this->timeout,
97
            ];
98
        }
99
100
        $response = $this->client->indices()->delete($params);
101
        if ($response['acknowledged'] !== true) {
102
            throw new ElasticSearchException('Something went wrong during index deletion');
103
        }
104
    }
105
106
    public function deleteIndexesByAlias(string $alias_name)
107
    {
108
        if (! $this->isEnabled()) {
109
            return;
110
        }
111
112
        $params = [
113
            'name' => $alias_name,
114
        ];
115
116
        $response = $this->client->indices()->getAlias($params);
117
        if (empty($response)) {
118
            throw new ElasticSearchException('Can not get alias ' . $alias_name);
119
        }
120
121
        $indexes = array_keys($response);
122
        $this->deleteIndexes($indexes);
123
    }
124
125
    /**
126
     * @throws \Longman\LaravelLodash\ElasticSearch\ElasticSearchException
127
     */
128 View Code Duplication
    public function addDocumentsToIndex(string $index_name, string $type_name, array $items)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
129
    {
130
        if (! $this->isEnabled()) {
131
            return;
132
        }
133
134
        $params = [
135
            'body' => [],
136
        ];
137
138
        if (! empty($this->timeout)) {
139
            $params['client'] = [
140
                'timeout' => $this->timeout,
141
            ];
142
        }
143
144
        foreach ($items as $id => $item) {
145
            $params['body'][] = [
146
                'create' => [
147
                    '_index' => $index_name,
148
                    '_type'  => $type_name,
149
                    '_id'    => $id,
150
                ],
151
            ];
152
153
            $params['body'][] = $item;
154
        }
155
156
        $responses = $this->client->bulk($params);
157
        if ($responses['errors'] === true) {
158
            $this->handleBulkError($responses);
159
        }
160
    }
161
162
    /**
163
     * @throws \Longman\LaravelLodash\ElasticSearch\ElasticSearchException
164
     */
165 View Code Duplication
    public function updateDocumentsInIndex(string $index_name, string $type_name, array $items)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
166
    {
167
        if (! $this->isEnabled()) {
168
            return;
169
        }
170
171
        $params = [
172
            'body' => [],
173
        ];
174
175
        if (! empty($this->timeout)) {
176
            $params['client'] = [
177
                'timeout' => $this->timeout,
178
            ];
179
        }
180
181
        foreach ($items as $id => $item) {
182
            $params['body'][] = [
183
                'update' => [
184
                    '_index' => $index_name,
185
                    '_type'  => $type_name,
186
                    '_id'    => $id,
187
                ],
188
            ];
189
190
            $params['body'][] = ['doc' => $item];
191
        }
192
193
        $responses = $this->client->bulk($params);
194
        if ($responses['errors'] === true) {
195
            $this->handleBulkError($responses);
196
        }
197
    }
198
199
    /**
200
     * @throws \Longman\LaravelLodash\ElasticSearch\ElasticSearchException
201
     */
202
    public function addOrUpdateDocumentsInIndex(string $index_name, string $type_name, array $items)
203
    {
204
        if (! $this->isEnabled()) {
205
            return;
206
        }
207
208
        $params = [
209
            'body' => [],
210
        ];
211
212
        if (! empty($this->timeout)) {
213
            $params['client'] = [
214
                'timeout' => $this->timeout,
215
            ];
216
        }
217
218
        foreach ($items as $id => $item) {
219
            $params['body'][] = [
220
                'index' => [
221
                    '_index' => $index_name,
222
                    '_type'  => $type_name,
223
                    '_id'    => $id,
224
                ],
225
            ];
226
227
            $params['body'][] = ['doc' => $item];
228
        }
229
230
        $responses = $this->client->bulk($params);
231
        if ($responses['errors'] === true) {
232
            $this->handleBulkError($responses);
233
        }
234
    }
235
236
    /**
237
     * @throws \Longman\LaravelLodash\ElasticSearch\ElasticSearchException
238
     */
239
    protected function handleBulkError(array $responses)
240
    {
241
        $errors = [];
242
        foreach ($responses['items'] as $item) {
243
            $row = $item;
244
            $row = reset($row);
245
            if (! empty($row['error'])) {
246
                $errors[] = $row['error'];
247
            }
248
        }
249
250
        throw new ElasticSearchException('Error occurred during bulk update', $errors);
251
    }
252
253 View Code Duplication
    public function refreshIndex(string $index_name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
254
    {
255
        if (! $this->isEnabled()) {
256
            return;
257
        }
258
259
        $params = [
260
            'index' => $index_name,
261
        ];
262
263
        if (! empty($this->timeout)) {
264
            $params['client'] = [
265
                'timeout' => $this->timeout,
266
            ];
267
        }
268
269
        $this->client->indices()->refresh($params);
270
    }
271
272 View Code Duplication
    public function performSearch(ElasticSearchQueryContract $query): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
273
    {
274
        if (! $this->isEnabled()) {
275
            return [];
276
        }
277
278
        $params = $query->build();
279
        if (! empty($this->timeout)) {
280
            $params['client'] = [
281
                'timeout' => $this->timeout,
282
            ];
283
        }
284
285
        $results = $this->client->search($params);
286
287
        return $results;
288
    }
289
290
    public function switchIndexAlias(string $alias_name, string $index_name)
291
    {
292
        if (! $this->isEnabled()) {
293
            return;
294
        }
295
296
        $params = [
297
            'name' => $alias_name,
298
        ];
299
300
        $exists = $this->client->indices()->existsAlias($params);
301
302
        $actions = [];
303
        // If alias already exists remove from indexes
304
        if ($exists) {
305
            $params = [
306
                'name' => $alias_name,
307
            ];
308
309
            $response = $this->client->indices()->getAlias($params);
310
            if (empty($response)) {
311
                throw new ElasticSearchException('Can not get alias ' . $alias_name);
312
            }
313
314
            $indexes = array_keys($response);
315
316
            foreach ($indexes as $index) {
317
                $actions[] = [
318
                    'remove' => [
319
                        'index' => $index,
320
                        'alias' => $alias_name,
321
                    ],
322
                ];
323
            }
324
        }
325
326
        $actions[] = [
327
            'add' => [
328
                'index' => $index_name,
329
                'alias' => $alias_name,
330
            ],
331
        ];
332
333
        $params = [
334
            'body' => [
335
                'actions' => $actions,
336
            ],
337
        ];
338
339
        $response = $this->client->indices()->updateAliases($params);
340
        if ($response['acknowledged'] !== true) {
341
            throw new ElasticSearchException('Switching alias response error');
342
        }
343
    }
344
345
    public function createTemplate(string $name, array $settings)
346
    {
347
        if (! $this->isEnabled()) {
348
            return;
349
        }
350
351
        $params = [
352
            'name' => $name,
353
            'body' => $settings,
354
        ];
355
356
        if (! empty($this->timeout)) {
357
            $params['client'] = [
358
                'timeout' => $this->timeout,
359
            ];
360
        }
361
362
        $response = $this->client->indices()->putTemplate($params);
363
364
        if ($response['acknowledged'] !== true) {
365
            throw new ElasticSearchException('Something went wrong during template creation');
366
        }
367
    }
368
369
    public function ping(): bool
370
    {
371
        if (! $this->isEnabled()) {
372
            return false;
373
        }
374
375
        return $this->client->ping();
376
    }
377
378
    public function getClient(): Client
379
    {
380
        return $this->client;
381
    }
382
383
    public function isEnabled(): bool
384
    {
385
        return $this->enabled;
386
    }
387
}
388