Passed
Push — master ( 6f99f9...0c6f75 )
by
unknown
02:34 queued 11s
created

Search::phrase()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 8
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
    /**
79
     * @param string $queryString
80
     * @return $this
81
     */
82
    public function search($queryString): self
83
    {
84
        if (is_object($queryString)) {
0 ignored issues
show
introduced by
The condition is_object($queryString) is always false.
Loading history...
85
            $this->query = $queryString;
86
            return $this;
87
        }
88
        $this->query->must(new QueryString($queryString));
89
        return $this;
90
    }
91
92
    public function match($keywords, $fields = null): self
93
    {
94
        $f = "*";
95
        if ($fields !== null && is_string($fields)) {
96
            $f = $fields;
97
        }
98
        $this->query->must(new MatchQuery($keywords, $f));
99
        return $this;
100
    }
101
102
    public function phrase($string, $fields = null): self
103
    {
104
        $f = "*";
105
        if ($fields !== null && is_string($fields)) {
106
            $f = $fields;
107
        }
108
        $this->query->must(new MatchPhrase($string, $f));
109
        return $this;
110
    }
111
112
    public function limit($limit): self
113
    {
114
        $this->params['limit'] = $limit;
115
        return $this;
116
    }
117
118
    /**
119
     * @param string $name
120
     * @param string $exp
121
     * @return $this
122
     */
123
    public function expression($name, $exp): self
124
    {
125
        if (!isset($this->params['script_fields'])) {
126
            $this->params['script_fields'] = new ScriptFields();
127
        }
128
        $this->params['script_fields']->add($name, $exp);
129
        return $this;
130
    }
131
132
    public function highlight($fields = [], $settings = []): self
133
    {
134
135
        if (count($fields) === 0 && count($settings)===0) {
136
            $this->params['highlight'] =  new \stdClass();
137
            return $this;
138
        }
139
        $this->params['highlight'] = [];
140
        if (count($fields) > 0) {
141
            $this->params['highlight']['fields'] =$fields;
142
        }
143
        if (count($settings)>0) {
144
            foreach ($settings as $name => $value) {
145
                $this->params['highlight'][$name] =$value;
146
            }
147
        }
148
        return $this;
149
    }
150
151
    public function distance($args): self
152
    {
153
        $this->query->must(new Distance($args));
154
        return $this;
155
    }
156
157
    protected function getAttrObject($attr, $op, $values)
158
    {
159
        $op = static::$replaceOperator[$op] ?? $op;
160
161
        switch ($op) {
162
            case 'range':
163
                $object = new Range($attr, [
164
                    'gte' => $values[0],
165
                    'lte' => $values[1]
166
                ]);
167
                break;
168
            case 'lt':
169
            case 'lte':
170
            case 'gt':
171
            case 'gte':
172
                $object = new Range($attr, [
173
                    $op => $values[0],
174
                ]);
175
                break;
176
            case 'in':
177
                $object = new In($attr, $values);
178
                break;
179
            case 'equals':
180
                $object = new Equals($attr, $values[0]);
181
                break;
182
            default:
183
                $object = null;
184
        }
185
186
        return $object;
187
    }
188
189
    public function filter($attr, $op = null, $values = null, $boolean = self::FILTER_AND): self
190
    {
191
        if (!is_object($attr)) {
192
            if (is_null($values)) {
193
                $values = $op;
194
                $op = "equals";
195
            }
196
197
            if (!is_array($values)) {
198
                $values = [$values];
199
            }
200
201
            $attr = $this->getAttrObject($attr, $op, $values);
202
203
            if (!$attr) {
204
                return $this;
205
            }
206
        }
207
208
        if ($boolean === self::FILTER_AND) {
209
            $this->query->must($attr);
210
        } elseif ($boolean === self::FILTER_OR) {
211
            $this->query->should($attr);
212
        } elseif ($boolean === self::FILTER_NOT) {
213
            $this->query->mustNot($attr);
214
        }
215
216
        return $this;
217
    }
218
219
    public function orFilter($attr, $op = null, $values = null): self
220
    {
221
        return $this->filter($attr, $op, $values, self::FILTER_OR);
222
    }
223
224
    public function notFilter($attr, $op = null, $values = null): self
225
    {
226
        return $this->filter($attr, $op, $values, self::FILTER_NOT);
227
    }
228
229
    public function offset($offset): self
230
    {
231
        $this->params['offset'] = $offset;
232
        return $this;
233
    }
234
235
    public function maxMatches($maxmatches): self
236
    {
237
        $this->params['max_matches'] = $maxmatches;
238
        return $this;
239
    }
240
241
    public function facet($field, $group = null, $limit = null) : self
242
    {
243
        // reset facets
244
        if ($field === false) {
245
            $this->params['aggs'] = [];
246
        }
247
        if ($group === null) {
248
            $group = $field;
249
        }
250
        $terms = ['field'=>$field];
251
        if ($limit !==null) {
252
            $terms['size'] = $limit;
253
        }
254
        $this->params['aggs'][$group] =['terms' =>$terms];
255
        return $this;
256
    }
257
258
    public function sort($field, $direction = 'asc', $mode = null): self
259
    {
260
        // reset sorting
261
        if ($field === false) {
262
            $this->params['sort'] = [];
263
        }
264
        //if 1st arg is array means we have a sorting expression
265
        if (is_array($field)) {
266
            //is 2nd arg is true we full set the sort with the expr, otherwise just add it
267
            if (isset($direction) && $direction === true) {
268
                $this->params['sort'] = $field;
269
            } else {
270
                $this->params['sort'] [] = $field;
271
            }
272
            return $this;
273
        }
274
        if (!isset($this->params['sort'])) {
275
            $this->params['sort'] = [];
276
        }
277
        if ($mode === null) {
278
            $this->params['sort'] [] = [$field => $direction];
279
        } else {
280
            $this->params['sort'] [] = [$field => ['order' => $direction, 'mode' => $mode]];
281
        }
282
283
        return $this;
284
    }
285
286
    public function option($name, $value): self
287
    {
288
        if (is_null($value)) {
289
            unset($this->params['options'][$name]);
290
        } else {
291
            $this->params['options'][$name] = $value;
292
        }
293
294
        return $this;
295
    }
296
297
    public function profile(): self
298
    {
299
        $this->params['profile'] = true;
300
        return $this;
301
    }
302
303
    /**
304
     * @return ResultSet
305
     */
306
    public function get()
307
    {
308
        $this->body = $this->compile();
309
        $resp = $this->client->search(['body' => $this->body], true);
310
        return new ResultSet($resp);
311
    }
312
313
    public function compile()
314
    {
315
        $body = $this->params;
316
        $query = $this->query->toArray();
317
        if ($query !== null) {
318
            $body['query'] = $query;
319
        }
320
321
        if (isset($this->params['script_fields'])) {
322
            $body['script_fields'] = $this->params['script_fields']->toArray();
323
            unset($this->params['script_fields']);
324
        }
325
326
        return $body;
327
    }
328
329
    public function getBody()
330
    {
331
        return $this->body;
332
    }
333
334
    public function reset()
335
    {
336
        $this->params = [];
337
        $this->query = new BoolQuery();
338
    }
339
340
    public function getClient()
341
    {
342
        return $this->client;
343
    }
344
}
345