Completed
Push — master ( ccbd3d...72cafb )
by Nicolas
03:59
created

Search::_validateOption()   C

Complexity

Conditions 14
Paths 14

Size

Total Lines 21
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 21
rs 6.5272
cc 14
eloc 17
nc 14
nop 1

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace Elastica;
3
4
use Elastica\Exception\InvalidException;
5
use Elastica\Filter\AbstractFilter;
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
31
    /*
32
     * Search types
33
     */
34
    const OPTION_SEARCH_TYPE_COUNT = 'count';
35
    const OPTION_SEARCH_TYPE_SCAN = 'scan';
36
    const OPTION_SEARCH_TYPE_DFS_QUERY_THEN_FETCH = 'dfs_query_then_fetch';
37
    const OPTION_SEARCH_TYPE_DFS_QUERY_AND_FETCH = 'dfs_query_and_fetch';
38
    const OPTION_SEARCH_TYPE_QUERY_THEN_FETCH = 'query_then_fetch';
39
    const OPTION_SEARCH_TYPE_QUERY_AND_FETCH = 'query_and_fetch';
40
    const OPTION_SEARCH_TYPE_SUGGEST = 'suggest';
41
    const OPTION_SEARCH_TYPE_SCROLL = 'scroll';
42
    const OPTION_SEARCH_IGNORE_UNAVAILABLE = 'ignore_unavailable';
43
44
    /**
45
     * @var BuilderInterface
46
     */
47
    private $_builder;
48
49
    /**
50
     * Array of indices.
51
     *
52
     * @var array
53
     */
54
    protected $_indices = [];
55
56
    /**
57
     * Array of types.
58
     *
59
     * @var array
60
     */
61
    protected $_types = [];
62
63
    /**
64
     * @var \Elastica\Query
65
     */
66
    protected $_query;
67
68
    /**
69
     * @var array
70
     */
71
    protected $_options = [];
72
73
    /**
74
     * Client object.
75
     *
76
     * @var \Elastica\Client
77
     */
78
    protected $_client;
79
80
    /**
81
     * Constructs search object.
82
     *
83
     * @param \Elastica\Client $client  Client object
84
     * @param BuilderInterface $builder
85
     */
86
    public function __construct(Client $client, BuilderInterface $builder = null)
87
    {
88
        $this->_builder = $builder ?: new DefaultBuilder();
89
        $this->_client = $client;
90
    }
91
92
    /**
93
     * Adds a index to the list.
94
     *
95
     * @param \Elastica\Index|string $index Index object or string
96
     *
97
     * @throws \Elastica\Exception\InvalidException
98
     *
99
     * @return $this
100
     */
101
    public function addIndex($index)
102
    {
103
        if ($index instanceof Index) {
104
            $index = $index->getName();
105
        }
106
107
        if (!is_scalar($index)) {
108
            throw new InvalidException('Invalid param type');
109
        }
110
111
        $this->_indices[] = (string) $index;
112
113
        return $this;
114
    }
115
116
    /**
117
     * Add array of indices at once.
118
     *
119
     * @param array $indices
120
     *
121
     * @return $this
122
     */
123
    public function addIndices(array $indices = [])
124
    {
125
        foreach ($indices as $index) {
126
            $this->addIndex($index);
127
        }
128
129
        return $this;
130
    }
131
132
    /**
133
     * Adds a type to the current search.
134
     *
135
     * @param \Elastica\Type|string $type Type name or object
136
     *
137
     * @throws \Elastica\Exception\InvalidException
138
     *
139
     * @return $this
140
     */
141
    public function addType($type)
142
    {
143
        if ($type instanceof Type) {
144
            $type = $type->getName();
145
        }
146
147
        if (!is_string($type)) {
148
            throw new InvalidException('Invalid type type');
149
        }
150
151
        $this->_types[] = $type;
152
153
        return $this;
154
    }
155
156
    /**
157
     * Add array of types.
158
     *
159
     * @param array $types
160
     *
161
     * @return $this
162
     */
163
    public function addTypes(array $types = [])
164
    {
165
        foreach ($types as $type) {
166
            $this->addType($type);
167
        }
168
169
        return $this;
170
    }
171
172
    /**
173
     * @param string|array|\Elastica\Query|\Elastica\Suggest|\Elastica\Query\AbstractQuery $query
174
     *
175
     * @return $this
176
     */
177
    public function setQuery($query)
178
    {
179
        if ($query instanceof AbstractFilter) {
180
            trigger_error('Deprecated: Elastica\Search::setQuery() passing AbstractFilter is deprecated. Create query and use setPostFilter with AbstractQuery instead.', E_USER_DEPRECATED);
181
        }
182
183
        $this->_query = Query::create($query);
184
185
        return $this;
186
    }
