MySQLExpressionProvider::onUnaryExpression()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 8

Duplication

Lines 13
Ratio 100 %

Importance

Changes 0
Metric Value
dl 13
loc 13
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 8
nc 3
nop 2
1
<?php
2
3
namespace POData\Providers\Expression;
4
5
6
use POData\UriProcessor\QueryProcessor\ExpressionParser\Expressions\ExpressionType;
7
use POData\Providers\Metadata\Type\IType;
8
use POData\Common\ODataConstants;
9
use POData\Providers\Expression\IExpressionProvider;
10
use POData\Providers\Metadata\ResourceType;
11
use POData\UriProcessor\QueryProcessor\ExpressionParser\Expressions\PropertyAccessExpression;
12
use POData\UriProcessor\QueryProcessor\FunctionDescription;
13
14
class MySQLExpressionProvider implements IExpressionProvider
15
{
16
    const ADD                   = '+';
17
    const CLOSE_BRACKET         = ')';
18
    const COMMA                 = ',';
19
    const DIVIDE                = '/';
20
    const SUBTRACT              = '-';
21
    const EQUAL                 = '=';
22
    const GREATER_THAN          = '>';
23
    const GREATER_THAN_OR_EQUAL = '>=';
24
    const LESS_THAN             = '<';
25
    const LESS_THAN_OR_EQUAL    = '<=';
26
    const LOGICAL_AND           = '&&';
27
    const LOGICAL_NOT           = '!';
28
    const LOGICAL_OR            = '||';
29
    const MEMBER_ACCESS         = '';
30
    const MODULO                = '%';
31
    const MULTIPLY              = '*';
32
    const NEGATE                = '-';
33
    const NOT_EQUAL             = '!=';
34
    const OPEN_BRACKET           = '(';
35
    
36
    /**
37
     * The type of the resource pointed by the resource path segment
38
     *
39
     * @var ResourceType
40
     */
41
    private $resourceType;
42
43
    private $entityMapping;
44
45
    /**
46
     * Constructs new instance of MySQLExpressionProvider
47
     *    
48
     */
49
    public function __construct()
50
    {
51
    	$this->entityMapping = array();
52
    }
53
54
55
    /**
56
     * Get the name of the iterator
57
     * 
58
     * @return string
59
     */
60
    public function getIteratorName()
61
    {
62
        return null;
63
    }
64
65
    /**
66
     * call-back for setting the resource type.
67
     *
68
     * @param ResourceType $resourceType The resource type on which the filter is going to be applied.
69
     *
70
     */
71
    public function setResourceType(ResourceType $resourceType)
72
    {
73
    	$this->resourceType = $resourceType;
74
    }
75
76
    /**
77
     * Call-back for logical expression
78
     * 
79
     * @param ExpressionType $expressionType The type of logical expression.
80
     * @param string         $left           The left expression.
81
     * @param string         $right          The left expression.
82
     * 
83
     * @return string
84
     */
85 View Code Duplication
    public function onLogicalExpression($expressionType, $left, $right)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
86
    {
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
     * Call-back for arithmetic expression
101
     * 
102
     * @param ExpressionType $expressionType The type of arithmetic expression.
103
     * @param string         $left           The left expression.
104
     * @param string         $right          The left expression.
105
     * 
106
     * @return string
107
     */
108 View Code Duplication
    public function onArithmeticExpression($expressionType, $left, $right)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
109
    {
110
        switch($expressionType) {
111
	        case ExpressionType::MULTIPLY:
112
	            return $this->_prepareBinaryExpression(self::MULTIPLY, $left, $right);
113
114
	        case ExpressionType::DIVIDE:
115
	            return $this->_prepareBinaryExpression(self::DIVIDE, $left, $right);
116
117
	        case ExpressionType::MODULO:
118
	            return $this->_prepareBinaryExpression(self::MODULO, $left, $right);
119
120
	        case ExpressionType::ADD:
121
	            return $this->_prepareBinaryExpression(self::ADD, $left, $right);
122
123
	        case ExpressionType::SUBTRACT:
124
	            return $this->_prepareBinaryExpression(self::SUBTRACT, $left, $right);
125
126
	        default:
127
	            throw new \InvalidArgumentException('onArithmeticExpression');
128
        }
129
    }
130
131
    /**
132
     * Call-back for relational expression
133
     * 
134
     * @param ExpressionType $expressionType The type of relation expression
135
     * @param string         $left           The left expression
136
     * @param string         $right          The left expression
137
     * 
138
     * @return string
139
     */
140 View Code Duplication
    public function onRelationalExpression($expressionType, $left, $right)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
141
    {
142
        switch($expressionType) {
143
	        case ExpressionType::GREATERTHAN:
144
	            return $this->_prepareBinaryExpression(self::GREATER_THAN, $left, $right);
145
146
	        case ExpressionType::GREATERTHAN_OR_EQUAL:
147
	            return $this->_prepareBinaryExpression(self::GREATER_THAN_OR_EQUAL, $left, $right);
148
149
	        case ExpressionType::LESSTHAN:
150
	            return $this->_prepareBinaryExpression(self::LESS_THAN, $left, $right);
151
152
	        case ExpressionType::LESSTHAN_OR_EQUAL:
153
	            return $this->_prepareBinaryExpression(self::LESS_THAN_OR_EQUAL, $left, $right);
154
155
	        case ExpressionType::EQUAL:
156
	            return $this->_prepareBinaryExpression(self::EQUAL, $left, $right);
157
158
	        case ExpressionType::NOTEQUAL:
159
	            return $this->_prepareBinaryExpression(self::NOT_EQUAL, $left, $right);
160
161
	        default:
162
	            throw new \InvalidArgumentException('onArithmeticExpression');
163
        }
164
    }
165
166
    /**
167
     * Call-back for unary expression
168
     * 
169
     * @param ExpressionType $expressionType The type of unary expression
170
     * @param string         $child          The child expression
171
     * 
172
     * @return string
173
     */
174 View Code Duplication
    public function onUnaryExpression($expressionType, $child)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
175
    {
176
        switch($expressionType) {
177
	        case ExpressionType::NEGATE:
178
	            return $this->_prepareUnaryExpression(self::NEGATE, $child);
179
180
	        case ExpressionType::NOT_LOGICAL:
181
	            return $this->_prepareUnaryExpression(self::LOGICAL_NOT, $child);
182
183
	        default:
184
	            throw new \InvalidArgumentException('onUnaryExpression');
185
        }
186
    }
187
188
    /**
189
     * Call-back for constant expression
190
     * 
191
     * @param IType  $type  The type of constant
192
     * @param mixed $value The value of the constant
193
     * 
194
     * @return string
195
     */
196 View Code Duplication
    public function onConstantExpression(IType $type, $value)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
197
    {
198
        if (is_bool($value)) {
199
            return var_export($value, true);
200
        } else if (is_null($value)) {
201
            return var_export(null, true);
202
        }
203
204
        return $value;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $value; (object|integer|double|string|array) is incompatible with the return type declared by the interface POData\Providers\Express...r::onConstantExpression of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
205
    }
206
207
    /**
208
     * Call-back for property access expression
209
     * 
210
     * @param PropertyAccessExpression $expression The property access expression
211
     * 
212
     * @return string
213
     */
214
215 View Code Duplication
    public function onPropertyAccessExpression($expression)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
216
    {
217
        $parent = $expression;
218
        $variable = null;
0 ignored issues
show
Unused Code introduced by
$variable is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
219
        $entityTypeName = $this->resourceType->getName();
220
        $propertyName = $parent->getResourceProperty()->getName();
221
        if (is_array($this->entityMapping)) {
222
        	if (array_key_exists($entityTypeName, $this->entityMapping)) {
223
        		if (array_key_exists($propertyName, $this->entityMapping[$entityTypeName])) {
224
        			return $this->entityMapping[$entityTypeName][$propertyName];
225
        		}
226
        	}
227
        }
228
     
229
        return $propertyName;
230
    }
231
232
    /**
233
     * Call-back for function call expression
234
     * 
235
     * @param FunctionDescription $functionDescription Description of the function.
236
     * @param array<string>       $params              Paameters to the function.
237
     * 
238
     * @return string
239
     */
240
    public function onFunctionCallExpression($functionDescription, $params)
241
    {
242
        switch($functionDescription->name) {
243
	        case ODataConstants::STRFUN_COMPARE:
244
	            return "STRCMP($params[0], $params[1])";
245
246
	        case ODataConstants::STRFUN_ENDSWITH:
247
	            return "(STRCMP($params[1],RIGHT($params[0],LENGTH($params[1]))) = 0)";
248
249
	        case ODataConstants::STRFUN_INDEXOF:
250
	            return "INSTR($params[0], $params[1]) - 1";
251
252
	        case ODataConstants::STRFUN_REPLACE:
253
	            return "REPLACE($params[0],$params[1],$params[2])";
254
255
	        case ODataConstants::STRFUN_STARTSWITH:
256
	            return "(STRCMP($params[1],LEFT($params[0],LENGTH($params[1]))) = 0)";
257
258
	        case ODataConstants::STRFUN_TOLOWER:
259
	            return "LOWER($params[0])";
260
261
	        case ODataConstants::STRFUN_TOUPPER:
262
	            return "UPPER($params[0])";
263
264
	        case ODataConstants::STRFUN_TRIM:
265
	            return "TRIM($params[0])";
266
267 View Code Duplication
	        case ODataConstants::STRFUN_SUBSTRING:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
268
	            return count($params) == 3 ?
269
	                "SUBSTRING($params[0], $params[1] + 1, $params[2])" :
270
	                "SUBSTRING($params[0], $params[1] + 1)";
271
272
	        case ODataConstants::STRFUN_SUBSTRINGOF:
273
	            return "(LOCATE($params[0], $params[1]) > 0)";
274
275
	        case ODataConstants::STRFUN_CONCAT:
276
	            return "CONCAT($params[0],$params[1])";
277
278
	        case ODataConstants::STRFUN_LENGTH:
279
	            return "LENGTH($params[0])";
280
281
	        case ODataConstants::GUIDFUN_EQUAL:
282
		        return "STRCMP($params[0], $params[1])";
283
284
	        case ODataConstants::DATETIME_COMPARE:
285
	            return "DATETIMECMP($params[0]; $params[1])";
286
287
	        case ODataConstants::DATETIME_YEAR:
288
	            return "EXTRACT(YEAR from ".$params[0].")";
289
290
	        case ODataConstants::DATETIME_MONTH:
291
	            return "EXTRACT(MONTH from ".$params[0].")";
292
293
	        case ODataConstants::DATETIME_DAY:
294
	            return "EXTRACT(DAY from ".$params[0].")";
295
296
	        case ODataConstants::DATETIME_HOUR:
297
	            return "EXTRACT(HOUR from ".$params[0].")";
298
299
	        case ODataConstants::DATETIME_MINUTE:
300
	            return "EXTRACT(MINUTE from ".$params[0].")";
301
302
	        case ODataConstants::DATETIME_SECOND:
303
	            return "EXTRACT(SECOND from ".$params[0].")";
304
305
	        case ODataConstants::MATHFUN_ROUND:
306
	            return "ROUND($params[0])";
307
308
	        case ODataConstants::MATHFUN_CEILING:
309
	            return "CEIL($params[0])";
310
311
	        case ODataConstants::MATHFUN_FLOOR:
312
	            return "FLOOR($params[0])";
313
314
	        case ODataConstants::BINFUL_EQUAL:
315
		        return "($params[0] = $params[1])";
316
317
	        case 'is_null':
318
	            return "is_null($params[0])";
319
320
	        default:
321
	            throw new \InvalidArgumentException('onFunctionCallExpression');
322
        }
323
    }
324
325
    /**
326
     * To format binary expression
327
     * 
328
     * @param string $operator The binary operator.
329
     * @param string $left     The left operand.
330
     * @param string $right    The right operand.
331
     * 
332
     * @return string
333
     */
334 View Code Duplication
    private function _prepareBinaryExpression($operator, $left, $right)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
335
    {
336
    	//DATETIMECMP
337
    	if (!substr_compare($left, "DATETIMECMP", 0, 11)) {
338
    		$str = explode(';', $left, 2);
339
    		$str[0] = str_replace('DATETIMECMP', '', $str[0]);
340
    		return self::OPEN_BRACKET
341
    			. $str[0] . ' ' . $operator
342
    			. ' ' . $str[1] . self::CLOSE_BRACKET;
343
    	}
344
345
        return self::OPEN_BRACKET . $left . ' ' . $operator . ' ' . $right . self::CLOSE_BRACKET;
346
    }
347
348
    /**
349
     * To format unary expression
350
     * 
351
     * @param string $operator The unary operator.
352
     * @param string $child    The operand.
353
     * 
354
     * @return string
355
     */
356
    private function _prepareUnaryExpression($operator, $child)
357
    {
358
        return $operator . self::OPEN_BRACKET . $child . self::CLOSE_BRACKET;
359
    }
360
}