ExpressionParser2::_processNodeForNullability()   C
last analyzed

Complexity

Conditions 8
Paths 8

Size

Total Lines 27
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 27
rs 5.3846
c 0
b 0
f 0
cc 8
eloc 21
nc 8
nop 3
1
<?php
2
3
namespace POData\UriProcessor\QueryProcessor\ExpressionParser;
4
5
6
use POData\Common\Messages;
7
use POData\Common\ODataException;
8
use POData\Providers\Expression\PHPExpressionProvider;
9
use POData\Providers\Metadata\Type\Boolean;
10
use POData\Providers\Metadata\ResourceType;
11
use POData\Providers\Metadata\ResourceTypeKind;
12
use POData\UriProcessor\QueryProcessor\ExpressionParser\Expressions\AbstractExpression;
13
use POData\UriProcessor\QueryProcessor\ExpressionParser\Expressions\ArithmeticExpression;
14
use POData\UriProcessor\QueryProcessor\ExpressionParser\Expressions\LogicalExpression;
15
use POData\UriProcessor\QueryProcessor\ExpressionParser\Expressions\RelationalExpression;
16
use POData\UriProcessor\QueryProcessor\ExpressionParser\Expressions\ConstantExpression;
17
use POData\UriProcessor\QueryProcessor\ExpressionParser\Expressions\PropertyAccessExpression;
18
use POData\UriProcessor\QueryProcessor\ExpressionParser\Expressions\FunctionCallExpression;
19
use POData\UriProcessor\QueryProcessor\ExpressionParser\Expressions\UnaryExpression;
20
use POData\UriProcessor\QueryProcessor\ExpressionParser\Expressions\ExpressionType;
21
use POData\UriProcessor\QueryProcessor\FunctionDescription;
22
use POData\Providers\Expression\IExpressionProvider;
23
24
/**
25
 * Class ExpressionParser2
26
 *
27
 * Build the basic expression tree for a given expression using base class
28
 * ExpressionParser, modify the expression tree to have null checks
29
 *
30
 * @package POData\UriProcessor\QueryProcessor\ExpressionParser
31
 */
