Completed
Push — master ( 621ee6...b11c76 )
by Alex
14s queued 11s
created

PHPExpressionProvider::onArithmeticExpression()   A

Complexity

Conditions 6
Paths 6

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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