Complex classes like Parser 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 Parser, and based on these observations, apply Extract Interface, too.
| 1 | <?php  | 
            ||
| 37 | class Parser  | 
            ||
| 38 | { | 
            ||
| 39 | /**  | 
            ||
| 40 | * READ-ONLY: Maps BUILT-IN string function names to AST class names.  | 
            ||
| 41 | *  | 
            ||
| 42 | * @var array  | 
            ||
| 43 | */  | 
            ||
| 44 | private static $_STRING_FUNCTIONS = [  | 
            ||
| 45 | 'concat' => Functions\ConcatFunction::class,  | 
            ||
| 46 | 'substring' => Functions\SubstringFunction::class,  | 
            ||
| 47 | 'trim' => Functions\TrimFunction::class,  | 
            ||
| 48 | 'lower' => Functions\LowerFunction::class,  | 
            ||
| 49 | 'upper' => Functions\UpperFunction::class,  | 
            ||
| 50 | 'identity' => Functions\IdentityFunction::class,  | 
            ||
| 51 | ];  | 
            ||
| 52 | |||
| 53 | /**  | 
            ||
| 54 | * READ-ONLY: Maps BUILT-IN numeric function names to AST class names.  | 
            ||
| 55 | *  | 
            ||
| 56 | * @var array  | 
            ||
| 57 | */  | 
            ||
| 58 | private static $_NUMERIC_FUNCTIONS = [  | 
            ||
| 59 | 'length' => Functions\LengthFunction::class,  | 
            ||
| 60 | 'locate' => Functions\LocateFunction::class,  | 
            ||
| 61 | 'abs' => Functions\AbsFunction::class,  | 
            ||
| 62 | 'sqrt' => Functions\SqrtFunction::class,  | 
            ||
| 63 | 'mod' => Functions\ModFunction::class,  | 
            ||
| 64 | 'size' => Functions\SizeFunction::class,  | 
            ||
| 65 | 'date_diff' => Functions\DateDiffFunction::class,  | 
            ||
| 66 | 'bit_and' => Functions\BitAndFunction::class,  | 
            ||
| 67 | 'bit_or' => Functions\BitOrFunction::class,  | 
            ||
| 68 | |||
| 69 | // Aggregate functions  | 
            ||
| 70 | 'min' => Functions\MinFunction::class,  | 
            ||
| 71 | 'max' => Functions\MaxFunction::class,  | 
            ||
| 72 | 'avg' => Functions\AvgFunction::class,  | 
            ||
| 73 | 'sum' => Functions\SumFunction::class,  | 
            ||
| 74 | 'count' => Functions\CountFunction::class,  | 
            ||
| 75 | ];  | 
            ||
| 76 | |||
| 77 | /**  | 
            ||
| 78 | * READ-ONLY: Maps BUILT-IN datetime function names to AST class names.  | 
            ||
| 79 | *  | 
            ||
| 80 | * @var array  | 
            ||
| 81 | */  | 
            ||
| 82 | private static $_DATETIME_FUNCTIONS = [  | 
            ||
| 83 | 'current_date' => Functions\CurrentDateFunction::class,  | 
            ||
| 84 | 'current_time' => Functions\CurrentTimeFunction::class,  | 
            ||
| 85 | 'current_timestamp' => Functions\CurrentTimestampFunction::class,  | 
            ||
| 86 | 'date_add' => Functions\DateAddFunction::class,  | 
            ||
| 87 | 'date_sub' => Functions\DateSubFunction::class,  | 
            ||
| 88 | ];  | 
            ||
| 89 | |||
| 90 | /*  | 
            ||
| 91 | * Expressions that were encountered during parsing of identifiers and expressions  | 
            ||
| 92 | * and still need to be validated.  | 
            ||
| 93 | */  | 
            ||
| 94 | |||
| 95 | /**  | 
            ||
| 96 | * @var array  | 
            ||
| 97 | */  | 
            ||
| 98 | private $deferredIdentificationVariables = [];  | 
            ||
| 99 | |||
| 100 | /**  | 
            ||
| 101 | * @var array  | 
            ||
| 102 | */  | 
            ||
| 103 | private $deferredPartialObjectExpressions = [];  | 
            ||
| 104 | |||
| 105 | /**  | 
            ||
| 106 | * @var array  | 
            ||
| 107 | */  | 
            ||
| 108 | private $deferredPathExpressions = [];  | 
            ||
| 109 | |||
| 110 | /**  | 
            ||
| 111 | * @var array  | 
            ||
| 112 | */  | 
            ||
| 113 | private $deferredResultVariables = [];  | 
            ||
| 114 | |||
| 115 | /**  | 
            ||
| 116 | * @var array  | 
            ||
| 117 | */  | 
            ||
| 118 | private $deferredNewObjectExpressions = [];  | 
            ||
| 119 | |||
| 120 | /**  | 
            ||
| 121 | * The lexer.  | 
            ||
| 122 | *  | 
            ||
| 123 | * @var \Doctrine\ORM\Query\Lexer  | 
            ||
| 124 | */  | 
            ||
| 125 | private $lexer;  | 
            ||
| 126 | |||
| 127 | /**  | 
            ||
| 128 | * The parser result.  | 
            ||
| 129 | *  | 
            ||
| 130 | * @var \Doctrine\ORM\Query\ParserResult  | 
            ||
| 131 | */  | 
            ||
| 132 | private $parserResult;  | 
            ||
| 133 | |||
| 134 | /**  | 
            ||
| 135 | * The EntityManager.  | 
            ||
| 136 | *  | 
            ||
| 137 | * @var \Doctrine\ORM\EntityManager  | 
            ||
| 138 | */  | 
            ||
| 139 | private $em;  | 
            ||
| 140 | |||
| 141 | /**  | 
            ||
| 142 | * The Query to parse.  | 
            ||
| 143 | *  | 
            ||
| 144 | * @var Query  | 
            ||
| 145 | */  | 
            ||
| 146 | private $query;  | 
            ||
| 147 | |||
| 148 | /**  | 
            ||
| 149 | * Map of declared query components in the parsed query.  | 
            ||
| 150 | *  | 
            ||
| 151 | * @var array  | 
            ||
| 152 | */  | 
            ||
| 153 | private $queryComponents = [];  | 
            ||
| 154 | |||
| 155 | /**  | 
            ||
| 156 | * Keeps the nesting level of defined ResultVariables.  | 
            ||
| 157 | *  | 
            ||
| 158 | * @var integer  | 
            ||
| 159 | */  | 
            ||
| 160 | private $nestingLevel = 0;  | 
            ||
| 161 | |||
| 162 | /**  | 
            ||
| 163 | * Any additional custom tree walkers that modify the AST.  | 
            ||
| 164 | *  | 
            ||
| 165 | * @var array  | 
            ||
| 166 | */  | 
            ||
| 167 | private $customTreeWalkers = [];  | 
            ||
| 168 | |||
| 169 | /**  | 
            ||
| 170 | * The custom last tree walker, if any, that is responsible for producing the output.  | 
            ||
| 171 | *  | 
            ||
| 172 | * @var TreeWalker  | 
            ||
| 173 | */  | 
            ||
| 174 | private $customOutputWalker;  | 
            ||
| 175 | |||
| 176 | /**  | 
            ||
| 177 | * @var array  | 
            ||
| 178 | */  | 
            ||
| 179 | private $identVariableExpressions = [];  | 
            ||
| 180 | |||
| 181 | /**  | 
            ||
| 182 | * Creates a new query parser object.  | 
            ||
| 183 | *  | 
            ||
| 184 | * @param Query $query The Query to parse.  | 
            ||
| 185 | */  | 
            ||
| 186 | 757 | public function __construct(Query $query)  | 
            |
| 193 | |||
| 194 | /**  | 
            ||
| 195 | * Sets a custom tree walker that produces output.  | 
            ||
| 196 | * This tree walker will be run last over the AST, after any other walkers.  | 
            ||
| 197 | *  | 
            ||
| 198 | * @param string $className  | 
            ||
| 199 | *  | 
            ||
| 200 | * @return void  | 
            ||
| 201 | */  | 
            ||
| 202 | 111 | public function setCustomOutputTreeWalker($className)  | 
            |
| 206 | |||
| 207 | /**  | 
            ||
| 208 | * Adds a custom tree walker for modifying the AST.  | 
            ||
| 209 | *  | 
            ||
| 210 | * @param string $className  | 
            ||
| 211 | *  | 
            ||
| 212 | * @return void  | 
            ||
| 213 | */  | 
            ||
| 214 | public function addCustomTreeWalker($className)  | 
            ||
| 218 | |||
| 219 | /**  | 
            ||
| 220 | * Gets the lexer used by the parser.  | 
            ||
| 221 | *  | 
            ||
| 222 | * @return \Doctrine\ORM\Query\Lexer  | 
            ||
| 223 | */  | 
            ||
| 224 | 27 | public function getLexer()  | 
            |
| 228 | |||
| 229 | /**  | 
            ||
| 230 | * Gets the ParserResult that is being filled with information during parsing.  | 
            ||
| 231 | *  | 
            ||
| 232 | * @return \Doctrine\ORM\Query\ParserResult  | 
            ||
| 233 | */  | 
            ||
| 234 | public function getParserResult()  | 
            ||
| 238 | |||
| 239 | /**  | 
            ||
| 240 | * Gets the EntityManager used by the parser.  | 
            ||
| 241 | *  | 
            ||
| 242 | * @return \Doctrine\ORM\EntityManager  | 
            ||
| 243 | */  | 
            ||
| 244 | public function getEntityManager()  | 
            ||
| 248 | |||
| 249 | /**  | 
            ||
| 250 | * Parses and builds AST for the given Query.  | 
            ||
| 251 | *  | 
            ||
| 252 | * @return \Doctrine\ORM\Query\AST\SelectStatement |  | 
            ||
| 253 | * \Doctrine\ORM\Query\AST\UpdateStatement |  | 
            ||
| 254 | * \Doctrine\ORM\Query\AST\DeleteStatement  | 
            ||
| 255 | */  | 
            ||
| 256 | 757 | public function getAST()  | 
            |
| 288 | |||
| 289 | /**  | 
            ||
| 290 | * Attempts to match the given token with the current lookahead token.  | 
            ||
| 291 | *  | 
            ||
| 292 | * If they match, updates the lookahead token; otherwise raises a syntax  | 
            ||
| 293 | * error.  | 
            ||
| 294 | *  | 
            ||
| 295 | * @param int $token The token type.  | 
            ||
| 296 | *  | 
            ||
| 297 | * @return void  | 
            ||
| 298 | *  | 
            ||
| 299 | * @throws QueryException If the tokens don't match.  | 
            ||
| 300 | */  | 
            ||
| 301 | 768 | public function match($token)  | 
            |
| 325 | |||
| 326 | /**  | 
            ||
| 327 | * Frees this parser, enabling it to be reused.  | 
            ||
| 328 | *  | 
            ||
| 329 | * @param boolean $deep Whether to clean peek and reset errors.  | 
            ||
| 330 | * @param integer $position Position to reset.  | 
            ||
| 331 | *  | 
            ||
| 332 | * @return void  | 
            ||
| 333 | */  | 
            ||
| 334 | public function free($deep = false, $position = 0)  | 
            ||
| 347 | |||
| 348 | /**  | 
            ||
| 349 | * Parses a query string.  | 
            ||
| 350 | *  | 
            ||
| 351 | * @return ParserResult  | 
            ||
| 352 | */  | 
            ||
| 353 | 757 | public function parse()  | 
            |
| 398 | |||
| 399 | /**  | 
            ||
| 400 | * Fixes order of identification variables.  | 
            ||
| 401 | *  | 
            ||
| 402 | * They have to appear in the select clause in the same order as the  | 
            ||
| 403 | * declarations (from ... x join ... y join ... z ...) appear in the query  | 
            ||
| 404 | * as the hydration process relies on that order for proper operation.  | 
            ||
| 405 | *  | 
            ||
| 406 | * @param AST\SelectStatement|AST\DeleteStatement|AST\UpdateStatement $AST  | 
            ||
| 407 | *  | 
            ||
| 408 | * @return void  | 
            ||
| 409 | */  | 
            ||
| 410 | 697 | private function fixIdentificationVariableOrder($AST)  | 
            |
| 429 | |||
| 430 | /**  | 
            ||
| 431 | * Generates a new syntax error.  | 
            ||
| 432 | *  | 
            ||
| 433 | * @param string $expected Expected string.  | 
            ||
| 434 | * @param array|null $token Got token.  | 
            ||
| 435 | *  | 
            ||
| 436 | * @return void  | 
            ||
| 437 | *  | 
            ||
| 438 | * @throws \Doctrine\ORM\Query\QueryException  | 
            ||
| 439 | */  | 
            ||
| 440 | 18 | public function syntaxError($expected = '', $token = null)  | 
            |
| 454 | |||
| 455 | /**  | 
            ||
| 456 | * Generates a new semantical error.  | 
            ||
| 457 | *  | 
            ||
| 458 | * @param string $message Optional message.  | 
            ||
| 459 | * @param array|null $token Optional token.  | 
            ||
| 460 | *  | 
            ||
| 461 | * @return void  | 
            ||
| 462 | *  | 
            ||
| 463 | * @throws \Doctrine\ORM\Query\QueryException  | 
            ||
| 464 | */  | 
            ||
| 465 | 29 | public function semanticalError($message = '', $token = null)  | 
            |
| 489 | |||
| 490 | /**  | 
            ||
| 491 | * Peeks beyond the matched closing parenthesis and returns the first token after that one.  | 
            ||
| 492 | *  | 
            ||
| 493 | * @param boolean $resetPeek Reset peek after finding the closing parenthesis.  | 
            ||
| 494 | *  | 
            ||
| 495 | * @return array  | 
            ||
| 496 | */  | 
            ||
| 497 | 91 | private function peekBeyondClosingParenthesis($resetPeek = true)  | 
            |
| 525 | |||
| 526 | /**  | 
            ||
| 527 | * Checks if the given token indicates a mathematical operator.  | 
            ||
| 528 | *  | 
            ||
| 529 | * @param array $token  | 
            ||
| 530 | *  | 
            ||
| 531 | * @return boolean TRUE if the token is a mathematical operator, FALSE otherwise.  | 
            ||
| 532 | */  | 
            ||
| 533 | 277 | private function isMathOperator($token)  | 
            |
| 537 | |||
| 538 | /**  | 
            ||
| 539 | * Checks if the next-next (after lookahead) token starts a function.  | 
            ||
| 540 | *  | 
            ||
| 541 | * @return boolean TRUE if the next-next tokens start a function, FALSE otherwise.  | 
            ||
| 542 | */  | 
            ||
| 543 | 319 | private function isFunction()  | 
            |
| 552 | |||
| 553 | /**  | 
            ||
| 554 | * Checks whether the given token type indicates an aggregate function.  | 
            ||
| 555 | *  | 
            ||
| 556 | * @param int $tokenType  | 
            ||
| 557 | *  | 
            ||
| 558 | * @return boolean TRUE if the token type is an aggregate function, FALSE otherwise.  | 
            ||
| 559 | */  | 
            ||
| 560 | 1 | private function isAggregateFunction($tokenType)  | 
            |
| 564 | |||
| 565 | /**  | 
            ||
| 566 | * Checks whether the current lookahead token of the lexer has the type T_ALL, T_ANY or T_SOME.  | 
            ||
| 567 | *  | 
            ||
| 568 | * @return boolean  | 
            ||
| 569 | */  | 
            ||
| 570 | 259 | private function isNextAllAnySome()  | 
            |
| 574 | |||
| 575 | /**  | 
            ||
| 576 | * Validates that the given <tt>IdentificationVariable</tt> is semantically correct.  | 
            ||
| 577 | * It must exist in query components list.  | 
            ||
| 578 | *  | 
            ||
| 579 | * @return void  | 
            ||
| 580 | */  | 
            ||
| 581 | 708 | private function processDeferredIdentificationVariables()  | 
            |
| 582 |     { | 
            ||
| 583 | 708 |         foreach ($this->deferredIdentificationVariables as $deferredItem) { | 
            |
| 584 | 696 | $identVariable = $deferredItem['expression'];  | 
            |
| 585 | |||
| 586 | // Check if IdentificationVariable exists in queryComponents  | 
            ||
| 587 | 696 |             if ( ! isset($this->queryComponents[$identVariable])) { | 
            |
| 588 | 1 | $this->semanticalError(  | 
            |
| 589 | 1 | "'$identVariable' is not defined.", $deferredItem['token']  | 
            |
| 590 | );  | 
            ||
| 591 | }  | 
            ||
| 592 | |||
| 593 | 696 | $qComp = $this->queryComponents[$identVariable];  | 
            |
| 594 | |||
| 595 | // Check if queryComponent points to an AbstractSchemaName or a ResultVariable  | 
            ||
| 596 | 696 |             if ( ! isset($qComp['metadata'])) { | 
            |
| 597 | $this->semanticalError(  | 
            ||
| 598 | "'$identVariable' does not point to a Class.", $deferredItem['token']  | 
            ||
| 599 | );  | 
            ||
| 600 | }  | 
            ||
| 601 | |||
| 602 | // Validate if identification variable nesting level is lower or equal than the current one  | 
            ||
| 603 | 696 |             if ($qComp['nestingLevel'] > $deferredItem['nestingLevel']) { | 
            |
| 604 | $this->semanticalError(  | 
            ||
| 605 | 696 | "'$identVariable' is used outside the scope of its declaration.", $deferredItem['token']  | 
            |
| 606 | );  | 
            ||
| 607 | }  | 
            ||
| 608 | }  | 
            ||
| 609 | 707 | }  | 
            |
| 610 | |||
| 611 | /**  | 
            ||
| 612 | * Validates that the given <tt>NewObjectExpression</tt>.  | 
            ||
| 613 | *  | 
            ||
| 614 | * @param \Doctrine\ORM\Query\AST\SelectClause $AST  | 
            ||
| 615 | *  | 
            ||
| 616 | * @return void  | 
            ||
| 617 | */  | 
            ||
| 618 | 26 | private function processDeferredNewObjectExpressions($AST)  | 
            |
| 659 | |||
| 660 | /**  | 
            ||
| 661 | * Validates that the given <tt>PartialObjectExpression</tt> is semantically correct.  | 
            ||
| 662 | * It must exist in query components list.  | 
            ||
| 663 | *  | 
            ||
| 664 | * @return void  | 
            ||
| 665 | */  | 
            ||
| 666 | 11 | private function processDeferredPartialObjectExpressions()  | 
            |
| 696 | |||
| 697 | /**  | 
            ||
| 698 | * Validates that the given <tt>ResultVariable</tt> is semantically correct.  | 
            ||
| 699 | * It must exist in query components list.  | 
            ||
| 700 | *  | 
            ||
| 701 | * @return void  | 
            ||
| 702 | */  | 
            ||
| 703 | 9 | private function processDeferredResultVariables()  | 
            |
| 732 | |||
| 733 | /**  | 
            ||
| 734 | * Validates that the given <tt>PathExpression</tt> is semantically correct for grammar rules:  | 
            ||
| 735 | *  | 
            ||
| 736 | * AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression  | 
            ||
| 737 | * SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression  | 
            ||
| 738 | * StateFieldPathExpression ::= IdentificationVariable "." StateField  | 
            ||
| 739 | * SingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField  | 
            ||
| 740 | * CollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField  | 
            ||
| 741 | *  | 
            ||
| 742 | * @return void  | 
            ||
| 743 | */  | 
            ||
| 744 | 511 | private function processDeferredPathExpressions()  | 
            |
| 809 | |||
| 810 | /**  | 
            ||
| 811 | * @return void  | 
            ||
| 812 | */  | 
            ||
| 813 | 698 | private function processRootEntityAliasSelected()  | 
            |
| 827 | |||
| 828 | /**  | 
            ||
| 829 | * QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement  | 
            ||
| 830 | *  | 
            ||
| 831 | * @return \Doctrine\ORM\Query\AST\SelectStatement |  | 
            ||
| 832 | * \Doctrine\ORM\Query\AST\UpdateStatement |  | 
            ||
| 833 | * \Doctrine\ORM\Query\AST\DeleteStatement  | 
            ||
| 834 | */  | 
            ||
| 835 | 757 | public function QueryLanguage()  | 
            |
| 864 | |||
| 865 | /**  | 
            ||
| 866 | * SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]  | 
            ||
| 867 | *  | 
            ||
| 868 | * @return \Doctrine\ORM\Query\AST\SelectStatement  | 
            ||
| 869 | */  | 
            ||
| 870 | 692 | public function SelectStatement()  | 
            |
| 881 | |||
| 882 | /**  | 
            ||
| 883 | * UpdateStatement ::= UpdateClause [WhereClause]  | 
            ||
| 884 | *  | 
            ||
| 885 | * @return \Doctrine\ORM\Query\AST\UpdateStatement  | 
            ||
| 886 | */  | 
            ||
| 887 | 31 | public function UpdateStatement()  | 
            |
| 895 | |||
| 896 | /**  | 
            ||
| 897 | * DeleteStatement ::= DeleteClause [WhereClause]  | 
            ||
| 898 | *  | 
            ||
| 899 | * @return \Doctrine\ORM\Query\AST\DeleteStatement  | 
            ||
| 900 | */  | 
            ||
| 901 | 40 | public function DeleteStatement()  | 
            |
| 909 | |||
| 910 | /**  | 
            ||
| 911 | * IdentificationVariable ::= identifier  | 
            ||
| 912 | *  | 
            ||
| 913 | * @return string  | 
            ||
| 914 | */  | 
            ||
| 915 | 734 | public function IdentificationVariable()  | 
            |
| 929 | |||
| 930 | /**  | 
            ||
| 931 | * AliasIdentificationVariable = identifier  | 
            ||
| 932 | *  | 
            ||
| 933 | * @return string  | 
            ||
| 934 | */  | 
            ||
| 935 | 717 | public function AliasIdentificationVariable()  | 
            |
| 948 | |||
| 949 | /**  | 
            ||
| 950 | * AbstractSchemaName ::= fully_qualified_name | aliased_name | identifier  | 
            ||
| 951 | *  | 
            ||
| 952 | * @return string  | 
            ||
| 953 | */  | 
            ||
| 954 | 738 | public function AbstractSchemaName()  | 
            |
| 974 | |||
| 975 | /**  | 
            ||
| 976 | * Validates an AbstractSchemaName, making sure the class exists.  | 
            ||
| 977 | *  | 
            ||
| 978 | * @param string $schemaName The name to validate.  | 
            ||
| 979 | *  | 
            ||
| 980 | * @throws QueryException if the name does not exist.  | 
            ||
| 981 | */  | 
            ||
| 982 | 732 | private function validateAbstractSchemaName($schemaName)  | 
            |
| 988 | |||
| 989 | /**  | 
            ||
| 990 | * AliasResultVariable ::= identifier  | 
            ||
| 991 | *  | 
            ||
| 992 | * @return string  | 
            ||
| 993 | */  | 
            ||
| 994 | 68 | public function AliasResultVariable()  | 
            |
| 995 |     { | 
            ||
| 996 | 68 | $this->match(Lexer::T_IDENTIFIER);  | 
            |
| 997 | |||
| 998 | 64 | $resultVariable = $this->lexer->token['value'];  | 
            |
| 999 | 64 | $exists = isset($this->queryComponents[$resultVariable]);  | 
            |
| 1000 | |||
| 1001 | 64 |         if ($exists) { | 
            |
| 1002 |             $this->semanticalError("'$resultVariable' is already defined.", $this->lexer->token); | 
            ||
| 1003 | }  | 
            ||
| 1004 | |||
| 1005 | 64 | return $resultVariable;  | 
            |
| 1006 | }  | 
            ||
| 1007 | |||
| 1008 | /**  | 
            ||
| 1009 | * ResultVariable ::= identifier  | 
            ||
| 1010 | *  | 
            ||
| 1011 | * @return string  | 
            ||
| 1012 | */  | 
            ||
| 1013 | 9 | public function ResultVariable()  | 
            |
| 1028 | |||
| 1029 | /**  | 
            ||
| 1030 | * JoinAssociationPathExpression ::= IdentificationVariable "." (CollectionValuedAssociationField | SingleValuedAssociationField)  | 
            ||
| 1031 | *  | 
            ||
| 1032 | * @return \Doctrine\ORM\Query\AST\JoinAssociationPathExpression  | 
            ||
| 1033 | */  | 
            ||
| 1034 | 228 | public function JoinAssociationPathExpression()  | 
            |
| 1059 | |||
| 1060 | /**  | 
            ||
| 1061 | * Parses an arbitrary path expression and defers semantical validation  | 
            ||
| 1062 | * based on expected types.  | 
            ||
| 1063 | *  | 
            ||
| 1064 |      * PathExpression ::= IdentificationVariable {"." identifier}* | 
            ||
| 1065 | *  | 
            ||
| 1066 | * @param integer $expectedTypes  | 
            ||
| 1067 | *  | 
            ||
| 1068 | * @return \Doctrine\ORM\Query\AST\PathExpression  | 
            ||
| 1069 | */  | 
            ||
| 1070 | 529 | public function PathExpression($expectedTypes)  | 
            |
| 1100 | |||
| 1101 | /**  | 
            ||
| 1102 | * AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression  | 
            ||
| 1103 | *  | 
            ||
| 1104 | * @return \Doctrine\ORM\Query\AST\PathExpression  | 
            ||
| 1105 | */  | 
            ||
| 1106 | public function AssociationPathExpression()  | 
            ||
| 1113 | |||
| 1114 | /**  | 
            ||
| 1115 | * SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression  | 
            ||
| 1116 | *  | 
            ||
| 1117 | * @return \Doctrine\ORM\Query\AST\PathExpression  | 
            ||
| 1118 | */  | 
            ||
| 1119 | 441 | public function SingleValuedPathExpression()  | 
            |
| 1126 | |||
| 1127 | /**  | 
            ||
| 1128 | * StateFieldPathExpression ::= IdentificationVariable "." StateField  | 
            ||
| 1129 | *  | 
            ||
| 1130 | * @return \Doctrine\ORM\Query\AST\PathExpression  | 
            ||
| 1131 | */  | 
            ||
| 1132 | 177 | public function StateFieldPathExpression()  | 
            |
| 1136 | |||
| 1137 | /**  | 
            ||
| 1138 | * SingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField  | 
            ||
| 1139 | *  | 
            ||
| 1140 | * @return \Doctrine\ORM\Query\AST\PathExpression  | 
            ||
| 1141 | */  | 
            ||
| 1142 | 9 | public function SingleValuedAssociationPathExpression()  | 
            |
| 1146 | |||
| 1147 | /**  | 
            ||
| 1148 | * CollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField  | 
            ||
| 1149 | *  | 
            ||
| 1150 | * @return \Doctrine\ORM\Query\AST\PathExpression  | 
            ||
| 1151 | */  | 
            ||
| 1152 | 21 | public function CollectionValuedPathExpression()  | 
            |
| 1156 | |||
| 1157 | /**  | 
            ||
| 1158 |      * SelectClause ::= "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression} | 
            ||
| 1159 | *  | 
            ||
| 1160 | * @return \Doctrine\ORM\Query\AST\SelectClause  | 
            ||
| 1161 | */  | 
            ||
| 1162 | 692 | public function SelectClause()  | 
            |
| 1186 | |||
| 1187 | /**  | 
            ||
| 1188 | * SimpleSelectClause ::= "SELECT" ["DISTINCT"] SimpleSelectExpression  | 
            ||
| 1189 | *  | 
            ||
| 1190 | * @return \Doctrine\ORM\Query\AST\SimpleSelectClause  | 
            ||
| 1191 | */  | 
            ||
| 1192 | 27 | public function SimpleSelectClause()  | 
            |
| 1205 | |||
| 1206 | /**  | 
            ||
| 1207 |      * UpdateClause ::= "UPDATE" AbstractSchemaName ["AS"] AliasIdentificationVariable "SET" UpdateItem {"," UpdateItem}* | 
            ||
| 1208 | *  | 
            ||
| 1209 | * @return \Doctrine\ORM\Query\AST\UpdateClause  | 
            ||
| 1210 | */  | 
            ||
| 1211 | 31 | public function UpdateClause()  | 
            |
| 1256 | |||
| 1257 | /**  | 
            ||
| 1258 | * DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName ["AS"] AliasIdentificationVariable  | 
            ||
| 1259 | *  | 
            ||
| 1260 | * @return \Doctrine\ORM\Query\AST\DeleteClause  | 
            ||
| 1261 | */  | 
            ||
| 1262 | 40 | public function DeleteClause()  | 
            |
| 1263 |     { | 
            ||
| 1264 | 40 | $this->match(Lexer::T_DELETE);  | 
            |
| 1265 | |||
| 1266 | 40 |         if ($this->lexer->isNextToken(Lexer::T_FROM)) { | 
            |
| 1267 | 8 | $this->match(Lexer::T_FROM);  | 
            |
| 1268 | }  | 
            ||
| 1269 | |||
| 1270 | 40 | $token = $this->lexer->lookahead;  | 
            |
| 1271 | 40 | $abstractSchemaName = $this->AbstractSchemaName();  | 
            |
| 1272 | |||
| 1273 | 40 | $this->validateAbstractSchemaName($abstractSchemaName);  | 
            |
| 1274 | |||
| 1275 | 40 | $deleteClause = new AST\DeleteClause($abstractSchemaName);  | 
            |
| 1276 | |||
| 1277 | 40 |         if ($this->lexer->isNextToken(Lexer::T_AS)) { | 
            |
| 1278 | $this->match(Lexer::T_AS);  | 
            ||
| 1279 | }  | 
            ||
| 1280 | |||
| 1281 | 40 | $aliasIdentificationVariable = $this->AliasIdentificationVariable();  | 
            |
| 1282 | |||
| 1283 | 39 | $deleteClause->aliasIdentificationVariable = $aliasIdentificationVariable;  | 
            |
| 1284 | 39 | $class = $this->em->getClassMetadata($deleteClause->abstractSchemaName);  | 
            |
| 1285 | |||
| 1286 | // Building queryComponent  | 
            ||
| 1287 | $queryComponent = [  | 
            ||
| 1288 | 39 | 'metadata' => $class,  | 
            |
| 1289 | 'parent' => null,  | 
            ||
| 1290 | 'relation' => null,  | 
            ||
| 1291 | 'map' => null,  | 
            ||
| 1292 | 39 | 'nestingLevel' => $this->nestingLevel,  | 
            |
| 1293 | 39 | 'token' => $token,  | 
            |
| 1294 | ];  | 
            ||
| 1295 | |||
| 1296 | 39 | $this->queryComponents[$aliasIdentificationVariable] = $queryComponent;  | 
            |
| 1297 | |||
| 1298 | 39 | return $deleteClause;  | 
            |
| 1299 | }  | 
            ||
| 1300 | |||
| 1301 | /**  | 
            ||
| 1302 |      * FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}* | 
            ||
| 1303 | *  | 
            ||
| 1304 | * @return \Doctrine\ORM\Query\AST\FromClause  | 
            ||
| 1305 | */  | 
            ||
| 1306 | 674 | public function FromClause()  | 
            |
| 1321 | |||
| 1322 | /**  | 
            ||
| 1323 |      * SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}* | 
            ||
| 1324 | *  | 
            ||
| 1325 | * @return \Doctrine\ORM\Query\AST\SubselectFromClause  | 
            ||
| 1326 | */  | 
            ||
| 1327 | 26 | public function SubselectFromClause()  | 
            |
| 1342 | |||
| 1343 | /**  | 
            ||
| 1344 | * WhereClause ::= "WHERE" ConditionalExpression  | 
            ||
| 1345 | *  | 
            ||
| 1346 | * @return \Doctrine\ORM\Query\AST\WhereClause  | 
            ||
| 1347 | */  | 
            ||
| 1348 | 313 | public function WhereClause()  | 
            |
| 1354 | |||
| 1355 | /**  | 
            ||
| 1356 | * HavingClause ::= "HAVING" ConditionalExpression  | 
            ||
| 1357 | *  | 
            ||
| 1358 | * @return \Doctrine\ORM\Query\AST\HavingClause  | 
            ||
| 1359 | */  | 
            ||
| 1360 | 4 | public function HavingClause()  | 
            |
| 1366 | |||
| 1367 | /**  | 
            ||
| 1368 |      * GroupByClause ::= "GROUP" "BY" GroupByItem {"," GroupByItem}* | 
            ||
| 1369 | *  | 
            ||
| 1370 | * @return \Doctrine\ORM\Query\AST\GroupByClause  | 
            ||
| 1371 | */  | 
            ||
| 1372 | 7 | public function GroupByClause()  | 
            |
| 1387 | |||
| 1388 | /**  | 
            ||
| 1389 |      * OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}* | 
            ||
| 1390 | *  | 
            ||
| 1391 | * @return \Doctrine\ORM\Query\AST\OrderByClause  | 
            ||
| 1392 | */  | 
            ||
| 1393 | 156 | public function OrderByClause()  | 
            |
| 1409 | |||
| 1410 | /**  | 
            ||
| 1411 | * Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]  | 
            ||
| 1412 | *  | 
            ||
| 1413 | * @return \Doctrine\ORM\Query\AST\Subselect  | 
            ||
| 1414 | */  | 
            ||
| 1415 | 27 | public function Subselect()  | 
            |
| 1432 | |||
| 1433 | /**  | 
            ||
| 1434 | * UpdateItem ::= SingleValuedPathExpression "=" NewValue  | 
            ||
| 1435 | *  | 
            ||
| 1436 | * @return \Doctrine\ORM\Query\AST\UpdateItem  | 
            ||
| 1437 | */  | 
            ||
| 1438 | 31 | public function UpdateItem()  | 
            |
| 1448 | |||
| 1449 | /**  | 
            ||
| 1450 | * GroupByItem ::= IdentificationVariable | ResultVariable | SingleValuedPathExpression  | 
            ||
| 1451 | *  | 
            ||
| 1452 | * @return string | \Doctrine\ORM\Query\AST\PathExpression  | 
            ||
| 1453 | */  | 
            ||
| 1454 | 7 | public function GroupByItem()  | 
            |
| 1455 |     { | 
            ||
| 1456 | // We need to check if we are in a IdentificationVariable or SingleValuedPathExpression  | 
            ||
| 1457 | 7 | $glimpse = $this->lexer->glimpse();  | 
            |
| 1458 | |||
| 1459 | 7 |         if ($glimpse['type'] === Lexer::T_DOT) { | 
            |
| 1460 | 1 | return $this->SingleValuedPathExpression();  | 
            |
| 1461 | }  | 
            ||
| 1462 | |||
| 1463 | // Still need to decide between IdentificationVariable or ResultVariable  | 
            ||
| 1464 | 6 | $lookaheadValue = $this->lexer->lookahead['value'];  | 
            |
| 1465 | |||
| 1466 | 6 |         if ( ! isset($this->queryComponents[$lookaheadValue])) { | 
            |
| 1467 |             $this->semanticalError('Cannot group by undefined identification or result variable.'); | 
            ||
| 1468 | }  | 
            ||
| 1469 | |||
| 1470 | 6 | return (isset($this->queryComponents[$lookaheadValue]['metadata']))  | 
            |
| 1471 | 4 | ? $this->IdentificationVariable()  | 
            |
| 1472 | 6 | : $this->ResultVariable();  | 
            |
| 1473 | }  | 
            ||
| 1474 | |||
| 1475 | /**  | 
            ||
| 1476 | * OrderByItem ::= (  | 
            ||
| 1477 | * SimpleArithmeticExpression | SingleValuedPathExpression |  | 
            ||
| 1478 | * ScalarExpression | ResultVariable | FunctionDeclaration  | 
            ||
| 1479 | * ) ["ASC" | "DESC"]  | 
            ||
| 1480 | *  | 
            ||
| 1481 | * @return \Doctrine\ORM\Query\AST\OrderByItem  | 
            ||
| 1482 | */  | 
            ||
| 1483 | 156 | public function OrderByItem()  | 
            |
| 1537 | |||
| 1538 | /**  | 
            ||
| 1539 | * NewValue ::= SimpleArithmeticExpression | StringPrimary | DatetimePrimary | BooleanPrimary |  | 
            ||
| 1540 | * EnumPrimary | SimpleEntityExpression | "NULL"  | 
            ||
| 1541 | *  | 
            ||
| 1542 | * NOTE: Since it is not possible to correctly recognize individual types, here is the full  | 
            ||
| 1543 | * grammar that needs to be supported:  | 
            ||
| 1544 | *  | 
            ||
| 1545 | * NewValue ::= SimpleArithmeticExpression | "NULL"  | 
            ||
| 1546 | *  | 
            ||
| 1547 | * SimpleArithmeticExpression covers all *Primary grammar rules and also SimpleEntityExpression  | 
            ||
| 1548 | *  | 
            ||
| 1549 | * @return AST\ArithmeticExpression  | 
            ||
| 1550 | */  | 
            ||
| 1551 | 31 | public function NewValue()  | 
            |
| 1567 | |||
| 1568 | /**  | 
            ||
| 1569 |      * IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {Join}* | 
            ||
| 1570 | *  | 
            ||
| 1571 | * @return \Doctrine\ORM\Query\AST\IdentificationVariableDeclaration  | 
            ||
| 1572 | */  | 
            ||
| 1573 | 670 | public function IdentificationVariableDeclaration()  | 
            |
| 1595 | |||
| 1596 | /**  | 
            ||
| 1597 | * SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration  | 
            ||
| 1598 | *  | 
            ||
| 1599 |      * {Internal note: WARNING: Solution is harder than a bare implementation. | 
            ||
| 1600 | * Desired EBNF support:  | 
            ||
| 1601 | *  | 
            ||
| 1602 | * SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration | (AssociationPathExpression ["AS"] AliasIdentificationVariable)  | 
            ||
| 1603 | *  | 
            ||
| 1604 | * It demands that entire SQL generation to become programmatical. This is  | 
            ||
| 1605 | * needed because association based subselect requires "WHERE" conditional  | 
            ||
| 1606 | * expressions to be injected, but there is no scope to do that. Only scope  | 
            ||
| 1607 | * accessible is "FROM", prohibiting an easy implementation without larger  | 
            ||
| 1608 | * changes.}  | 
            ||
| 1609 | *  | 
            ||
| 1610 | * @return \Doctrine\ORM\Query\AST\SubselectIdentificationVariableDeclaration |  | 
            ||
| 1611 | * \Doctrine\ORM\Query\AST\IdentificationVariableDeclaration  | 
            ||
| 1612 | */  | 
            ||
| 1613 | 26 | public function SubselectIdentificationVariableDeclaration()  | 
            |
| 1654 | |||
| 1655 | /**  | 
            ||
| 1656 | * Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN"  | 
            ||
| 1657 | * (JoinAssociationDeclaration | RangeVariableDeclaration)  | 
            ||
| 1658 | * ["WITH" ConditionalExpression]  | 
            ||
| 1659 | *  | 
            ||
| 1660 | * @return \Doctrine\ORM\Query\AST\Join  | 
            ||
| 1661 | */  | 
            ||
| 1662 | 247 | public function Join()  | 
            |
| 1710 | |||
| 1711 | /**  | 
            ||
| 1712 | * RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable  | 
            ||
| 1713 | *  | 
            ||
| 1714 | * @return \Doctrine\ORM\Query\AST\RangeVariableDeclaration  | 
            ||
| 1715 | */  | 
            ||
| 1716 | 670 | public function RangeVariableDeclaration()  | 
            |
| 1744 | |||
| 1745 | /**  | 
            ||
| 1746 | * JoinAssociationDeclaration ::= JoinAssociationPathExpression ["AS"] AliasIdentificationVariable [IndexBy]  | 
            ||
| 1747 | *  | 
            ||
| 1748 | * @return \Doctrine\ORM\Query\AST\JoinAssociationPathExpression  | 
            ||
| 1749 | */  | 
            ||
| 1750 | 228 | public function JoinAssociationDeclaration()  | 
            |
| 1781 | |||
| 1782 | /**  | 
            ||
| 1783 | * PartialObjectExpression ::= "PARTIAL" IdentificationVariable "." PartialFieldSet  | 
            ||
| 1784 |      * PartialFieldSet ::= "{" SimpleStateField {"," SimpleStateField}* "}" | 
            ||
| 1785 | *  | 
            ||
| 1786 | * @return \Doctrine\ORM\Query\AST\PartialObjectExpression  | 
            ||
| 1787 | */  | 
            ||
| 1788 | 11 | public function PartialObjectExpression()  | 
            |
| 1839 | |||
| 1840 | /**  | 
            ||
| 1841 |      * NewObjectExpression ::= "NEW" AbstractSchemaName "(" NewObjectArg {"," NewObjectArg}* ")" | 
            ||
| 1842 | *  | 
            ||
| 1843 | * @return \Doctrine\ORM\Query\AST\NewObjectExpression  | 
            ||
| 1844 | */  | 
            ||
| 1845 | 26 | public function NewObjectExpression()  | 
            |
| 1875 | |||
| 1876 | /**  | 
            ||
| 1877 |      * NewObjectArg ::= ScalarExpression | "(" Subselect ")" | 
            ||
| 1878 | *  | 
            ||
| 1879 | * @return mixed  | 
            ||
| 1880 | */  | 
            ||
| 1881 | 26 | public function NewObjectArg()  | 
            |
| 1896 | |||
| 1897 | /**  | 
            ||
| 1898 | * IndexBy ::= "INDEX" "BY" StateFieldPathExpression  | 
            ||
| 1899 | *  | 
            ||
| 1900 | * @return \Doctrine\ORM\Query\AST\IndexBy  | 
            ||
| 1901 | */  | 
            ||
| 1902 | 11 | public function IndexBy()  | 
            |
| 1913 | |||
| 1914 | /**  | 
            ||
| 1915 | * ScalarExpression ::= SimpleArithmeticExpression | StringPrimary | DateTimePrimary |  | 
            ||
| 1916 | * StateFieldPathExpression | BooleanPrimary | CaseExpression |  | 
            ||
| 1917 | * InstanceOfExpression  | 
            ||
| 1918 | *  | 
            ||
| 1919 | * @return mixed One of the possible expressions or subexpressions.  | 
            ||
| 1920 | */  | 
            ||
| 1921 | 129 | public function ScalarExpression()  | 
            |
| 1922 |     { | 
            ||
| 1923 | 129 | $lookahead = $this->lexer->lookahead['type'];  | 
            |
| 1924 | 129 | $peek = $this->lexer->glimpse();  | 
            |
| 1925 | |||
| 1926 |         switch (true) { | 
            ||
| 1927 | 129 | case ($lookahead === Lexer::T_INTEGER):  | 
            |
| 1928 | 126 | case ($lookahead === Lexer::T_FLOAT):  | 
            |
| 1929 | // SimpleArithmeticExpression : (- u.value ) or ( + u.value ) or ( - 1 ) or ( + 1 )  | 
            ||
| 1930 | 126 | case ($lookahead === Lexer::T_MINUS):  | 
            |
| 1931 | 126 | case ($lookahead === Lexer::T_PLUS):  | 
            |
| 1932 | 15 | return $this->SimpleArithmeticExpression();  | 
            |
| 1933 | |||
| 1934 | 126 | case ($lookahead === Lexer::T_STRING):  | 
            |
| 1935 | 13 | return $this->StringPrimary();  | 
            |
| 1936 | |||
| 1937 | 124 | case ($lookahead === Lexer::T_TRUE):  | 
            |
| 1938 | 124 | case ($lookahead === Lexer::T_FALSE):  | 
            |
| 1939 | 3 | $this->match($lookahead);  | 
            |
| 1940 | |||
| 1941 | 3 | return new AST\Literal(AST\Literal::BOOLEAN, $this->lexer->token['value']);  | 
            |
| 1942 | |||
| 1943 | 124 | case ($lookahead === Lexer::T_INPUT_PARAMETER):  | 
            |
| 1944 |                 switch (true) { | 
            ||
| 1945 | case $this->isMathOperator($peek):  | 
            ||
| 1946 | // :param + u.value  | 
            ||
| 1947 | return $this->SimpleArithmeticExpression();  | 
            ||
| 1948 | default:  | 
            ||
| 1949 | return $this->InputParameter();  | 
            ||
| 1950 | }  | 
            ||
| 1951 | |||
| 1952 | 124 | case ($lookahead === Lexer::T_CASE):  | 
            |
| 1953 | 120 | case ($lookahead === Lexer::T_COALESCE):  | 
            |
| 1954 | 120 | case ($lookahead === Lexer::T_NULLIF):  | 
            |
| 1955 | // Since NULLIF and COALESCE can be identified as a function,  | 
            ||
| 1956 | // we need to check these before checking for FunctionDeclaration  | 
            ||
| 1957 | 8 | return $this->CaseExpression();  | 
            |
| 1958 | |||
| 1959 | 120 | case ($lookahead === Lexer::T_OPEN_PARENTHESIS):  | 
            |
| 1960 | 3 | return $this->SimpleArithmeticExpression();  | 
            |
| 1961 | |||
| 1962 | // this check must be done before checking for a filed path expression  | 
            ||
| 1963 | 117 | case ($this->isFunction()):  | 
            |
| 1964 | 4 |                 $this->lexer->peek(); // "(" | 
            |
| 1965 | |||
| 1966 |                 switch (true) { | 
            ||
| 1967 | 4 | case ($this->isMathOperator($this->peekBeyondClosingParenthesis())):  | 
            |
| 1968 | // SUM(u.id) + COUNT(u.id)  | 
            ||
| 1969 | return $this->SimpleArithmeticExpression();  | 
            ||
| 1970 | |||
| 1971 | default:  | 
            ||
| 1972 | // IDENTITY(u)  | 
            ||
| 1973 | 4 | return $this->FunctionDeclaration();  | 
            |
| 1974 | }  | 
            ||
| 1975 | |||
| 1976 | break;  | 
            ||
| 1977 | // it is no function, so it must be a field path  | 
            ||
| 1978 | 116 | case ($lookahead === Lexer::T_IDENTIFIER):  | 
            |
| 1979 | 116 | $this->lexer->peek(); // lookahead => '.'  | 
            |
| 1980 | 116 | $this->lexer->peek(); // lookahead => token after '.'  | 
            |
| 1981 | 116 | $peek = $this->lexer->peek(); // lookahead => token after the token after the '.'  | 
            |
| 1982 | 116 | $this->lexer->resetPeek();  | 
            |
| 1983 | |||
| 1984 | 116 |                 if ($this->isMathOperator($peek)) { | 
            |
| 1985 | 6 | return $this->SimpleArithmeticExpression();  | 
            |
| 1986 | }  | 
            ||
| 1987 | |||
| 1988 | 112 | return $this->StateFieldPathExpression();  | 
            |
| 1989 | |||
| 1990 | default:  | 
            ||
| 1991 | $this->syntaxError();  | 
            ||
| 1992 | }  | 
            ||
| 1993 | }  | 
            ||
| 1994 | |||
| 1995 | /**  | 
            ||
| 1996 | * CaseExpression ::= GeneralCaseExpression | SimpleCaseExpression | CoalesceExpression | NullifExpression  | 
            ||
| 1997 |      * GeneralCaseExpression ::= "CASE" WhenClause {WhenClause}* "ELSE" ScalarExpression "END" | 
            ||
| 1998 | * WhenClause ::= "WHEN" ConditionalExpression "THEN" ScalarExpression  | 
            ||
| 1999 |      * SimpleCaseExpression ::= "CASE" CaseOperand SimpleWhenClause {SimpleWhenClause}* "ELSE" ScalarExpression "END" | 
            ||
| 2000 | * CaseOperand ::= StateFieldPathExpression | TypeDiscriminator  | 
            ||
| 2001 | * SimpleWhenClause ::= "WHEN" ScalarExpression "THEN" ScalarExpression  | 
            ||
| 2002 |      * CoalesceExpression ::= "COALESCE" "(" ScalarExpression {"," ScalarExpression}* ")" | 
            ||
| 2003 |      * NullifExpression ::= "NULLIF" "(" ScalarExpression "," ScalarExpression ")" | 
            ||
| 2004 | *  | 
            ||
| 2005 | * @return mixed One of the possible expressions or subexpressions.  | 
            ||
| 2006 | */  | 
            ||
| 2007 | 18 | public function CaseExpression()  | 
            |
| 2035 | |||
| 2036 | /**  | 
            ||
| 2037 |      * CoalesceExpression ::= "COALESCE" "(" ScalarExpression {"," ScalarExpression}* ")" | 
            ||
| 2038 | *  | 
            ||
| 2039 | * @return \Doctrine\ORM\Query\AST\CoalesceExpression  | 
            ||
| 2040 | */  | 
            ||
| 2041 | 3 | public function CoalesceExpression()  | 
            |
| 2060 | |||
| 2061 | /**  | 
            ||
| 2062 |      * NullIfExpression ::= "NULLIF" "(" ScalarExpression "," ScalarExpression ")" | 
            ||
| 2063 | *  | 
            ||
| 2064 | * @return \Doctrine\ORM\Query\AST\NullIfExpression  | 
            ||
| 2065 | */  | 
            ||
| 2066 | 5 | public function NullIfExpression()  | 
            |
| 2079 | |||
| 2080 | /**  | 
            ||
| 2081 |      * GeneralCaseExpression ::= "CASE" WhenClause {WhenClause}* "ELSE" ScalarExpression "END" | 
            ||
| 2082 | *  | 
            ||
| 2083 | * @return \Doctrine\ORM\Query\AST\GeneralCaseExpression  | 
            ||
| 2084 | */  | 
            ||
| 2085 | 8 | public function GeneralCaseExpression()  | 
            |
| 2102 | |||
| 2103 | /**  | 
            ||
| 2104 |      * SimpleCaseExpression ::= "CASE" CaseOperand SimpleWhenClause {SimpleWhenClause}* "ELSE" ScalarExpression "END" | 
            ||
| 2105 | * CaseOperand ::= StateFieldPathExpression | TypeDiscriminator  | 
            ||
| 2106 | *  | 
            ||
| 2107 | * @return AST\SimpleCaseExpression  | 
            ||
| 2108 | */  | 
            ||
| 2109 | 5 | public function SimpleCaseExpression()  | 
            |
| 2127 | |||
| 2128 | /**  | 
            ||
| 2129 | * WhenClause ::= "WHEN" ConditionalExpression "THEN" ScalarExpression  | 
            ||
| 2130 | *  | 
            ||
| 2131 | * @return \Doctrine\ORM\Query\AST\WhenClause  | 
            ||
| 2132 | */  | 
            ||
| 2133 | 8 | public function WhenClause()  | 
            |
| 2141 | |||
| 2142 | /**  | 
            ||
| 2143 | * SimpleWhenClause ::= "WHEN" ScalarExpression "THEN" ScalarExpression  | 
            ||
| 2144 | *  | 
            ||
| 2145 | * @return \Doctrine\ORM\Query\AST\SimpleWhenClause  | 
            ||
| 2146 | */  | 
            ||
| 2147 | 5 | public function SimpleWhenClause()  | 
            |
| 2155 | |||
| 2156 | /**  | 
            ||
| 2157 | * SelectExpression ::= (  | 
            ||
| 2158 | * IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration |  | 
            ||
| 2159 |      *     PartialObjectExpression | "(" Subselect ")" | CaseExpression | NewObjectExpression | 
            ||
| 2160 | * ) [["AS"] ["HIDDEN"] AliasResultVariable]  | 
            ||
| 2161 | *  | 
            ||
| 2162 | * @return \Doctrine\ORM\Query\AST\SelectExpression  | 
            ||
| 2163 | */  | 
            ||
| 2164 | 692 | public function SelectExpression()  | 
            |
| 2165 |     { | 
            ||
| 2166 | 692 | $expression = null;  | 
            |
| 2167 | 692 | $identVariable = null;  | 
            |
| 2168 | 692 | $peek = $this->lexer->glimpse();  | 
            |
| 2169 | 692 | $lookaheadType = $this->lexer->lookahead['type'];  | 
            |
| 2170 | |||
| 2171 |         switch (true) { | 
            ||
| 2172 | // ScalarExpression (u.name)  | 
            ||
| 2173 | 692 | case ($lookaheadType === Lexer::T_IDENTIFIER && $peek['type'] === Lexer::T_DOT):  | 
            |
| 2174 | 91 | $expression = $this->ScalarExpression();  | 
            |
| 2175 | 91 | break;  | 
            |
| 2176 | |||
| 2177 | // IdentificationVariable (u)  | 
            ||
| 2178 | 634 | case ($lookaheadType === Lexer::T_IDENTIFIER && $peek['type'] !== Lexer::T_OPEN_PARENTHESIS):  | 
            |
| 2179 | 557 | $expression = $identVariable = $this->IdentificationVariable();  | 
            |
| 2180 | 557 | break;  | 
            |
| 2181 | |||
| 2182 | // CaseExpression (CASE ... or NULLIF(...) or COALESCE(...))  | 
            ||
| 2183 | 111 | case ($lookaheadType === Lexer::T_CASE):  | 
            |
| 2184 | 106 | case ($lookaheadType === Lexer::T_COALESCE):  | 
            |
| 2185 | 104 | case ($lookaheadType === Lexer::T_NULLIF):  | 
            |
| 2186 | 9 | $expression = $this->CaseExpression();  | 
            |
| 2187 | 9 | break;  | 
            |
| 2188 | |||
| 2189 | // DQL Function (SUM(u.value) or SUM(u.value) + 1)  | 
            ||
| 2190 | 102 | case ($this->isFunction()):  | 
            |
| 2191 | 42 |                 $this->lexer->peek(); // "(" | 
            |
| 2192 | |||
| 2193 |                 switch (true) { | 
            ||
| 2194 | 42 | case ($this->isMathOperator($this->peekBeyondClosingParenthesis())):  | 
            |
| 2195 | // SUM(u.id) + COUNT(u.id)  | 
            ||
| 2196 | $expression = $this->ScalarExpression();  | 
            ||
| 2197 | break;  | 
            ||
| 2198 | |||
| 2199 | default:  | 
            ||
| 2200 | // IDENTITY(u)  | 
            ||
| 2201 | 42 | $expression = $this->FunctionDeclaration();  | 
            |
| 2202 | 31 | break;  | 
            |
| 2203 | }  | 
            ||
| 2204 | |||
| 2205 | 31 | break;  | 
            |
| 2206 | |||
| 2207 |             // PartialObjectExpression (PARTIAL u.{id, name}) | 
            ||
| 2208 | 60 | case ($lookaheadType === Lexer::T_PARTIAL):  | 
            |
| 2209 | 11 | $expression = $this->PartialObjectExpression();  | 
            |
| 2210 | 11 | $identVariable = $expression->identificationVariable;  | 
            |
| 2211 | 11 | break;  | 
            |
| 2212 | |||
| 2213 | // Subselect  | 
            ||
| 2214 | 49 | case ($lookaheadType === Lexer::T_OPEN_PARENTHESIS && $peek['type'] === Lexer::T_SELECT):  | 
            |
| 2215 | 5 | $this->match(Lexer::T_OPEN_PARENTHESIS);  | 
            |
| 2216 | 5 | $expression = $this->Subselect();  | 
            |
| 2217 | 5 | $this->match(Lexer::T_CLOSE_PARENTHESIS);  | 
            |
| 2218 | 5 | break;  | 
            |
| 2219 | |||
| 2220 | // Shortcut: ScalarExpression => SimpleArithmeticExpression  | 
            ||
| 2221 | 44 | case ($lookaheadType === Lexer::T_OPEN_PARENTHESIS):  | 
            |
| 2222 | 41 | case ($lookaheadType === Lexer::T_INTEGER):  | 
            |
| 2223 | 39 | case ($lookaheadType === Lexer::T_STRING):  | 
            |
| 2224 | 30 | case ($lookaheadType === Lexer::T_FLOAT):  | 
            |
| 2225 | // SimpleArithmeticExpression : (- u.value ) or ( + u.value )  | 
            ||
| 2226 | 30 | case ($lookaheadType === Lexer::T_MINUS):  | 
            |
| 2227 | 30 | case ($lookaheadType === Lexer::T_PLUS):  | 
            |
| 2228 | 15 | $expression = $this->SimpleArithmeticExpression();  | 
            |
| 2229 | 15 | break;  | 
            |
| 2230 | |||
| 2231 | // NewObjectExpression (New ClassName(id, name))  | 
            ||
| 2232 | 29 | case ($lookaheadType === Lexer::T_NEW):  | 
            |
| 2233 | 26 | $expression = $this->NewObjectExpression();  | 
            |
| 2234 | 26 | break;  | 
            |
| 2235 | |||
| 2236 | default:  | 
            ||
| 2237 | 3 | $this->syntaxError(  | 
            |
| 2238 | 3 |                     'IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression', | 
            |
| 2239 | 3 | $this->lexer->lookahead  | 
            |
| 2240 | );  | 
            ||
| 2241 | }  | 
            ||
| 2242 | |||
| 2243 | // [["AS"] ["HIDDEN"] AliasResultVariable]  | 
            ||
| 2244 | 685 | $mustHaveAliasResultVariable = false;  | 
            |
| 2245 | |||
| 2246 | 685 |         if ($this->lexer->isNextToken(Lexer::T_AS)) { | 
            |
| 2247 | 66 | $this->match(Lexer::T_AS);  | 
            |
| 2248 | |||
| 2249 | 66 | $mustHaveAliasResultVariable = true;  | 
            |
| 2250 | }  | 
            ||
| 2251 | |||
| 2252 | 685 | $hiddenAliasResultVariable = false;  | 
            |
| 2253 | |||
| 2254 | 685 |         if ($this->lexer->isNextToken(Lexer::T_HIDDEN)) { | 
            |
| 2255 | 2 | $this->match(Lexer::T_HIDDEN);  | 
            |
| 2256 | |||
| 2257 | 2 | $hiddenAliasResultVariable = true;  | 
            |
| 2258 | }  | 
            ||
| 2259 | |||
| 2260 | 685 | $aliasResultVariable = null;  | 
            |
| 2261 | |||
| 2262 | 685 |         if ($mustHaveAliasResultVariable || $this->lexer->isNextToken(Lexer::T_IDENTIFIER)) { | 
            |
| 2263 | 68 | $token = $this->lexer->lookahead;  | 
            |
| 2264 | 68 | $aliasResultVariable = $this->AliasResultVariable();  | 
            |
| 2265 | |||
| 2266 | // Include AliasResultVariable in query components.  | 
            ||
| 2267 | 64 | $this->queryComponents[$aliasResultVariable] = [  | 
            |
| 2268 | 64 | 'resultVariable' => $expression,  | 
            |
| 2269 | 64 | 'nestingLevel' => $this->nestingLevel,  | 
            |
| 2270 | 64 | 'token' => $token,  | 
            |
| 2271 | ];  | 
            ||
| 2272 | }  | 
            ||
| 2273 | |||
| 2274 | // AST  | 
            ||
| 2275 | |||
| 2276 | 681 | $expr = new AST\SelectExpression($expression, $aliasResultVariable, $hiddenAliasResultVariable);  | 
            |
| 2277 | |||
| 2278 | 681 |         if ($identVariable) { | 
            |
| 2279 | 565 | $this->identVariableExpressions[$identVariable] = $expr;  | 
            |
| 2280 | }  | 
            ||
| 2281 | |||
| 2282 | 681 | return $expr;  | 
            |
| 2283 | }  | 
            ||
| 2284 | |||
| 2285 | /**  | 
            ||
| 2286 | * SimpleSelectExpression ::= (  | 
            ||
| 2287 | * StateFieldPathExpression | IdentificationVariable | FunctionDeclaration |  | 
            ||
| 2288 |      *      AggregateExpression | "(" Subselect ")" | ScalarExpression | 
            ||
| 2289 | * ) [["AS"] AliasResultVariable]  | 
            ||
| 2290 | *  | 
            ||
| 2291 | * @return \Doctrine\ORM\Query\AST\SimpleSelectExpression  | 
            ||
| 2292 | */  | 
            ||
| 2293 | 27 | public function SimpleSelectExpression()  | 
            |
| 2294 |     { | 
            ||
| 2295 | 27 | $peek = $this->lexer->glimpse();  | 
            |
| 2296 | |||
| 2297 | 27 |         switch ($this->lexer->lookahead['type']) { | 
            |
| 2298 | 27 | case Lexer::T_IDENTIFIER:  | 
            |
| 2299 |                 switch (true) { | 
            ||
| 2300 | 19 | case ($peek['type'] === Lexer::T_DOT):  | 
            |
| 2301 | 16 | $expression = $this->StateFieldPathExpression();  | 
            |
| 2302 | |||
| 2303 | 16 | return new AST\SimpleSelectExpression($expression);  | 
            |
| 2304 | |||
| 2305 | 3 | case ($peek['type'] !== Lexer::T_OPEN_PARENTHESIS):  | 
            |
| 2306 | 2 | $expression = $this->IdentificationVariable();  | 
            |
| 2307 | |||
| 2308 | 2 | return new AST\SimpleSelectExpression($expression);  | 
            |
| 2309 | |||
| 2310 | 1 | case ($this->isFunction()):  | 
            |
| 2311 | // SUM(u.id) + COUNT(u.id)  | 
            ||
| 2312 | 1 |                         if ($this->isMathOperator($this->peekBeyondClosingParenthesis())) { | 
            |
| 2313 | return new AST\SimpleSelectExpression($this->ScalarExpression());  | 
            ||
| 2314 | }  | 
            ||
| 2315 | // COUNT(u.id)  | 
            ||
| 2316 | 1 |                         if ($this->isAggregateFunction($this->lexer->lookahead['type'])) { | 
            |
| 2317 | return new AST\SimpleSelectExpression($this->AggregateExpression());  | 
            ||
| 2318 | }  | 
            ||
| 2319 | // IDENTITY(u)  | 
            ||
| 2320 | 1 | return new AST\SimpleSelectExpression($this->FunctionDeclaration());  | 
            |
| 2321 | |||
| 2322 | default:  | 
            ||
| 2323 | // Do nothing  | 
            ||
| 2324 | }  | 
            ||
| 2325 | break;  | 
            ||
| 2326 | |||
| 2327 | 8 | case Lexer::T_OPEN_PARENTHESIS:  | 
            |
| 2328 |                 if ($peek['type'] !== Lexer::T_SELECT) { | 
            ||
| 2329 | // Shortcut: ScalarExpression => SimpleArithmeticExpression  | 
            ||
| 2330 | $expression = $this->SimpleArithmeticExpression();  | 
            ||
| 2331 | |||
| 2332 | return new AST\SimpleSelectExpression($expression);  | 
            ||
| 2333 | }  | 
            ||
| 2334 | |||
| 2335 | // Subselect  | 
            ||
| 2336 | $this->match(Lexer::T_OPEN_PARENTHESIS);  | 
            ||
| 2337 | $expression = $this->Subselect();  | 
            ||
| 2338 | $this->match(Lexer::T_CLOSE_PARENTHESIS);  | 
            ||
| 2339 | |||
| 2340 | return new AST\SimpleSelectExpression($expression);  | 
            ||
| 2341 | |||
| 2342 | default:  | 
            ||
| 2343 | // Do nothing  | 
            ||
| 2344 | }  | 
            ||
| 2345 | |||
| 2346 | 8 | $this->lexer->peek();  | 
            |
| 2347 | |||
| 2348 | 8 | $expression = $this->ScalarExpression();  | 
            |
| 2349 | 7 | $expr = new AST\SimpleSelectExpression($expression);  | 
            |
| 2350 | |||
| 2351 | 7 |         if ($this->lexer->isNextToken(Lexer::T_AS)) { | 
            |
| 2352 | $this->match(Lexer::T_AS);  | 
            ||
| 2353 | }  | 
            ||
| 2354 | |||
| 2355 | 7 |         if ($this->lexer->isNextToken(Lexer::T_IDENTIFIER)) { | 
            |
| 2356 | $token = $this->lexer->lookahead;  | 
            ||
| 2357 | $resultVariable = $this->AliasResultVariable();  | 
            ||
| 2358 | $expr->fieldIdentificationVariable = $resultVariable;  | 
            ||
| 2359 | |||
| 2360 | // Include AliasResultVariable in query components.  | 
            ||
| 2361 | $this->queryComponents[$resultVariable] = [  | 
            ||
| 2362 | 'resultvariable' => $expr,  | 
            ||
| 2363 | 'nestingLevel' => $this->nestingLevel,  | 
            ||
| 2364 | 'token' => $token,  | 
            ||
| 2365 | ];  | 
            ||
| 2366 | }  | 
            ||
| 2367 | |||
| 2368 | 7 | return $expr;  | 
            |
| 2369 | }  | 
            ||
| 2370 | |||
| 2371 | /**  | 
            ||
| 2372 |      * ConditionalExpression ::= ConditionalTerm {"OR" ConditionalTerm}* | 
            ||
| 2373 | *  | 
            ||
| 2374 | * @return \Doctrine\ORM\Query\AST\ConditionalExpression  | 
            ||
| 2375 | */  | 
            ||
| 2376 | 337 | public function ConditionalExpression()  | 
            |
| 2395 | |||
| 2396 | /**  | 
            ||
| 2397 |      * ConditionalTerm ::= ConditionalFactor {"AND" ConditionalFactor}* | 
            ||
| 2398 | *  | 
            ||
| 2399 | * @return \Doctrine\ORM\Query\AST\ConditionalTerm  | 
            ||
| 2400 | */  | 
            ||
| 2401 | 337 | public function ConditionalTerm()  | 
            |
| 2420 | |||
| 2421 | /**  | 
            ||
| 2422 | * ConditionalFactor ::= ["NOT"] ConditionalPrimary  | 
            ||
| 2423 | *  | 
            ||
| 2424 | * @return \Doctrine\ORM\Query\AST\ConditionalFactor  | 
            ||
| 2425 | */  | 
            ||
| 2426 | 337 | public function ConditionalFactor()  | 
            |
| 2449 | |||
| 2450 | /**  | 
            ||
| 2451 |      * ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")" | 
            ||
| 2452 | *  | 
            ||
| 2453 | * @return \Doctrine\ORM\Query\AST\ConditionalPrimary  | 
            ||
| 2454 | */  | 
            ||
| 2455 | 337 | public function ConditionalPrimary()  | 
            |
| 2482 | |||
| 2483 | /**  | 
            ||
| 2484 | * SimpleConditionalExpression ::=  | 
            ||
| 2485 | * ComparisonExpression | BetweenExpression | LikeExpression |  | 
            ||
| 2486 | * InExpression | NullComparisonExpression | ExistsExpression |  | 
            ||
| 2487 | * EmptyCollectionComparisonExpression | CollectionMemberExpression |  | 
            ||
| 2488 | * InstanceOfExpression  | 
            ||
| 2489 | */  | 
            ||
| 2490 | 337 | public function SimpleConditionalExpression()  | 
            |
| 2579 | |||
| 2580 | /**  | 
            ||
| 2581 | * EmptyCollectionComparisonExpression ::= CollectionValuedPathExpression "IS" ["NOT"] "EMPTY"  | 
            ||
| 2582 | *  | 
            ||
| 2583 | * @return \Doctrine\ORM\Query\AST\EmptyCollectionComparisonExpression  | 
            ||
| 2584 | */  | 
            ||
| 2585 | 4 | public function EmptyCollectionComparisonExpression()  | 
            |
| 2601 | |||
| 2602 | /**  | 
            ||
| 2603 | * CollectionMemberExpression ::= EntityExpression ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpression  | 
            ||
| 2604 | *  | 
            ||
| 2605 | * EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression  | 
            ||
| 2606 | * SimpleEntityExpression ::= IdentificationVariable | InputParameter  | 
            ||
| 2607 | *  | 
            ||
| 2608 | * @return \Doctrine\ORM\Query\AST\CollectionMemberExpression  | 
            ||
| 2609 | */  | 
            ||
| 2610 | 7 | public function CollectionMemberExpression()  | 
            |
| 2634 | |||
| 2635 | /**  | 
            ||
| 2636 | * Literal ::= string | char | integer | float | boolean  | 
            ||
| 2637 | *  | 
            ||
| 2638 | * @return \Doctrine\ORM\Query\AST\Literal  | 
            ||
| 2639 | */  | 
            ||
| 2640 | 146 | public function Literal()  | 
            |
| 2665 | |||
| 2666 | /**  | 
            ||
| 2667 | * InParameter ::= Literal | InputParameter  | 
            ||
| 2668 | *  | 
            ||
| 2669 | * @return string | \Doctrine\ORM\Query\AST\InputParameter  | 
            ||
| 2670 | */  | 
            ||
| 2671 | 25 | public function InParameter()  | 
            |
| 2679 | |||
| 2680 | /**  | 
            ||
| 2681 | * InputParameter ::= PositionalParameter | NamedParameter  | 
            ||
| 2682 | *  | 
            ||
| 2683 | * @return \Doctrine\ORM\Query\AST\InputParameter  | 
            ||
| 2684 | */  | 
            ||
| 2685 | 161 | public function InputParameter()  | 
            |
| 2691 | |||
| 2692 | /**  | 
            ||
| 2693 |      * ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")" | 
            ||
| 2694 | *  | 
            ||
| 2695 | * @return \Doctrine\ORM\Query\AST\ArithmeticExpression  | 
            ||
| 2696 | */  | 
            ||
| 2697 | 294 | public function ArithmeticExpression()  | 
            |
| 2717 | |||
| 2718 | /**  | 
            ||
| 2719 |      * SimpleArithmeticExpression ::= ArithmeticTerm {("+" | "-") ArithmeticTerm}* | 
            ||
| 2720 | *  | 
            ||
| 2721 | * @return \Doctrine\ORM\Query\AST\SimpleArithmeticExpression  | 
            ||
| 2722 | */  | 
            ||
| 2723 | 364 | public function SimpleArithmeticExpression()  | 
            |
| 2743 | |||
| 2744 | /**  | 
            ||
| 2745 |      * ArithmeticTerm ::= ArithmeticFactor {("*" | "/") ArithmeticFactor}* | 
            ||
| 2746 | *  | 
            ||
| 2747 | * @return \Doctrine\ORM\Query\AST\ArithmeticTerm  | 
            ||
| 2748 | */  | 
            ||
| 2749 | 364 | public function ArithmeticTerm()  | 
            |
| 2769 | |||
| 2770 | /**  | 
            ||
| 2771 |      * ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary | 
            ||
| 2772 | *  | 
            ||
| 2773 | * @return \Doctrine\ORM\Query\AST\ArithmeticFactor  | 
            ||
| 2774 | */  | 
            ||
| 2775 | 364 | public function ArithmeticFactor()  | 
            |
| 2794 | |||
| 2795 | /**  | 
            ||
| 2796 | * ArithmeticPrimary ::= SingleValuedPathExpression | Literal | ParenthesisExpression  | 
            ||
| 2797 | * | FunctionsReturningNumerics | AggregateExpression | FunctionsReturningStrings  | 
            ||
| 2798 | * | FunctionsReturningDatetime | IdentificationVariable | ResultVariable  | 
            ||
| 2799 | * | InputParameter | CaseExpression  | 
            ||
| 2800 | */  | 
            ||
| 2801 | 368 | public function ArithmeticPrimary()  | 
            |
| 2849 | |||
| 2850 | /**  | 
            ||
| 2851 |      * StringExpression ::= StringPrimary | ResultVariable | "(" Subselect ")" | 
            ||
| 2852 | *  | 
            ||
| 2853 | * @return \Doctrine\ORM\Query\AST\Subselect |  | 
            ||
| 2854 | * string  | 
            ||
| 2855 | */  | 
            ||
| 2856 | 13 | public function StringExpression()  | 
            |
| 2877 | |||
| 2878 | /**  | 
            ||
| 2879 | * StringPrimary ::= StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression | CaseExpression  | 
            ||
| 2880 | */  | 
            ||
| 2881 | 49 | public function StringPrimary()  | 
            |
| 2919 | |||
| 2920 | /**  | 
            ||
| 2921 | * EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression  | 
            ||
| 2922 | *  | 
            ||
| 2923 | * @return \Doctrine\ORM\Query\AST\PathExpression |  | 
            ||
| 2924 | * \Doctrine\ORM\Query\AST\SimpleEntityExpression  | 
            ||
| 2925 | */  | 
            ||
| 2926 | 7 | public function EntityExpression()  | 
            |
| 2936 | |||
| 2937 | /**  | 
            ||
| 2938 | * SimpleEntityExpression ::= IdentificationVariable | InputParameter  | 
            ||
| 2939 | *  | 
            ||
| 2940 | * @return string | \Doctrine\ORM\Query\AST\InputParameter  | 
            ||
| 2941 | */  | 
            ||
| 2942 | 6 | public function SimpleEntityExpression()  | 
            |
| 2950 | |||
| 2951 | /**  | 
            ||
| 2952 | * AggregateExpression ::=  | 
            ||
| 2953 |      *  ("AVG" | "MAX" | "MIN" | "SUM" | "COUNT") "(" ["DISTINCT"] SimpleArithmeticExpression ")" | 
            ||
| 2954 | *  | 
            ||
| 2955 | * @return \Doctrine\ORM\Query\AST\AggregateExpression  | 
            ||
| 2956 | */  | 
            ||
| 2957 | 15 | public function AggregateExpression()  | 
            |
| 2958 |     { | 
            ||
| 2959 | 15 | $lookaheadType = $this->lexer->lookahead['type'];  | 
            |
| 2960 | 15 | $isDistinct = false;  | 
            |
| 2961 | |||
| 2962 | 15 |         if ( ! in_array($lookaheadType, [Lexer::T_COUNT, Lexer::T_AVG, Lexer::T_MAX, Lexer::T_MIN, Lexer::T_SUM])) { | 
            |
| 2963 |             $this->syntaxError('One of: MAX, MIN, AVG, SUM, COUNT'); | 
            ||
| 2964 | }  | 
            ||
| 2965 | |||
| 2966 | 15 | $this->match($lookaheadType);  | 
            |
| 2967 | 15 | $functionName = $this->lexer->token['value'];  | 
            |
| 2968 | 15 | $this->match(Lexer::T_OPEN_PARENTHESIS);  | 
            |
| 2969 | |||
| 2970 | 15 |         if ($this->lexer->isNextToken(Lexer::T_DISTINCT)) { | 
            |
| 2971 | $this->match(Lexer::T_DISTINCT);  | 
            ||
| 2972 | $isDistinct = true;  | 
            ||
| 2973 | }  | 
            ||
| 2974 | |||
| 2975 | 15 | $pathExp = $this->SimpleArithmeticExpression();  | 
            |
| 2976 | |||
| 2977 | 15 | $this->match(Lexer::T_CLOSE_PARENTHESIS);  | 
            |
| 2978 | |||
| 2979 | 15 | return new AST\AggregateExpression($functionName, $pathExp, $isDistinct);  | 
            |
| 2980 | }  | 
            ||
| 2981 | |||
| 2982 | /**  | 
            ||
| 2983 |      * QuantifiedExpression ::= ("ALL" | "ANY" | "SOME") "(" Subselect ")" | 
            ||
| 2984 | *  | 
            ||
| 2985 | * @return \Doctrine\ORM\Query\AST\QuantifiedExpression  | 
            ||
| 2986 | */  | 
            ||
| 2987 | 3 | public function QuantifiedExpression()  | 
            |
| 3006 | |||
| 3007 | /**  | 
            ||
| 3008 | * BetweenExpression ::= ArithmeticExpression ["NOT"] "BETWEEN" ArithmeticExpression "AND" ArithmeticExpression  | 
            ||
| 3009 | *  | 
            ||
| 3010 | * @return \Doctrine\ORM\Query\AST\BetweenExpression  | 
            ||
| 3011 | */  | 
            ||
| 3012 | 8 | public function BetweenExpression()  | 
            |
| 3032 | |||
| 3033 | /**  | 
            ||
| 3034 | * ComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression )  | 
            ||
| 3035 | *  | 
            ||
| 3036 | * @return \Doctrine\ORM\Query\AST\ComparisonExpression  | 
            ||
| 3037 | */  | 
            ||
| 3038 | 261 | public function ComparisonExpression()  | 
            |
| 3050 | |||
| 3051 | /**  | 
            ||
| 3052 |      * InExpression ::= SingleValuedPathExpression ["NOT"] "IN" "(" (InParameter {"," InParameter}* | Subselect) ")" | 
            ||
| 3053 | *  | 
            ||
| 3054 | * @return \Doctrine\ORM\Query\AST\InExpression  | 
            ||
| 3055 | */  | 
            ||
| 3056 | 34 | public function InExpression()  | 
            |
| 3086 | |||
| 3087 | /**  | 
            ||
| 3088 |      * InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (InstanceOfParameter | "(" InstanceOfParameter {"," InstanceOfParameter}* ")") | 
            ||
| 3089 | *  | 
            ||
| 3090 | * @return \Doctrine\ORM\Query\AST\InstanceOfExpression  | 
            ||
| 3091 | */  | 
            ||
| 3092 | 12 | public function InstanceOfExpression()  | 
            |
| 3130 | |||
| 3131 | /**  | 
            ||
| 3132 | * InstanceOfParameter ::= AbstractSchemaName | InputParameter  | 
            ||
| 3133 | *  | 
            ||
| 3134 | * @return mixed  | 
            ||
| 3135 | */  | 
            ||
| 3136 | 12 | public function InstanceOfParameter()  | 
            |
| 3150 | |||
| 3151 | /**  | 
            ||
| 3152 | * LikeExpression ::= StringExpression ["NOT"] "LIKE" StringPrimary ["ESCAPE" char]  | 
            ||
| 3153 | *  | 
            ||
| 3154 | * @return \Doctrine\ORM\Query\AST\LikeExpression  | 
            ||
| 3155 | */  | 
            ||
| 3156 | 13 | public function LikeExpression()  | 
            |
| 3189 | |||
| 3190 | /**  | 
            ||
| 3191 | * NullComparisonExpression ::= (InputParameter | NullIfExpression | CoalesceExpression | AggregateExpression | FunctionDeclaration | IdentificationVariable | SingleValuedPathExpression | ResultVariable) "IS" ["NOT"] "NULL"  | 
            ||
| 3192 | *  | 
            ||
| 3193 | * @return \Doctrine\ORM\Query\AST\NullComparisonExpression  | 
            ||
| 3194 | */  | 
            ||
| 3195 | 11 | public function NullComparisonExpression()  | 
            |
| 3196 |     { | 
            ||
| 3197 |         switch (true) { | 
            ||
| 3198 | 11 | case $this->lexer->isNextToken(Lexer::T_INPUT_PARAMETER):  | 
            |
| 3199 | $this->match(Lexer::T_INPUT_PARAMETER);  | 
            ||
| 3200 | |||
| 3201 | $expr = new AST\InputParameter($this->lexer->token['value']);  | 
            ||
| 3202 | break;  | 
            ||
| 3203 | |||
| 3204 | 11 | case $this->lexer->isNextToken(Lexer::T_NULLIF):  | 
            |
| 3205 | 1 | $expr = $this->NullIfExpression();  | 
            |
| 3206 | 1 | break;  | 
            |
| 3207 | |||
| 3208 | 11 | case $this->lexer->isNextToken(Lexer::T_COALESCE):  | 
            |
| 3209 | 1 | $expr = $this->CoalesceExpression();  | 
            |
| 3210 | 1 | break;  | 
            |
| 3211 | |||
| 3212 | 11 | case $this->isFunction():  | 
            |
| 3213 | 2 | $expr = $this->FunctionDeclaration();  | 
            |
| 3214 | 1 | break;  | 
            |
| 3215 | |||
| 3216 | default:  | 
            ||
| 3217 | // We need to check if we are in a IdentificationVariable or SingleValuedPathExpression  | 
            ||
| 3218 | 10 | $glimpse = $this->lexer->glimpse();  | 
            |
| 3219 | |||
| 3220 | 10 |                 if ($glimpse['type'] === Lexer::T_DOT) { | 
            |
| 3221 | 9 | $expr = $this->SingleValuedPathExpression();  | 
            |
| 3222 | |||
| 3223 | // Leave switch statement  | 
            ||
| 3224 | 9 | break;  | 
            |
| 3225 | }  | 
            ||
| 3226 | |||
| 3227 | 1 | $lookaheadValue = $this->lexer->lookahead['value'];  | 
            |
| 3228 | |||
| 3229 | // Validate existing component  | 
            ||
| 3230 | 1 |                 if ( ! isset($this->queryComponents[$lookaheadValue])) { | 
            |
| 3231 |                     $this->semanticalError('Cannot add having condition on undefined result variable.'); | 
            ||
| 3232 | }  | 
            ||
| 3233 | |||
| 3234 | // Validate SingleValuedPathExpression (ie.: "product")  | 
            ||
| 3235 | 1 |                 if (isset($this->queryComponents[$lookaheadValue]['metadata'])) { | 
            |
| 3236 | 1 | $expr = $this->SingleValuedPathExpression();  | 
            |
| 3237 | 1 | break;  | 
            |
| 3238 | }  | 
            ||
| 3239 | |||
| 3240 | // Validating ResultVariable  | 
            ||
| 3241 |                 if ( ! isset($this->queryComponents[$lookaheadValue]['resultVariable'])) { | 
            ||
| 3242 |                     $this->semanticalError('Cannot add having condition on a non result variable.'); | 
            ||
| 3243 | }  | 
            ||
| 3244 | |||
| 3245 | $expr = $this->ResultVariable();  | 
            ||
| 3246 | break;  | 
            ||
| 3247 | }  | 
            ||
| 3248 | |||
| 3249 | 11 | $nullCompExpr = new AST\NullComparisonExpression($expr);  | 
            |
| 3250 | |||
| 3251 | 11 | $this->match(Lexer::T_IS);  | 
            |
| 3252 | |||
| 3253 | 11 |         if ($this->lexer->isNextToken(Lexer::T_NOT)) { | 
            |
| 3254 | 3 | $this->match(Lexer::T_NOT);  | 
            |
| 3255 | |||
| 3256 | 3 | $nullCompExpr->not = true;  | 
            |
| 3257 | }  | 
            ||
| 3258 | |||
| 3259 | 11 | $this->match(Lexer::T_NULL);  | 
            |
| 3260 | |||
| 3261 | 11 | return $nullCompExpr;  | 
            |
| 3262 | }  | 
            ||
| 3263 | |||
| 3264 | /**  | 
            ||
| 3265 |      * ExistsExpression ::= ["NOT"] "EXISTS" "(" Subselect ")" | 
            ||
| 3266 | *  | 
            ||
| 3267 | * @return \Doctrine\ORM\Query\AST\ExistsExpression  | 
            ||
| 3268 | */  | 
            ||
| 3269 | 7 | public function ExistsExpression()  | 
            |
| 3288 | |||
| 3289 | /**  | 
            ||
| 3290 | * ComparisonOperator ::= "=" | "<" | "<=" | "<>" | ">" | ">=" | "!="  | 
            ||
| 3291 | *  | 
            ||
| 3292 | * @return string  | 
            ||
| 3293 | */  | 
            ||
| 3294 | 259 | public function ComparisonOperator()  | 
            |
| 3337 | |||
| 3338 | /**  | 
            ||
| 3339 | * FunctionDeclaration ::= FunctionsReturningStrings | FunctionsReturningNumerics | FunctionsReturningDatetime  | 
            ||
| 3340 | *  | 
            ||
| 3341 | * @return \Doctrine\ORM\Query\AST\Functions\FunctionNode  | 
            ||
| 3342 | */  | 
            ||
| 3343 | 71 | public function FunctionDeclaration()  | 
            |
| 3368 | |||
| 3369 | /**  | 
            ||
| 3370 | * Helper function for FunctionDeclaration grammar rule.  | 
            ||
| 3371 | *  | 
            ||
| 3372 | * @return \Doctrine\ORM\Query\AST\Functions\FunctionNode  | 
            ||
| 3373 | */  | 
            ||
| 3374 | 71 | private function CustomFunctionDeclaration()  | 
            |
| 3396 | |||
| 3397 | /**  | 
            ||
| 3398 | * FunctionsReturningNumerics ::=  | 
            ||
| 3399 |      *      "LENGTH" "(" StringPrimary ")" | | 
            ||
| 3400 |      *      "LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" | | 
            ||
| 3401 |      *      "ABS" "(" SimpleArithmeticExpression ")" | | 
            ||
| 3402 |      *      "SQRT" "(" SimpleArithmeticExpression ")" | | 
            ||
| 3403 |      *      "MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")" | | 
            ||
| 3404 |      *      "SIZE" "(" CollectionValuedPathExpression ")" | | 
            ||
| 3405 |      *      "DATE_DIFF" "(" ArithmeticPrimary "," ArithmeticPrimary ")" | | 
            ||
| 3406 |      *      "BIT_AND" "(" ArithmeticPrimary "," ArithmeticPrimary ")" | | 
            ||
| 3407 |      *      "BIT_OR" "(" ArithmeticPrimary "," ArithmeticPrimary ")" | 
            ||
| 3408 | *  | 
            ||
| 3409 | * @return \Doctrine\ORM\Query\AST\Functions\FunctionNode  | 
            ||
| 3410 | */  | 
            ||
| 3411 | 37 | public function FunctionsReturningNumerics()  | 
            |
| 3421 | |||
| 3422 | /**  | 
            ||
| 3423 | * @return \Doctrine\ORM\Query\AST\Functions\FunctionNode  | 
            ||
| 3424 | */  | 
            ||
| 3425 | 2 | public function CustomFunctionsReturningNumerics()  | 
            |
| 3439 | |||
| 3440 | /**  | 
            ||
| 3441 | * FunctionsReturningDateTime ::=  | 
            ||
| 3442 | * "CURRENT_DATE" |  | 
            ||
| 3443 | * "CURRENT_TIME" |  | 
            ||
| 3444 | * "CURRENT_TIMESTAMP" |  | 
            ||
| 3445 |      *     "DATE_ADD" "(" ArithmeticPrimary "," ArithmeticPrimary "," StringPrimary ")" | | 
            ||
| 3446 |      *     "DATE_SUB" "(" ArithmeticPrimary "," ArithmeticPrimary "," StringPrimary ")" | 
            ||
| 3447 | *  | 
            ||
| 3448 | * @return \Doctrine\ORM\Query\AST\Functions\FunctionNode  | 
            ||
| 3449 | */  | 
            ||
| 3450 | 7 | public function FunctionsReturningDatetime()  | 
            |
| 3460 | |||
| 3461 | /**  | 
            ||
| 3462 | * @return \Doctrine\ORM\Query\AST\Functions\FunctionNode  | 
            ||
| 3463 | */  | 
            ||
| 3464 | public function CustomFunctionsReturningDatetime()  | 
            ||
| 3478 | |||
| 3479 | /**  | 
            ||
| 3480 | * FunctionsReturningStrings ::=  | 
            ||
| 3481 |      *   "CONCAT" "(" StringPrimary "," StringPrimary {"," StringPrimary}* ")" | | 
            ||
| 3482 |      *   "SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" | | 
            ||
| 3483 |      *   "TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")" | | 
            ||
| 3484 |      *   "LOWER" "(" StringPrimary ")" | | 
            ||
| 3485 |      *   "UPPER" "(" StringPrimary ")" | | 
            ||
| 3486 |      *   "IDENTITY" "(" SingleValuedAssociationPathExpression {"," string} ")" | 
            ||
| 3487 | *  | 
            ||
| 3488 | * @return \Doctrine\ORM\Query\AST\Functions\FunctionNode  | 
            ||
| 3489 | */  | 
            ||
| 3490 | 29 | public function FunctionsReturningStrings()  | 
            |
| 3500 | |||
| 3501 | /**  | 
            ||
| 3502 | * @return \Doctrine\ORM\Query\AST\Functions\FunctionNode  | 
            ||
| 3503 | */  | 
            ||
| 3504 | 2 | public function CustomFunctionsReturningStrings()  | 
            |
| 3518 | }  | 
            ||
| 3519 | 
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..