Completed
Push — master ( aee63e...997989 )
by Nicolas
02:11
created

Search::addIndices()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
namespace Elastica;
4
5
use Elastica\Exception\InvalidException;
6
use Elastica\ResultSet\BuilderInterface;
7
use Elastica\ResultSet\DefaultBuilder;
8
9
/**
10
 * Elastica search object.
11
 *
12
 * @author   Nicolas Ruflin <[email protected]>
13
 */
14
class Search
15
{
16
    /*
17
     * Options
18
     */
19
    const OPTION_SEARCH_TYPE = 'search_type';
20
    const OPTION_ROUTING = 'routing';
21
    const OPTION_PREFERENCE = 'preference';
22
    const OPTION_VERSION = 'version';
23
    const OPTION_TIMEOUT = 'timeout';
24
    const OPTION_FROM = 'from';
25
    const OPTION_SIZE = 'size';
26
    const OPTION_SCROLL = 'scroll';
27
    const OPTION_SCROLL_ID = 'scroll_id';
28
    const OPTION_QUERY_CACHE = 'query_cache';
29
    const OPTION_TERMINATE_AFTER = 'terminate_after';
30
    const OPTION_SHARD_REQUEST_CACHE = 'request_cache';
31
    const OPTION_FILTER_PATH = 'filter_path';
32
    const OPTION_TYPED_KEYS = 'typed_keys';
33
34
    /*
35
     * Search types
36
     */
37
    const OPTION_SEARCH_TYPE_DFS_QUERY_THEN_FETCH = 'dfs_query_then_fetch';
38
    const OPTION_SEARCH_TYPE_QUERY_THEN_FETCH = 'query_then_fetch';
39
    const OPTION_SEARCH_TYPE_SUGGEST = 'suggest';
40
    const OPTION_SEARCH_IGNORE_UNAVAILABLE = 'ignore_unavailable';
41
42
    /**
43
     * @var BuilderInterface
44
     */
45
    private $_builder;
46
47
    /**
48
     * Array of indices.
49
     *
50
     * @var array
51
     */
52
    protected $_indices = [];
53
54
    /**
55
     * Array of types.
56
     *
57
     * @var array
58
     */
59
    protected $_types = [];
60
61
    /**
62
     * @var \Elastica\Query
63
     */
64
    protected $_query;
65
66
    /**
67
     * @var array
68
     */
69
    protected $_options = [];
70
71
    /**
72
     * Client object.
73
     *
74
     * @var \Elastica\Client
75
     */
76
    protected $_client;
77
78
    /**
79
     * Constructs search object.
80
     *
81
     * @param \Elastica\Client $client  Client object
82
     * @param BuilderInterface $builder
83
     */
84
    public function __construct(Client $client, BuilderInterface $builder = null)
85
    {
86
        $this->_builder = $builder ?: new DefaultBuilder();
87
        $this->_client = $client;
88
    }
89
90
    /**
91
     * Adds a index to the list.
92
     *
93
     * @param Index|string $index Index object or string
94
     *
95
     * @throws InvalidException
96
     *
97
     * @return $this
98
     */
99
    public function addIndex($index)
100
    {
101
        if ($index instanceof Index) {
102
            $index = $index->getName();
103
        }
104
105
        if (!\is_scalar($index)) {
106
            throw new InvalidException('Invalid param type');
107
        }
108
109
        $this->_indices[] = (string) $index;
110
111
        return $this;
112
    }
113
114
    /**
115
     * Add array of indices at once.
116
     *
117
     * @param array $indices
118
     *
119
     * @return $this
120
     */
121
    public function addIndices(array $indices = [])
122
    {
123
        foreach ($indices as $index) {
124
            $this->addIndex($index);
125
        }
126
127
        return $this;
128
    }
129
130
    /**
131
     * @param string|array|Query|Suggest|Query\AbstractQuery $query
132
     *
133
     * @return $this
134
     */
135
    public function setQuery($query)
136
    {
137
        $this->_query = Query::create($query);
138
139
        return $this;
140
    }
141
142
    /**
143
     * @param string $key
144
     * @param mixed  $value
145
     *
146
     * @return $this
147
     */
148
    public function setOption($key, $value)
149
    {
150
        $this->_validateOption($key);
151
152
        $this->_options[$key] = $value;
153
154
        return $this;
155
    }
156
157
    /**
158
     * @param array $options
159
     *
160
     * @return $this
161
     */
162
    public function setOptions(array $options)
163
    {
164
        $this->clearOptions();
165
166
        foreach ($options as $key => $value) {
167
            $this->setOption($key, $value);
168
        }
169
170
        return $this;
171
    }
172
173
    /**
174
     * @return $this
175
     */
176
    public function clearOptions()
177
    {
178
        $this->_options = [];
179
180
        return $this;
181
    }
182
183
    /**
184
     * @param string $key
185
     * @param mixed  $value
186
     *
187
     * @return $this
188
     */
189
    public function addOption($key, $value)
190
    {
191
        $this->_validateOption($key);
192
193
        $this->_options[$key][] = $value;
194
195
        return $this;
196
    }
197
198
    /**
199
     * @param string $key
200
     *
201
     * @return bool
202
     */
203
    public function hasOption($key)
204
    {
205
        return isset($this->_options[$key]);
206
    }
207
208
    /**
209
     * @param string $key
210
     *
211
     * @throws InvalidException
212
     *
213
     * @return mixed
214
     */
215
    public function getOption($key)
216
    {
217
        if (!$this->hasOption($key)) {
218
            throw new InvalidException('Option '.$key.' does not exist');
219
        }
220
221
        return $this->_options[$key];
222
    }
223
224
    /**
225
     * @return array
226
     */
227
    public function getOptions()
228
    {
229
        return $this->_options;
230
    }
231
232
    /**
233
     * @param string $key
234
     *
235
     * @throws InvalidException
236
     *
237
     * @return bool
238
     */
239
    protected function _validateOption($key)
240
    {
241
        switch ($key) {
242
            case self::OPTION_SEARCH_TYPE:
243
            case self::OPTION_ROUTING:
244
            case self::OPTION_PREFERENCE:
245
            case self::OPTION_VERSION:
246
            case self::OPTION_TIMEOUT:
247
            case self::OPTION_FROM:
248
            case self::OPTION_SIZE:
249
            case self::OPTION_SCROLL:
250
            case self::OPTION_SCROLL_ID:
251
            case self::OPTION_SEARCH_TYPE_SUGGEST:
252
            case self::OPTION_SEARCH_IGNORE_UNAVAILABLE:
253
            case self::OPTION_QUERY_CACHE:
254
            case self::OPTION_TERMINATE_AFTER:
255
            case self::OPTION_SHARD_REQUEST_CACHE:
256
            case self::OPTION_FILTER_PATH:
257
            case self::OPTION_TYPED_KEYS:
258
                return true;
259
        }
260
261
        throw new InvalidException('Invalid option '.$key);
262
    }
263
264
    /**
265
     * Return client object.
266
     *
267
     * @return \Elastica\Client Client object
268
     */
269
    public function getClient()
270
    {
271
        return $this->_client;
272
    }
273
274
    /**
275
     * Return array of indices.
276
     *
277
     * @return array List of index names
278
     */
279
    public function getIndices()
280
    {
281
        return $this->_indices;
282
    }
283
284
    /**
285
     * @return bool
286
     */
287
    public function hasIndices()
288
    {
289
        return \count($this->_indices) > 0;
290
    }
291
292
    /**
293
     * @param Index|string $index
294
     *
295
     * @return bool
296
     */
297
    public function hasIndex($index)
298
    {
299
        if ($index instanceof Index) {
300
            $index = $index->getName();
301
        }
302
303
        return \in_array($index, $this->_indices);
304
    }
305
306
    /**
307
     * @return Query
308
     */
309
    public function getQuery()
310
    {
311
        if (null === $this->_query) {
312
            $this->_query = Query::create('');
313
        }
314
315
        return $this->_query;
316
    }
317
318
    /**
319
     * Creates new search object.
320
     *
321
     * @param SearchableInterface $searchObject
322
     *
323
     * @return Search
324
     */
325
    public static function create(SearchableInterface $searchObject)
326
    {
327
        return $searchObject->createSearch();
328
    }
329
330
    /**
331
     * Combines indices to the search request path.
332
     *
333
     * @return string Search path
334
     */
335
    public function getPath()
336
    {
337
        if (isset($this->_options[self::OPTION_SCROLL_ID])) {
338
            return '_search/scroll';
339
        }
340
341
        return \implode(',', $this->getIndices()).'/_search';
342
    }
343
344
    /**
345
     * Search in the set indices.
346
     *
347
     * @param mixed     $query
348
     * @param int|array $options OPTIONAL Limit or associative array of options (option=>value)
349
     * @param string    $method  OPTIONAL Request method (use const's) (default = Request::POST)
350
     *
351
     * @throws InvalidException
352
     *
353
     * @return ResultSet
354
     */
355
    public function search($query = '', $options = null, $method = Request::POST)
356
    {
357
        $this->setOptionsAndQuery($options, $query);
358
359
        $query = $this->getQuery();
360
        $path = $this->getPath();
361
362
        $params = $this->getOptions();
363
364
        // Send scroll_id via raw HTTP body to handle cases of very large (> 4kb) ids.
365
        if ('_search/scroll' === $path) {
366
            $data = [self::OPTION_SCROLL_ID => $params[self::OPTION_SCROLL_ID]];
367
            unset($params[self::OPTION_SCROLL_ID]);
368
        } else {
369
            $data = $query->toArray();
370
        }
371
372
        $response = $this->getClient()->request(
373
            $path,
374
            $method,
375
            $data,
376
            $params
377
        );
378
379
        return $this->_builder->buildResultSet($response, $query);
380
    }
381
382
    /**
383
     * @param mixed $query
384
     * @param $fullResult (default = false) By default only the total hit count is returned. If set to true, the full ResultSet including aggregations is returned
385
     * @param string $method OPTIONAL Request method (use const's) (default = Request::POST)
386
     *
387
     * @return int|ResultSet
388
     */
389
    public function count($query = '', $fullResult = false, $method = Request::POST)
390
    {
391
        $this->setOptionsAndQuery(null, $query);
392
393
        // Clone the object as we do not want to modify the original query.
394
        $query = clone $this->getQuery();
395
        $query->setSize(0);
396
        $path = $this->getPath();
397
398
        $response = $this->getClient()->request(
399
            $path,
400
            $method,
401
            $query->toArray(),
402
            [self::OPTION_SEARCH_TYPE => self::OPTION_SEARCH_TYPE_QUERY_THEN_FETCH]
403
        );
404
        $resultSet = $this->_builder->buildResultSet($response, $query);
405
406
        return $fullResult ? $resultSet : $resultSet->getTotalHits();
407
    }
408
409
    /**
410
     * @param array|int          $options
411
     * @param string|array|Query $query
412
     *
413
     * @return $this
414
     */
415
    public function setOptionsAndQuery($options = null, $query = '')
416
    {
417
        if ('' !== $query) {
418
            $this->setQuery($query);
419
        }
420
421
        if (\is_int($options)) {
422
            $this->getQuery()->setSize($options);
423
        } elseif (\is_array($options)) {
424
            if (isset($options['limit'])) {
425
                $this->getQuery()->setSize($options['limit']);
426
                unset($options['limit']);
427
            }
428
            if (isset($options['explain'])) {
429
                $this->getQuery()->setExplain($options['explain']);
430
                unset($options['explain']);
431
            }
432
            $this->setOptions($options);
433
        }
434
435
        return $this;
436
    }
437
438
    /**
439
     * @param Suggest $suggest
440
     *
441
     * @return $this
442
     */
443
    public function setSuggest(Suggest $suggest)
444
    {
445
        return $this->setOptionsAndQuery([self::OPTION_SEARCH_TYPE_SUGGEST => 'suggest'], $suggest);
0 ignored issues
show
Documentation introduced by
$suggest is of type object<Elastica\Suggest>, but the function expects a string|array|object<Elastica\Query>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
446
    }
447
448
    /**
449
     * Returns the Scroll Iterator.
450
     *
451
     * @see Scroll
452
     *
453
     * @param string $expiryTime
454
     *
455
     * @return Scroll
456
     */
457
    public function scroll($expiryTime = '1m')
458
    {
459
        return new Scroll($this, $expiryTime);
460
    }
461
462
    /**
463
     * @return BuilderInterface
464
     */
465
    public function getResultSetBuilder()
466
    {
467
        return $this->_builder;
468
    }
469
}
470