Completed
Branch develop (9e5d0f)
by Nate
01:59
created

QueryHelper::assembleParamValue()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 16
ccs 0
cts 13
cp 0
rs 8.8571
c 1
b 0
f 0
cc 5
eloc 8
nc 4
nop 3
crap 30
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\ember\helpers;
10
11
use craft\helpers\ArrayHelper;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, flipbox\ember\helpers\ArrayHelper.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
12
use craft\helpers\StringHelper;
13
use yii\db\Query;
14
use yii\db\QueryInterface;
15
16
/**
17
 * @author Flipbox Factory <[email protected]>
18
 * @since 1.0.0
19
 */
20
class QueryHelper
21
{
22
    /**
23
     * @var array
24
     */
25
    protected static $operators = ['not ', '!=', '<=', '>=', '<', '>', '='];
26
27
    /**
28
     * @param QueryInterface|Query $query
29
     * @param array $config
30
     * @return QueryInterface
31
     */
32
    public static function configure(QueryInterface $query, $config = []): QueryInterface
33
    {
34
        // Halt
35
        if (empty($config)) {
36
            return $query;
37
        }
38
39
        // Force array
40
        if (!is_array($config)) {
41
            $config = ArrayHelper::toArray($config, [], false);
42
        }
43
44
        // Populate query attributes
45
        foreach ($config as $name => $value) {
46
            if ($query->canSetProperty($name)) {
47
                $query->$name = $value;
48
            }
49
        }
50
51
        return $query;
52
    }
53
54
    /**
55
     * Standard param parsing.
56
     *
57
     * @param $value
58
     * @param $join
59
     * @return bool
60
     */
61
    public static function parseBaseParam(&$value, &$join): bool
62
    {
63
        // Force array
64
        if (!is_array($value)) {
65
            $value = [$value];
66
        }
67
68
        // Get join type ('and' , 'or')
69
        $join = static::getJoinType($value, $join);
0 ignored issues
show
Bug introduced by
Since getJoinType() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of getJoinType() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
70
71
        // Check for object array (via 'id' key)
72
        if ($id = static::findIdFromObjectArray($value)) {
0 ignored issues
show
Bug introduced by
Since findIdFromObjectArray() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of findIdFromObjectArray() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
73
            $value = [$id];
74
            return true;
75
        }
76
77
        return false;
78
    }
79
80
    /**
81
     * Attempt to resolve a param value by the value.
82
     * Return false if a 'handle' or other string identifier is detected.
83
     *
84
     * @param $value
85
     * @param $operator
86
     * @return bool
87
     */
88
    public static function findParamValue(&$value, &$operator): bool
89
    {
90
        if (is_array($value) || is_object($value)) {
91
            $value = static::assembleParamValue($value, $operator);
92
        } else {
93
            static::normalizeEmptyValue($value);
0 ignored issues
show
Bug introduced by
Since normalizeEmptyValue() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of normalizeEmptyValue() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
94
95
            $operator = static::parseParamOperator($value);
0 ignored issues
show
Bug introduced by
Since parseParamOperator() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of parseParamOperator() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
96
97
            if (is_numeric($value)) {
98
                $value = static::prependOperator($value, $operator);
0 ignored issues
show
Bug introduced by
Since prependOperator() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of prependOperator() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
99
            } else {
100
                $value = StringHelper::toLowerCase($value);
101
102
                if ($value !== ':empty:' || $value !== 'not :empty:') {
103
                    // Trim any whitespace from the value
104
                    $value = StringHelper::trim($value);
105
106
                    return false;
107
                }
108
            }
109
        }
110
111
        return true;
112
    }
113
114
    /**
115
     * Format the param value so that we return a string w/ a prepended operator.
116
     *
117
     * @param $value
118
     * @param $operator
119
     * @param string|int|mixed $defaultValue
120
     * @return string
121
     */
122
    public static function assembleParamValue($value, $operator, $defaultValue = ':default:')
123
    {
124
        if (is_array($value) || is_object($value)) {
125
            $id = static::findIdFromObjectArray($value, $operator);
0 ignored issues
show
Bug introduced by
Since findIdFromObjectArray() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of findIdFromObjectArray() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
126
127
            if ($id !== null) {
128
                return static::prependOperator($id, $operator);
0 ignored issues
show
Bug introduced by
Since prependOperator() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of prependOperator() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
Bug Compatibility introduced by
The expression static::prependOperator($id, $operator); of type string|array adds the type array to the return on line 128 which is incompatible with the return type documented by flipbox\ember\helpers\Qu...per::assembleParamValue of type string.
Loading history...
129
            }
130
131
            if (is_object($value)) {
132
                return $defaultValue;
133
            }
134
        }
135
136
        return static::prependOperator($value, $operator);
0 ignored issues
show
Bug introduced by
Since prependOperator() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of prependOperator() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
Bug Compatibility introduced by
The expression static::prependOperator($value, $operator); of type string|array adds the type array to the return on line 136 which is incompatible with the return type documented by flipbox\ember\helpers\Qu...per::assembleParamValue of type string.
Loading history...
137
    }
138
139
    /**
140
     * Attempt to resolve a param value by the value.
141
     * Return false if a 'handle' or other string identifier is detected.
142
     *
143
     * @param $value
144
     * @param $operator
145
     * @return bool
146
     */
147
    public static function prepParamValue(&$value, &$operator): bool
148
    {
149
150
        if (is_array($value)) {
151
            return true;
152
        } else {
153
            static::normalizeEmptyValue($value);
0 ignored issues
show
Bug introduced by
Since normalizeEmptyValue() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of normalizeEmptyValue() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
154
            $operator = static::parseParamOperator($value);
0 ignored issues
show
Bug introduced by
Since parseParamOperator() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of parseParamOperator() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
155
156
            if (is_numeric($value)) {
157
                return true;
158
            } else {
159
                $value = StringHelper::toLowerCase($value);
160
161
                if ($value !== ':empty:' || $value !== 'not :empty:') {
162
                    // Trim any whitespace from the value
163
                    $value = StringHelper::trim($value);
164
165
                    return false;
166
                }
167
            }
168
        }
169
170
        return true;
171
    }
172
173
    /**
174
     * @param $value
175
     * @param string $default
176
     * @return mixed|string
177
     */
178
    private static function getJoinType(&$value, $default = 'or')
179
    {
180
181
        // Get first value in array
182
        $joinType = ArrayHelper::firstValue($value);
183
184
        // Make sure first value is a string
185
        $firstVal = is_string($joinType) ? StringHelper::toLowerCase($joinType) : '';
186
187
        if ($firstVal == 'and' || $firstVal == 'or') {
188
            $join = array_shift($value);
189
        } else {
190
            $join = $default;
191
        }
192
193
        return $join;
194
    }
195
196
    /**
197
     * Attempt to get a numeric value from an object array.
198
     * @param $value
199
     * @param null $operator
200
     * @return mixed|string
201
     */
202
    private static function findIdFromObjectArray($value, $operator = null)
203
    {
204
        if ($id = ArrayHelper::getValue($value, 'id')) {
205
            return static::prependOperator($id, $operator);
0 ignored issues
show
Bug introduced by
Since prependOperator() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of prependOperator() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
206
        }
207
208
        return $id;
209
    }
210
211
    /**
212
     * Prepend the operator to a value
213
     *
214
     * @param $value
215
     * @param null $operator
216
     * @return string|array
217
     */
218
    private static function prependOperator($value, $operator = null)
219
    {
220
221
        if ($operator) {
222
            $operator = StringHelper::toLowerCase($operator);
223
224
            if (in_array($operator, static::$operators) || $operator === 'not') {
225
                if (is_array($value)) {
226
                    $values = [];
227
228
                    foreach ($value as $v) {
229
                        $values[] = $operator . ($operator === 'not' ? ' ' : '') . $v;
230
                    }
231
232
                    return $values;
233
                }
234
235
                return $operator . ($operator === 'not' ? ' ' : '') . $value;
236
            }
237
        }
238
239
        return $value;
240
    }
241
242
    /**
243
     * Normalizes “empty” values.
244
     *
245
     * @param string &$value The param value.
246
     */
247
    private static function normalizeEmptyValue(&$value)
248
    {
249
        if ($value === null) {
250
            $value = ':empty:';
251
        } else {
252
            if (StringHelper::toLowerCase($value) == ':notempty:') {
253
                $value = 'not :empty:';
254
            }
255
        }
256
    }
257
258
    /**
259
     * Extracts the operator from a DB param and returns it.
260
     *
261
     * @param string &$value Te param value.
262
     *
263
     * @return string The operator.
264
     */
265
    private static function parseParamOperator(&$value)
266
    {
267
        foreach (static::$operators as $testOperator) {
268
            // Does the value start with this operator?
269
            $operatorLength = strlen($testOperator);
270
271
            if (strncmp(
272
                StringHelper::toLowerCase($value),
273
                $testOperator,
274
                $operatorLength
275
            ) == 0
276
            ) {
277
                $value = mb_substr($value, $operatorLength);
278
279
                if ($testOperator == 'not ') {
280
                    return 'not';
281
                } else {
282
                    return $testOperator;
283
                }
284
            }
285
        }
286
287
        return '';
288
    }
289
}
290