Test Failed
Pull Request — master (#39)
by Christopher
03:39
created

onFunctionCallExpression()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

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