Completed
Push — master ( 5414b4...e2db15 )
by Nate
03:02 queued 01:44
created

QueryHelper   F

Complexity

Total Complexity 66

Size/Duplication

Total Lines 411
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 66
lcom 1
cbo 2
dl 0
loc 411
ccs 0
cts 213
cp 0
rs 3.12
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A conditionToCriteria() 0 15 3
A configure() 0 21 5
B prepareParam() 0 39 10
B prepareParamValue() 0 36 8
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
     * Prepares a query params input value to be used as a condition.  This will attempt to resolve an object
75
     * or look one up based on a 'handle' or other unique string identifier (via the lookup callable).
76
     *
77
     * ```php
78
     *
79
     * [
80
     *      'and',
81
     *      'not' => [
82
     *          4, elementFiveHandle, $someElementWithIdOfSix
83
     *      ]
84
     * ]
85
     * ```
86
     * Would result in a query condition as `NOT IN (4, 5, 6)`.
87
     *
88
     * @param $value
89
     * @param callable|null $lookup
90
     * @return array|string
91
     */
92
    public static function prepareParam($value, callable $lookup = null)
93
    {
94
        if (!is_array($value)) {
95
            // An object (model, element, record)
96
            if (is_object($value)) {
97
                // Try to grab the Id from it
98
                try {
99
                    return $value->id;
100
                } catch (\Exception $e) {
0 ignored issues
show
Unused Code introduced by
catch (\Exception $e) { } does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
101
                    // Carry on
102
                }
103
            }
104
105
            // alpha identifier (handle, etc)
106
            if (is_string($value) &&
107
                !in_array($value, ['and', 'or'], true) &&
108
                StringHelper::isAlpha($value)
109
            ) {
110
                if (null !== $lookup) {
111
                    if (null !== ($val = call_user_func($lookup, $value))) {
112
                        return static::prepareParam($val, $lookup);
113
                    }
114
                }
115
            }
116
117
            return $value;
118
        }
119
120
        // Traverse
121
        $return = [];
122
        foreach ($value as $key => $val) {
123
            $return = ArrayHelper::merge(
124
                $return,
125
                static::prepareParamValue($key, $val, $lookup)
126
            );
127
        }
128
129
        return $return;
130
    }
131
132
    /**
133
     * @param $key
134
     * @param $value
135
     * @param callable|null $lookup
136
     * @return array
137
     */
138
    protected static function prepareParamValue($key, $value, callable $lookup = null): array
139
    {
140
        $value = static::prepareParam($value, $lookup);
141
142
        // Move arrays up one level
143
        if (is_array($value)) {
144
            $values = [];
145
146
            $firstVal = strtolower(reset($value));
147
148
            foreach ($value as $k => $val) {
149
                $values = ArrayHelper::merge(
150
                    $values,
151
                    static::prepareParamValue(
152
                        is_numeric($k) ? $key : $k,
153
                        $val,
154
                        $lookup
155
                    )
156
                );
157
            }
158
159
            if (in_array($firstVal, ['and', 'or'], true)) {
160
                return [$values];
161
            }
162
163
            return $values;
164
        }
165
166
        if (!is_numeric($key)) {
167
            if (is_string($value) || is_numeric($value)) {
168
                $value = $key . ' ' . $value;
169
            }
170
        }
171
172
        return [$value];
173
    }
174
175
176
    /**
177
     * Standard param parsing.
178
     *
179
     * @param $value
180
     * @param $join
181
     * @return bool
182
     *
183
     * @deprecated
184
     */
185
    public static function parseBaseParam(&$value, &$join): bool
186
    {
187
        // Force array
188
        if (!is_array($value)) {
189
            $value = [$value];
190
        }
191
192
        // Get join type ('and' , 'or')
193
        $join = self::getJoinType($value, $join);
0 ignored issues
show
Deprecated Code introduced by
The method flipbox\craft\ember\help...ryHelper::getJoinType() has been deprecated.

This method has been deprecated.

Loading history...
194
195
        // Check for object array (via 'id' key)
196
        if ($id = self::findIdFromObjectArray($value)) {
0 ignored issues
show
Deprecated Code introduced by
The method flipbox\craft\ember\help...findIdFromObjectArray() has been deprecated.

This method has been deprecated.

Loading history...
197
            $value = [$id];
198
            return true;
199
        }
200
201
        return false;
202
    }
