Completed
Push — master ( e6b8da...9a4b62 )
by Alex
05:25
created

LaravelExpressionProvider::replace()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 7

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 11
ccs 0
cts 9
cp 0
rs 9.4285
cc 3
eloc 7
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
     * 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
     * @param string $iteratorName The name of the iterator
0 ignored issues
show
Bug introduced by
There is no parameter named $iteratorName. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

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