Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
98.08% |
51 / 52 |
|
90.00% |
9 / 10 |
CRAP | |
0.00% |
0 / 1 |
Filter | |
98.08% |
51 / 52 |
|
90.00% |
9 / 10 |
29 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
create | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
__toString | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
empty | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
params | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
parse | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
parseQueryFilters | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
5 | |||
filterGroupToFilterString | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
buildFilterWithParams | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
createFilterWithParams | |
94.74% |
18 / 19 |
|
0.00% |
0 / 1 |
16.04 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace Projom\Storage\SQL\Component; |
6 | |
7 | use Projom\Storage\SQL\Component\ComponentInterface; |
8 | use Projom\Storage\SQL\Component\Column; |
9 | use Projom\Storage\SQL\Component\Filter\Between; |
10 | use Projom\Storage\SQL\Component\Filter\In; |
11 | use Projom\Storage\SQL\Component\Filter\Nullable; |
12 | use Projom\Storage\SQL\Component\Filter\Standard; |
13 | use Projom\Storage\SQL\Component\Filter\Util; |
14 | use Projom\Storage\SQL\Util\Operator; |
15 | |
16 | class Filter implements ComponentInterface |
17 | { |
18 | private readonly string $filter; |
19 | private readonly array $params; |
20 | |
21 | private int $filterID = 0; |
22 | |
23 | public function __construct(array $queryFilters) |
24 | { |
25 | $this->parse($queryFilters); |
26 | } |
27 | |
28 | public static function create(array $queryFilters): Filter |
29 | { |
30 | return new Filter($queryFilters); |
31 | } |
32 | |
33 | public function __toString(): string |
34 | { |
35 | return $this->filter; |
36 | } |
37 | |
38 | public function empty(): bool |
39 | { |
40 | return empty($this->filter); |
41 | } |
42 | |
43 | public function params(): array |
44 | { |
45 | return $this->params; |
46 | } |
47 | |
48 | private function parse(array $queryFilters): void |
49 | { |
50 | [$filterGroups, $filterParams] = $this->parseQueryFilters($queryFilters); |
51 | |
52 | $filter = Util::join($filterGroups, ' '); |
53 | |
54 | // Remove empty params and set. |
55 | $filterParams = Util::removeEmpty($filterParams); |
56 | $params = Util::flatten($filterParams); |
57 | |
58 | $this->filter = $filter; |
59 | $this->params = $params; |
60 | } |
61 | |
62 | private function parseQueryFilters(array $queryFilters): array |
63 | { |
64 | $filterGroups = []; |
65 | $filterParams = []; |
66 | |
67 | foreach ($queryFilters as [$queryFilterList, $outerLogicalOperator]) { |
68 | |
69 | $filterGroup = []; |
70 | foreach ($queryFilterList as [$field, $operator, $value, $innerLogicalOperator]) { |
71 | |
72 | [$filter, $params] = $this->buildFilterWithParams($field, $operator, $value); |
73 | |
74 | if ($filterGroup) |
75 | $filterGroup[] = $innerLogicalOperator->value; |
76 | |
77 | $filterGroup[] = $filter; |
78 | $filterParams[] = $params; |
79 | } |
80 | |
81 | if ($filterGroups) |
82 | $filterGroups[] = $outerLogicalOperator->value; |
83 | |
84 | $filterGroups[] = $this->filterGroupToFilterString($filterGroup); |
85 | } |
86 | |
87 | $filterGroups = Util::addParentheses($filterGroups); |
88 | |
89 | return [$filterGroups, $filterParams]; |
90 | } |
91 | |
92 | private function filterGroupToFilterString(array $filterGroup): string |
93 | { |
94 | $filterGroupString = Util::join($filterGroup, ' '); |
95 | $filterGroupString = "( $filterGroupString )"; |
96 | return $filterGroupString; |
97 | } |
98 | |
99 | private function buildFilterWithParams(string $field, Operator $operator, mixed $value): array |
100 | { |
101 | $this->filterID++; |
102 | $column = Column::create([$field]); |
103 | [$filter, $params] = $this->createFilterWithParams($column, $operator, $value); |
104 | |
105 | return [$filter, $params]; |
106 | } |
107 | |
108 | private function createFilterWithParams(Column $column, Operator $operator, mixed $value): array |
109 | { |
110 | switch ($operator) { |
111 | case Operator::IS_NULL: |
112 | case Operator::IS_NOT_NULL: |
113 | return Nullable::create($column, $operator); |
114 | |
115 | case Operator::IN: |
116 | case Operator::NOT_IN: |
117 | return In::create($column, $operator, $value, $this->filterID); |
118 | |
119 | case Operator::EQ: |
120 | case Operator::NE: |
121 | case Operator::GT: |
122 | case Operator::GTE: |
123 | case Operator::LT: |
124 | case Operator::LTE: |
125 | case Operator::LIKE: |
126 | case Operator::NOT_LIKE: |
127 | return Standard::create($column, $operator, $value, $this->filterID); |
128 | |
129 | case Operator::BETWEEN: |
130 | case Operator::NOT_BETWEEN: |
131 | return Between::create($column, $operator, $value, $this->filterID); |
132 | |
133 | |
134 | default: |
135 | throw new \Exception("Operator not implemented: {$operator->value}", 400); |
136 | } |
137 | } |
138 | } |