Filter   A
last analyzed

Complexity

Total Complexity 26

Size/Duplication

Total Lines 186
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 26
eloc 77
c 2
b 0
f 0
dl 0
loc 186
ccs 54
cts 54
cp 1
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getByParam() 0 10 3
C __construct() 0 32 12
A appendParam() 0 5 1
A getIterator() 0 3 1
A removeByParam() 0 14 3
A toArray() 0 3 1
A replaceParam() 0 15 5
1
<?php
2
/**
3
 * Created by Marcin.
4
 * Date: 16.06.2018
5
 * Time: 19:05
6
 */
7
declare(strict_types=1);
8
9
namespace Mrcnpdlk\Lib\UrlSearchParser\Criteria;
10
11
use function array_key_exists;
12
use ArrayIterator;
13
use function gettype;
14
use function in_array;
15
use function is_array;
16
use function is_string;
17
use IteratorAggregate;
18
use Mrcnpdlk\Lib\UrlSearchParser\Exception\InvalidParamException;
19
use Traversable;
20
21
/**
22
 * Class Filter
23
 */
24
class Filter implements IteratorAggregate
25
{
26
    public const DELIMITER = ',';
27
28
    public const PARAM_EQ         = 'eq';
29
    public const PARAM_GT         = 'gt';
30
    public const PARAM_GTE        = 'gte';
31
    public const PARAM_LT         = 'lt';
32
    public const PARAM_LTE        = 'lte';
33
    public const PARAM_LIKE       = 'like';
34
    public const PARAM_LIKE_RIGHT = 'rlike';
35
    public const PARAM_LIKE_LEFT  = 'llike';
36
    public const PARAM_IN         = 'in';
37
    public const PARAM_NOTIN      = 'notin';
38
    public const PARAM_NULL       = 'null';
39
    public const PARAM_NOTNULL    = 'notnull';
40
    public const PARAM_NOT        = 'not';
41
    public const PARAM_REGEXP     = 'reg';
42
43
    /**
44
     * @var array<string,string|null>
45
     */
46
    public static $allowedOperators = [
47
        self::PARAM_EQ         => '=',
48
        self::PARAM_GT         => '>',
49
        self::PARAM_GTE        => '>=',
50
        self::PARAM_LT         => '<',
51
        self::PARAM_LTE        => '<=',
52
        self::PARAM_LIKE       => 'like',
53
        self::PARAM_LIKE_RIGHT => 'like',
54
        self::PARAM_LIKE_LEFT  => 'like',
55
        self::PARAM_IN         => null,
56
        self::PARAM_NOTIN      => null,
57
        self::PARAM_NULL       => null,
58
        self::PARAM_NOTNULL    => null,
59
        self::PARAM_NOT        => '!=',
60
        self::PARAM_REGEXP     => 'regexp',
61
    ];
62
63
    /**
64
     * @var \Mrcnpdlk\Lib\UrlSearchParser\Criteria\FilterParam[]
65
     */
66
    private $filters = [];
67
68
    /**
69
     * Filter constructor.
70
     *
71
     * @param array|FilterParam[] $filterArray
72
     *
73
     * @throws \Mrcnpdlk\Lib\UrlSearchParser\Exception\InvalidParamException
74
     *
75
     * @todo Check PLUS sign in string %2B code
76
     */
77 25
    public function __construct($filterArray = [])
78
    {
79 25
        if (!is_array($filterArray)) {
0 ignored issues
show
introduced by
The condition is_array($filterArray) is always true.
Loading history...
80 1
            throw new InvalidParamException(sprintf('FILTER params are invalid. Is [%s], Array expected', gettype($filterArray)));
81
        }
82
83
        /** @var FilterParam|string|array<string,string> $filters */
84 24
        foreach ($filterArray as $param => $filters) {
85 8
            if ($filters instanceof FilterParam) {
86 3
                $this->appendParam($filters);
87 3
                continue;
88
            }
89
90 8
            if (!is_string($param)) {
91 2
                throw new InvalidParamException(sprintf('Key in FILTER param is not a string'));
92
            }
93 6
            if (is_array($filters)) {
94
                /** @var string $operator */
95 6
                foreach ($filters as $operator => $value) {
96 6
                    if (!array_key_exists($operator, self::$allowedOperators)) {
97 2
                        throw new InvalidParamException(sprintf('Operator [%s] in FILTER is not allowed', $operator));
98
                    }
99 4
                    if (in_array($operator, [self::PARAM_IN, self::PARAM_NOTIN], true)) {
100 1
                        $value = '' === $value ? [] : explode(self::DELIMITER, $value);
101
                    }
102 4
                    if (in_array($operator, [self::PARAM_NULL, self::PARAM_NOTNULL], true)) {
103 1
                        $value = null;
104
                    }
105 4
                    $this->appendParam(new FilterParam($param, $operator, $value));
106
                }
107 1
            } elseif (is_string($filters)) {
108 4
                $this->appendParam(new FilterParam($param, self::PARAM_EQ, $filters));
109
            }
110
        }
111 20
    }
112
113
    /**
114
     * @param \Mrcnpdlk\Lib\UrlSearchParser\Criteria\FilterParam $filterParam
115
     *
116
     * @return \Mrcnpdlk\Lib\UrlSearchParser\Criteria\Filter<\Mrcnpdlk\Lib\UrlSearchParser\Criteria\FilterParam>
117
     */
118 4
    public function appendParam(FilterParam $filterParam): Filter
119
    {
120 4
        $this->filters[] = $filterParam;
121
122 4
        return $this;
123
    }
124
125
    /**
126
     * @param string $paramName
127
     *
128
     * @throws \Mrcnpdlk\Lib\UrlSearchParser\Exception\InvalidParamException
129
     *
130
     * @return \Mrcnpdlk\Lib\UrlSearchParser\Criteria\Filter<\Mrcnpdlk\Lib\UrlSearchParser\Criteria\FilterParam>
131
     */
132 2
    public function getByParam(string $paramName): Filter
133
    {
134 2
        $params = [];
135 2
        foreach ($this as $item) {
136 2
            if ($item->param === $paramName) {
137 2
                $params[] = $item;
138
            }
139
        }
140
141 2
        return new self($params);
142
    }
143
144
    /**
145
     * Retrieve an external iterator
146
     *
147
     * @see   http://php.net/manual/en/iteratoraggregate.getiterator.php
148
     *
149
     * @return Traversable<\Mrcnpdlk\Lib\UrlSearchParser\Criteria\FilterParam> An instance of an object implementing <b>Iterator</b> or
150
     *                                                                         <b>Traversable</b>
151
     *
152
     * @since 5.0.0
153
     */
154 4
    public function getIterator(): Traversable
155
    {
156 4
        return new ArrayIterator($this->filters);
157
    }
158
159
    /**
160
     * @param string $paramName
161
     *
162
     * @throws \Mrcnpdlk\Lib\UrlSearchParser\Exception\InvalidParamException
163
     *
164
     * @return \Mrcnpdlk\Lib\UrlSearchParser\Criteria\Filter Return removed part of filters
165
     */
166 1
    public function removeByParam(string $paramName): Filter
167
    {
168 1
        $i   = 0;
169 1
        $res = [];
170 1
        foreach ($this->filters as $item) {
171 1
            if ($item->param === $paramName) {
172 1
                $res[] = $item;
173 1
                unset($this->filters[$i]);
174
            }
175 1
            ++$i;
176
        }
177 1
        $this->filters = array_values($this->filters);
178
179 1
        return new self($res);
180
    }
181
182
    /**
183
     * @param \Mrcnpdlk\Lib\UrlSearchParser\Criteria\FilterParam $filterParam
184
     *
185
     * @return \Mrcnpdlk\Lib\UrlSearchParser\Criteria\Filter
186
     */
187 1
    public function replaceParam(FilterParam $filterParam): Filter
188
    {
189 1
        $isChanged = false;
190 1
        foreach ($this->filters as &$filter) {
191 1
            if ($filter->param === $filterParam->param && $filter->operator = $filterParam->operator) {
192 1
                $filter->value = $filterParam->value;
193 1
                $isChanged     = true;
194
            }
195
        }
196 1
        unset($filter);
197 1
        if (!$isChanged) {
198 1
            $this->appendParam($filterParam);
199
        }
200
201 1
        return $this;
202
    }
203
204
    /**
205
     * @return \Mrcnpdlk\Lib\UrlSearchParser\Criteria\FilterParam[]
206
     */
207 20
    public function toArray(): array
208
    {
209 20
        return $this->filters;
210
    }
211
}
212