Completed
Push — master ( 11971b...eeafb3 )
by Nate
01:16
created

QueryHelper   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 290
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 48
lcom 1
cbo 2
dl 0
loc 290
ccs 0
cts 155
cp 0
rs 8.5599
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A conditionToCriteria() 0 15 3
A configure() 0 21 5
A parseBaseParam() 0 18 3
B findParamValue() 0 25 6
A assembleParamValue() 0 16 5
A prepParamValue() 0 25 5
A getJoinType() 0 17 4
A findIdFromObjectArray() 0 8 2
B prependOperator() 0 23 8
A normalizeEmptyValue() 0 10 3
A parseParamOperator() 0 24 4

How to fix   Complexity   

Complex Class

Complex classes like QueryHelper 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 QueryHelper, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://github.com/flipboxfactory/craft-ember/blob/master/LICENSE
6
 * @link       https://github.com/flipboxfactory/craft-ember/
7
 */
8
9
namespace flipbox\craft\ember\helpers;
10
11
use craft\helpers\StringHelper;
12
use yii\db\Query;
13
use yii\db\QueryInterface;
14
15
/**
16
 * @author Flipbox Factory <[email protected]>
17
 * @since 2.0.0
18
 */
19
class QueryHelper
20
{
21
    /**
22
     * @var array
23
     */
24
    protected static $operators = ['not ', '!=', '<=', '>=', '<', '>', '='];
25
26
    /**
27
     * @param $condition
28
     * @return array
29
     */
30
    public static function conditionToCriteria($condition)
31
    {
32
        if (empty($condition)) {
33
            return $condition;
34
        }
35
36
        // Assume it's an id
37
        if (!is_array($condition)) {
38
            $condition = [
39
                'id' => $condition
40
            ];
41
        }
42
43
        return ['where' => ['and', $condition]];
44
    }
45
46
    /**
47
     * @param QueryInterface|Query $query
48
     * @param array $config
49
     * @return QueryInterface
50
     */
51
    public static function configure(QueryInterface $query, $config = []): QueryInterface
52
    {
53
        // Halt
54
        if (empty($config)) {
55
            return $query;
56
        }
57
58
        // Force array
59
        if (!is_array($config)) {
60
            $config = ArrayHelper::toArray($config, [], false);
61
        }
62
63
        // Populate query attributes
64
        foreach ($config as $name => $value) {
65
            if ($query->canSetProperty($name)) {
66
                $query->$name = $value;
67
            }
68
        }
69
70
        return $query;
71
    }
72
73
    /**
74
     * Standard param parsing.
75
     *
76
     * @param $value
77
     * @param $join
78
     * @return bool
79
     */
80
    public static function parseBaseParam(&$value, &$join): bool
81
    {
82
        // Force array
83
        if (!is_array($value)) {
84
            $value = [$value];
85
        }
86
87
        // Get join type ('and' , 'or')
88
        $join = self::getJoinType($value, $join);
89
90
        // Check for object array (via 'id' key)
91
        if ($id = self::findIdFromObjectArray($value)) {
92
            $value = [$id];
93
            return true;
94
        }
95
96
        return false;
97
    }
98
99
    /**
100
     * Attempt to resolve a param value by the value.
101
     * Return false if a 'handle' or other string identifier is detected.
102
     *
103
     * @param $value
104
     * @param $operator
105
     * @return bool
106
     */
107
    public static function findParamValue(&$value, &$operator): bool
108
    {
109
        if (is_array($value) || is_object($value)) {
110
            $value = static::assembleParamValue($value, $operator);
111
        } else {
112
            self::normalizeEmptyValue($value);
113
114
            $operator = self::parseParamOperator($value);
115
116
            if (is_numeric($value)) {
117
                $value = self::prependOperator($value, $operator);
118
            } else {
119
                $value = StringHelper::toLowerCase($value);
120
121
                if ($value !== ':empty:' || $value !== 'not :empty:') {
122
                    // Trim any whitespace from the value
123
                    $value = StringHelper::trim($value);
124
125
                    return false;
126
                }
127
            }
128
        }
129
130
        return true;
131
    }
132
133
    /**
134
     * Format the param value so that we return a string w/ a prepended operator.
135
     *
136
     * @param $value
137
     * @param $operator
138
     * @param string|int|mixed $defaultValue
139
     * @return array|string
140
     */
141
    public static function assembleParamValue($value, $operator, $defaultValue = ':default:')
142
    {
143
        if (is_array($value) || is_object($value)) {
144
            $id = self::findIdFromObjectArray($value, $operator);
145
146
            if ($id !== null) {
147
                return self::prependOperator($id, $operator);
148
            }
149
150
            if (is_object($value)) {
151
                return $defaultValue;
152
            }
153
        }
154
155
        return self::prependOperator($value, $operator);
156
    }
157
158
    /**
159
     * Attempt to resolve a param value by the value.
160
     * Return false if a 'handle' or other string identifier is detected.
161
     *
162
     * @param $value
163
     * @param $operator
164
     * @return bool
165
     */
166
    public static function prepParamValue(&$value, &$operator): bool
167
    {
168
169
        if (is_array($value)) {
170
            return true;
171
        } else {
172
            self::normalizeEmptyValue($value);
173
            $operator = self::parseParamOperator($value);
174
175
            if (is_numeric($value)) {
176
                return true;
177
            } else {
178
                $value = StringHelper::toLowerCase($value);
179
180
                if ($value !== ':empty:' || $value !== 'not :empty:') {
181
                    // Trim any whitespace from the value
182
                    $value = StringHelper::trim($value);
183
184
                    return false;
185
                }
186
            }
187
        }
188
189
        return true;
190
    }
191
192
    /**
193
     * @param $value
194
     * @param string $default
195
     * @return mixed|string
196
     */
197
    private static function getJoinType(&$value, $default = 'or')
198
    {
199
200
        // Get first value in array
201
        $joinType = ArrayHelper::firstValue($value);
202
203
        // Make sure first value is a string
204
        $firstVal = is_string($joinType) ? StringHelper::toLowerCase($joinType) : '';
205
206
        if ($firstVal == 'and' || $firstVal == 'or') {
207
            $join = array_shift($value);
208
        } else {
209
            $join = $default;
210
        }
211
212
        return $join;
213
    }
214
215
    /**
216
     * Attempt to get a numeric value from an object array.
217
     * @param $value
218
     * @param null $operator
219
     * @return mixed|string
220
     */
221
    private static function findIdFromObjectArray($value, $operator = null)
222
    {
223
        if ($id = ArrayHelper::getValue($value, 'id')) {
224
            return self::prependOperator($id, $operator);
225
        }
226
227
        return $id;
228
    }
229
230
    /**
231
     * Prepend the operator to a value
232
     *
233
     * @param $value
234
     * @param null $operator
235
     * @return string|array
236
     */
237
    private static function prependOperator($value, $operator = null)
238
    {
239
240
        if ($operator) {
241
            $operator = StringHelper::toLowerCase($operator);
242
243
            if (in_array($operator, static::$operators) || $operator === 'not') {
244
                if (is_array($value)) {
245
                    $values = [];
246
247
                    foreach ($value as $v) {
248
                        $values[] = $operator . ($operator === 'not' ? ' ' : '') . $v;
249
                    }
250
251
                    return $values;
252
                }
253
254
                return $operator . ($operator === 'not' ? ' ' : '') . $value;
255
            }
256
        }
257
258
        return $value;
259
    }
260
261
    /**
262
     * Normalizes “empty” values.
263
     *
264
     * @param string &$value The param value.
265
     */
266
    private static function normalizeEmptyValue(&$value)
267
    {
268
        if ($value === null) {
269
            $value = ':empty:';
270
        } else {
271
            if (StringHelper::toLowerCase($value) == ':notempty:') {
272
                $value = 'not :empty:';
273
            }
274
        }
275
    }
276
277
    /**
278
     * Extracts the operator from a DB param and returns it.
279
     *
280
     * @param string &$value Te param value.
281
     *
282
     * @return string The operator.
283
     */
284
    private static function parseParamOperator(&$value)
285
    {
286
        foreach (static::$operators as $testOperator) {
287
            // Does the value start with this operator?
288
            $operatorLength = strlen($testOperator);
289
290
            if (strncmp(
291
                StringHelper::toLowerCase($value),
292
                $testOperator,
293
                $operatorLength
294
            ) == 0
295
            ) {
296
                $value = mb_substr($value, $operatorLength);
297
298
                if ($testOperator == 'not ') {
299
                    return 'not';
300
                } else {
301
                    return $testOperator;
302
                }
303
            }
304
        }
305
306
        return '';
307
    }
308
}
309