32
class ExpressionParser2 extends ExpressionParser
33
{
34
35
    /**
36
     * 
37
     * @var array
38
     */
39
    private $_mapTable;
40
41
    /**
42
     * Collection of navigation properties used in the expression.
43
     * 
44
     * @var array(array(ResourceProperty))
45
     */
46
    private $_navigationPropertiesUsedInTheExpression;
47
48
    /**
49
     * Indicates whether the end user has implemented IExpressionProvider or not.
50
     * 
51
     * @var bool
52
     */
53
    private $_isPHPExpressionProvider;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
54
   
55
    /**
56
     * Create new instance of ExpressionParser2
57
     *      
58
     * @param string       $text                       The text expression to parse.
59
     * @param ResourceType $resourceType               The resource type in which 
60
     *                                                 expression will be applied.
61
     * @param Bool         $isPHPExpressionProvider True if IExpressionProvider provider is
62
     *                                                 implemented by user, False otherwise
63
     */
64
    public function __construct($text, ResourceType $resourceType, $isPHPExpressionProvider
65
    ) {
66
        parent::__construct($text, $resourceType, $isPHPExpressionProvider);
67
        $this->_navigationPropertiesUsedInTheExpression = array();
68
        $this->_isPHPExpressionProvider = $isPHPExpressionProvider;
69
    }
70
71
    /**
72
     * Parse and generate expression from the the given odata expression.
73
     *
74
     * 
75
     * @param string              $text               The text expression to parse
76
     * @param ResourceType        $resourceType       The resource type in which
77
     * @param IExpressionProvider $expressionProvider Implementation of IExpressionProvider
78
     * 
79
     * @return FilterInfo
80
     * 
81
     * @throws ODataException If any error occurs while parsing the odata expression or building the php/custom expression.
82
     *
83
     */
84
    public static function parseExpression2($text, ResourceType $resourceType, \POData\Providers\Expression\IExpressionProvider $expressionProvider) {
85
86
        $expressionParser2 = new ExpressionParser2($text, $resourceType, $expressionProvider instanceof PHPExpressionProvider);
87
        $expressionTree = $expressionParser2->parseFilter();
88
89
90
        $expressionAsString = null;
91
92
        $expressionProvider->setResourceType($resourceType);
93
        $expressionProcessor = new ExpressionProcessor($expressionProvider);
94
95
        try {
96
            $expressionAsString = $expressionProcessor->processExpression( $expressionTree );
97
        } catch (\InvalidArgumentException $invalidArgumentException) {
98
            throw ODataException::createInternalServerError( $invalidArgumentException->getMessage() );
99
        }
100
101
        
102
        return new FilterInfo(
103
            $expressionParser2->_navigationPropertiesUsedInTheExpression,
104
            $expressionAsString
105
        );
106
    }
107
108
    /**
109
     * Parse the expression
110
     * 
111
     * @see library/POData/QueryProcessor/ExpressionParser::parseFilter()
112
     * 
113
     * @return AbstractExpression
114
     * 
115
     * @throws ODataException
116
     */
117
    public  function parseFilter()
118
    {
119
        $expression = parent::parseFilter();
120
        if (!$expression->typeIs(new Boolean())) {
121
            throw ODataException::createSyntaxError(
122
                Messages::expressionParser2BooleanRequired()
123
            );
124
        }
125
        if ($this->_isPHPExpressionProvider) {
126
            $resultExpression = $this->_processNodeForNullability($expression, null);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a object<POData\UriProcess...ons\AbstractExpression>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
127
            if ($resultExpression != null) {
128
                return $resultExpression;
129
            }
130
        }
131
        return $expression;
132
    }
133
134
    /**
135
     * Process the expression node for nullability
136
     * 
137
     * @param AbstractExpression $expression The expression node to process.
138
     * @param AbstractExpression $parentExpression The parent expression of expression node to process.
139
     * @param boolean            $checkNullForMostChild whether to include null check for current property.
140
     * 
141
     * @return AbstractExpression New expression tree with nullability check
142
     * 
143
     * @throws ODataException
144
     */
145
    private function _processNodeForNullability($expression, $parentExpression, 
146
        $checkNullForMostChild = true
147
    ) {
148
        if ($expression instanceof ArithmeticExpression) {
149
            return $this->_processArithmeticNode($expression);
150
        } else if ($expression instanceof ConstantExpression) {
151
            return null;
152
        } else if ($expression instanceof FunctionCallExpression) {
153
            return $this->_processFunctionCallNode($expression, $parentExpression);
154
        } else if ($expression instanceof LogicalExpression) {
155
            return $this->_processLogicalNode($expression, $parentExpression);
156
        } else if ($expression instanceof PropertyAccessExpression) {
157
            return $this->_processPropertyAccessNode(
158
                $expression, 
159
                $parentExpression, 
160
                $checkNullForMostChild
161
            );
162
        } else if ($expression instanceof RelationalExpression) {
163
            return $this->_processRelationalNode($expression, $parentExpression);
164
        } else if ($expression instanceof UnaryExpression) {
165
            return $this->_processUnaryNode($expression, $parentExpression);
166
        }
167
168
        throw ODataException::createSyntaxError(
169
            Messages::expressionParser2UnexpectedExpression(get_class($expression))
170
        );
171
    }
172
173
    /**
174
     * Process an arithmetic expression node for nullability
175
     * 
176
     * @param ArithmeticExpression $expression The arithmetic expression node
177
     *                                         to process.
178
     *                                          
179
     * @return LogicalExpression|null
180
     */
181
    private function _processArithmeticNode(ArithmeticExpression $expression)
182
    {
183
        $leftNullableExpTree = $this->_processNodeForNullability(
184
            $expression->getLeft(), 
185
            $expression
186
        );
187
        $rightNullableExpTree = $this->_processNodeForNullability(
188
            $expression->getRight(), 
189
            $expression
190
        );
191
        $resultExpression = null;
0 ignored issues
show
Unused Code introduced by
$resultExpression is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
192 View Code Duplication
        if ($leftNullableExpTree != null && $rightNullableExpTree != null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
193
            $resultExpression = $this->_mergeNullableExpressionTrees(
194
                $leftNullableExpTree, 
195
                $rightNullableExpTree
196
            );
197
        } else {
198
            $resultExpression = $leftNullableExpTree != null 
199
                               ? $leftNullableExpTree : $rightNullableExpTree; 
200
        }
201
        
202
        return $resultExpression;
203
    }
204
205
    /**
206
     * Process an arithmetic expression node for nullability
207
     * 
208
     * @param FunctionCallExpression $expression       The function call expression
209
     *                                                 node to process.
210
     * @param AbstractExpression     $parentExpression The parent expression of 
211
     *                                                 expression node to process.
212
     * 
213
     * @return LogicalExpression|null
214
     */
215
    private function _processFunctionCallNode(FunctionCallExpression $expression,
216
        $parentExpression
217
    ) {
218
        $paramExpressions = $expression->getParamExpressions();
219
        $checkNullForMostChild 
220
            = strcmp(
221
                $expression->getFunctionDescription()->name,
222
                'is_null'
223
            ) === 0;
224
        $resultExpression = null;
225
        foreach ($paramExpressions as $paramExpression) {
226
            $resultExpression1 = $this->_processNodeForNullability(
227
                $paramExpression, 
228
                $expression,
229
                !$checkNullForMostChild
230
            );
231
            if ($resultExpression1 != null && $resultExpression != null) {
232
                $resultExpression = $this->_mergeNullableExpressionTrees(
233
                    $resultExpression, 
234
                    $resultExpression1
235
                );
236
            } else if ($resultExpression1 != null && $resultExpression == null) {
237
                $resultExpression = $resultExpression1;
238
            }
239
        }
240
        
241
        if ($resultExpression == null) {
242
            return null;
243
        }
244
           
245
        if ($parentExpression == null) {
246
            return new LogicalExpression(
247
                $resultExpression, 
248
                $expression, 
249
                ExpressionType::AND_LOGICAL
250
            );
251
        }
252
        
253
        return $resultExpression;
254
    }
255
256
    /**
257
     * Process an logical expression node for nullability.
258
     * 
259
     * @param LogicalExpression  $expression       The logical expression node
260
     *                                             to process.
261
     * @param AbstractExpression $parentExpression The parent expression of 
262
     *                                             expression node to process.
263
     * 
264
     * @return LogicalExpression|null
265
     */
266
    private function _processLogicalNode(
267
        LogicalExpression $expression, $parentExpression
268
    ) {
269
        $leftNullableExpTree = $this->_processNodeForNullability(
270
            $expression->getLeft(), 
271
            $expression
272
        );
273
        $rightNullableExpTree = $this->_processNodeForNullability(
274
            $expression->getRight(), 
275
            $expression
276
        );
277
        if ($expression->getNodeType() == ExpressionType::OR_LOGICAL) {
278
            if ($leftNullableExpTree !== null) {
279
                $resultExpression = new LogicalExpression(
280
                    $leftNullableExpTree, 
281
                    $expression->getLeft(), 
282
                    ExpressionType::AND_LOGICAL
283
                );
284
                $expression->setLeft($resultExpression);
285
            }
286
             
287
            if ($rightNullableExpTree !== null) {
288
                $resultExpression = new LogicalExpression(
289
                    $rightNullableExpTree, 
290
                    $expression->getRight(), 
291
                    ExpressionType::AND_LOGICAL
292
                );
293
                $expression->setRight($resultExpression);
294
            }
295
            
296
            return null;
297
        }
298
299
        $resultExpression = null;
0 ignored issues
show
Unused Code introduced by
$resultExpression is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
300 View Code Duplication
        if ($leftNullableExpTree != null && $rightNullableExpTree != null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
301
            $resultExpression = $this->_mergeNullableExpressionTrees(
302
                $leftNullableExpTree, 
303
                $rightNullableExpTree
304
            );
305
        } else {
306
            $resultExpression = $leftNullableExpTree != null 
307
                               ? $leftNullableExpTree : $rightNullableExpTree;
308
        }
309
310
        if ($resultExpression == null) {
311
               return null;
312
        }
313
           
314
        if ($parentExpression == null) {
315
            return new LogicalExpression(
316
                $resultExpression, 
317
                $expression, 
318
                ExpressionType::AND_LOGICAL
319
            );
320
        }
321
           
322
        return $resultExpression;
323
    }
324
325
    /**
326
     * Process an property access expression node for nullability
327
     * 
328
     * @param PropertyAccessExpression $expression            The property access 
329
     *                                                        expression node to process.
330
     * @param AbstractExpression       $parentExpression      The parent expression of 
331
     *                                                        expression node to process.
332
     * @param boolean                  $checkNullForMostChild Wheter to check null for 
333
     *                                                        most child node or not.
334
     * 
335
     * @return LogicalExpression|RelationalExpression|null
336
     */
337
    private function _processPropertyAccessNode(
338
        PropertyAccessExpression $expression, 
339
        $parentExpression, $checkNullForMostChild
340
    ) {
341
        $navigationsUsed = $expression->getNavigationPropertiesInThePath();
342
        if (!empty($navigationsUsed)) {
343
            $this->_navigationPropertiesUsedInTheExpression[] = $navigationsUsed;
344
        } 
345
346
        $nullableExpTree = $expression->createNullableExpressionTree($checkNullForMostChild);
347
        
348
        if ($parentExpression == null) {
349
            return new LogicalExpression(
350
                $nullableExpTree, 
0 ignored issues
show
Bug introduced by
It seems like $nullableExpTree defined by $expression->createNulla...$checkNullForMostChild) on line 346 can also be of type null; however, POData\UriProcessor\Quer...pression::__construct() does only seem to accept object<POData\UriProcess...ons\AbstractExpression>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
351
                $expression, 
352
                ExpressionType::AND_LOGICAL
353
            );
354
        }
355
        
356
        return $nullableExpTree;
357
    }
