Completed
Pull Request — master (#8)
by Alex
03:06 queued 10s
created

LaravelExpressionProvider::setResourceType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 0
cts 4
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
crap 2
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 2
    public function __construct()
50
    {
51 2
    }
52
    /**
53
     * Get the name of the iterator.
54
     *
55
     * @return string
56
     */
57
    public function getIteratorName()
58
    {
59
        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
    public function setResourceType(ResourceType $resourceType)
68
    {
69
        $this->iteratorName = "$" . $resourceType->getName();
70
        $this->resourceType = $resourceType;
71
    }
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
    public function onLogicalExpression($expressionType, $left, $right)
82
    {
83
        switch ($expressionType) {
84
            case ExpressionType::AND_LOGICAL:
85
                return $this->_prepareBinaryExpression(self::LOGICAL_AND, $left, $right);
86
            case ExpressionType::OR_LOGICAL:
87
                return $this->_prepareBinaryExpression(self::LOGICAL_OR, $left, $right);
88
            default:
89
                throw new \InvalidArgumentException('onLogicalExpression');
90
        }
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
    public function onArithmeticExpression($expressionType, $left, $right)
102
    {
103
        switch ($expressionType) {
104
            case ExpressionType::MULTIPLY:
105
                return $this->_prepareBinaryExpression(self::MULTIPLY, $left, $right);
106
            case ExpressionType::DIVIDE:
107
                return $this->_prepareBinaryExpression(self::DIVIDE, $left, $right);
108
            case ExpressionType::MODULO:
109
                return $this->_prepareBinaryExpression(self::MODULO, $left, $right);
110
            case ExpressionType::ADD:
111
                return $this->_prepareBinaryExpression(self::ADD, $left, $right);
112
            case ExpressionType::SUBTRACT:
113
                return $this->_prepareBinaryExpression(self::SUBTRACT, $left, $right);
114
            default:
115
                throw new \InvalidArgumentException('onArithmeticExpression');
116
        }
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
    public function onRelationalExpression($expressionType, $left, $right)
128
    {
129
        switch ($expressionType) {
130
            case ExpressionType::GREATERTHAN:
131
                return $this->_prepareBinaryExpression(self::GREATER_THAN, $left, $right);
132
            case ExpressionType::GREATERTHAN_OR_EQUAL:
133
                return $this->_prepareBinaryExpression(self::GREATER_THAN_OR_EQUAL, $left, $right);
134
            case ExpressionType::LESSTHAN:
135
                return $this->_prepareBinaryExpression(self::LESS_THAN, $left, $right);
136
            case ExpressionType::LESSTHAN_OR_EQUAL:
137
                return $this->_prepareBinaryExpression(self::LESS_THAN_OR_EQUAL, $left, $right);
138
            case ExpressionType::EQUAL:
139
                return $this->_prepareBinaryExpression(self::EQUAL, $left, $right);
140
            case ExpressionType::NOTEQUAL:
141
                return $this->_prepareBinaryExpression(self::NOT_EQUAL, $left, $right);
142
            default:
143
                throw new \InvalidArgumentException('onArithmeticExpression');
144
        }
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
    public function onUnaryExpression($expressionType, $child)
155
    {
156
        switch ($expressionType) {
157
            case ExpressionType::NEGATE:
158
                return $this->_prepareUnaryExpression(self::NEGATE, $child);
159
            case ExpressionType::NOT_LOGICAL:
160
                return $this->_prepareUnaryExpression(self::LOGICAL_NOT, $child);
161
            default:
162
                throw new \InvalidArgumentException('onUnaryExpression');
163
        }
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
    public function onConstantExpression(IType $type, $value)
174
    {
175
        if (is_bool($value)) {
176
            return var_export($value, true);
177
        } elseif (is_null($value)) {
178
            return var_export(null, true);
179
        }
180
        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
    public function onPropertyAccessExpression($expression)
190
    {
191
        $parent = $expression;
192
        $variable = null;
193
        do {
194
            $variable = $parent->getResourceProperty()->getName().self::MEMBER_ACCESS.$variable;
195
            $parent = $parent->getParent();
196
        } while ($parent != null);
197
        $variable = rtrim($variable, self::MEMBER_ACCESS);
198
        $variable = $this->getIteratorName().self::MEMBER_ACCESS.$variable;
199
        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              Paameters to the function
206
     *
207
     * @return string
208
     */
209
    public function onFunctionCallExpression($functionDescription, $params)
210
    {
211
        switch ($functionDescription->name) {
212
            case ODataConstants::STRFUN_COMPARE:
213
                return "strcmp($params[0], $params[1])";
214
            case ODataConstants::STRFUN_ENDSWITH:
215
                return "(strcmp(substr($params[0], strlen($params[0]) - strlen($params[1])), $params[1]) === 0)";
216
            case ODataConstants::STRFUN_INDEXOF:
217
                return "strpos($params[0], $params[1])";
218
            case ODataConstants::STRFUN_REPLACE:
219
                return "str_replace($params[1], $params[2], $params[0])";
220
            case ODataConstants::STRFUN_STARTSWITH:
221
                return "(strpos($params[0], $params[1]) === 0)";
222
            case ODataConstants::STRFUN_TOLOWER:
223
                return "strtolower($params[0])";
224
            case ODataConstants::STRFUN_TOUPPER:
225
                return "strtoupper($params[0])";
226
            case ODataConstants::STRFUN_TRIM:
227
                return "trim($params[0])";
228
            case ODataConstants::STRFUN_SUBSTRING:
229
                return count($params) == 3 ?
230
                    "substr($params[0], $params[1], $params[2])" : "substr($params[0], $params[1])";
231
            case ODataConstants::STRFUN_SUBSTRINGOF:
232
                return "(strpos($params[1], $params[0]) !== false)";
233
            case ODataConstants::STRFUN_CONCAT:
234
                return $params[0].' . '.$params[1];
235
            case ODataConstants::STRFUN_LENGTH:
236
                return "strlen($params[0])";
237
            case ODataConstants::GUIDFUN_EQUAL:
238
                return self::TYPE_NAMESPACE."Guid::guidEqual($params[0], $params[1])";
239
            case ODataConstants::DATETIME_COMPARE:
240
                return self::TYPE_NAMESPACE."DateTime::dateTimeCmp($params[0], $params[1])";
241
            case ODataConstants::DATETIME_YEAR:
242
                return self::TYPE_NAMESPACE."DateTime::year($params[0])";
243
            case ODataConstants::DATETIME_MONTH:
244
                return self::TYPE_NAMESPACE."DateTime::month($params[0])";
245
            case ODataConstants::DATETIME_DAY:
246
                return self::TYPE_NAMESPACE."DateTime::day($params[0])";
247
            case ODataConstants::DATETIME_HOUR:
248
                return self::TYPE_NAMESPACE."DateTime::hour($params[0])";
249
            case ODataConstants::DATETIME_MINUTE:
250
                return self::TYPE_NAMESPACE."DateTime::minute($params[0])";
251
            case ODataConstants::DATETIME_SECOND:
252
                return self::TYPE_NAMESPACE."DateTime::second($params[0])";
253
            case ODataConstants::MATHFUN_ROUND:
254
                return "round($params[0])";
255
            case ODataConstants::MATHFUN_CEILING:
256
                return "ceil($params[0])";
257
            case ODataConstants::MATHFUN_FLOOR:
258
                return "floor($params[0])";
259
            case ODataConstants::BINFUL_EQUAL:
260
                return self::TYPE_NAMESPACE."Binary::binaryEqual($params[0], $params[1])";
261
            case 'is_null':
262
                return "is_null($params[0])";
263
            default:
264
                throw new \InvalidArgumentException('onFunctionCallExpression');
265
        }
266
    }
267
    /**
268
     * To format binary expression.
269
     *
270
     * @param string $operator The binary operator
271
     * @param string $left     The left operand
272
     * @param string $right    The right operand
273
     *
274
     * @return string
275
     */
276
    private function _prepareBinaryExpression($operator, $left, $right)
277
    {
278
        return
279
            self::OPEN_BRACKET.$left.' '.$operator.' '.$right.self::CLOSE_BRACKET;
280
    }
281
    /**
282
     * To format unary expression.
283
     *
284
     * @param string $operator The unary operator
285
     * @param string $child    The operand
286
     *
287
     * @return string
288
     */
289
    private function _prepareUnaryExpression($operator, $child)
290
    {
291
        return $operator.self::OPEN_BRACKET.$child.self::CLOSE_BRACKET;
292
    }
293
}
294