187
188
    /**
189
     * @param string $key
190
     * @param mixed  $value
191
     *
192
     * @return $this
193
     */
194
    public function setOption($key, $value)
195
    {
196
        $this->_validateOption($key);
197
198
        $this->_options[$key] = $value;
199
200
        return $this;
201
    }
202
203
    /**
204
     * @param array $options
205
     *
206
     * @return $this
207
     */
208
    public function setOptions(array $options)
209
    {
210
        $this->clearOptions();
211
212
        foreach ($options as $key => $value) {
213
            $this->setOption($key, $value);
214
        }
215
216
        return $this;
217
    }
218
219
    /**
220
     * @return $this
221
     */
222
    public function clearOptions()
223
    {
224
        $this->_options = [];
225
226
        return $this;
227
    }
228
229
    /**
230
     * @param string $key
231
     * @param mixed  $value
232
     *
233
     * @return $this
234
     */
235
    public function addOption($key, $value)
236
    {
237
        $this->_validateOption($key);
238
239
        $this->_options[$key][] = $value;
240
241
        return $this;
242
    }
243
244
    /**
245
     * @param string $key
246
     *
247
     * @return bool
248
     */
249
    public function hasOption($key)
250
    {
251
        return isset($this->_options[$key]);
252
    }
253
254
    /**
255
     * @param string $key
256
     *
257
     * @throws \Elastica\Exception\InvalidException
258
     *
259
     * @return mixed
260
     */
261
    public function getOption($key)
262
    {
263
        if (!$this->hasOption($key)) {
264
            throw new InvalidException('Option '.$key.' does not exist');
265
        }
266
267
        return $this->_options[$key];
268
    }
269
270
    /**
271
     * @return array
272
     */
273
    public function getOptions()
274
    {
275
        return $this->_options;
276
    }
277
278
    /**
279
     * @param string $key
280
     *
281
     * @throws \Elastica\Exception\InvalidException
282
     *
283
     * @return bool
284
     */
285
    protected function _validateOption($key)
286
    {
287
        switch ($key) {
288
            case self::OPTION_SEARCH_TYPE:
289
            case self::OPTION_ROUTING:
290
            case self::OPTION_PREFERENCE:
291
            case self::OPTION_VERSION:
292
            case self::OPTION_TIMEOUT:
293
            case self::OPTION_FROM:
294
            case self::OPTION_SIZE:
295
            case self::OPTION_SCROLL:
296
            case self::OPTION_SCROLL_ID:
297
            case self::OPTION_SEARCH_TYPE_SUGGEST:
298
            case self::OPTION_SEARCH_IGNORE_UNAVAILABLE:
299
            case self::OPTION_QUERY_CACHE:
300
            case self::OPTION_TERMINATE_AFTER:
301
                return true;
302
        }
303
304
        throw new InvalidException('Invalid option '.$key);
305
    }
306
307
    /**
308
     * Return client object.
309
     *
310
     * @return \Elastica\Client Client object
311
     */
312
    public function getClient()
313
    {
314
        return $this->_client;
315
    }
316
317
    /**
318
     * Return array of indices.
319
     *
320
     * @return array List of index names
321
     */
322
    public function getIndices()
323
    {
324
        return $this->_indices;
325
    }
326
327
    /**
328
     * @return bool
329
     */
330
    public function hasIndices()
331
    {
332
        return count($this->_indices) > 0;
333
    }
334
335
    /**
336
     * @param Index|string $index
337
     *
338
     * @return bool
339
     */
340
    public function hasIndex($index)
341
    {
342
        if ($index instanceof Index) {
343
            $index = $index->getName();
344
        }
345
346
        return in_array($index, $this->_indices);
347
    }
348
349
    /**
350
     * Return array of types.
351
     *
352
     * @return array List of types
353
     */
354
    public function getTypes()
355
    {
356
        return $this->_types;
357
    }
358
359
    /**
360
     * @return bool
361
     */
362
    public function hasTypes()
363
    {
364
        return count($this->_types) > 0;
365
    }
366
367
    /**
368
     * @param \Elastica\Type|string $type
369
     *
370
     * @return bool
371
     */
372
    public function hasType($type)
373
    {
374
        if ($type instanceof Type) {
375
            $type = $type->getName();
376
        }
377
378
        return in_array($type, $this->_types);
379
    }
380
381
    /**
382
     * @return \Elastica\Query
383
     */
384
    public function getQuery()
385
    {
386
        if (null === $this->_query) {
387
            $this->_query = Query::create('');
388
        }
389
390
        return $this->_query;
391
    }
392
393
    /**
394
     * Creates new search object.
395
     *
396
     * @param \Elastica\SearchableInterface $searchObject
397
     *
398
     * @return Search
399
     */
400
    public static function create(SearchableInterface $searchObject)
401
    {
402
        return $searchObject->createSearch();
403
    }
