Completed
Push — master ( 6b4094...cc9a05 )
by Avtandil
03:04
created

ElasticSearchManager::handleBulkError()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 1
dl 0
loc 13
ccs 0
cts 12
cp 0
crap 12
rs 9.4285
c 0
b 0
f 0
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
    protected function handleBulkError(array $responses)
203
    {
204
        $errors = [];
205
        foreach ($responses['items'] as $item) {
206
            $row = $item;
207
            $row = reset($row);
208
            if (! empty($row['error'])) {
209
                $errors[] = $row['error'];
210
            }
211
        }
212
213
        throw new ElasticSearchException('Error occurred during bulk update', $errors);
214
    }
215
216 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...
217
    {
218
        if (! $this->isEnabled()) {
219
            return;
220
        }
221
222
        $params = [
223
            'index' => $index_name,
224
        ];
225
226
        if (! empty($this->timeout)) {
227
            $params['client'] = [
228
                'timeout' => $this->timeout,
229
            ];
230
        }
231
232
        $this->client->indices()->refresh($params);
233
    }
234
235 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...
236
    {
237
        if (! $this->isEnabled()) {
238
            return [];
239
        }
240
241
        $params = $query->build();
242
        if (! empty($this->timeout)) {
243
            $params['client'] = [
244
                'timeout' => $this->timeout,
245
            ];
246
        }
247
248
        $results = $this->client->search($params);
249
250
        return $results;
251
    }
252
253
    public function switchIndexAlias(string $alias_name, string $index_name)
254
    {
255
        if (! $this->isEnabled()) {
256
            return;
257
        }
258
259
        $params = [
260
            'name' => $alias_name,
261
        ];
262
263
        $exists = $this->client->indices()->existsAlias($params);
264
265
        $actions = [];
266
        // If alias already exists remove from indexes
267
        if ($exists) {
268
            $params = [
269
                'name' => $alias_name,
270
            ];
271
272
            $response = $this->client->indices()->getAlias($params);
273
            if (empty($response)) {
274
                throw new ElasticSearchException('Can not get alias ' . $alias_name);
275
            }
276
277
            $indexes = array_keys($response);
278
279
            foreach ($indexes as $index) {
280
                $actions[] = [
281
                    'remove' => [
282
                        'index' => $index,
283
                        'alias' => $alias_name,
284
                    ],
285
                ];
286
            }
287
        }
288
289
        $actions[] = [
290
            'add' => [
291
                'index' => $index_name,
292
                'alias' => $alias_name,
293
            ],
294
        ];
295
296
        $params = [
297
            'body' => [
298
                'actions' => $actions,
299
            ],
300
        ];
301
302
        $response = $this->client->indices()->updateAliases($params);
303
        if ($response['acknowledged'] !== true) {
304
            throw new ElasticSearchException('Switching alias response error');
305
        }
306
    }
307
308
    public function createTemplate(string $name, array $settings)
309
    {
310
        if (! $this->isEnabled()) {
311
            return;
312
        }
313
314
        $params = [
315
            'name' => $name,
316
            'body' => $settings,
317
        ];
318
319
        if (! empty($this->timeout)) {
320
            $params['client'] = [
321
                'timeout' => $this->timeout,
322
            ];
323
        }
324
325
        $response = $this->client->indices()->putTemplate($params);
326
327
        if ($response['acknowledged'] !== true) {
328
            throw new ElasticSearchException('Something went wrong during template creation');
329
        }
330
    }
331
332
    public function ping(): bool
333
    {
334
        if (! $this->isEnabled()) {
335
            return false;
336
        }
337
338
        return $this->client->ping();
339
    }
340
341
    public function getClient(): Client
342
    {
343
        return $this->client;
344
    }
345
346
    public function isEnabled(): bool
347
    {
348
        return $this->enabled;
349
    }
350
}
351