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