Completed
Push — upgrade ( f08820 )
by Simonas
14:39
created

IndexService::getScrollConfiguration()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 10
Ratio 100 %

Importance

Changes 0
Metric Value
dl 10
loc 10
rs 9.9332
c 0
b 0
f 0
cc 2
nc 2
nop 2
1
<?php
2
3
/*
4
 * This file is part of the ONGR package.
5
 *
6
 * (c) NFQ Technologies UAB <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace ONGR\ElasticsearchBundle\Service;
13
14
use Elasticsearch\Client;
15
use ONGR\ElasticsearchBundle\Result\ArrayIterator;
16
use ONGR\ElasticsearchBundle\Result\RawIterator;
17
use ONGR\ElasticsearchDSL\Query\FullText\QueryStringQuery;
18
use ONGR\ElasticsearchDSL\Query\Compound\BoolQuery;
19
use ONGR\ElasticsearchDSL\Search;
20
use ONGR\ElasticsearchDSL\Sort\FieldSort;
21
use ONGR\ElasticsearchBundle\Result\DocumentIterator;
22
23
/**
24
 * Document repository class.
25
 */
26 View Code Duplication
class IndexService
0 ignored issues
show
Duplication introduced by
This class 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...
27
{
28
    /**
29
     * @var Client
30
     */
31
    private $client;
32
33
    /**
34
     * @var string Fully qualified class name
35
     */
36
    private $className;
37
38
    /**
39
     * @deprecated will be removed in v7 since there will be no more types in the indexes.
40
     *
41
     * @var string Elasticsearch type name
42
     */
43
    private $typeName;
44
45
    /**
46
     * @var string Elasticsearch index name
47
     */
48
    private $indexName;
49
50
    /**
51
     * Constructor.
52
     *
53
     * @param Client $client
54
     * @param string  $className
55
     */
56
    public function __construct($client, $className)
57
    {
58
        if (!is_string($className)) {
59
            throw new \InvalidArgumentException('Class name must be a string.');
60
        }
61
62
        if (!class_exists($className)) {
63
            throw new \InvalidArgumentException(
64
                sprintf('Cannot create a service for non-existing class "%s".', $className)
65
            );
66
        }
67
68
        $this->client = $client;
69
        $this->className = $className;
70
        $this->type = $this->resolveType($className);
0 ignored issues
show
Bug introduced by
The property type does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
71
    }
72
73
    /**
74
     * @return array
75
     */
76
    public function getType()
77
    {
78
        return $this->type;
79
    }
80
81
    /**
82
     * Returns a single document data by ID or null if document is not found.
83
     *
84
     * @param string $id      Document ID to find
85
     * @param string $routing Custom routing for the document
86
     *
87
     * @return object
88
     */
89
    public function find($id, $routing = null)
90
    {
91
        return $this->manager->find($this->type, $id, $routing);
0 ignored issues
show
Bug introduced by
The property manager does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
92
    }
93
94
    /**
95
     * Returns documents by a set of ids
96
     *
97
     * @param array $ids
98
     *
99
     * @return DocumentIterator The objects.
100
     */
101
    public function findByIds(array $ids)
102
    {
103
        $args = [];
104
        $manager = $this->getManager();
0 ignored issues
show
Bug introduced by
The method getManager() does not seem to exist on object<ONGR\Elasticsearc...e\Service\IndexService>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
105
        $args['body']['docs'] = [];
106
        $args['index'] = $manager->getIndexName();
107
        $args['type'] = $this->getType();
108
109
        foreach ($ids as $id) {
110
            $args['body']['docs'][] = [
111
                '_id' => $id
112
            ];
113
        }
114
115
        $mgetResponse = $manager->getClient()->mget($args);
116
117
        $return = [
118
            'hits' => [
119
                'hits' => [],
120
                'total' => 0,
121
            ]
122
        ];
123
124
        foreach ($mgetResponse['docs'] as $item) {
125
            if ($item['found']) {
126
                $return['hits']['hits'][] = $item;
127
            }
128
        }
129
130
        $return['hits']['total'] = count($return['hits']['hits']);
131
132
        return new DocumentIterator($return, $manager);
133
    }
134
135
    /**
136
     * Finds documents by a set of criteria.
137
     *
138
     * @param array      $criteria   Example: ['group' => ['best', 'worst'], 'job' => 'medic'].
139
     * @param array|null $orderBy    Example: ['name' => 'ASC', 'surname' => 'DESC'].
140
     * @param int|null   $limit      Example: 5.
141
     * @param int|null   $offset     Example: 30.
142
     *
143
     * @return array|DocumentIterator The objects.
144
     */
145
    public function findBy(
146
        array $criteria,
147
        array $orderBy = [],
148
        $limit = null,
149
        $offset = null
150
    ) {
151
        $search = $this->createSearch();
152
153
        if ($limit !== null) {
154
            $search->setSize($limit);
155
        }
156
        if ($offset !== null) {
157
            $search->setFrom($offset);
158
        }
159
160
        foreach ($criteria as $field => $value) {
161
            if (preg_match('/^!(.+)$/', $field)) {
162
                $boolType = BoolQuery::MUST_NOT;
163
                $field = preg_replace('/^!/', '', $field);
164
            } else {
165
                $boolType = BoolQuery::MUST;
166
            }
167
168
            $search->addQuery(
169
                new QueryStringQuery(is_array($value) ? implode(' OR ', $value) : $value, ['default_field' => $field]),
170
                $boolType
171
            );
172
        }
173
174
        foreach ($orderBy as $field => $direction) {
175
            $search->addSort(new FieldSort($field, $direction));
176
        }
177
178
        return $this->findDocuments($search);
179
    }
180
181
    /**
182
     * Finds a single document by a set of criteria.
183
     *
184
     * @param array      $criteria   Example: ['group' => ['best', 'worst'], 'job' => 'medic'].
185
     * @param array|null $orderBy    Example: ['name' => 'ASC', 'surname' => 'DESC'].
186
     *
187
     * @return object|null The object.
188
     */
189
    public function findOneBy(array $criteria, array $orderBy = [])
190
    {
191
        return $this->findBy($criteria, $orderBy, 1, null)->current();
192
    }
193
194
    /**
195
     * Returns search instance.
196
     *
197
     * @return Search
198
     */
199
    public function createSearch()
200
    {
201
        return new Search();
202
    }
203
204
    /**
205
     * Parses scroll configuration from raw response.
206
     *
207
     * @param array  $raw
208
     * @param string $scrollDuration
209
     *
210
     * @return array
211
     */
212
    public function getScrollConfiguration($raw, $scrollDuration)
213
    {
214
        $scrollConfig = [];
215
        if (isset($raw['_scroll_id'])) {
216
            $scrollConfig['_scroll_id'] = $raw['_scroll_id'];
217
            $scrollConfig['duration'] = $scrollDuration;
218
        }
219
220
        return $scrollConfig;
221
    }
222
223
    /**
224
     * Returns DocumentIterator with composed Document objects from array response.
225
     *
226
     * @param Search $search
227
     *
228
     * @return DocumentIterator
229
     */
230
    public function findDocuments(Search $search)
231
    {
232
        $results = $this->executeSearch($search);
233
234
        return new DocumentIterator(
235
            $results,
236
            $this->getManager(),
0 ignored issues
show
Bug introduced by
The method getManager() does not seem to exist on object<ONGR\Elasticsearc...e\Service\IndexService>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
237
            $this->getScrollConfiguration($results, $search->getScroll())
238
        );
239
    }
240
241
242
    /**
243
     * Returns ArrayIterator with access to unmodified documents directly.
244
     *
245
     * @param Search $search
246
     *
247
     * @return ArrayIterator
248
     */
249
    public function findArray(Search $search)
250
    {
251
        $results = $this->executeSearch($search);
252
253
        return new ArrayIterator(
254
            $results,
255
            $this->getManager(),
0 ignored issues
show
Bug introduced by
The method getManager() does not seem to exist on object<ONGR\Elasticsearc...e\Service\IndexService>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
256
            $this->getScrollConfiguration($results, $search->getScroll())
257
        );
258
    }
259
260
    /**
261
     * Returns RawIterator with access to node with all returned values included.
262
     *
263
     * @param Search $search
264
     *
265
     * @return RawIterator
266
     */
267
    public function findRaw(Search $search)
268
    {
269
        $results = $this->executeSearch($search);
270
271
        return new RawIterator(
272
            $results,
273
            $this->getManager(),
0 ignored issues
show
Bug introduced by
The method getManager() does not seem to exist on object<ONGR\Elasticsearc...e\Service\IndexService>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
274
            $this->getScrollConfiguration($results, $search->getScroll())
275
        );
276
    }
277
278
    /**
279
     * Executes search to the elasticsearch and returns raw response.
280
     *
281
     * @param Search $search
282
     *
283
     * @return array
284
     */
285
    private function executeSearch(Search $search)
286
    {
287
        return $this->getManager()->search([$this->getType()], $search->toArray(), $search->getUriParams());
0 ignored issues
show
Bug introduced by
The method getManager() does not seem to exist on object<ONGR\Elasticsearc...e\Service\IndexService>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
288
    }
289
290
    /**
291
     * Counts documents by given search.
292
     *
293
     * @param Search $search
294
     * @param array  $params
295
     * @param bool   $returnRaw If set true returns raw response gotten from client.
296
     *
297
     * @return int|array
298
     */
299
    public function count(Search $search, array $params = [], $returnRaw = false)
300
    {
301
        $body = array_merge(
302
            [
303
                'index' => $this->getManager()->getIndexName(),
0 ignored issues
show
Bug introduced by
The method getManager() does not seem to exist on object<ONGR\Elasticsearc...e\Service\IndexService>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
304
                'type' => $this->type,
305
                'body' => $search->toArray(),
306
            ],
307
            $params
308
        );
309
310
        $results = $this
0 ignored issues
show
Bug introduced by
The method getManager() does not seem to exist on object<ONGR\Elasticsearc...e\Service\IndexService>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
311
            ->getManager()
312
            ->getClient()->count($body);
313
314
        if ($returnRaw) {
315
            return $results;
316
        } else {
317
            return $results['count'];
318
        }
319
    }
320
321
    /**
322
     * Removes a single document data by ID.
323
     *
324
     * @param string $id      Document ID to remove
325
     * @param string $routing Custom routing for the document
326
     *
327
     * @return array
328
     *
329
     * @throws \LogicException
330
     */
331
    public function remove($id, $routing = null)
332
    {
333
        $params = [
334
            'index' => $this->getManager()->getIndexName(),
0 ignored issues
show
Bug introduced by
The method getManager() does not seem to exist on object<ONGR\Elasticsearc...e\Service\IndexService>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
335
            'type' => $this->type,
336
            'id' => $id,
337
        ];
338
339
        if ($routing) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $routing of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
340
            $params['routing'] = $routing;
341
        }
342
343
        $response = $this->getManager()->getClient()->delete($params);
0 ignored issues
show
Bug introduced by
The method getManager() does not seem to exist on object<ONGR\Elasticsearc...e\Service\IndexService>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
344
345
        return $response;
346
    }