358
359
    /**
360
     * Process a releational expression node for nullability.
361
     *     
362
     * @param RelationalExpression $expression       The relational expression node
363
     *                                               to process.
364
     * @param AbstractExpression   $parentExpression The parent expression of 
365
     *                                               expression node to process.
366
     * 
367
     * @return LogicalExpression|null
368
     */
369
    private function _processRelationalNode(RelationalExpression $expression, 
370
        $parentExpression
371
    ) {
372
        $leftNullableExpTree = $this->_processNodeForNullability(
373
            $expression->getLeft(), 
374
            $expression
375
        );
376
        $rightNullableExpTree = $this->_processNodeForNullability(
377
            $expression->getRight(), 
378
            $expression
379
        );
380
        $resultExpression = null;
0 ignored issues
show
Unused Code introduced by
$resultExpression is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
381 View Code Duplication
        if ($leftNullableExpTree != null && $rightNullableExpTree != null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
382
            $resultExpression = $this->_mergeNullableExpressionTrees(
383
                $leftNullableExpTree, 
384
                $rightNullableExpTree
385
            );
386
        } else {
387
            $resultExpression = $leftNullableExpTree != null 
388
                               ? $leftNullableExpTree : $rightNullableExpTree; 
389
        }
390
        
391
        if ($resultExpression == null) {
392
               return null;
393
        }
394
           
395
        if ($parentExpression == null) {
396
            return new LogicalExpression(
397
                $resultExpression, 
398
                $expression, 
399
                ExpressionType::AND_LOGICAL
400
            );
401
        }
402
        
403
        return $resultExpression;
404
    }
