OrderByParser   B
last analyzed

Complexity

Total Complexity 51

Size/Duplication

Total Lines 452
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 14

Importance

Changes 0
Metric Value
wmc 51
lcom 1
cbo 14
dl 0
loc 452
rs 8.3206
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B parseOrderByClause() 0 30 2
D _buildOrderByTree() 0 183 27
C _createOrderInfo() 0 30 7
B _generateTopLevelComparisonFunction() 0 24 3
D _readOrderBy() 0 42 9
A _assertion() 0 6 2

How to fix   Complexity   

Complex Class

Complex classes like OrderByParser often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use OrderByParser, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace POData\UriProcessor\QueryProcessor\OrderByParser;
4
5
use POData\UriProcessor\QueryProcessor\AnonymousFunction;
6
use POData\UriProcessor\QueryProcessor\ExpressionParser\ExpressionLexer;
7
use POData\UriProcessor\QueryProcessor\ExpressionParser\ExpressionTokenId;
8
use POData\Providers\ProvidersWrapper;
9
use POData\Providers\Metadata\Type\Binary;
10
use POData\Providers\Metadata\ResourceSetWrapper;
11
use POData\Providers\Metadata\ResourceType;
12
use POData\Providers\Metadata\ResourcePropertyKind;
13
use POData\Common\ODataException;
14
use POData\Common\Messages;
15
16
/**
17
 * Class OrderByParser
18
 *
19
 * Class to parse $orderby query option and perform syntax validation
20
 * and build 'OrderBy Tree' along with next level of validation, the
21
 * created tree is used for building sort functions and 'OrderByInfo' structure.
22
 *
23
 * The syntax of orderby clause is:
24
 *
25
 * OrderByClause         : OrderByPathSegment [, OrderByPathSegment]*
26
 * OrderByPathSegment    : OrderBySubPathSegment[/OrderBySubPathSegment]*[asc|desc]?
27
 * OrderBySubPathSegment : identifier
28
 *
29
 * @package POData\UriProcessor\QueryProcessor\OrderByParser
30
 */
