PHPExpressionProvider::onFunctionCallExpression()   D
last analyzed

Complexity

Conditions 27
Paths 27

Size

Total Lines 84
Code Lines 57

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 27
eloc 57
nc 27
nop 2
dl 0
loc 84
rs 4.1666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace POData\Providers\Expression;
6
7
use InvalidArgumentException;
8
use POData\Common\ODataConstants;
9
use POData\Providers\Metadata\ResourceType;
10
use POData\Providers\Metadata\Type\IType;
11
use POData\UriProcessor\QueryProcessor\ExpressionParser\Expressions\ExpressionType;
12
use POData\UriProcessor\QueryProcessor\ExpressionParser\Expressions\PropertyAccessExpression;
13
use POData\UriProcessor\QueryProcessor\FunctionDescription;
14
15
/**
16
 * Class PHPExpressionProvider.
17
 */
18
class PHPExpressionProvider implements IExpressionProvider
19
{
20
    const ADD                   = '+';
21
    const CLOSE_BRACKET         = ')';
22
    const COMMA                 = ',';
23
    const DIVIDE                = '/';
24
    const SUBTRACT              = '-';
25
    const EQUAL                 = '==';
26
    const GREATER_THAN          = '>';
27
    const GREATER_THAN_OR_EQUAL = '>=';
28
    const LESS_THAN             = '<';
29
    const LESS_THAN_OR_EQUAL    = '<=';
30
    const LOGICAL_AND           = '&&';
31
    const LOGICAL_NOT           = '!';
32
    const LOGICAL_OR            = '||';
33
    const MEMBER_ACCESS         = '->';
34
    const MODULO                = '%';
35
    const MULTIPLY              = '*';
36
    const NEGATE                = '-';
37
    const NOT_EQUAL             = '!=';
38
    const OPEN_BRACKET          = '(';
39
    const TYPE_NAMESPACE        = 'POData\\Providers\\Metadata\\Type\\';
40
41
    /**
42
     * The name of iterator.
43
     *
44
     * @var string
45
     */
46
    private $iteratorName;
47
48
    /**
49
     * The type of the resource pointed by the resource path segment.
50
     *
51
     * @var ResourceType
52
     */
53
    private $resourceType;
54
55
    /**
56
     * @param string $iteratorName The name of the iterator
57
     */
58
    public function __construct($iteratorName)
59
    {
60
        $this->iteratorName = $iteratorName;
61
    }
62
63
    /**
64
     * call-back for setting the resource type.
65
     *
66
     * @param ResourceType $resourceType The resource type on which the filter is going to be applied
67
     *
68
     * @return void
69
     */
70
    public function setResourceType(ResourceType $resourceType)
71
    {
72
        $this->resourceType = $resourceType;
73
    }
74
75
    /**
76
     * Call-back for logical expression.
77
     *
78
     * @param ExpressionType $expressionType The type of logical expression
79
     * @param string         $left           The left expression
80
     * @param string         $right          The left expression
81
     *
82
     * @return string
83
     */
84
    public function onLogicalExpression(ExpressionType $expressionType, $left, $right)
85
    {
86
        assert($expressionType instanceof ExpressionType, get_class($expressionType));
87
        switch ($expressionType) {
88
            case ExpressionType::AND_LOGICAL():
89
                return $this->prepareBinaryExpression(self::LOGICAL_AND, $left, $right);
90
91
            case ExpressionType::OR_LOGICAL():
92
                return $this->prepareBinaryExpression(self::LOGICAL_OR, $left, $right);
93
94
            default:
95
                throw new InvalidArgumentException('onLogicalExpression');
96
        }
97
    }
98
99
    /**
100
     * To format binary expression.
101
     *
102
     * @param string $operator The binary operator
103
     * @param string $left     The left operand
104
     * @param string $right    The right operand
105
     *
106
     * @return string
107
     */
108
    private function prepareBinaryExpression($operator, $left, $right)
109
    {
110
        return
111
            self::OPEN_BRACKET . $left . ' ' . $operator . ' ' . $right . self::CLOSE_BRACKET;
112
    }
113
114
    /**
115
     * Call-back for arithmetic expression.
116
     *
117
     * @param ExpressionType $expressionType The type of arithmetic expression
118
     * @param string         $left           The left expression
119
     * @param string         $right          The left expression
120
     *
121
     * @return string
122
     */
123
    public function onArithmeticExpression(ExpressionType $expressionType, $left, $right)
124
    {
125
        switch ($expressionType) {
126
            case ExpressionType::MULTIPLY():
127
                return $this->prepareBinaryExpression(self::MULTIPLY, $left, $right);
128
129
            case ExpressionType::DIVIDE():
130
                return $this->prepareBinaryExpression(self::DIVIDE, $left, $right);
131
132
            case ExpressionType::MODULO():
133
                return $this->prepareBinaryExpression(self::MODULO, $left, $right);
134
135
            case ExpressionType::ADD():
136
                return $this->prepareBinaryExpression(self::ADD, $left, $right);
137
138
            case ExpressionType::SUBTRACT():
139
                return $this->prepareBinaryExpression(self::SUBTRACT, $left, $right);
140
141
            default:
142
                throw new InvalidArgumentException('onArithmeticExpression');
143
        }
144
    }
145
146
    /**
147
     * Call-back for relational expression.
148
     *
149
     * @param ExpressionType $expressionType The type of relation expression
150
     * @param string         $left           The left expression
151
     * @param string         $right          The left expression
152
     *
153
     * @return string
154
     */
155
    public function onRelationalExpression(ExpressionType $expressionType, $left, $right)
156
    {
157
        switch ($expressionType) {
158
            case ExpressionType::GREATERTHAN():
159
                return $this->prepareBinaryExpression(self::GREATER_THAN, $left, $right);
160
161
            case ExpressionType::GREATERTHAN_OR_EQUAL():
162
                return $this->prepareBinaryExpression(self::GREATER_THAN_OR_EQUAL, $left, $right);
163
164
            case ExpressionType::LESSTHAN():
165
                return $this->prepareBinaryExpression(self::LESS_THAN, $left, $right);
166
167
            case ExpressionType::LESSTHAN_OR_EQUAL():
168
                return $this->prepareBinaryExpression(self::LESS_THAN_OR_EQUAL, $left, $right);
169
170
            case ExpressionType::EQUAL():
171
                return $this->prepareBinaryExpression(self::EQUAL, $left, $right);
172
173
            case ExpressionType::NOTEQUAL():
174
                return $this->prepareBinaryExpression(self::NOT_EQUAL, $left, $right);
175
176
            default:
177
                throw new InvalidArgumentException('onRelationalExpression');
178
        }
179
    }
180
181
    /**
182
     * Call-back for unary expression.
183
     *
184
     * @param ExpressionType $expressionType The type of unary expression
185
     * @param string         $child          The child expression
186
     *
187
     * @return string
188
     */
189
    public function onUnaryExpression(ExpressionType $expressionType, $child)
190
    {
191
        switch ($expressionType) {
192
            case ExpressionType::NEGATE():
193
                return $this->prepareUnaryExpression(self::NEGATE, $child);
194
195
            case ExpressionType::NOT_LOGICAL():
196
                return $this->prepareUnaryExpression(self::LOGICAL_NOT, $child);
197
198
            default:
199
                throw new InvalidArgumentException('onUnaryExpression');
200
        }
201
    }
202
203
    /**
204
     * To format unary expression.
205
     *
206
     * @param string $operator The unary operator
207
     * @param string $child    The operand
208
     *
209
     * @return string
210
     */
211
    private function prepareUnaryExpression($operator, $child)
212
    {
213
        return $operator . self::OPEN_BRACKET . $child . self::CLOSE_BRACKET;
214
    }
215
216
    /**
217
     * Call-back for constant expression.
218
     *
219
     * @param IType $type  The type of constant
220
     * @param mixed $value The value of the constant
221
     *
222
     * @return string
223
     */
224
    public function onConstantExpression(IType $type, $value)
225
    {
226
        if (is_bool($value)) {
227
            return var_export($value, true);
228
        } elseif (null === $value) {
229
            return var_export(null, true);
230
        }
231
232
        return strval($value);
233
    }
234
235
    /**
236
     * Call-back for property access expression.
237
     *
238
     * @param PropertyAccessExpression $expression The property access expression
239
     *
240
     * @return string
241
     */
242
    public function onPropertyAccessExpression(PropertyAccessExpression $expression): string
243
    {
244
        if (null == $this->resourceType) {
245
            throw new InvalidArgumentException('onPropertyAccessExpression - resourceType null');
246
        }
247
        if (empty($this->resourceType->getName())) {
248
            throw new InvalidArgumentException('onPropertyAccessExpression - resourceType has no name');
249
        }
250
251
        $parent   = $expression;
252
        $variable = null;
253
254
        do {
255
            $variable = $parent->getResourceProperty()->getName() . self::MEMBER_ACCESS . $variable;
256
            $parent   = $parent->getParent();
257
        } while ($parent != null);
258
259
        $variable = rtrim($variable, self::MEMBER_ACCESS);
260
        $variable = $this->getIteratorName() . self::MEMBER_ACCESS . $variable;
261
262
        return $variable;
263
    }
264
265
    /**
266
     * Get the name of the iterator.
267
     *
268
     * @return string
269
     */
270
    public function getIteratorName()
271
    {
272
        return $this->iteratorName;
273
    }
274
275
    /**
276
     * Call-back for function call expression.
277
     *
278
     * @param FunctionDescription $functionDescription Description of the function
279
     * @param array<string>       $params              Parameters to the function
280
     *
281
     * @return string
282
     */
283
    public function onFunctionCallExpression($functionDescription, $params)
284
    {
285
        switch ($functionDescription->name) {
286
            case ODataConstants::STRFUN_COMPARE:
287
                return 'strcmp(' . $params[0] . ', ' . $params[1] . ')';
288
289
            case ODataConstants::STRFUN_ENDSWITH:
290
                return '(strcmp(substr(' . $params[0] . ', strlen(' . $params[0] . ') - strlen(' . $params[1] . ')), '
291
                    . $params[1] . ') === 0)';
292
293
            case ODataConstants::STRFUN_INDEXOF:
294
                return 'strpos(' . $params[0] . ', ' . $params[1] . ')';
295
296
            case ODataConstants::STRFUN_REPLACE:
297
                return 'str_replace(' . $params[1] . ', ' . $params[2] . ', ' . $params[0] . ')';
298
299
            case ODataConstants::STRFUN_STARTSWITH:
300
                return '(strpos(' . $params[0] . ', ' . $params[1] . ') === 0)';
301
302
            case ODataConstants::STRFUN_TOLOWER:
303
                return 'strtolower(' . $params[0] . ')';
304
305
            case ODataConstants::STRFUN_TOUPPER:
306
                return 'strtoupper(' . $params[0] . ')';
307
308
            case ODataConstants::STRFUN_TRIM:
309
                return 'trim(' . $params[0] . ')';
310
311
            case ODataConstants::STRFUN_SUBSTRING:
312
                return count($params) == 3 ?
313
                    'substr(' . $params[0] . ', ' . $params[1] .
314
                    ', ' . $params[2] . ')' : 'substr(' . $params[0] .
315
                    ', ' . $params[1] . ')';
316
317
            case ODataConstants::STRFUN_SUBSTRINGOF:
318
                return '(strpos(' . $params[1] . ', ' . $params[0] . ') !== false)';
319
320
            case ODataConstants::STRFUN_CONCAT:
321
                return $params[0] . ' . ' . $params[1];
322
323
            case ODataConstants::STRFUN_LENGTH:
324
                return 'strlen(' . $params[0] . ')';
325
326
            case ODataConstants::GUIDFUN_EQUAL:
327
                return self::TYPE_NAMESPACE . 'Guid::guidEqual(' . $params[0] . ', ' . $params[1] . ')';
328
329
            case ODataConstants::DATETIME_COMPARE:
330
                return self::TYPE_NAMESPACE . 'DateTime::dateTimeCmp(' . $params[0] . ', ' . $params[1] . ')';
331
332
            case ODataConstants::DATETIME_YEAR:
333
                return self::TYPE_NAMESPACE . 'DateTime::year(' . $params[0] . ')';
334
335
            case ODataConstants::DATETIME_MONTH:
336
                return self::TYPE_NAMESPACE . 'DateTime::month(' . $params[0] . ')';
337
338
            case ODataConstants::DATETIME_DAY:
339
                return self::TYPE_NAMESPACE . 'DateTime::day(' . $params[0] . ')';
340
341
            case ODataConstants::DATETIME_HOUR:
342
                return self::TYPE_NAMESPACE . 'DateTime::hour(' . $params[0] . ')';
343
344
            case ODataConstants::DATETIME_MINUTE:
345
                return self::TYPE_NAMESPACE . 'DateTime::minute(' . $params[0] . ')';
346
347
            case ODataConstants::DATETIME_SECOND:
348
                return self::TYPE_NAMESPACE . 'DateTime::second(' . $params[0] . ')';
349
350
            case ODataConstants::MATHFUN_ROUND:
351
                return 'round(' . $params[0] . ')';
352
353
            case ODataConstants::MATHFUN_CEILING:
354
                return 'ceil(' . $params[0] . ')';
355
356
            case ODataConstants::MATHFUN_FLOOR:
357
                return 'floor(' . $params[0] . ')';
358
359
            case ODataConstants::BINFUL_EQUAL:
360
                return self::TYPE_NAMESPACE . 'Binary::binaryEqual(' . $params[0] . ', ' . $params[1] . ')';
361
362
            case 'is_null':
363
                return 'is_null(' . $params[0] . ')';
364
365
            default:
366
                throw new InvalidArgumentException('onFunctionCallExpression');
367
        }
368
    }
369
}
370