Passed
Push — master ( 0295e5...64c976 )
by Marcin
07:48 queued 04:50
created

RequestParser::getLimit()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
c 0
b 0
f 0
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * Created by Marcin.
4
 * Date: 16.06.2018
5
 * Time: 13:45
6
 */
7
declare(strict_types=1);
8
9
namespace Mrcnpdlk\Lib\UrlSearchParser;
10
11
use function in_array;
12
use InvalidArgumentException;
13
use function is_array;
14
use function is_string;
15
use Mrcnpdlk\Lib\UrlSearchParser\Criteria\Filter;
16
use Mrcnpdlk\Lib\UrlSearchParser\Criteria\Sort;
17
use Mrcnpdlk\Lib\UrlSearchParser\Exception\InvalidParamException;
18
use RuntimeException;
19
20
class RequestParser
21
{
22
    public const SORT_IDENTIFIER   = 'sort';
23
    public const FILTER_IDENTIFIER = 'filter';
24
    public const LIMIT_IDENTIFIER  = 'limit';
25
    public const OFFSET_IDENTIFIER = 'offset';
26
    public const PAGE_IDENTIFIER   = 'page';
27
    public const PHRASE_IDENTIFIER = 'phrase';
28
    /**
29
     * @var \Mrcnpdlk\Lib\UrlSearchParser\Criteria\Filter
30
     */
31
    private $filter;
32
    /**
33
     * @var int|null
34
     */
35
    private $limit;
36
    /**
37
     * @var int|null
38
     */
39
    private $offset;
40
    /**
41
     * @var int|null
42
     */
43
    private $page;
44
    /**
45
     * @var string|null
46
     */
47
    private $phrase;
48
    /**
49
     * @var array
50
     */
51
    private $queryParams = [];
52
    /**
53
     * @var \Mrcnpdlk\Lib\UrlSearchParser\Criteria\Sort
54
     */
55
    private $sort;
56
57
    /**
58
     * RequestParser constructor.
59
     *
60
     * @param string $query
61
     *
62
     * @throws \Mrcnpdlk\Lib\UrlSearchParser\Exception\DuplicateParamException
63
     * @throws \Mrcnpdlk\Lib\UrlSearchParser\Exception\EmptyParamException
64
     * @throws \Mrcnpdlk\Lib\UrlSearchParser\Exception\InvalidParamException
65
     */
66 24
    public function __construct(string $query)
67
    {
68 24
        $this->parse($query);
69 14
    }
70
71
    public function __toString(): string
72
    {
73
        return $this->getQuery();
74
    }
75
76
    /**
77
     * @return \Mrcnpdlk\Lib\UrlSearchParser\Criteria\Filter
78
     */
79 4
    public function getFilter(): Filter
80
    {
81 4
        return $this->filter;
82
    }
83
84
    /**
85
     * @param \Mrcnpdlk\Lib\UrlSearchParser\Criteria\Filter $filter
86
     *
87
     * @return $this
88
     */
89 17
    public function setFilter(Filter $filter): self
90
    {
91 17
        $this->filter = $filter;
92
93 17
        $tRes = [];
94 17
        foreach ($filter->toArray() as $item) {
95 3
            if (!array_key_exists($item->param, $tRes)) {
96 3
                $tRes[$item->param] = [];
97
            }
98 3
            $tRes[$item->param][$item->operator] = $item->value;
99
        }
100
101 17
        if (0 === count($tRes)) {
102 14
            unset($this->queryParams[self::FILTER_IDENTIFIER]);
103
        } else {
104 3
            $this->queryParams[self::FILTER_IDENTIFIER] = $tRes;
105
        }
106
107 17
        return $this;
108
    }
109
110
    /**
111
     * @param int|null $default
112
     *
113
     * @return int|null
114
     */
115 2
    public function getLimit(int $default = null): ?int
116
    {
117 2
        return $this->limit ?? $default;
118
    }
119
120
    /**
121
     * @param int|null $limit
122
     *
123
     * @throws \Mrcnpdlk\Lib\UrlSearchParser\Exception\InvalidParamException
124
     *
125
     * @return $this
126
     */
127 17
    public function setLimit(?int $limit): self
128
    {
129 17
        $this->limit = $limit;
130 17
        if (null !== $this->limit && $this->limit < 0) {
131 1
            throw new InvalidParamException('Limit value cannot be lower than 0');
132
        }
133 16
        if (null === $limit) {
134 16
            unset($this->queryParams[self::LIMIT_IDENTIFIER]);
135
        } else {
136
            $this->queryParams[self::LIMIT_IDENTIFIER] = $limit;
137
        }
138
139 16
        return $this;
140
    }
141
142
    /**
143
     * @param int|null $default
144
     *
145
     * @return int|null
146
     */
147 2
    public function getOffset(int $default = null): ?int
148
    {
149 2
        return $this->offset ?? $default;
150
    }
151
152
    /**
153
     * @param int|null $offset
154
     *
155
     * @throws \Mrcnpdlk\Lib\UrlSearchParser\Exception\InvalidParamException
156
     *
157
     * @return $this
158
     */
159 16
    public function setOffset(?int $offset): self
160
    {
161 16
        $this->offset = $offset;
162 16
        if (null !== $this->offset && $this->offset < 0) {
163 1
            throw new InvalidParamException('Offset value cannot be lower than 0');
164
        }
165 15
        if (null === $offset) {
166 15
            unset($this->queryParams[self::OFFSET_IDENTIFIER]);
167
        } else {
168
            $this->queryParams[self::OFFSET_IDENTIFIER] = $offset;
169
        }
170
171 15
        return $this;
172
    }
173
174
    /**
175
     * @param int|null $default
176
     *
177
     * @return int|null
178
     */
179 2
    public function getPage(int $default = null): ?int
180
    {
181 2
        return $this->page ?? $default;
182
    }
183
184
    /**
185
     * @param int|null $page
186
     *
187
     * @throws \Mrcnpdlk\Lib\UrlSearchParser\Exception\InvalidParamException
188
     *
189
     * @return $this
190
     */
191 15
    public function setPage(?int $page): self
192
    {
193 15
        $this->page = $page;
194 15
        if (null !== $this->page && $this->page < 0) {
195 1
            throw new InvalidParamException('Page value cannot be lower than 0');
196
        }
197 14
        if (null === $page) {
198 14
            unset($this->queryParams[self::PAGE_IDENTIFIER]);
199
        } else {
200
            $this->queryParams[self::PAGE_IDENTIFIER] = $page;
201
        }
202
203 14
        return $this;
204
    }
205
206
    /**
207
     * @return string|null
208
     */
209 2
    public function getPhrase(): ?string
210
    {
211 2
        return $this->phrase;
212
    }
213
214
    /**
215
     * @param string|null $phrase
216
     *
217
     * @return $this
218
     */
219 14
    public function setPhrase(?string $phrase): self
220
    {
221 14
        $this->phrase = $phrase;
222 14
        if (null === $phrase) {
223 13
            unset($this->queryParams[self::PHRASE_IDENTIFIER]);
224
        } else {
225 1
            $this->queryParams[self::PHRASE_IDENTIFIER] = $phrase;
226
        }
227
228 14
        return $this;
229
    }
230
231
    /**
232
     * @param string|null $arg_separator
233
     * @param int         $enc_type
234
     *
235
     * @return string
236
     */
237 1
    public function getQuery(string $arg_separator = null, int $enc_type = \PHP_QUERY_RFC1738): string
238
    {
239 1
        return http_build_query($this->queryParams, null ?? '', $arg_separator ?? (ini_get('arg_separator.output') ?: '&'), $enc_type);
240
    }
241
242
    /**
243
     * @throws \Mrcnpdlk\Lib\UrlSearchParser\Exception
244
     *
245
     * @return string
246
     */
247
    public function getQueryHash(): string
248
    {
249
        try {
250
            $resJson = json_encode($this->queryParams);
251
            if (false === $resJson) {
252
                throw new RuntimeException('Cannot generate json_encode');
253
            }
254
            /** @var string|false $res */
255
            $res = md5($resJson);
256
            if (false === $res) {
257
                throw new RuntimeException('Cannot generate md5 hash');
258
            }
259
        } catch (RuntimeException $e) {
260
            throw new Exception(sprintf('Cannot query hash. %s', $e->getMessage()));
261
        }
262
263
        return $res;
264
    }
265
266
    /**
267
     * @param string      $param
268
     * @param string|null $type    If NULL return value AS IS
269
     * @param mixed|null  $default
270
     *
271
     * @return mixed|null
272
     */
273 24
    public function getQueryParam(string $param, string $type = null, $default = null)
274
    {
275 24
        if (isset($this->queryParams[$param])) {
276 24
            if (null !== $type) {
277 22
                $type = strtolower($type);
278 22
                if (!in_array($type, ['boolean', 'bool', 'integer', 'int', 'float', 'double', 'string', 'array'])) {
279 1
                    throw new InvalidArgumentException(sprintf('Unsupported type [%s]', $type));
280
                }
281
282 21
                $var = $this->queryParams[$param];
283
284 21
                if ('array' === $type && is_string($var)) {
285 2
                    $var = explode(',', $var);
286 20
                } elseif ('string' === $type && is_array($var)) {
287 1
                    $var = implode(',', $var);
288 20
                } elseif (in_array($type, ['boolean', 'bool']) && in_array(strtolower($var), ['true', 'false'])) {
289 2
                    $var = ('true' === strtolower($var));
290 20
                } elseif (!settype($var, $type)) {
291
                    throw new RuntimeException(sprintf('Cannot set type [%s]', $type));
292
                }
293
294 21
                return $var;
295
            }
296
297 2
            return $this->queryParams[$param];
298
        }
299
300 21
        return $default ?? null;
301
    }
302
303
    /**
304
     * @return \Mrcnpdlk\Lib\UrlSearchParser\Criteria\Sort
305
     */
306 3
    public function getSort(): Sort
307
    {
308 3
        return $this->sort;
309
    }
310
311
    /**
312
     * @param \Mrcnpdlk\Lib\UrlSearchParser\Criteria\Sort $sort
313
     *
314
     * @return $this
315
     */
316 21
    public function setSort(Sort $sort): self
317
    {
318 21
        $this->sort = $sort;
319
320 21
        $tRes = [];
321 21
        foreach ($sort->toArray() as $param) {
322 2
            $tRes[] = Sort::DIRECTION_DESC === $param->direction ? Sort::DESC_IDENTIFIER . $param->param : $param->param;
323
        }
324 21
        if (0 === count($tRes)) {
325 19
            unset($this->queryParams[self::SORT_IDENTIFIER]);
326
        } else {
327 2
            $this->queryParams[self::SORT_IDENTIFIER] = implode(Sort::DELIMITER, $tRes);
328
        }
329
330 21
        return $this;
331
    }
332
333
    /**
334
     * @param string $param
335
     *
336
     * @throws \Mrcnpdlk\Lib\UrlSearchParser\Exception\InvalidParamException
337
     *
338
     * @return $this
339
     */
340 2
    public function removeQueryParam(string $param): self
341
    {
342 2
        if (in_array($param, [
343 2
            self::FILTER_IDENTIFIER,
344 2
            self::SORT_IDENTIFIER,
345 2
            self::PHRASE_IDENTIFIER,
346 2
            self::OFFSET_IDENTIFIER,
347 2
            self::LIMIT_IDENTIFIER,
348 2
            self::PAGE_IDENTIFIER,
349 2
        ], true)) {
350 1
            throw new InvalidParamException(sprintf('Cannot remove %s param. Use `set<param name>` with empty arg', $param));
351
        }
352 1
        unset($this->queryParams[$param]);
353
354 1
        return $this;
355
    }
356
357
    /**
358
     * @param string $param
359
     * @param        $value
360
     *
361
     * @throws \Mrcnpdlk\Lib\UrlSearchParser\Exception\InvalidParamException
362
     *
363
     * @return $this
364
     */
365 1
    public function setQueryParam(string $param, $value): self
366
    {
367 1
        if (in_array($param, [
368 1
            self::FILTER_IDENTIFIER,
369 1
            self::SORT_IDENTIFIER,
370 1
            self::PHRASE_IDENTIFIER,
371 1
            self::OFFSET_IDENTIFIER,
372 1
            self::LIMIT_IDENTIFIER,
373 1
            self::PAGE_IDENTIFIER,
374 1
        ], true)) {
375
            throw new InvalidParamException(sprintf('Cannot set %s param. Use `set<param name>` with empty arg', $param));
376
        }
377 1
        $this->queryParams[$param] = $value;
378
379 1
        return $this;
380
    }
381
382
    /**
383
     * @param string $query
384
     *
385
     * @throws \Mrcnpdlk\Lib\UrlSearchParser\Exception\DuplicateParamException
386
     * @throws \Mrcnpdlk\Lib\UrlSearchParser\Exception\EmptyParamException
387
     * @throws \Mrcnpdlk\Lib\UrlSearchParser\Exception\InvalidParamException
388
     */
389 24
    private function parse(string $query): void
390
    {
391 24
        parse_str($query, $this->queryParams);
392
393 24
        $this->setSort(new Sort($this->getQueryParam(self::SORT_IDENTIFIER, 'string')));
394 21
        $this->setFilter(new Filter($this->getQueryParam(self::FILTER_IDENTIFIER, 'array', [])));
395 17
        $this->setLimit($this->getQueryParam(self::LIMIT_IDENTIFIER, 'int'));
396 16
        $this->setOffset($this->getQueryParam(self::OFFSET_IDENTIFIER, 'int'));
397 15
        $this->setPage($this->getQueryParam(self::PAGE_IDENTIFIER, 'int'));
398 14
        $this->setPhrase($this->getQueryParam(self::PHRASE_IDENTIFIER, 'string'));
399 14
    }
400
}
401