31
class OrderByParser
32
{
33
    /**
34
     * Collection of anonymous sorter function corresponding to 
35
     * each orderby path segment.
36
     * 
37
     * @var AnonymousFunction[]
38
     */
39
    private $_comparisonFunctions = array();
40
41
    /**
42
     * The top level sorter function generated from orderby path 
43
     * segments.
44
     * 
45
     * @var AnonymousFunction
46
     */
47
    private $_topLevelComparisonFunction;
48
49
    /**
50
     * The structure holds information about the navigation properties 
51
     * used in the orderby clause (if any) and orderby path if IDSQP 
52
     * implementor want to perform sorting.
53
     * 
54
     * @var OrderByInfo
55
     */
56
    private $_orderByInfo;
57
58
    /**
59
     * Reference to metadata and query provider wrapper
60
     * 
61
     * @var ProvidersWrapper
62
     */
63
    private $_providerWrapper;
64
65
    /**
66
     * This object will be of type of the resource set identified by the 
67
     * request uri.
68
     * 
69
     * @var mixed
70
     */
71
    private $_dummyObject;
72
73
    /**
74
     * Creates new instance of OrderByParser
75
     * 
76
     * @param ProvidersWrapper $providerWrapper Reference to metadata
77
     *                                                      and query provider 
78
     *                                                      wrapper
79
     */
80
    private function __construct(ProvidersWrapper $providerWrapper)
81
    {
82
        $this->_providerWrapper = $providerWrapper;
83
    }
84
85
    /**
86
     * This function perform the following tasks with the help of internal helper
87
     * functions
88
     * (1) Read the orderby clause and perform basic syntax errors
89
     * (2) Build 'Order By Tree', creates anonymous sorter function for each leaf 
90
     *     node and check for error
91
     * (3) Build 'OrderInfo' structure, holds information about the navigation 
92
     *     properties used in the orderby clause (if any) and orderby path if 
93
     *     IDSQP implementor want to perform sorting
94
     * (4) Build top level anonymous sorter function
95
     * (4) Release resources hold by the 'Order By Tree'
96
     * (5) Create 'InternalOrderInfo' structure, which wraps 'OrderInfo' and top 
97
     *     level sorter function 
98
     * 
99
     * @param ResourceSetWrapper           $resourceSetWrapper ResourceSetWrapper for the resource targeted by resource path.
100
     * @param ResourceType                 $resourceType       ResourceType for the resource targeted by resource path.
101
     * @param string                       $orderBy            The orderby clause.
102
     * @param ProvidersWrapper $providerWrapper    Reference to the wrapper for IDSQP and IDSMP impl.
103
     * 
104
     * @return InternalOrderByInfo
105
     * 
106
     * @throws ODataException If any error occur while parsing orderby clause
107
     */
108
    public static function parseOrderByClause(
109
	    ResourceSetWrapper $resourceSetWrapper,
110
        ResourceType $resourceType,
111
        $orderBy,
112
        ProvidersWrapper $providerWrapper
113
    ) {
114
        $orderByParser = new OrderByParser($providerWrapper);
115
        try {
116
            $orderByParser->_dummyObject = $resourceType->getInstanceType()->newInstance();
0 ignored issues
show
Bug introduced by
The method newInstance does only exist in ReflectionClass, but not in POData\Providers\Metadata\Type\IType.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
117
        } catch (\ReflectionException $reflectionException) {
118
            throw ODataException::createInternalServerError(Messages::orderByParserFailedToCreateDummyObject());
119
        }
120
        $orderByParser->_rootOrderByNode = new OrderByRootNode($resourceSetWrapper, $resourceType);
0 ignored issues
show
Bug introduced by
The property _rootOrderByNode does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
121
        $orderByPathSegments = $orderByParser->_readOrderBy($orderBy);
122
        $orderByParser->_buildOrderByTree($orderByPathSegments);
123
        $orderByParser->_createOrderInfo($orderByPathSegments);
124
        $orderByParser->_generateTopLevelComparisonFunction();
125
        //Recursively release the resources
126
        $orderByParser->_rootOrderByNode->free();
127
        //creates internal order info wrapper 
128
        $internalOrderInfo = new InternalOrderByInfo(
129
            $orderByParser->_orderByInfo, 
130
            $orderByParser->_comparisonFunctions, 
131
            $orderByParser->_topLevelComparisonFunction, 
132
            $orderByParser->_dummyObject
133
        );
134
        unset($orderByParser->_orderByInfo);
135
        unset($orderByParser->_topLevelComparisonFunction);
136
        return $internalOrderInfo;        
137
    }
138
139
    /**
140
     * Build 'OrderBy Tree' from the given orderby path segments, also build 
141
     * comparsion function for each path segment.
142
     * 
143
     * @param array(array) &$orderByPathSegments Collection of orderby path segments,
144
     *                                           this is passed by reference
145
     *                                           since we need this function to 
146
     *                                           modify this array in two cases:
147
     *                                           1. if asc or desc present, then the 
148
     *                                              corresponding sub path segment 
149
     *                                              should be removed
150
     *                                           2. remove duplicate orderby path 
151
     *                                              segment
152
     * 
153
     * @return void
154
     * 
155
     * @throws ODataException If any error occurs while processing the orderby path 
156
     *                        segments
157
     */
158
    private function _buildOrderByTree(&$orderByPathSegments)
159
    {
160
        foreach ($orderByPathSegments as $index1 => &$orderBySubPathSegments) {
161
            $currentNode = $this->_rootOrderByNode;
162
            $currentObject = $this->_dummyObject;
163
            $ascending = true;
164
            $subPathCount = count($orderBySubPathSegments);
165
            // Check sort order is specified in the path, if so set a 
166
            // flag and remove that segment
167
            if ($subPathCount > 1) {
168
                if ($orderBySubPathSegments[$subPathCount - 1] === '*desc') {
169
                    $ascending = false;
170
                    unset($orderBySubPathSegments[$subPathCount - 1]);
171
                    $subPathCount--;
172
                } else if ($orderBySubPathSegments[$subPathCount - 1] === '*asc') {
173
                    unset($orderBySubPathSegments[$subPathCount - 1]);
174
                    $subPathCount--;
175
                }
176
            }
177
178
            $ancestors = array($this->_rootOrderByNode->getResourceSetWrapper()->getName());
179
            foreach ($orderBySubPathSegments as $index2 => $orderBySubPathSegment) {
180
                $isLastSegment = ($index2 == $subPathCount - 1);
181
                $resourceSetWrapper = null;
182
                $resourceType = $currentNode->getResourceType();
183
                $resourceProperty = $resourceType->resolveProperty($orderBySubPathSegment);
184
                if (is_null($resourceProperty)) {
185
                    throw ODataException::createSyntaxError(
186
                        Messages::orderByParserPropertyNotFound(
187
                            $resourceType->getFullName(), $orderBySubPathSegment
188
                        )
189
                    );
190
                }
191
192
                if ($resourceProperty->isKindOf(ResourcePropertyKind::BAG)) {
193
					throw ODataException::createBadRequestError(
194
                        Messages::orderByParserBagPropertyNotAllowed(
195
                            $resourceProperty->getName()
196
                        )
197
                    );
198
                } else if ($resourceProperty->isKindOf(ResourcePropertyKind::PRIMITIVE)) {
199
                    if (!$isLastSegment) {
200
						throw ODataException::createBadRequestError(
201
                            Messages::orderByParserPrimitiveAsIntermediateSegment(
202
                                $resourceProperty->getName()
203
                            )
204
                        );
205
                    }
206
207
                    $type = $resourceProperty->getInstanceType();
208
                    if ($type instanceof Binary) {
209
						throw ODataException::createBadRequestError(Messages::orderByParserSortByBinaryPropertyNotAllowed($resourceProperty->getName()));
210
                    }
211
                } else if ($resourceProperty->getKind() == ResourcePropertyKind::RESOURCESET_REFERENCE 
212
                    || $resourceProperty->getKind() == ResourcePropertyKind::RESOURCE_REFERENCE
213
                ) {
214
                    $this->_assertion($currentNode instanceof OrderByRootNode || $currentNode instanceof OrderByNode);
215
                    $resourceSetWrapper = $currentNode->getResourceSetWrapper();
216
                    $this->_assertion(!is_null($resourceSetWrapper));
217
                    $resourceSetWrapper 
218
                        = $this->_providerWrapper->getResourceSetWrapperForNavigationProperty(
219
                            $resourceSetWrapper, $resourceType, $resourceProperty
220
                        );
221
                    if (is_null($resourceSetWrapper)) {
222
						throw ODataException::createBadRequestError(
223
                            Messages::badRequestInvalidPropertyNameSpecified(
224
                                $resourceType->getFullName(), $orderBySubPathSegment
225
                            )
226
                        );
227
                    }
228
229
                    if ($resourceProperty->getKind() == ResourcePropertyKind::RESOURCESET_REFERENCE) {
230
						throw ODataException::createBadRequestError(
231
                            Messages::orderByParserResourceSetReferenceNotAllowed(
232
                                $resourceProperty->getName(), $resourceType->getFullName()
233
                            )
234
                        );
235
                    }
236
237
                    $resourceSetWrapper->checkResourceSetRightsForRead(true);
238
                    if ($isLastSegment) {
239
						throw ODataException::createBadRequestError(
240
                            Messages::orderByParserSortByNavigationPropertyIsNotAllowed(
241
                                $resourceProperty->getName()
242
                            )
243
                        );
244
                    }
245
246
                    $ancestors[] = $orderBySubPathSegment;
247
                } else if ($resourceProperty->isKindOf(ResourcePropertyKind::COMPLEX_TYPE)) {
248
                    if ($isLastSegment) {
249
						throw ODataException::createBadRequestError(
250
                            Messages::orderByParserSortByComplexPropertyIsNotAllowed(
251
                                $resourceProperty->getName()
252
                            )
253
                        );
254
                    }
255
256
                    $ancestors[] = $orderBySubPathSegment;
257
                } else {
258
                    throw ODataException::createInternalServerError(
259
                        Messages::orderByParserUnexpectedPropertyType()
260
                    );
261
                }
262
263
                $node = $currentNode->findNode($orderBySubPathSegment);
264
                if (is_null($node)) {
265
                    if ($resourceProperty->isKindOf(ResourcePropertyKind::PRIMITIVE)) {
266
                        $node = new OrderByLeafNode(
267
                            $orderBySubPathSegment, $resourceProperty, 
268
                            $ascending
269
                        );                        
270
                        $this->_comparisonFunctions[] 
271
                            = $node->buildComparisonFunction($ancestors);
272
                    } else if ($resourceProperty->getKind() == ResourcePropertyKind::RESOURCE_REFERENCE) {
273
                        $node = new OrderByNode(
274
                            $orderBySubPathSegment, $resourceProperty, 
275
                            $resourceSetWrapper
0 ignored issues
show
Bug introduced by
It seems like $resourceSetWrapper can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
276
                        );
277
                        // Initialize this member variable (identified by 
278
                        // $resourceProperty) of parent object. 
279
                        try {
280
                            $dummyProperty 
281
                                = new \ReflectionProperty(
282
                                    $currentObject, $resourceProperty->getName()
283
                                );
284
                            $object = $resourceProperty->getInstanceType()->newInstance();
285
                            $dummyProperty->setValue($currentObject, $object);
286
                            $currentObject = $object;
287
                        } catch (\ReflectionException $reflectionException) {
288
                            throw ODataException::createInternalServerError(
289
                                Messages::orderByParserFailedToAccessOrInitializeProperty(
290
                                    $resourceProperty->getName(), $resourceType->getName()
291
                                )
292
                            );
293
                        }
294
                    } else if ($resourceProperty->getKind() == ResourcePropertyKind::COMPLEX_TYPE) {
295
                        $node = new OrderByNode($orderBySubPathSegment, $resourceProperty, null);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a object<POData\Providers\...ata\ResourceSetWrapper>.

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...
296
                        // Initialize this member variable
297
                        // (identified by $resourceProperty)of parent object. 
298
                        try {
299
                            $dummyProperty 
300
                                = new \ReflectionProperty(
301
                                    $currentObject, $resourceProperty->getName()
302
                                );
303
                            $object = $resourceProperty->getInstanceType()->newInstance();
304
                            $dummyProperty->setValue($currentObject, $object);
305
                            $currentObject = $object;
306
                        } catch (\ReflectionException $reflectionException) {
307
                            throw ODataException::createInternalServerError(
308
                                Messages::orderByParserFailedToAccessOrInitializeProperty(
309
                                    $resourceProperty->getName(), $resourceType->getName()
310
                                )
311
                            );
312
                        }
313
                    }
314
315
                    $currentNode->addNode($node);
316
                } else {
317
                    try {
318
                        $dummyProperty = new \ReflectionProperty(
319
                            $currentObject, $resourceProperty->getName()
320
                        );
321
                        $currentObject = $dummyProperty->getValue($currentObject);
322
                    } catch (\ReflectionException $reflectionException) {
323
                            throw ODataException::createInternalServerError(
324
                                Messages::orderByParserFailedToAccessOrInitializeProperty(
325
                                    $resourceProperty->getName(), 
326
                                    $resourceType->getName()
327
                                )
328
                            );
329
                    }
330
331
                    if ($node instanceof OrderByLeafNode) {
332
                        //remove duplicate orderby path
333
                        unset($orderByPathSegments[$index1]);
334
                    }
335
                }
336
337
                $currentNode = $node;
338
            }
339
        }
340
    }
341
342
    /**
343
     * Traverse 'Order By Tree' and create 'OrderInfo' structure
344
     * 
345
     * @param array(array) $orderByPaths The orderby paths.
0 ignored issues
show
Documentation introduced by
The doc-type array(array) could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
346
     * 
347
     * @return OrderByInfo
348
     * 
349
     * @throws ODataException In case parser found any tree inconsisitent 
350
     *                        state, throws unexpected state error 
351
     */
352
    private function _createOrderInfo($orderByPaths)
353
    {
354
        $orderByPathSegments = array();
355
        $navigationPropertiesInThePath = array();
356
        foreach ($orderByPaths as $index => $orderBySubPaths) {
357
            $currentNode = $this->_rootOrderByNode;
358
            $orderBySubPathSegments = array();
359
            foreach ($orderBySubPaths as $orderBySubPath) {
360
                $node = $currentNode->findNode($orderBySubPath);
361
                $this->_assertion(!is_null($node));
362
                $resourceProperty = $node->getResourceProperty();
363
                if ($node instanceof OrderByNode && !is_null($node->getResourceSetWrapper())) {
364
                    if (!array_key_exists($index, $navigationPropertiesInThePath)) {
365
                        $navigationPropertiesInThePath[$index] = array();
366
                    }
367
368
                    $navigationPropertiesInThePath[$index][] = $resourceProperty;
369
                }
370
371
                $orderBySubPathSegments[] = new OrderBySubPathSegment($resourceProperty);
372
                $currentNode = $node;
373
            }
374
375
            $this->_assertion($currentNode instanceof OrderByLeafNode);
376
            $orderByPathSegments[] = new OrderByPathSegment($orderBySubPathSegments, $currentNode->isAscending());
377
            unset($orderBySubPathSegments);
378
        }
379
380
        $this->_orderByInfo = new OrderByInfo($orderByPathSegments, empty($navigationPropertiesInThePath) ? null : $navigationPropertiesInThePath);
381
    }
382
383
    /**
384
     * Generates top level comparison function from sub comparison functions.
385
     * 
386
     * @return void
387
     */
388
    private function _generateTopLevelComparisonFunction()
389
    {
390
        $comparisonFunctionCount = count($this->_comparisonFunctions);
391
        $this->_assertion($comparisonFunctionCount > 0);
392
        $parameters = $this->_comparisonFunctions[0]->getParameters();
393
        //$parameters[] = '&$matchLevel = 0';
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
394
        if ($comparisonFunctionCount == 1) {
395
            $this->_topLevelComparisonFunction = $this->_comparisonFunctions[0];
396
        } else {
397
            $code = null;
398
            for ($i = 0; $i < $comparisonFunctionCount; $i++) {
399
                $subComparisonFunctionName = substr($this->_comparisonFunctions[$i]->getReference(), 1);
400
                $code .= "\$result = call_user_func_array(chr(0) . '$subComparisonFunctionName', array($parameters[0], $parameters[1]));";
401
                $code .= "
402
                         if (\$result != 0) {
403
                            return \$result;
404
                         }
405
                         ";
406
            }
407
408
            $code .= "return \$result;";
409
            $this->_topLevelComparisonFunction = new AnonymousFunction($parameters, $code);
410
        }        
411
    }
412
413
    /**
414
     * Read orderby clause.
415
     * 
416
     * @param string $value orderby clause to read.
417
     * 
418
     * @return array(array) An array of 'OrderByPathSegment's, each of which 
0 ignored issues
show
Documentation introduced by
The doc-type array(array) could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
419
     *                      is array of 'OrderBySubPathSegment's
420
     * 
421
     * @throws ODataException If any syntax error found while reading the clause
422
     */
423
    private function _readOrderBy($value)
424
    {
425
        $orderByPathSegments = array();
426
        $lexer = new ExpressionLexer($value);
427
        $i = 0;
428
        while ($lexer->getCurrentToken()->Id != ExpressionTokenId::END) {
429
            $orderBySubPathSegment = $lexer->readDottedIdentifier();
430
            if (!array_key_exists($i, $orderByPathSegments)) {
431
                $orderByPathSegments[$i] = array();
432
            }
433
434
            $orderByPathSegments[$i][] = $orderBySubPathSegment;
435
            $tokenId = $lexer->getCurrentToken()->Id;
436
            if ($tokenId != ExpressionTokenId::END) {
437
                if ($tokenId != ExpressionTokenId::SLASH) {
438
                    if ($tokenId != ExpressionTokenId::COMMA) {
439
                        $lexer->validateToken(ExpressionTokenId::IDENTIFIER);
440
                        $identifier = $lexer->getCurrentToken()->Text;
441
                        if ($identifier !== 'asc' && $identifier !== 'desc') {
442
                            // force lexer to throw syntax error as we found 
443
                            // unexpected identifier
444
                            $lexer->validateToken(ExpressionTokenId::DOT);
445
                        }
446
447
                        $orderByPathSegments[$i][] = '*' . $identifier;
448
                        $lexer->nextToken();
449
                        $tokenId = $lexer->getCurrentToken()->Id;
450
                        if ($tokenId != ExpressionTokenId::END) {
451
                            $lexer->validateToken(ExpressionTokenId::COMMA);
452
                            $i++;
453
                        }
454
                    } else {
455
                        $i++;
456
                    }
457
                }
458
459
                $lexer->nextToken();
460
            }
461
        }
462
463
        return $orderByPathSegments;
464
    }
465
466
    /**
467
     * Assert that the given condition is true, if false throw 
468
     * ODataException for unexpected state
469
     * 
470
     * @param boolean $condition The condition to assert
471
     * 
472
     * @return void
473
     * 
474
     * @throws ODataException
475
     */
476
    private function _assertion($condition)
477
    {
478
        if (!$condition) {
479
            throw ODataException::createInternalServerError(Messages::orderByParserUnExpectedState());
480
        }
481
    }
482
}