MySQLExpressionProvider   F
last analyzed

Complexity

Total Complexity 60

Size/Duplication

Total Lines 344
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 145
dl 0
loc 344
rs 3.6
c 0
b 0
f 0
wmc 60

12 Methods

Rating   Name   Duplication   Size   Complexity  
B onRelationalExpression() 0 23 7
A prepareUnaryExpression() 0 3 1
A __construct() 0 3 1
A onArithmeticExpression() 0 20 6
A onUnaryExpression() 0 11 3
A onLogicalExpression() 0 11 3
A onConstantExpression() 0 9 3
A getIteratorName() 0 2 1
A prepareBinaryExpression() 0 13 2
A setResourceType() 0 3 1
D onFunctionCallExpression() 0 82 27
A onPropertyAccessExpression() 0 18 5

How to fix   Complexity   

Complex Class

Complex classes like MySQLExpressionProvider often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use MySQLExpressionProvider, and based on these observations, apply Extract Interface, too.

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