Completed
Push — master ( b6c184...f575f0 )
by Christopher
03:43
created

onRelationalExpression()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 19
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 7

Importance

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