Completed
Pull Request — master (#230)
by Alex
08:54
created

onPropertyAccessExpression()   A

Complexity

Conditions 6
Paths 6

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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