Passed
Push — master ( 0272f5...3a0c5f )
by Aleksandr
28:04 queued 25:53
created

Config::createExpression()   B

Complexity

Conditions 11
Paths 11

Size

Total Lines 45
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 11.0061

Importance

Changes 0
Metric Value
cc 11
eloc 34
nc 11
nop 3
dl 0
loc 45
ccs 26
cts 27
cp 0.963
crap 11.0061
rs 7.3166
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * This file is part of the eav package.
4
 * @author    Aleksandr Drobotik <[email protected]>
5
 * @copyright 2023 Aleksandr Drobotik
6
 * @license   https://opensource.org/license/mit  The MIT License
7
 */
8
declare(strict_types=1);
9
10
namespace Drobotik\Eav\QueryBuilder;
11
12
use Drobotik\Eav\Enum\_ATTR;
13
use Drobotik\Eav\Enum\ATTR_TYPE;
14
use Drobotik\Eav\Enum\QB_CONDITION;
15
use Drobotik\Eav\Enum\QB_CONFIG;
16
use Drobotik\Eav\Enum\QB_JOIN;
17
use Drobotik\Eav\Enum\QB_OPERATOR;
18
use Drobotik\Eav\Exception\QueryBuilderException;
19
use Drobotik\Eav\Value\ValueEmpty;
20
use InvalidArgumentException;
21
22
class Config
23
{
24
    // :domainKey
25
    private string $domainKeyParam;
26
    // :setKey
27
    private string $setKeyParam;
28
    // joins which will be performed
29
    private array $joins = [];
30
    // eav attributes array for internal usage to not allow wrong fields to query
31
    private array $attributes = [];
32
    // result columns which should be visible on grid
33
    private array $columns = [];
34
    // fields that need to be in the SELECT statement
35
    private array $selected = [];
36
    // query bind parameters with values
37
    private array $parameters = [];
38
    // query expressions recursive array
39
    /** @var Expression[] $expressions */
40
    private array $expressions = [];
41
42 1
    public function getDomainKeyParam() : string
43
    {
44 1
        return $this->domainKeyParam;
45
    }
46
47 1
    public function setDomainKey(int $key) : void
48
    {
49 1
        $paramName = $this->createParameter('domainKey', $key);
50 1
        $this->domainKeyParam = $paramName;
51
    }
52
53 1
    public function getSetKeyParam() : string
54
    {
55 1
        return $this->setKeyParam;
56
    }
57
58 1
    public function setSetKey(int $key) : void
59
    {
60 1
        $paramName = $this->createParameter('setKey', $key);
61 1
        $this->setKeyParam = $paramName;
62
    }
63
64 1
    public function hasJoin(string $name) : bool
65
    {
66 1
        return key_exists($name, $this->joins);
67
    }
68
69 1
    public function addJoin(string $table, string $name, int $attrKey) : void
70
    {
71 1
        $paramName = $this->createParameter(
72 1
            sprintf('%s_join_%s', $name, QB_JOIN::ATTR_PARAM), $attrKey);
73
74 1
        $this->joins[$name] = [
75 1
            QB_JOIN::NAME => $name,
76 1
            QB_JOIN::TABLE => $table,
77 1
            QB_JOIN::ATTR_PARAM => $paramName
78 1
        ];
79
    }
80
81 1
    public function getJoins() : array
82
    {
83 1
        return $this->joins;
84
    }
85
86 1
    public function getJoin(string $name) : array
87
    {
88 1
        return $this->joins[$name];
89
    }
90
91 2
    public function addColumns(array $columns) : void
92
    {
93 2
        $this->columns = array_values(array_unique($columns));
94
    }
95
96 2
    public function getColumns() : array
97
    {
98 2
        return $this->columns;
99
    }
100
101 1
    public function addAttributes(array $attributes) : void
102
    {
103 1
        foreach ($attributes as $attribute)
104 1
            $this->addAttribute($attribute);
105
    }
106
107 1
    public function getAttributes(): array
108
    {
109 1
        return $this->attributes;
110
    }
111
112 1
    public function addAttribute(array $attribute): void
113
    {
114 1
        $this->attributes[$attribute[_ATTR::NAME]] = $attribute;
115
    }
116
117 1
    public function getAttribute(string $name) : array
118
    {
119 1
        return $this->attributes[$name];
120
    }
121
122 1
    public function hasAttribute(string $name) : bool
123
    {
124 1
        return key_exists($name, $this->attributes);
125
    }
126
127 1
    public function addSelect(string $field) : void
128
    {
129 1
        $this->selected[] = $field;
130
    }
131
132 2
    public function getSelected() : array
133
    {
134 2
        $selected = $this->selected;
135 2
        $columns = $this->getColumns();
136 2
        usort($selected, function ($a, $b) use ( $columns) {
137 1
            $indexA = array_search($a, $columns);
138 1
            $indexB = array_search($b, $columns);
139 1
            return $indexA - $indexB;
140 2
        });
141 2
        $selected = array_unique($selected);
142 2
        return array_merge(array_intersect($columns, $selected), array_diff($selected, $columns));
143
    }
144 1
    public function isSelected(string $field) : bool
145
    {
146 1
        return in_array($field, $this->selected);
147
    }
148
149 1
    public function hasParameter(string $name): bool
150
    {
151 1
        return key_exists($name, $this->parameters);
152
    }
153
154 1
    public function getParameterValue(string $name) : mixed
155
    {
156 1
        return $this->parameters[$name];
157
    }
158
159 2
    public function createParameter(string $name, mixed $value) : string
160
    {
161 2
        if($this->hasParameter($name)) {
162 1
            $uniqueName = sprintf('%s_%s', $name, substr(md5(uniqid()), 0, 5));
163 1
            return $this->createParameter($uniqueName, $value);
164
        } else {
165 2
            $this->parameters[$name] = $value;
166
        }
167 2
        return $name;
168
    }
169
170 1
    public function getParameters() : array
171
    {
172 1
        return $this->parameters;
173
    }
174
175 1
    public function getExpressions() : array
176
    {
177 1
        return $this->expressions;
178
    }
179
180 3
    public function handleColumns(): void
181
    {
182 3
        foreach($this->getColumns() as $column)
183
        {
184 3
            if (!$this->hasAttribute($column)) {
185 1
                QueryBuilderException::unsupportedAttribute($column);
186
            }
187
188 2
            $attribute = $this->getAttribute($column);
189 2
            $attributeKey = $attribute[_ATTR::ID];
190 2
            $table = ATTR_TYPE::valueTable(ATTR_TYPE::getCase($attribute[_ATTR::TYPE]));
191
192
            // if in search it should be joined
193 1
            if(!$this->hasJoin($column)) {
194 1
                $this->addJoin($table, $column, $attributeKey);
195 1
                if(!$this->isSelected($column)) {
196 1
                    $this->addSelect($column);
197
                }
198
            }
199
        }
200
    }
201
202 2
    public function handleGroup(array $group) : array
203
    {
204 2
        $result = [];
205 2
        $result[] = QB_CONDITION::getCase($group[QB_CONFIG::CONDITION]);
206 1
        $rules = $group[QB_CONFIG::RULES];
207 1
        foreach($rules as $rule)
208
        {
209 1
            if (key_exists(QB_CONFIG::CONDITION, $rule)) {
210 1
                $result[] = $this->handleGroup($rule);
211
            }
212
            else {
213 1
                $result[] = $this->handleRule($rule);
214
            }
215
        }
216 1
        return $result;
217
    }
218
219 5
    public function createExpression(string $field, $operator, mixed $value) : Expression
220
    {
221 5
        $operator = QB_OPERATOR::getCase($operator);
222 5
        $expression = new Expression();
223 5
        $expression->setField($field);
224 5
        $expression->setOperator($operator);
225
226 5
        if(QB_OPERATOR::isBetween($operator)) {
227 1
            $value1 = $value[0];
228 1
            $value2 = $value[1];
229 1
            $param1 = $this->createParameter($field .'_cond_1', $value1);
230 1
            $param2 = $this->createParameter($field .'_cond_2', $value2);
231 1
            $expression->setParam1($param1);
232 1
            $expression->setParam2($param2);
233
234 4
        } else if(QB_OPERATOR::isEmpty($operator)) {
235 1
            $param = $this->createParameter($field .'_cond', '');
236 1
            $expression->setParam1($param);
237
238 3
        } else if(!QB_OPERATOR::isNull($operator)) {
239 2
            if(QB_OPERATOR::isLike($operator)) {
240
                switch ($operator) {
241
                    case QB_OPERATOR::BEGINS_WITH:
242
                    case QB_OPERATOR::NOT_BEGINS_WITH:
243 1
                        $value = $value . '%';
244 1
                        break;
245
246
                    case QB_OPERATOR::CONTAINS:
247
                    case QB_OPERATOR::NOT_CONTAINS:
248 1
                        $value = '%' . $value . '%';
249 1
                        break;
250
251
                    case QB_OPERATOR::ENDS_WITH:
252
                    case QB_OPERATOR::NOT_ENDS_WITH:
253 1
                        $value = '%' . $value;
254 1
                        break;
255
                    default:
256
                        throw new InvalidArgumentException("Unhandled operator: " . $operator);
257
                }
258
            }
259 2
            $param = $this->createParameter($field .'_cond', $value);
260 2
            $expression->setParam1($param);
261
        }
262
263 5
        return $expression;
264
    }
265
266 2
    public function registerSelect(string $field) : void
267
    {
268 2
        if(!$this->isSelected($field)) {
269 1
            $this->addSelect($field);
270
        }
271
    }
272
273 3
    public function registerJoin(string $field) : void
274
    {
275 3
        if(!$this->hasJoin($field)) {
276 2
            $attribute = $this->getAttribute($field);
277 2
            $table = ATTR_TYPE::valueTable(ATTR_TYPE::getCase($attribute[_ATTR::TYPE]));
278 1
            $attributeKey = $attribute[_ATTR::ID];
279 1
            $this->addJoin($table, $field, $attributeKey);
280
        }
281
    }
282
283 3
    public function handleRule(array $rule) : Expression
284
    {
285 3
        $field = $rule[QB_CONFIG::NAME];
286 3
        $operator = QB_OPERATOR::getCase($rule[QB_CONFIG::OPERATOR]);
287 2
        $value = key_exists(QB_CONFIG::VALUE, $rule)
288 1
            ? $rule[QB_CONFIG::VALUE]
289 1
            : new ValueEmpty();
290
291 2
        $this->registerSelect($field);
292 2
        $this->registerJoin($field);
293
294 2
        return $this->createExpression($field, $operator, $value);
295
    }
296
297 2
    public function parse(array $config) : void
298
    {
299 2
        if(empty($config))
300 1
            return;
301
302 1
        $this->expressions = $this->handleGroup($config);
303
    }
304
305
}