405
406
    /**
407
     * Process an unary expression node for nullability 
408
     * 
409
     * @param UnaryExpression    $expression       The unary expression node
410
     *                                             to process.
411
     * @param AbstractExpression $parentExpression The parent expression of 
412
     *                                             expression node to process.
413
     * 
414
     * @return LogicalExpression|null
415
     */
416
    private function _processUnaryNode(UnaryExpression $expression, 
417
        $parentExpression
418
    ) {       
419
        if ($expression->getNodeType() == ExpressionType::NEGATE) {
420
            return $this->_processNodeForNullability(
421
                $expression->getChild(), 
422
                $expression
423
            );
424
        }
425
426
        if ($expression->getNodeType() == ExpressionType::NOT_LOGICAL) {
427
            $resultExpression = $this->_processNodeForNullability(
428
                $expression->getChild(), 
429
                $expression
430
            );
431
            if ($resultExpression == null) {
432
                return null;
433
            }
434
           
435
            if ($parentExpression == null) {
436
                return new LogicalExpression(
437
                    $resultExpression, 
438
                    $expression, 
439
                    ExpressionType::AND_LOGICAL
440
                );
441
            }
442
           
443
            return $resultExpression;
444
        }
445
446
        throw ODataException::createSyntaxError(
447
            Messages::expressionParser2UnexpectedExpression(get_class($expression))
448
        );
449
    }