404
405
    /**
406
     * Combines indices and types to the search request path.
407
     *
408
     * @return string Search path
409
     */
410
    public function getPath()
411
    {
412
        if (isset($this->_options[self::OPTION_SCROLL_ID])) {
413
            return '_search/scroll';
414
        }
415
416
        $indices = $this->getIndices();
417
418
        $path = '';
419
        $types = $this->getTypes();
420
421
        if (empty($indices)) {
422
            if (!empty($types)) {
423
                $path .= '_all';
424
            }
425
        } else {
426
            $path .= implode(',', $indices);
427
        }
428
429
        if (!empty($types)) {
430
            $path .= '/'.implode(',', $types);
431
        }
432
433
        // Add full path based on indices and types -> could be all
434
        return $path.'/_search';
435
    }
436
437
    /**
438
     * Search in the set indices, types.
439
     *
440
     * @param mixed     $query
441
     * @param int|array $options OPTIONAL Limit or associative array of options (option=>value)
442
     *
443
     * @throws \Elastica\Exception\InvalidException
444
     *
445
     * @return \Elastica\ResultSet
446
     */
447
    public function search($query = '', $options = null)
448
    {
449
        $this->setOptionsAndQuery($options, $query);
450
451
        $query = $this->getQuery();
452
        $path = $this->getPath();
453
454
        $params = $this->getOptions();
455
456
        // Send scroll_id via raw HTTP body to handle cases of very large (> 4kb) ids.
457
        if ('_search/scroll' == $path) {
458
            $data = $params[self::OPTION_SCROLL_ID];
459
            unset($params[self::OPTION_SCROLL_ID]);
460
        } else {
461
            $data = $query->toArray();
462
        }
463
464
        $response = $this->getClient()->request(
465
            $path,
466
            Request::GET,
467
            $data,
468
            $params
469
        );
470
471
        return $this->_builder->buildResultSet($response, $query);
472
    }
473
474
    /**
475
     * @param mixed $query
476
     * @param $fullResult (default = false) By default only the total hit count is returned. If set to true, the full ResultSet including aggregations is returned.
477
     *
478
     * @return int|ResultSet
479
     */
480
    public function count($query = '', $fullResult = false)
481
    {
482
        $this->setOptionsAndQuery(null, $query);
483
484
        $query = $this->getQuery();
485
        $path = $this->getPath();
486
487
        $response = $this->getClient()->request(
488
            $path,
489
            Request::GET,
490
            $query->toArray(),
491
            [self::OPTION_SEARCH_TYPE => self::OPTION_SEARCH_TYPE_COUNT]
492
        );
493
        $resultSet = $this->_builder->buildResultSet($response, $query);
494
495
        return $fullResult ? $resultSet : $resultSet->getTotalHits();
496
    }
497
498
    /**
499
     * @param array|int                    $options
500
     * @param string|array|\Elastica\Query $query
501
     *
502
     * @return $this
503
     */
504
    public function setOptionsAndQuery($options = null, $query = '')
505
    {
506
        if ('' != $query) {
507
            $this->setQuery($query);
508
        }
509
510
        if (is_int($options)) {
511
            $this->getQuery()->setSize($options);
512
        } elseif (is_array($options)) {
513
            if (isset($options['limit'])) {
514
                $this->getQuery()->setSize($options['limit']);
515
                unset($options['limit']);
516
            }
517
            if (isset($options['explain'])) {
518
                $this->getQuery()->setExplain($options['explain']);
519
                unset($options['explain']);
520
            }
521
            $this->setOptions($options);
522
        }
523
524
        return $this;
525
    }
526
527
    /**
528
     * @param Suggest $suggest
529
     *
530
     * @return $this
531
     */
532
    public function setSuggest(Suggest $suggest)
533
    {
534
        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...
535
    }
536
537
    /**
538
     * Returns the Scroll Iterator.
539
     *
540
     * @see Elastica\Scroll
541
     *
542
     * @param string $expiryTime
543
     *
544
     * @return Scroll
545
     */
546
    public function scroll($expiryTime = '1m')
547
    {
548
        return new Scroll($this, $expiryTime);
549
    }
550
551
    /**
552
     * Returns the ScanAndScroll Iterator.
553
     *
554
     * @see Elastica\ScanAndScroll
555
     *
556
     * @param string $expiryTime
557
     * @param int    $sizePerShard
558
     *
559
     * @return ScanAndScroll
560
     */
561
    public function scanAndScroll($expiryTime = '1m', $sizePerShard = 1000)
562
    {
563
        return new ScanAndScroll($this, $expiryTime, $sizePerShard);
564
    }
565
566
    /**
567
     * @return BuilderInterface
568
     */
569
    public function getResultSetBuilder()
570
    {
571
        return $this->_builder;
572
    }
573
}
574