Passed
Pull Request — master (#154)
by Alex
07:05
created

LaravelExpressionProvider   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 338
Duplicated Lines 10.65 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 36
c 1
b 0
f 0
dl 36
loc 338
ccs 131
cts 131
cp 1
rs 8.8

14 Methods

Rating   Name   Duplication   Size   Complexity  
A setResourceType() 0 4 1
A onPropertyAccessExpression() 0 11 2
A unpackExpressionType() 0 8 2
A onUnaryExpression() 10 10 3
B onArithmeticExpression() 0 16 6
A getResourceType() 0 3 1
A onLogicalExpression() 10 10 3
A prepareUnaryExpression() 0 3 1
A onFunctionCallExpression() 0 9 3
B __construct() 12 78 2
B onRelationalExpression() 0 18 7
A getIteratorName() 0 3 1
A prepareBinaryExpression() 0 3 1
A onConstantExpression() 0 8 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace AlgoWeb\PODataLaravel\Query;
4
5
use POData\Common\ODataConstants;
6
use POData\Providers\Expression\IExpressionProvider;
7
use POData\Providers\Metadata\ResourceType;
8
use POData\Providers\Metadata\Type\IType;
9
use POData\UriProcessor\QueryProcessor\ExpressionParser\Expressions\ExpressionType;
10
use POData\UriProcessor\QueryProcessor\ExpressionParser\Expressions\PropertyAccessExpression;
11
12
class LaravelExpressionProvider implements IExpressionProvider
13
{
14
    const ADD = '+';
15
    const CLOSE_BRACKET = ')';
16
    const COMMA = ',';
17
    const DIVIDE = '/';
18
    const SUBTRACT = '-';
19
    const EQUAL = '==';
20
    const GREATER_THAN = '>';
21
    const GREATER_THAN_OR_EQUAL = '>=';
22
    const LESS_THAN = '<';
23
    const LESS_THAN_OR_EQUAL = '<=';
24
    const LOGICAL_AND = '&&';
25
    const LOGICAL_NOT = '!';
26
    const LOGICAL_OR = '||';
27
    const MEMBER_ACCESS = '->';
28
    const MODULO = '%';
29
    const MULTIPLY = '*';
30
    const NEGATE = '-';
31
    const NOT_EQUAL = '!=';
32
    const OPEN_BRACKET = '(';
33
    const TYPE_NAMESPACE = 'POData\\Providers\\Metadata\\Type\\';
34
35
    private $functionDescriptionParsers;
36
37
    /**
38
     * The name of iterator.
39
     *
40
     * @var string
41
     */
42
    private $iteratorName;
43
    /**
44
     * The type of the resource pointed by the resource path segment.
45
     *
46
     * @var ResourceType
47
     */
48
    private $resourceType;
49 52
50
    public function __construct()
51 52
    {
52
        $this->functionDescriptionParsers[ODataConstants::STRFUN_COMPARE] = function ($params) {
53
            return 'strcmp(' . $params[0] . ', ' . $params[1] . ')';
54
        };
55
        $this->functionDescriptionParsers[ODataConstants::STRFUN_ENDSWITH] = function ($params) {
56
            return '(strcmp(substr(' . $params[0] . ', strlen(' . $params[0] . ') - strlen(' . $params[1] . ')), '
57 1
                   .$params[1] . ') === 0)';
58
        };
59 1
        $this->functionDescriptionParsers[ODataConstants::STRFUN_INDEXOF] = function ($params) {
60
            return 'strpos(' . $params[0] . ', ' . $params[1] . ')';
61
        };
62 View Code Duplication
        $this->functionDescriptionParsers[ODataConstants::STRFUN_REPLACE] = function ($params) {
63
            return 'str_replace(' . $params[1] . ', ' . $params[2] . ', ' . $params[0] . ')';
64
        };
65
        $this->functionDescriptionParsers[ODataConstants::STRFUN_STARTSWITH] = function ($params) {
66
            return '(strpos(' . $params[0] . ', ' . $params[1] . ') === 0)';
67 1
        };
68
        $this->functionDescriptionParsers[ODataConstants::STRFUN_TOLOWER] = function ($params) {
69 1
            return 'strtolower(' . $params[0] . ')';
70 1
        };
71 1
        $this->functionDescriptionParsers[ODataConstants::STRFUN_TOUPPER] = function ($params) {
72
            return 'strtoupper(' . $params[0] . ')';
73
        };
74
        $this->functionDescriptionParsers[ODataConstants::STRFUN_TRIM] = function ($params) {
75
            return 'trim(' . $params[0] . ')';
76
        };
77
        $this->functionDescriptionParsers[ODataConstants::STRFUN_SUBSTRING] = function ($params) {
78
            return count($params) == 3 ?
79
                'substr(' . $params[0] . ', ' . $params[1] . ', ' . $params[2] . ')' : 'substr(' . $params[0] . ', ' . $params[1] . ')';
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 136 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
80
        };
81 3
        $this->functionDescriptionParsers[ODataConstants::STRFUN_SUBSTRINGOF] = function ($params) {
82
            return '(strpos(' . $params[1] . ', ' . $params[0] . ') !== false)';
83
        };
84 3
        $this->functionDescriptionParsers[ODataConstants::STRFUN_CONCAT] = function ($params) {
85 1
            return $params[0] . ' . ' . $params[1];
86 2
        };
87 1
        $this->functionDescriptionParsers[ODataConstants::STRFUN_LENGTH] = function ($params) {
88 1
            return 'strlen(' . $params[0] . ')';
89 1
        };
90 1 View Code Duplication
        $this->functionDescriptionParsers[ODataConstants::GUIDFUN_EQUAL] = function ($params) {
91
            return self::TYPE_NAMESPACE . 'Guid::guidEqual(' . $params[0] . ', ' . $params[1] . ')';
92
        };
93 View Code Duplication
        $this->functionDescriptionParsers[ODataConstants::DATETIME_COMPARE] = function ($params) {
94
            return self::TYPE_NAMESPACE . 'DateTime::dateTimeCmp(' . $params[0] . ', ' . $params[1] . ')';
95
        };
96
        $this->functionDescriptionParsers[ODataConstants::DATETIME_YEAR] = function ($params) {
97
            return self::TYPE_NAMESPACE . 'DateTime::year(' . $params[0] . ')';
98
        };
99
        $this->functionDescriptionParsers[ODataConstants::DATETIME_MONTH] = function ($params) {
100
            return self::TYPE_NAMESPACE . 'DateTime::month(' . $params[0] . ')';
101 6
        };
102
        $this->functionDescriptionParsers[ODataConstants::DATETIME_DAY] = function ($params) {
103
            return self::TYPE_NAMESPACE . 'DateTime::day(' . $params[0] . ')';
104 6
        };
105 1
        $this->functionDescriptionParsers[ODataConstants::DATETIME_HOUR] = function ($params) {
106 5
            return self::TYPE_NAMESPACE . 'DateTime::hour(' . $params[0] . ')';
107 1
        };
108 4
        $this->functionDescriptionParsers[ODataConstants::DATETIME_MINUTE] = function ($params) {
109 1
            return self::TYPE_NAMESPACE . 'DateTime::minute(' . $params[0] . ')';
110 3
        };
111 1
        $this->functionDescriptionParsers[ODataConstants::DATETIME_SECOND] = function ($params) {
112 2
            return self::TYPE_NAMESPACE . 'DateTime::second(' . $params[0] . ')';
113 1
        };
114 1
        $this->functionDescriptionParsers[ODataConstants::MATHFUN_ROUND] = function ($params) {
115 1
            return 'round(' . $params[0] . ')';
116 1
        };
117
        $this->functionDescriptionParsers[ODataConstants::MATHFUN_CEILING] = function ($params) {
118
            return 'ceil(' . $params[0] . ')';
119
        };
120
        $this->functionDescriptionParsers[ODataConstants::MATHFUN_FLOOR] = function ($params) {
121
            return 'floor(' . $params[0] . ')';
122
        };
123 View Code Duplication
        $this->functionDescriptionParsers[ODataConstants::BINFUL_EQUAL] = function ($params) {
124
            return self::TYPE_NAMESPACE . 'Binary::binaryEqual(' . $params[0] . ', ' . $params[1] . ')';
125
        };
126
        $this->functionDescriptionParsers['is_null'] = function ($params) {
127 7
            return 'is_null(' . $params[0] . ')';
128
        };
129
    }
130 7
    /**
131 1
     * Get the name of the iterator.
132 6
     *
133 1
     * @return string
134 5
     */
135 1
    public function getIteratorName()
136 4
    {
137 1
        return $this->iteratorName;
138 3
    }
139 1
140 2
    /**
141 1
     * Get the resource type.
142 1
     *
143 1
     * @return object|null
144 1
     */
145
    public function getResourceType()
146
    {
147
        return $this->resourceType;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->resourceType returns the type POData\Providers\Metadata\ResourceType which is incompatible with the documented return type object|null.
Loading history...
148
    }
149
150
    /**
151
     * call-back for setting the resource type.
152
     *
153
     * @param ResourceType $resourceType The resource type on which the filter
154 3
     *                                   is going to be applied
155
     */
156
    public function setResourceType(ResourceType $resourceType)
157 3
    {
158 1
        $this->iteratorName = '$' . $resourceType->getName();
159 2
        $this->resourceType = $resourceType;
160 1
    }
161 1
    /**
162 1
     * Call-back for logical expression.
163 1
     *
164
     * @param ExpressionType $expressionType The type of logical expression
165
     * @param string         $left           The left expression
166
     * @param string         $right          The left expression
167
     *
168
     * @return string
169
     */
170 View Code Duplication
    public function onLogicalExpression($expressionType, $left, $right)
171
    {
172
        $type = $this->unpackExpressionType($expressionType);
173 8
        switch ($type) {
174
            case ExpressionType::AND_LOGICAL:
175 8
                return $this->prepareBinaryExpression(self::LOGICAL_AND, $left, $right);
176 2
            case ExpressionType::OR_LOGICAL:
177 6
                return $this->prepareBinaryExpression(self::LOGICAL_OR, $left, $right);
178 1
            default:
179
                throw new \InvalidArgumentException('onLogicalExpression');
180 5
        }
181
    }
182
    /**
183
     * Call-back for arithmetic expression.
184
     *
185
     * @param ExpressionType $expressionType The type of arithmetic expression
186
     * @param string         $left           The left expression
187
     * @param string         $right          The left expression
188
     *
189 1
     * @return string
190
     */
191 1
    public function onArithmeticExpression($expressionType, $left, $right)
192 1
    {
193
        $type = $this->unpackExpressionType($expressionType);
194 1
        switch ($type) {
195 1
            case ExpressionType::MULTIPLY:
196 1
                return $this->prepareBinaryExpression(self::MULTIPLY, $left, $right);
197 1
            case ExpressionType::DIVIDE:
198 1
                return $this->prepareBinaryExpression(self::DIVIDE, $left, $right);
199 1
            case ExpressionType::MODULO:
200
                return $this->prepareBinaryExpression(self::MODULO, $left, $right);
201
            case ExpressionType::ADD:
202
                return $this->prepareBinaryExpression(self::ADD, $left, $right);
203
            case ExpressionType::SUBTRACT:
204
                return $this->prepareBinaryExpression(self::SUBTRACT, $left, $right);
205
            default:
206
                throw new \InvalidArgumentException('onArithmeticExpression');
207
        }
208
    }
209 28
    /**
210
     * Call-back for relational expression.
211 28
     *
212 1
     * @param ExpressionType $expressionType The type of relation expression
213
     * @param string         $left           The left expression
214 27
     * @param string         $right          The left expression
215 27
     *
216 1
     * @return string
217 26
     */
218 1
    public function onRelationalExpression($expressionType, $left, $right)
219 25
    {
220 1
        $type = $this->unpackExpressionType($expressionType);
221 24
        switch ($type) {
222 1
            case ExpressionType::GREATERTHAN:
223 23
                return $this->prepareBinaryExpression(self::GREATER_THAN, $left, $right);
224 1
            case ExpressionType::GREATERTHAN_OR_EQUAL:
225 22
                return $this->prepareBinaryExpression(self::GREATER_THAN_OR_EQUAL, $left, $right);
226 1
            case ExpressionType::LESSTHAN:
227 21
                return $this->prepareBinaryExpression(self::LESS_THAN, $left, $right);
228 1
            case ExpressionType::LESSTHAN_OR_EQUAL:
229 20
                return $this->prepareBinaryExpression(self::LESS_THAN_OR_EQUAL, $left, $right);
230 1
            case ExpressionType::EQUAL:
231 19
                return $this->prepareBinaryExpression(self::EQUAL, $left, $right);
232 2
            case ExpressionType::NOTEQUAL:
233 2
                return $this->prepareBinaryExpression(self::NOT_EQUAL, $left, $right);
234 17
            default:
235 1
                throw new \InvalidArgumentException('onRelationalExpression');
236 16
        }
237 1
    }
238 15
    /**
239 1
     * Call-back for unary expression.
240 14
     *
241 1
     * @param ExpressionType $expressionType The type of unary expression
242 13
     * @param string         $child          The child expression
243 1
     *
244 12
     * @return string
245 1
     */
246 11 View Code Duplication
    public function onUnaryExpression($expressionType, $child)
247 1
    {
248 10
        $type = $this->unpackExpressionType($expressionType);
249 1
        switch ($type) {
250 9
            case ExpressionType::NEGATE:
251 1
                return $this->prepareUnaryExpression(self::NEGATE, $child);
252 8
            case ExpressionType::NOT_LOGICAL:
253 1
                return $this->prepareUnaryExpression(self::LOGICAL_NOT, $child);
254 7
            default:
255 1
                throw new \InvalidArgumentException('onUnaryExpression');
256 6
        }
257 1
    }
258 5
    /**
259 1
     * Call-back for constant expression.
260 4
     *
261 1
     * @param IType $type  The type of constant
262 3
     * @param mixed $value The value of the constant
263 1
     *
264 2
     * @return string
265 1
     */
266 1
    public function onConstantExpression(IType $type, $value)
267 1
    {
268 1
        if (is_bool($value)) {
269
            return var_export($value, true);
270
        } elseif (null === $value) {
271
            return var_export(null, true);
272
        }
273
        return $value;
274
    }
275
    /**
276
     * Call-back for property access expression.
277
     *
278
     * @param PropertyAccessExpression $expression The property access expression
279 13
     *
280
     * @return string
281
     */
282 13
    public function onPropertyAccessExpression($expression)
283
    {
284
        $parent = $expression;
285
        $variable = null;
286
        do {
287
            $variable = $parent->getResourceProperty()->getName() . self::MEMBER_ACCESS . $variable;
288
            $parent = $parent->getParent();
289
        } while ($parent != null);
290
        $variable = rtrim($variable, self::MEMBER_ACCESS);
291
        $variable = $this->getIteratorName() . self::MEMBER_ACCESS . $variable;
292 2
        return $variable;
293
    }
294 2
    /**
295
     * Call-back for function call expression.
296
     *
297
     * @param \POData\UriProcessor\QueryProcessor\FunctionDescription $functionDescription Description of the function
298
     * @param array<string>                                           $params              Parameters to the function
299
     *
300
     * @return string
301
     */
302
    public function onFunctionCallExpression($functionDescription, $params)
303
    {
304
        if (!isset($functionDescription)) {
305
            throw new \InvalidArgumentException('onFunctionCallExpression');
306
        }
307
        if (!array_key_exists($functionDescription->name, $this->functionDescriptionParsers)) {
308
            throw new \InvalidArgumentException('onFunctionCallExpression');
309
        }
310
        return $this->functionDescriptionParsers[$functionDescription->name]($params);
311
    }
312
    /**
313
     * To format binary expression.
314
     *
315
     * @param string $operator The binary operator
316
     * @param string $left     The left operand
317
     * @param string $right    The right operand
318
     *
319
     * @return string
320
     */
321
    private function prepareBinaryExpression($operator, $left, $right)
322
    {
323
        return self::OPEN_BRACKET . $left . ' ' . $operator . ' ' . $right . self::CLOSE_BRACKET;
324
    }
325
    /**
326
     * To format unary expression.
327
     *
328
     * @param string $operator The unary operator
329
     * @param string $child    The operand
330
     *
331
     * @return string
332
     */
333
    private function prepareUnaryExpression($operator, $child)
334
    {
335
        return $operator . self::OPEN_BRACKET . $child . self::CLOSE_BRACKET;
336
    }
337
338
    /**
339
     * @param $expressionType
340
     * @return mixed
341
     */
342
    private function unpackExpressionType($expressionType)
343
    {
344
        if ($expressionType instanceof ExpressionType) {
345
            $type = $expressionType->getValue();
346
        } else {
347
            $type = $expressionType;
348
        }
349
        return $type;
350
    }
351
}
352