203
204
    /**
205
     * Attempt to resolve a param value by the value.
206
     * Return false if a 'handle' or other string identifier is detected.
207
     *
208
     * @param $value
209
     * @param $operator
210
     * @return bool
211
     *
212
     * @deprecated
213
     */
214
    public static function findParamValue(&$value, &$operator): bool
215
    {
216
        if (is_array($value) || is_object($value)) {
217
            $value = static::assembleParamValue($value, $operator);
0 ignored issues
show
Deprecated Code introduced by
The method flipbox\craft\ember\help...r::assembleParamValue() has been deprecated.

This method has been deprecated.

Loading history...
218
        } else {
219
            self::normalizeEmptyValue($value);
0 ignored issues
show
Deprecated Code introduced by
The method flipbox\craft\ember\help...::normalizeEmptyValue() has been deprecated.

This method has been deprecated.

Loading history...
220
221
            $operator = self::parseParamOperator($value);
0 ignored issues
show
Deprecated Code introduced by
The method flipbox\craft\ember\help...r::parseParamOperator() has been deprecated.

This method has been deprecated.

Loading history...
222
223
            if (is_numeric($value)) {
224
                $value = self::prependOperator($value, $operator);
0 ignored issues
show
Deprecated Code introduced by
The method flipbox\craft\ember\help...lper::prependOperator() has been deprecated.

This method has been deprecated.

Loading history...
225
            } else {
226
                $value = StringHelper::toLowerCase($value);
227
228
                if ($value !== ':empty:' || $value !== 'not :empty:') {
229
                    // Trim any whitespace from the value
230
                    $value = StringHelper::trim($value);
231
232
                    return false;
233
                }
234
            }
235
        }
236
237
        return true;
238
    }
239
240
    /**
241
     * Format the param value so that we return a string w/ a prepended operator.
242
     *
243
     * @param $value
244
     * @param $operator
245
     * @param string|int|mixed $defaultValue
246
     * @return array|string
247
     *
248
     * @deprecated
249
     */
250
    public static function assembleParamValue($value, $operator, $defaultValue = ':default:')
251
    {
252
        if (is_array($value) || is_object($value)) {
253
            $id = self::findIdFromObjectArray($value, $operator);
0 ignored issues
show
Deprecated Code introduced by
The method flipbox\craft\ember\help...findIdFromObjectArray() has been deprecated.

This method has been deprecated.

Loading history...
254
255
            if ($id !== null) {
256
                return self::prependOperator($id, $operator);
0 ignored issues
show
Deprecated Code introduced by
The method flipbox\craft\ember\help...lper::prependOperator() has been deprecated.

This method has been deprecated.

Loading history...
257
            }
258
259
            if (is_object($value)) {
260
                return $defaultValue;
261
            }
262
        }
263
264
        return self::prependOperator($value, $operator);
0 ignored issues
show
Deprecated Code introduced by
The method flipbox\craft\ember\help...lper::prependOperator() has been deprecated.

This method has been deprecated.

Loading history...
265
    }
266
267
    /**
268
     * Attempt to resolve a param value by the value.
269
     * Return false if a 'handle' or other string identifier is detected.
270
     *
271
     * @param $value
272
     * @param $operator
273
     * @return bool
274
     *
275
     * @deprecated
276
     */
277
    public static function prepParamValue(&$value, &$operator): bool
