Search::limit()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 4
rs 10
1
<?php
2
3
4
namespace Manticoresearch;
5
6
use Manticoresearch\Query\BoolQuery;
7
use Manticoresearch\Query\Distance;
8
use Manticoresearch\Query\Equals;
9
use Manticoresearch\Query\In;
10
use Manticoresearch\Query\MatchQuery;
11
use Manticoresearch\Query\MatchPhrase;
12
use Manticoresearch\Query\QueryString;
13
use Manticoresearch\Query\Range;
14
use Manticoresearch\Query\ScriptFields;
15
16
/**
17
 * Manticore search object
18
 * @category ManticoreSearch
19
 * @package ManticoreSearch
20
 * @author Adrian Nuta <[email protected]>
21
 * @link https://manticoresearch.com
22
 */
23
class Search
24
{
25
    const FILTER_AND = "AND";
26
    const FILTER_OR = "OR";
27
    const FILTER_NOT = "NOT";
28
29
    /**
30
     * @var Client
31
     */
32
    protected $client;
33
34
    protected $query;
35
    protected $body;
36
    /**
37
     * @var array
38
     */
39
    protected $params = [];
40
41
    protected static $replaceOperator = [
42
        '=' => 'equals',
43
        '>=' => 'gte',
44
        '>' => 'gt',
45
        '<' => 'lt',
46
        '<=' => 'lte',
47
    ];
48
49
    public function __construct(Client $client)
50
    {
51
        $this->client = $client;
52
        $this->query = new BoolQuery();
53
    }
54
55
    public function setIndex($index): self
56
    {
57
        $this->params['index'] = $index;
58
        return $this;
59
    }
60
61
    public function setSource($source): self
62
    {
63
        $this->params['_source'] = $source;
64
        return $this;
65
    }
66
67
    public function trackScores($trackScores): self
68
    {
69
        if (is_null($trackScores)) {
70
            unset($this->params['track_scores']);
71
        } else {
72
            $this->params['track_scores'] = (bool)$trackScores;
73
        }
74
75
        return $this;
76
    }
77
78
    public function stripBadUtf8($stripBadUtf8): self
79
    {
80
        if (is_null($stripBadUtf8)) {
81
            unset($this->params['strip_bad_utf8']);
82
        } else {
83
            $this->params['strip_bad_utf8'] = (bool)$stripBadUtf8;
84
        }
85
        
86
        return $this;
87
    }
88
    
89
    /**
90
     * @param string|BoolQuery $queryString
91
     * @return $this
92
     */
93
    public function search($queryString): self
94
    {
95
        if (is_object($queryString)) {
96
            $this->query = $queryString;
97
            return $this;
98
        }
99
        $this->query->must(new QueryString($queryString));
100
        return $this;
101
    }
102
103
    public function match($keywords, $fields = null): self
104
    {
105
        $f = "*";
106
        if ($fields !== null && is_string($fields)) {
107
            $f = $fields;
108
        }
109
        $this->query->must(new MatchQuery($keywords, $f));
110
        return $this;
111
    }
112
113
    public function phrase($string, $fields = null): self
114
    {
115
        $f = "*";
116
        if ($fields !== null && is_string($fields)) {
117
            $f = $fields;
118
        }
119
        $this->query->must(new MatchPhrase($string, $f));
120
        return $this;
121
    }
122
123
    public function limit($limit): self
124
    {
125
        $this->params['limit'] = $limit;
126
        return $this;
127
    }
128
129
    /**
130
     * @param string $name
131
     * @param string $exp
132
     * @return $this
133
     */
134
    public function expression($name, $exp): self
135
    {
136
        if (!isset($this->params['script_fields'])) {
137
            $this->params['script_fields'] = new ScriptFields();
138
        }
139
        $this->params['script_fields']->add($name, $exp);
140
        return $this;
141
    }
142
143
    public function highlight($fields = [], $settings = []): self
144
    {
145
146
        if (count($fields) === 0 && count($settings)===0) {
147
            $this->params['highlight'] =  new \stdClass();
148
            return $this;
149
        }
150
        $this->params['highlight'] = [];
151
        if (count($fields) > 0) {
152
            $this->params['highlight']['fields'] =$fields;
153
        }
154
        if (count($settings)>0) {
155
            foreach ($settings as $name => $value) {
156
                $this->params['highlight'][$name] =$value;
157
            }
158
        }
159
        return $this;
160
    }
161
162
    public function distance($args): self
163
    {
164
        $this->query->must(new Distance($args));
165
        return $this;
166
    }
167
168
    protected function getAttrObject($attr, $op, $values)
169
    {
170
        $op = static::$replaceOperator[$op] ?? $op;
171
172
        switch ($op) {
173
            case 'range':
174
                $object = new Range($attr, [
175
                    'gte' => $values[0],
176
                    'lte' => $values[1]
177
                ]);
178
                break;
179
            case 'lt':
180
            case 'lte':
181
            case 'gt':
182
            case 'gte':
183
                $object = new Range($attr, [
184
                    $op => $values[0],
185
                ]);
186
                break;
187
            case 'in':
188
                $object = new In($attr, $values);
189
                break;
190
            case 'equals':
191
                $value = is_bool($values[0]) ? (int)$values[0] : $values[0];
192
                $object = new Equals($attr, $value);
193
                break;
194
            default:
195
                $object = null;
196
        }
197
198
        return $object;
199
    }
200
201
    public function filter($attr, $op = null, $values = null, $boolean = self::FILTER_AND): self
202
    {
203
        if (!is_object($attr)) {
204
            if (is_null($values)) {
205
                $values = $op;
206
                $op = "equals";
207
            }
208
209
            if (!is_array($values)) {
210
                $values = [$values];
211
            }
212
213
            $attr = $this->getAttrObject($attr, $op, $values);
214
215
            if (!$attr) {
216
                return $this;
217
            }
218
        }
219
220
        if ($boolean === static::FILTER_AND) {
221
            $this->query->must($attr);
222
        } elseif ($boolean === static::FILTER_OR) {
223
            $this->query->should($attr);
224
        } elseif ($boolean === static::FILTER_NOT) {
225
            $this->query->mustNot($attr);
226
        }
227
228
        return $this;
229
    }
230
231
    public function orFilter($attr, $op = null, $values = null): self
232
    {
233
        return $this->filter($attr, $op, $values, static::FILTER_OR);
234
    }
235
236
    public function notFilter($attr, $op = null, $values = null): self
237
    {
238
        return $this->filter($attr, $op, $values, static::FILTER_NOT);
239
    }
240
241
    public function offset($offset): self
242
    {
243
        $this->params['offset'] = $offset;
244
        return $this;
245
    }
246
247
    public function maxMatches($maxmatches): self
248
    {
249
        $this->params['max_matches'] = $maxmatches;
250
        return $this;
251
    }
252
253
    public function facet($field, $group = null, $limit = null, $sortField = null, $sortDirection = 'desc') : self
254
    {
255
        // reset facets
256
        if ($field === false) {
257
            $this->params['aggs'] = [];
258
        }
259
        if ($group === null) {
260
            $group = $field;
261
        }
262
            $terms = ['field'=>$field];
263
        if ($limit !==null) {
264
            $terms['size'] = $limit;
265
        }
266
        $this->params['aggs'][$group] = ['terms' =>$terms];
267
        if ($sortField !== null) {
268
            $this->params['aggs'][$group]['sort'] = [ [$sortField => $sortDirection] ];
269
        }
270
        return $this;
271
    }
272
273
    public function sort($field, $direction = 'asc', $mode = null): self
274
    {
275
        // reset sorting
276
        if ($field === false) {
277
            $this->params['sort'] = [];
278
        }
279
        //if 1st arg is array means we have a sorting expression
280
        if (is_array($field)) {
281
            //if 2nd arg is true we full set the sort with the expr, otherwise just add it
282
            //we let passing uppercased directions here as well
283
            foreach ($field as $k => $v) {
284
                if (is_string($v)) {
285
                    $field[$k] = strtolower($v);
286
                }
287
            }
288
            if (isset($direction) && $direction === true) {
289
                $this->params['sort'] = $field;
290
            } else {
291
                $this->params['sort'] [] = $field;
292
            }
293
            return $this;
294
        }
295
        if (!isset($this->params['sort'])) {
296
            $this->params['sort'] = [];
297
        }
298
        $direction = strtolower($direction);
299
        if ($mode === null) {
300
            $this->params['sort'] [] = [$field => $direction];
301
        } else {
302
            $this->params['sort'] [] = [$field => ['order' => $direction, 'mode' => $mode]];
303
        }
304
305
        return $this;
306
    }
307
308
    public function option($name, $value): self
309
    {
310
        if (is_null($value)) {
311
            unset($this->params['options'][$name]);
312
        } else {
313
            $this->params['options'][$name] = $value;
314
        }
315
316
        return $this;
317
    }
318
319
    public function profile(): self
320
    {
321
        $this->params['profile'] = true;
322
        return $this;
323
    }
324
325
    /**
326
     * @return ResultSet
327
     */
328
    public function get()
329
    {
330
        $this->body = $this->compile();
331
        $resp = $this->client->search(['body' => $this->body], true);
332
        return new ResultSet($resp);
333
    }
334
335
    public function compile()
336
    {
337
        $body = $this->params;
338
        $query = $this->query->toArray();
339
        if ($query !== null) {
340
            $body['query'] = $query;
341
        }
342
343
        if (isset($this->params['script_fields'])) {
344
            $body['script_fields'] = $this->params['script_fields']->toArray();
345
        }
346
347
        return $body;
348
    }
349
350
    public function getBody()
351
    {
352
        return $this->body;
353
    }
354
355
    public function reset()
356
    {
357
        $this->params = [];
358
        $this->query = new BoolQuery();
359
    }
360
361
    public function getClient()
362
    {
363
        return $this->client;
364
    }
365
}
366