Completed
Push — master ( a8f028...4e52eb )
by Oscar
05:21
created

SearchQuery::setQuery()   C

Complexity

Conditions 8
Paths 2

Size

Total Lines 31
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 31
rs 5.3846
c 0
b 0
f 0
cc 8
eloc 19
nc 2
nop 1
1
<?php
2
3
namespace Folk;
4
5
/**
6
 * Class to manage a query to search rows.
7
 */
8
class SearchQuery
9
{
10
    protected $limit = 50;
11
    protected $page;
12
    protected $ids = [];
13
    protected $conditions = [];
14
    protected $words = [];
15
    protected $sort = [];
16
17
    /**
18
     * @param array $query
19
     */
20
    public function __construct(array $query = [])
21
    {
22
        if (!empty($query['query'])) {
23
            $this->setQuery($query['query']);
24
        }
25
26
        if (!empty($query['page'])) {
27
            $this->setPage($query['page']);
28
        }
29
30
        if (!empty($query['sort'])) {
31
            $this->setSort($query['sort']);
32
        }
33
    }
34
35
    /**
36
     * Set the a query.
37
     *
38
     * @param string $query
39
     *
40
     * @return self
41
     */
42
    public function setQuery($query)
43
    {
44
        $this->conditions = $this->ids = $this->words = [];
45
46
        preg_match_all('/([\w]+:)?("([^"]*)"|([^ ]*))/', trim($query), $pieces, PREG_SET_ORDER);
47
48
        if (is_array($pieces)) {
49
            foreach ($pieces as $piece) {
50
                if (empty($piece[0])) {
51
                    continue;
52
                }
53
54
                $name = $piece[1] ? substr($piece[1], 0, -1) : null;
55
                $value = $piece[4] ?? $piece[3];
56
57
                if ($name !== null) {
58
                    if (!isset($this->conditions[$name])) {
59
                        $this->conditions[$name] = [$value];
60
                    } else {
61
                        $this->conditions[$name][] = $value;
62
                    }
63
                } elseif (preg_match('/^#[\w-]+$/', $value)) {
64
                    $this->ids[] = substr($value, 1);
65
                } else {
66
                    $this->words[] = $value;
67
                }
68
            }
69
        }
70
71
        return $this;
72
    }
73
74
    /**
75
     * Returns the page number.
76
     *
77
     * @return null|int
78
     */
79
    public function getPage()
80
    {
81
        return $this->page;
82
    }
83
84
    /**
85
     * Set the page.
86
     *
87
     * @param null|int $page
88
     * 
89
     * @return self
90
     */
91
    public function setPage($page): self
92
    {
93
        $this->page = (int) $page;
94
95
        return $this;
96
    }
97
98
    /**
99
     * Returns the limit of results per page.
100
     *
101
     * @return int
102
     */
103
    public function getLimit(): int
104
    {
105
        return $this->limit;
106
    }
107
108
    /**
109
     * Set the limit of results per page.
110
     *
111
     * @param int $limit
112
     * 
113
     * @return self
114
     */
115
    public function setLimit(int $limit): self
116
    {
117
        $this->limit = (int) $limit;
118
119
        return $this;
120
    }
121
122
    /**
123
     * Returns all ids found.
124
     *
125
     * @return array
126
     */
127
    public function getIds(): array
128
    {
129
        return $this->ids;
130
    }
131
132
    /**
133
     * Set new ids.
134
     *
135
     * @param array $ids
136
     * 
137
     * @return self
138
     */
139
    public function setIds(array $ids): self
140
    {
141
        $this->ids = $ids;
142
143
        return $this;
144
    }
145
146
    /**
147
     * Returns all words in the query.
148
     *
149
     * @return array
150
     */
151
    public function getWords(): array
152
    {
153
        return $this->words;
154
    }
155
156
    /**
157
     * Set new words.
158
     *
159
     * @param array $words
160
     * 
161
     * @return self
162
     */
163
    public function setWords(array $words): self
164
    {
165
        $this->words = $words;
166
167
        return $this;
168
    }
169
170
    /**
171
     * Set new conditions.
172
     *
173
     * @param array $conditions
174
     * 
175
     * @return self
176
     */
177
    public function setConditions(array $conditions): self
178
    {
179
        $this->conditions = $conditions;
180
181
        return $this;
182
    }
183
184
    /**
185
     * Return all conditions.
186
     *
187
     * @return array
188
     */
189
    public function getConditions(): array
190
    {
191
        return $this->conditions;
192
    }
193
194
    /**
195
     * Return the sort fields.
196
     *
197
     * @return array ['field' => 'direction']
198
     */
199
    public function getSort(): array
200
    {
201
        return $this->sort;
202
    }
203
204
    /**
205
     * Set the sort and direction fields.
206
     *
207
     * @param string $sort
208
     */
209
    public function setSort(string $sort)
210
    {
211
        $this->sort = [];
212
213
        foreach (array_filter(array_map('trim', explode(',', $sort))) as $field) {
214
            if ($field[0] === '-') {
215
                $direction = 'DESC';
216
                $field = substr($field, 1);
217
            } else {
218
                $direction = 'ASC';
219
            }
220
221
            $this->sort[$field] = $direction;
222
        }
223
    }
224
225
    /**
226
     * Returns the query as string.
227
     *
228
     * @return string
229
     */
230
    public function buildQuery(): string
231
    {
232
        $query = implode(' ', $this->words);
233
234
        foreach ($this->ids as $id) {
235
            $query .= " #{$id}";
236
        }
237
238
        foreach ($this->conditions as $name => $values) {
239
            foreach ($values as $value) {
240
                if (strpos($value, ' ') === false) {
241
                    $query .= " {$name}:{$value}";
242
                } else {
243
                    $query .= " {$name}:\"{$value}\"";
244
                }
245
            }
246
        }
247
248
        return trim($query);
249
    }
250
251
    /**
252
     * Returns the sort as string.
253
     *
254
     * @return string
255
     */
256
    public function buildSort(): string
257
    {
258
        $sort = [];
259
260
        foreach ($this->sort as $field => $direction) {
261
            if ($direction === 'DESC') {
262
                $sort[] = '-'.$field;
263
            } else {
264
                $sort[] = $field;
265
            }
266
        }
267
268
        return implode(',', $sort);
269
    }
270
}
271