450
    
451
    /**
452
     * Merge two null check expression trees by removing duplicate nodes.
453
     *
454
     * @param AbstractExpression $nullCheckExpTree1 First expression.
455
     * @param AbstractExpression $nullCheckExpTree2 Second expression.
456
     * 
457
     * @return UnaryExpression|LogicalExpression
458
     */
459
    private function _mergeNullableExpressionTrees($nullCheckExpTree1, 
460
        $nullCheckExpTree2
461
    ) {
462
        $this->_mapTable = array();
463
        $this->_map($nullCheckExpTree1);
464
        $this->_map($nullCheckExpTree2);
465
        $expression = null;
466
        $isNullFunctionDescription = null; 
0 ignored issues
show
Unused Code introduced by
$isNullFunctionDescription is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
467
        foreach ($this->_mapTable as $node) {
468
            if ($expression == null) {
469
                $expression = new UnaryExpression(
470
                    new FunctionCallExpression(
0 ignored issues
show
Documentation introduced by
new \POData\UriProcessor...tType()), array($node)) is of type object<POData\UriProcess...FunctionCallExpression>, but the function expects a object<POData\UriProcess...pressions\unknown_type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
471
                        FunctionDescription::isNullCheckFunction($node->getType()), 
472
                        array($node)
473
                    ), 
474
                    ExpressionType::NOT_LOGICAL, 
475
                    new Boolean()
0 ignored issues
show
Documentation introduced by
new \POData\Providers\Metadata\Type\Boolean() is of type object<POData\Providers\Metadata\Type\Boolean>, but the function expects a object<POData\UriProcess...pressions\unknown_type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
476
                );
477
            } else {
478
                $expression = new LogicalExpression(
479
                    $expression, 
480
                    new UnaryExpression(
481
                        new FunctionCallExpression(
0 ignored issues
show
Documentation introduced by
new \POData\UriProcessor...tType()), array($node)) is of type object<POData\UriProcess...FunctionCallExpression>, but the function expects a object<POData\UriProcess...pressions\unknown_type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
482
                            FunctionDescription::isNullCheckFunction(
483
                                $node->getType()
484
                            ), 
485
                            array($node)
486
                        ), 
487
                        ExpressionType::NOT_LOGICAL, 
488
                        new Boolean()
0 ignored issues
show
Documentation introduced by
new \POData\Providers\Metadata\Type\Boolean() is of type object<POData\Providers\Metadata\Type\Boolean>, but the function expects a object<POData\UriProcess...pressions\unknown_type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
489
                    ), 
490
                    ExpressionType::AND_LOGICAL
491
                ); 
492
            }
493
        }
494
        
495
        return $expression;
496
    }
497
498
    /**
499
     *  Populate map table 
500
     *
501
     * @param AbstractExpression $nullCheckExpTree The expression to verfiy.
502
     * 
503
     * @return void
504
     * 
505
     * @throws ODataException
506
     */
507
    private function _map($nullCheckExpTree)
508
    {
509
        if ($nullCheckExpTree instanceof LogicalExpression) {
510
            $this->_map($nullCheckExpTree->getLeft());
511
            $this->_map($nullCheckExpTree->getRight());
512
        } else if ($nullCheckExpTree instanceof UnaryExpression) {
513
            $this->_map($nullCheckExpTree->getChild());
514
        } else if ($nullCheckExpTree instanceof FunctionCallExpression) {
515
            $param = $nullCheckExpTree->getParamExpressions();
516
            $this->_map($param[0]);
517
        } else if ($nullCheckExpTree instanceof PropertyAccessExpression) {
518
            $parent = $nullCheckExpTree;
519
            $key = null;        
520
            do {
521
                $key = $parent->getResourceProperty()->getName() . '_' . $key;
522
                $parent = $parent->getParent();
523
            } while ($parent != null);
524
                        
525
            $this->_mapTable[$key] = $nullCheckExpTree;
526
        } else {
527
            throw ODataException::createSyntaxError(
528
                Messages::expressionParser2UnexpectedExpression(get_class($nullCheckExpTree))
529
            );
530
            
531
        }
532
    }
533
}