Completed
Push — master ( 8729b7...837531 )
by Nicolas
01:48
created

Search::clearOptions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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