Passed
Push — master ( 61ffee...578120 )
by Aleksandr
13:14
created

Config   A

Complexity

Total Complexity 42

Size/Duplication

Total Lines 247
Duplicated Lines 0 %

Test Coverage

Coverage 86.67%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 102
dl 0
loc 247
ccs 104
cts 120
cp 0.8667
rs 9.0399
c 1
b 0
f 0
wmc 42

27 Methods

Rating   Name   Duplication   Size   Complexity  
A getAttribute() 0 3 1
A getSetKeyParam() 0 3 1
B handleRule() 0 41 7
A addSelect() 0 3 1
A getJoin() 0 3 1
A isSelected() 0 3 1
A getJoins() 0 3 1
A hasParameter() 0 3 1
A getParameterValue() 0 3 1
A getDomainKeyParam() 0 3 1
A addJoin() 0 9 1
A getParameters() 0 3 1
A handleGroup() 0 15 3
A hasJoin() 0 3 1
A setDomainKey() 0 4 1
A hasAttribute() 0 3 1
A createParameter() 0 9 2
A addAttribute() 0 3 1
A getSelected() 0 11 1
A addColumns() 0 3 1
A parse() 0 6 2
A addAttributes() 0 4 2
A getExpressions() 0 3 1
A setSetKey() 0 4 1
A getColumns() 0 3 1
A getAttributes() 0 3 1
A handleColumns() 0 17 5

How to fix   Complexity   

Complex Class

Complex classes like Config often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Config, and based on these observations, apply Extract Interface, too.

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