347
348
    /**
349
     * Partial document update.
350
     *
351
     * @param string $id     Document id to update.
352
     * @param array  $fields Fields array to update.
353
     * @param string $script Groovy script to update fields.
354
     * @param array  $params Additional parameters to pass to the client.
355
     *
356
     * @return array
357
     */
358
    public function update($id, array $fields = [], $script = null, array $params = [])
359
    {
360
        $body = array_filter(
361
            [
362
                'doc' => $fields,
363
                'script' => $script,
364
            ]
365
        );
366
367
        $params = array_merge(
368
            [
369
                'id' => $id,
370
                'index' => $this->getManager()->getIndexName(),
0 ignored issues
show
Bug introduced by
The method getManager() does not seem to exist on object<ONGR\Elasticsearc...e\Service\IndexService>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
371
                'type' => $this->type,
372
                'body' => $body,
373
            ],
374
            $params
375
        );
376
377
        return $this->getManager()->getClient()->update($params);
0 ignored issues
show
Bug introduced by
The method getManager() does not seem to exist on object<ONGR\Elasticsearc...e\Service\IndexService>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
378
    }
379
380
    /**
381
     * Resolves elasticsearch type by class name.
382
     *
383
     * @param string $className
384
     *
385
     * @return array
386
     */
387
    private function resolveType($className)
388
    {
389
        return $this->getManager()->getMetadataCollector()->getDocumentType($className);
0 ignored issues
show
Bug introduced by
The method getManager() does not seem to exist on object<ONGR\Elasticsearc...e\Service\IndexService>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
390
    }
391
392
    /**
393
     * Returns fully qualified class name.
394
     *
395
     * @return string
396
     */
397
    public function getClassName()
398
    {
399
        return $this->className;
400
    }
401
}
402