278
    {
279
280
        if (is_array($value)) {
281
            return true;
282
        } else {
283
            self::normalizeEmptyValue($value);
0 ignored issues
show
Deprecated Code introduced by
The method flipbox\craft\ember\help...::normalizeEmptyValue() has been deprecated.

This method has been deprecated.

Loading history...
284
            $operator = self::parseParamOperator($value);
0 ignored issues
show
Deprecated Code introduced by
The method flipbox\craft\ember\help...r::parseParamOperator() has been deprecated.

This method has been deprecated.

Loading history...
285
286
            if (is_numeric($value)) {
287
                return true;
288
            } else {
289
                $value = StringHelper::toLowerCase($value);
290
291
                if ($value !== ':empty:' || $value !== 'not :empty:') {
292
                    // Trim any whitespace from the value
293
                    $value = StringHelper::trim($value);
294
295
                    return false;
296
                }
297
            }
298
        }
299
300
        return true;
301
    }
302
303
    /**
304
     * @param $value
305
     * @param string $default
306
     * @return mixed|string
307
     *
308
     * @deprecated
309
     */
310
    private static function getJoinType(&$value, $default = 'or')
311
    {
312
313
        // Get first value in array
314
        $joinType = ArrayHelper::firstValue($value);
315
316
        // Make sure first value is a string
317
        $firstVal = is_string($joinType) ? StringHelper::toLowerCase($joinType) : '';
318
319
        if ($firstVal == 'and' || $firstVal == 'or') {
320
            $join = array_shift($value);
321
        } else {
322
            $join = $default;
323
        }
324
325
        return $join;
326
    }
327
328
    /**
329
     * Attempt to get a numeric value from an object array.
330
     * @param $value
331
     * @param null $operator
332
     * @return mixed|string
333
     *
334
     * @deprecated
335
     */
336
    private static function findIdFromObjectArray($value, $operator = null)
337
    {
338
        if ($id = ArrayHelper::getValue($value, 'id')) {
339
            return self::prependOperator($id, $operator);
0 ignored issues
show
Deprecated Code introduced by
The method flipbox\craft\ember\help...lper::prependOperator() has been deprecated.

This method has been deprecated.

Loading history...
340
        }
341
342
        return $id;
343
    }
344
345
    /**
346
     * Prepend the operator to a value
347
     *
348
     * @param $value
349
     * @param null $operator
350
     * @return string|array
351
     *
352
     * @deprecated
353
     */
354
    private static function prependOperator($value, $operator = null)
355
    {
356
357
        if ($operator) {
358
            $operator = StringHelper::toLowerCase($operator);
359
360
            if (in_array($operator, static::$operators) || $operator === 'not') {
361
                if (is_array($value)) {
362
                    $values = [];
363
364
                    foreach ($value as $v) {
365
                        $values[] = $operator . ($operator === 'not' ? ' ' : '') . $v;
366
                    }
367
368
                    return $values;
369
                }
370
371
                return $operator . ($operator === 'not' ? ' ' : '') . $value;
372
            }
373
        }
374
375
        return $value;
376
    }
377
378
    /**
379
     * Normalizes “empty” values.
380
     *
381
     * @param string &$value The param value.
382
     *
383
     * @deprecated
384
     */
385
    private static function normalizeEmptyValue(&$value)
386
    {
387
        if ($value === null) {
388
            $value = ':empty:';
389
        } else {
390
            if (StringHelper::toLowerCase($value) == ':notempty:') {
391
                $value = 'not :empty:';
392
            }
393
        }
394
    }
395
396
    /**
397
     * Extracts the operator from a DB param and returns it.
398
     *
399
     * @param string &$value Te param value.
400
     *
401
     * @return string The operator.
402
     *
403
     * @deprecated
404
     */
405
    private static function parseParamOperator(&$value)
406
    {
407
        foreach (static::$operators as $testOperator) {
408
            // Does the value start with this operator?
409
            $operatorLength = strlen($testOperator);
410
411
            if (strncmp(
412
                StringHelper::toLowerCase($value),
413
                $testOperator,
414
                $operatorLength
415
            ) == 0
416
            ) {
417
                $value = mb_substr($value, $operatorLength);
418
419
                if ($testOperator == 'not ') {
420
                    return 'not';
421
                } else {
422
                    return $testOperator;
423
                }
424
            }
425
        }
426
427
        return '';
428
    }
429
}
430