Completed
Pull Request — master (#643)
by
unknown
02:58
created

Repository::findByIds()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 28
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 28
rs 8.5806
cc 4
eloc 16
nc 6
nop 1
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 ONGR\ElasticsearchBundle\Result\RawIterator;
15
use ONGR\ElasticsearchBundle\Result\Result;
16
use ONGR\ElasticsearchDSL\Query\QueryStringQuery;
17
use ONGR\ElasticsearchDSL\Search;
18
use ONGR\ElasticsearchDSL\Sort\FieldSort;
19
use ONGR\ElasticsearchBundle\Result\DocumentIterator;
20
21
/**
22
 * Document repository class.
23
 */
24
class Repository
25
{
26
    /**
27
     * @var Manager
28
     */
29
    private $manager;
30
31
    /**
32
     * @var string Fully qualified class name
33
     */
34
    private $className;
35
36
    /**
37
     * @var string Elasticsearch type name
38
     */
39
    private $type;
40
41
    /**
42
     * Constructor.
43
     *
44
     * @param Manager $manager
45
     * @param string  $className
46
     */
47
    public function __construct($manager, $className)
48
    {
49
        if (!is_string($className)) {
50
            throw new \InvalidArgumentException('Class name must be a string.');
51
        }
52
53
        if (!class_exists($className)) {
54
            throw new \InvalidArgumentException(
55
                sprintf('Cannot create repository for non-existing class "%s".', $className)
56
            );
57
        }
58
59
        $this->manager = $manager;
60
        $this->className = $className;
61
        $this->type = $this->resolveType($className);
62
    }
63
64
    /**
65
     * Returns elasticsearch manager used in the repository.
66
     *
67
     * @return Manager
68
     */
69
    public function getManager()
70
    {
71
        return $this->manager;
72
    }
73
74
    /**
75
     * @return array
76
     */
77
    public function getType()
78
    {
79
        return $this->type;
80
    }
81
82
    /**
83
     * Returns a single document data by ID or null if document is not found.
84
     *
85
     * @param string $id Document ID to find
86
     *
87
     * @return object
88
     */
89
    public function find($id)
90
    {
91
        return $this->manager->find($this->type, $id);
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();
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
119
        foreach ($mgetResponse['docs'] as $item) {
120
            if ($item['found']) {
121
                $return['hits']['hits'][] = $item;
122
            }
123
        }
124
125
        $return['hits']['total'] = count($return['hits']['hits']);
126
127
        return new DocumentIterator($return, $manager);
128
    }
129
130
    /**
131
     * Finds documents by a set of criteria.
132
     *
133
     * @param array      $criteria   Example: ['group' => ['best', 'worst'], 'job' => 'medic'].
134
     * @param array|null $orderBy    Example: ['name' => 'ASC', 'surname' => 'DESC'].
135
     * @param int|null   $limit      Example: 5.
136
     * @param int|null   $offset     Example: 30.
137
     *
138
     * @return array|DocumentIterator The objects.
139
     */
140
    public function findBy(
141
        array $criteria,
142
        array $orderBy = [],
143
        $limit = null,
144
        $offset = null
145
    ) {
146
        $search = $this->createSearch();
147
148
        if ($limit !== null) {
149
            $search->setSize($limit);
150
        }
151
        if ($offset !== null) {
152
            $search->setFrom($offset);
153
        }
154
155
        foreach ($criteria as $field => $value) {
156
            $search->addQuery(
157
                new QueryStringQuery(is_array($value) ? implode(' OR ', $value) : $value, ['default_field' => $field])
158
            );
159
        }
160
161
        foreach ($orderBy as $field => $direction) {
162
            $search->addSort(new FieldSort($field, $direction));
163
        }
164
165
        return $this->execute($search);
166
    }
167
168
    /**
169
     * Finds a single document by a set of criteria.
170
     *
171
     * @param array      $criteria   Example: ['group' => ['best', 'worst'], 'job' => 'medic'].
172
     * @param array|null $orderBy    Example: ['name' => 'ASC', 'surname' => 'DESC'].
173
     *
174
     * @return object|null The object.
175
     */
176
    public function findOneBy(array $criteria, array $orderBy = [])
177
    {
178
        $result = $this->findBy($criteria, $orderBy, null, null);
179
180
        return $result->first();
181
    }
182
183
    /**
184
     * Returns search instance.
185
     *
186
     * @return Search
187
     */
188
    public function createSearch()
189
    {
190
        return new Search();
191
    }
192
193
    /**
194
     * Executes given search.
195
     *
196
     * @param Search $search
197
     * @param string $resultsType
198
     *
199
     * @return DocumentIterator|RawIterator|array
200
     *
201
     * @throws \Exception
202
     */
203
    public function execute(Search $search, $resultsType = Result::RESULTS_OBJECT)
204
    {
205
        return $this->manager->execute([$this->type], $search, $resultsType);
206
    }
207
208
    /**
209
     * Counts documents by given search.
210
     *
211
     * @param Search $search
212
     * @param array  $params
213
     * @param bool   $returnRaw If set true returns raw response gotten from client.
214
     *
215
     * @return int|array
216
     */
217
    public function count(Search $search, array $params = [], $returnRaw = false)
218
    {
219
        $body = array_merge(
220
            [
221
                'index' => $this->getManager()->getIndexName(),
222
                'type' => $this->type,
223
                'body' => $search->toArray(),
224
            ],
225
            $params
226
        );
227
228
        $results = $this
229
            ->getManager()
230
            ->getClient()->count($body);
231
232
        if ($returnRaw) {
233
            return $results;
234
        } else {
235
            return $results['count'];
236
        }
237
    }
238
239
    /**
240
     * Removes a single document data by ID.
241
     *
242
     * @param string $id Document ID to remove.
243
     *
244
     * @return array
245
     *
246
     * @throws \LogicException
247
     */
248
    public function remove($id)
249
    {
250
        $params = [
251
            'index' => $this->getManager()->getIndexName(),
252
            'type' => $this->type,
253
            'id' => $id,
254
        ];
255
256
        $response = $this->getManager()->getClient()->delete($params);
257
258
        return $response;
259
    }
260
261
    /**
262
     * Partial document update.
263
     *
264
     * @param string $id     Document id to update.
265
     * @param array  $fields Fields array to update.
266
     * @param string $script Groovy script to update fields.
267
     * @param array  $params Additional parameters to pass to the client.
268
     *
269
     * @return array
270
     */
271
    public function update($id, array $fields = [], $script = null, array $params = [])
272
    {
273
        $body = array_filter(
274
            [
275
                'doc' => $fields,
276
                'script' => $script,
277
            ]
278
        );
279
280
        $params = array_merge(
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $params. This often makes code more readable.
Loading history...
281
            [
282
                'id' => $id,
283
                'index' => $this->getManager()->getIndexName(),
284
                'type' => $this->type,
285
                'body' => $body,
286
            ],
287
            $params
288
        );
289
290
        return $this->getManager()->getClient()->update($params);
291
    }
292
293
    /**
294
     * Resolves elasticsearch type by class name.
295
     *
296
     * @param string $className
297
     *
298
     * @return array
299
     */
300
    private function resolveType($className)
301
    {
302
        return $this->getManager()->getMetadataCollector()->getDocumentType($className);
303
    }
304
305
    /**
306
     * Returns fully qualified class name.
307
     *
308
     * @return string
309
     */
310
    public function getClassName()
311
    {
312
        return $this->className;
313
    }
314
}
315