Completed
Push — master ( 06fdcb...b3189d )
by Alex
50s
created

_prepareBinaryExpression()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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