Parser.php 94KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868
  1. <?php
  2. /*
  3. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  4. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  5. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  6. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  7. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  8. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  9. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  10. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  11. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  14. *
  15. * This software consists of voluntary contributions made by many individuals
  16. * and is licensed under the LGPL. For more information, see
  17. * <http://www.doctrine-project.org>.
  18. */
  19. namespace Doctrine\ORM\Query;
  20. use Doctrine\ORM\Query;
  21. use Doctrine\ORM\Mapping\ClassMetadata;
  22. /**
  23. * An LL(*) recursive-descent parser for the context-free grammar of the Doctrine Query Language.
  24. * Parses a DQL query, reports any errors in it, and generates an AST.
  25. *
  26. * @since 2.0
  27. * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
  28. * @author Jonathan Wage <jonwage@gmail.com>
  29. * @author Roman Borschel <roman@code-factory.org>
  30. * @author Janne Vanhala <jpvanhal@cc.hut.fi>
  31. */
  32. class Parser
  33. {
  34. /** READ-ONLY: Maps BUILT-IN string function names to AST class names. */
  35. private static $_STRING_FUNCTIONS = array(
  36. 'concat' => 'Doctrine\ORM\Query\AST\Functions\ConcatFunction',
  37. 'substring' => 'Doctrine\ORM\Query\AST\Functions\SubstringFunction',
  38. 'trim' => 'Doctrine\ORM\Query\AST\Functions\TrimFunction',
  39. 'lower' => 'Doctrine\ORM\Query\AST\Functions\LowerFunction',
  40. 'upper' => 'Doctrine\ORM\Query\AST\Functions\UpperFunction'
  41. );
  42. /** READ-ONLY: Maps BUILT-IN numeric function names to AST class names. */
  43. private static $_NUMERIC_FUNCTIONS = array(
  44. 'length' => 'Doctrine\ORM\Query\AST\Functions\LengthFunction',
  45. 'locate' => 'Doctrine\ORM\Query\AST\Functions\LocateFunction',
  46. 'abs' => 'Doctrine\ORM\Query\AST\Functions\AbsFunction',
  47. 'sqrt' => 'Doctrine\ORM\Query\AST\Functions\SqrtFunction',
  48. 'mod' => 'Doctrine\ORM\Query\AST\Functions\ModFunction',
  49. 'size' => 'Doctrine\ORM\Query\AST\Functions\SizeFunction',
  50. 'date_diff' => 'Doctrine\ORM\Query\AST\Functions\DateDiffFunction',
  51. );
  52. /** READ-ONLY: Maps BUILT-IN datetime function names to AST class names. */
  53. private static $_DATETIME_FUNCTIONS = array(
  54. 'current_date' => 'Doctrine\ORM\Query\AST\Functions\CurrentDateFunction',
  55. 'current_time' => 'Doctrine\ORM\Query\AST\Functions\CurrentTimeFunction',
  56. 'current_timestamp' => 'Doctrine\ORM\Query\AST\Functions\CurrentTimestampFunction',
  57. 'date_add' => 'Doctrine\ORM\Query\AST\Functions\DateAddFunction',
  58. 'date_sub' => 'Doctrine\ORM\Query\AST\Functions\DateSubFunction',
  59. );
  60. /**
  61. * Expressions that were encountered during parsing of identifiers and expressions
  62. * and still need to be validated.
  63. */
  64. private $_deferredIdentificationVariables = array();
  65. private $_deferredPartialObjectExpressions = array();
  66. private $_deferredPathExpressions = array();
  67. private $_deferredResultVariables = array();
  68. /**
  69. * The lexer.
  70. *
  71. * @var \Doctrine\ORM\Query\Lexer
  72. */
  73. private $_lexer;
  74. /**
  75. * The parser result.
  76. *
  77. * @var \Doctrine\ORM\Query\ParserResult
  78. */
  79. private $_parserResult;
  80. /**
  81. * The EntityManager.
  82. *
  83. * @var EnityManager
  84. */
  85. private $_em;
  86. /**
  87. * The Query to parse.
  88. *
  89. * @var Query
  90. */
  91. private $_query;
  92. /**
  93. * Map of declared query components in the parsed query.
  94. *
  95. * @var array
  96. */
  97. private $_queryComponents = array();
  98. /**
  99. * Keeps the nesting level of defined ResultVariables
  100. *
  101. * @var integer
  102. */
  103. private $_nestingLevel = 0;
  104. /**
  105. * Any additional custom tree walkers that modify the AST.
  106. *
  107. * @var array
  108. */
  109. private $_customTreeWalkers = array();
  110. /**
  111. * The custom last tree walker, if any, that is responsible for producing the output.
  112. *
  113. * @var TreeWalker
  114. */
  115. private $_customOutputWalker;
  116. /**
  117. * @var array
  118. */
  119. private $_identVariableExpressions = array();
  120. /**
  121. * Creates a new query parser object.
  122. *
  123. * @param Query $query The Query to parse.
  124. */
  125. public function __construct(Query $query)
  126. {
  127. $this->_query = $query;
  128. $this->_em = $query->getEntityManager();
  129. $this->_lexer = new Lexer($query->getDql());
  130. $this->_parserResult = new ParserResult();
  131. }
  132. /**
  133. * Sets a custom tree walker that produces output.
  134. * This tree walker will be run last over the AST, after any other walkers.
  135. *
  136. * @param string $className
  137. */
  138. public function setCustomOutputTreeWalker($className)
  139. {
  140. $this->_customOutputWalker = $className;
  141. }
  142. /**
  143. * Adds a custom tree walker for modifying the AST.
  144. *
  145. * @param string $className
  146. */
  147. public function addCustomTreeWalker($className)
  148. {
  149. $this->_customTreeWalkers[] = $className;
  150. }
  151. /**
  152. * Gets the lexer used by the parser.
  153. *
  154. * @return \Doctrine\ORM\Query\Lexer
  155. */
  156. public function getLexer()
  157. {
  158. return $this->_lexer;
  159. }
  160. /**
  161. * Gets the ParserResult that is being filled with information during parsing.
  162. *
  163. * @return \Doctrine\ORM\Query\ParserResult
  164. */
  165. public function getParserResult()
  166. {
  167. return $this->_parserResult;
  168. }
  169. /**
  170. * Gets the EntityManager used by the parser.
  171. *
  172. * @return EntityManager
  173. */
  174. public function getEntityManager()
  175. {
  176. return $this->_em;
  177. }
  178. /**
  179. * Parse and build AST for the given Query.
  180. *
  181. * @return \Doctrine\ORM\Query\AST\SelectStatement |
  182. * \Doctrine\ORM\Query\AST\UpdateStatement |
  183. * \Doctrine\ORM\Query\AST\DeleteStatement
  184. */
  185. public function getAST()
  186. {
  187. // Parse & build AST
  188. $AST = $this->QueryLanguage();
  189. // Process any deferred validations of some nodes in the AST.
  190. // This also allows post-processing of the AST for modification purposes.
  191. $this->_processDeferredIdentificationVariables();
  192. if ($this->_deferredPartialObjectExpressions) {
  193. $this->_processDeferredPartialObjectExpressions();
  194. }
  195. if ($this->_deferredPathExpressions) {
  196. $this->_processDeferredPathExpressions($AST);
  197. }
  198. if ($this->_deferredResultVariables) {
  199. $this->_processDeferredResultVariables();
  200. }
  201. return $AST;
  202. }
  203. /**
  204. * Attempts to match the given token with the current lookahead token.
  205. *
  206. * If they match, updates the lookahead token; otherwise raises a syntax
  207. * error.
  208. *
  209. * @param int token type
  210. * @return void
  211. * @throws QueryException If the tokens dont match.
  212. */
  213. public function match($token)
  214. {
  215. // short-circuit on first condition, usually types match
  216. if ($this->_lexer->lookahead['type'] !== $token &&
  217. $token !== Lexer::T_IDENTIFIER &&
  218. $this->_lexer->lookahead['type'] <= Lexer::T_IDENTIFIER
  219. ) {
  220. $this->syntaxError($this->_lexer->getLiteral($token));
  221. }
  222. $this->_lexer->moveNext();
  223. }
  224. /**
  225. * Free this parser enabling it to be reused
  226. *
  227. * @param boolean $deep Whether to clean peek and reset errors
  228. * @param integer $position Position to reset
  229. */
  230. public function free($deep = false, $position = 0)
  231. {
  232. // WARNING! Use this method with care. It resets the scanner!
  233. $this->_lexer->resetPosition($position);
  234. // Deep = true cleans peek and also any previously defined errors
  235. if ($deep) {
  236. $this->_lexer->resetPeek();
  237. }
  238. $this->_lexer->token = null;
  239. $this->_lexer->lookahead = null;
  240. }
  241. /**
  242. * Parses a query string.
  243. *
  244. * @return ParserResult
  245. */
  246. public function parse()
  247. {
  248. $AST = $this->getAST();
  249. $this->fixIdentificationVariableOrder($AST);
  250. $this->assertSelectEntityRootAliasRequirement();
  251. if (($customWalkers = $this->_query->getHint(Query::HINT_CUSTOM_TREE_WALKERS)) !== false) {
  252. $this->_customTreeWalkers = $customWalkers;
  253. }
  254. if (($customOutputWalker = $this->_query->getHint(Query::HINT_CUSTOM_OUTPUT_WALKER)) !== false) {
  255. $this->_customOutputWalker = $customOutputWalker;
  256. }
  257. // Run any custom tree walkers over the AST
  258. if ($this->_customTreeWalkers) {
  259. $treeWalkerChain = new TreeWalkerChain($this->_query, $this->_parserResult, $this->_queryComponents);
  260. foreach ($this->_customTreeWalkers as $walker) {
  261. $treeWalkerChain->addTreeWalker($walker);
  262. }
  263. if ($AST instanceof AST\SelectStatement) {
  264. $treeWalkerChain->walkSelectStatement($AST);
  265. } else if ($AST instanceof AST\UpdateStatement) {
  266. $treeWalkerChain->walkUpdateStatement($AST);
  267. } else {
  268. $treeWalkerChain->walkDeleteStatement($AST);
  269. }
  270. }
  271. if ($this->_customOutputWalker) {
  272. $outputWalker = new $this->_customOutputWalker(
  273. $this->_query, $this->_parserResult, $this->_queryComponents
  274. );
  275. } else {
  276. $outputWalker = new SqlWalker(
  277. $this->_query, $this->_parserResult, $this->_queryComponents
  278. );
  279. }
  280. // Assign an SQL executor to the parser result
  281. $this->_parserResult->setSqlExecutor($outputWalker->getExecutor($AST));
  282. return $this->_parserResult;
  283. }
  284. private function assertSelectEntityRootAliasRequirement()
  285. {
  286. if ( count($this->_identVariableExpressions) > 0) {
  287. $foundRootEntity = false;
  288. foreach ($this->_identVariableExpressions AS $dqlAlias => $expr) {
  289. if (isset($this->_queryComponents[$dqlAlias]) && $this->_queryComponents[$dqlAlias]['parent'] === null) {
  290. $foundRootEntity = true;
  291. }
  292. }
  293. if (!$foundRootEntity) {
  294. $this->semanticalError('Cannot select entity through identification variables without choosing at least one root entity alias.');
  295. }
  296. }
  297. }
  298. /**
  299. * Fix order of identification variables.
  300. *
  301. * They have to appear in the select clause in the same order as the
  302. * declarations (from ... x join ... y join ... z ...) appear in the query
  303. * as the hydration process relies on that order for proper operation.
  304. *
  305. * @param AST\SelectStatement|AST\DeleteStatement|AST\UpdateStatement $AST
  306. * @return void
  307. */
  308. private function fixIdentificationVariableOrder($AST)
  309. {
  310. if ( count($this->_identVariableExpressions) > 1) {
  311. foreach ($this->_queryComponents as $dqlAlias => $qComp) {
  312. if (isset($this->_identVariableExpressions[$dqlAlias])) {
  313. $expr = $this->_identVariableExpressions[$dqlAlias];
  314. $key = array_search($expr, $AST->selectClause->selectExpressions);
  315. unset($AST->selectClause->selectExpressions[$key]);
  316. $AST->selectClause->selectExpressions[] = $expr;
  317. }
  318. }
  319. }
  320. }
  321. /**
  322. * Generates a new syntax error.
  323. *
  324. * @param string $expected Expected string.
  325. * @param array $token Got token.
  326. *
  327. * @throws \Doctrine\ORM\Query\QueryException
  328. */
  329. public function syntaxError($expected = '', $token = null)
  330. {
  331. if ($token === null) {
  332. $token = $this->_lexer->lookahead;
  333. }
  334. $tokenPos = (isset($token['position'])) ? $token['position'] : '-1';
  335. $message = "line 0, col {$tokenPos}: Error: ";
  336. if ($expected !== '') {
  337. $message .= "Expected {$expected}, got ";
  338. } else {
  339. $message .= 'Unexpected ';
  340. }
  341. if ($this->_lexer->lookahead === null) {
  342. $message .= 'end of string.';
  343. } else {
  344. $message .= "'{$token['value']}'";
  345. }
  346. throw QueryException::syntaxError($message);
  347. }
  348. /**
  349. * Generates a new semantical error.
  350. *
  351. * @param string $message Optional message.
  352. * @param array $token Optional token.
  353. *
  354. * @throws \Doctrine\ORM\Query\QueryException
  355. */
  356. public function semanticalError($message = '', $token = null)
  357. {
  358. if ($token === null) {
  359. $token = $this->_lexer->lookahead;
  360. }
  361. // Minimum exposed chars ahead of token
  362. $distance = 12;
  363. // Find a position of a final word to display in error string
  364. $dql = $this->_query->getDql();
  365. $length = strlen($dql);
  366. $pos = $token['position'] + $distance;
  367. $pos = strpos($dql, ' ', ($length > $pos) ? $pos : $length);
  368. $length = ($pos !== false) ? $pos - $token['position'] : $distance;
  369. // Building informative message
  370. $message = 'line 0, col ' . (
  371. (isset($token['position']) && $token['position'] > 0) ? $token['position'] : '-1'
  372. ) . " near '" . substr($dql, $token['position'], $length) . "': Error: " . $message;
  373. throw \Doctrine\ORM\Query\QueryException::semanticalError($message);
  374. }
  375. /**
  376. * Peeks beyond the specified token and returns the first token after that one.
  377. *
  378. * @param array $token
  379. * @return array
  380. */
  381. private function _peekBeyond($token)
  382. {
  383. $peek = $this->_lexer->peek();
  384. while ($peek['value'] != $token) {
  385. $peek = $this->_lexer->peek();
  386. }
  387. $peek = $this->_lexer->peek();
  388. $this->_lexer->resetPeek();
  389. return $peek;
  390. }
  391. /**
  392. * Peek beyond the matched closing parenthesis and return the first token after that one.
  393. *
  394. * @return array
  395. */
  396. private function _peekBeyondClosingParenthesis()
  397. {
  398. $token = $this->_lexer->peek();
  399. $numUnmatched = 1;
  400. while ($numUnmatched > 0 && $token !== null) {
  401. if ($token['value'] == ')') {
  402. --$numUnmatched;
  403. } else if ($token['value'] == '(') {
  404. ++$numUnmatched;
  405. }
  406. $token = $this->_lexer->peek();
  407. }
  408. $this->_lexer->resetPeek();
  409. return $token;
  410. }
  411. /**
  412. * Checks if the given token indicates a mathematical operator.
  413. *
  414. * @return boolean TRUE if the token is a mathematical operator, FALSE otherwise.
  415. */
  416. private function _isMathOperator($token)
  417. {
  418. return in_array($token['value'], array("+", "-", "/", "*"));
  419. }
  420. /**
  421. * Checks if the next-next (after lookahead) token starts a function.
  422. *
  423. * @return boolean TRUE if the next-next tokens start a function, FALSE otherwise.
  424. */
  425. private function _isFunction()
  426. {
  427. $peek = $this->_lexer->peek();
  428. $nextpeek = $this->_lexer->peek();
  429. $this->_lexer->resetPeek();
  430. // We deny the COUNT(SELECT * FROM User u) here. COUNT won't be considered a function
  431. return ($peek['value'] === '(' && $nextpeek['type'] !== Lexer::T_SELECT);
  432. }
  433. /**
  434. * Checks whether the given token type indicates an aggregate function.
  435. *
  436. * @return boolean TRUE if the token type is an aggregate function, FALSE otherwise.
  437. */
  438. private function _isAggregateFunction($tokenType)
  439. {
  440. return $tokenType == Lexer::T_AVG || $tokenType == Lexer::T_MIN ||
  441. $tokenType == Lexer::T_MAX || $tokenType == Lexer::T_SUM ||
  442. $tokenType == Lexer::T_COUNT;
  443. }
  444. /**
  445. * Checks whether the current lookahead token of the lexer has the type
  446. * T_ALL, T_ANY or T_SOME.
  447. *
  448. * @return boolean
  449. */
  450. private function _isNextAllAnySome()
  451. {
  452. return $this->_lexer->lookahead['type'] === Lexer::T_ALL ||
  453. $this->_lexer->lookahead['type'] === Lexer::T_ANY ||
  454. $this->_lexer->lookahead['type'] === Lexer::T_SOME;
  455. }
  456. /**
  457. * Checks whether the next 2 tokens start a subselect.
  458. *
  459. * @return boolean TRUE if the next 2 tokens start a subselect, FALSE otherwise.
  460. */
  461. private function _isSubselect()
  462. {
  463. $la = $this->_lexer->lookahead;
  464. $next = $this->_lexer->glimpse();
  465. return ($la['value'] === '(' && $next['type'] === Lexer::T_SELECT);
  466. }
  467. /**
  468. * Validates that the given <tt>IdentificationVariable</tt> is semantically correct.
  469. * It must exist in query components list.
  470. *
  471. * @return void
  472. */
  473. private function _processDeferredIdentificationVariables()
  474. {
  475. foreach ($this->_deferredIdentificationVariables as $deferredItem) {
  476. $identVariable = $deferredItem['expression'];
  477. // Check if IdentificationVariable exists in queryComponents
  478. if ( ! isset($this->_queryComponents[$identVariable])) {
  479. $this->semanticalError(
  480. "'$identVariable' is not defined.", $deferredItem['token']
  481. );
  482. }
  483. $qComp = $this->_queryComponents[$identVariable];
  484. // Check if queryComponent points to an AbstractSchemaName or a ResultVariable
  485. if ( ! isset($qComp['metadata'])) {
  486. $this->semanticalError(
  487. "'$identVariable' does not point to a Class.", $deferredItem['token']
  488. );
  489. }
  490. // Validate if identification variable nesting level is lower or equal than the current one
  491. if ($qComp['nestingLevel'] > $deferredItem['nestingLevel']) {
  492. $this->semanticalError(
  493. "'$identVariable' is used outside the scope of its declaration.", $deferredItem['token']
  494. );
  495. }
  496. }
  497. }
  498. /**
  499. * Validates that the given <tt>PartialObjectExpression</tt> is semantically correct.
  500. * It must exist in query components list.
  501. *
  502. * @return void
  503. */
  504. private function _processDeferredPartialObjectExpressions()
  505. {
  506. foreach ($this->_deferredPartialObjectExpressions as $deferredItem) {
  507. $expr = $deferredItem['expression'];
  508. $class = $this->_queryComponents[$expr->identificationVariable]['metadata'];
  509. foreach ($expr->partialFieldSet as $field) {
  510. if ( ! isset($class->fieldMappings[$field])) {
  511. $this->semanticalError(
  512. "There is no mapped field named '$field' on class " . $class->name . ".",
  513. $deferredItem['token']
  514. );
  515. }
  516. }
  517. if (array_intersect($class->identifier, $expr->partialFieldSet) != $class->identifier) {
  518. $this->semanticalError(
  519. "The partial field selection of class " . $class->name . " must contain the identifier.",
  520. $deferredItem['token']
  521. );
  522. }
  523. }
  524. }
  525. /**
  526. * Validates that the given <tt>ResultVariable</tt> is semantically correct.
  527. * It must exist in query components list.
  528. *
  529. * @return void
  530. */
  531. private function _processDeferredResultVariables()
  532. {
  533. foreach ($this->_deferredResultVariables as $deferredItem) {
  534. $resultVariable = $deferredItem['expression'];
  535. // Check if ResultVariable exists in queryComponents
  536. if ( ! isset($this->_queryComponents[$resultVariable])) {
  537. $this->semanticalError(
  538. "'$resultVariable' is not defined.", $deferredItem['token']
  539. );
  540. }
  541. $qComp = $this->_queryComponents[$resultVariable];
  542. // Check if queryComponent points to an AbstractSchemaName or a ResultVariable
  543. if ( ! isset($qComp['resultVariable'])) {
  544. $this->semanticalError(
  545. "'$identVariable' does not point to a ResultVariable.", $deferredItem['token']
  546. );
  547. }
  548. // Validate if identification variable nesting level is lower or equal than the current one
  549. if ($qComp['nestingLevel'] > $deferredItem['nestingLevel']) {
  550. $this->semanticalError(
  551. "'$resultVariable' is used outside the scope of its declaration.", $deferredItem['token']
  552. );
  553. }
  554. }
  555. }
  556. /**
  557. * Validates that the given <tt>PathExpression</tt> is semantically correct for grammar rules:
  558. *
  559. * AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression
  560. * SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression
  561. * StateFieldPathExpression ::= IdentificationVariable "." StateField
  562. * SingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField
  563. * CollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField
  564. *
  565. * @param array $deferredItem
  566. * @param mixed $AST
  567. */
  568. private function _processDeferredPathExpressions($AST)
  569. {
  570. foreach ($this->_deferredPathExpressions as $deferredItem) {
  571. $pathExpression = $deferredItem['expression'];
  572. $qComp = $this->_queryComponents[$pathExpression->identificationVariable];
  573. $class = $qComp['metadata'];
  574. if (($field = $pathExpression->field) === null) {
  575. $field = $pathExpression->field = $class->identifier[0];
  576. }
  577. // Check if field or association exists
  578. if ( ! isset($class->associationMappings[$field]) && ! isset($class->fieldMappings[$field])) {
  579. $this->semanticalError(
  580. 'Class ' . $class->name . ' has no field or association named ' . $field,
  581. $deferredItem['token']
  582. );
  583. }
  584. if (isset($class->fieldMappings[$field])) {
  585. $fieldType = AST\PathExpression::TYPE_STATE_FIELD;
  586. } else {
  587. $assoc = $class->associationMappings[$field];
  588. $class = $this->_em->getClassMetadata($assoc['targetEntity']);
  589. if ($assoc['type'] & ClassMetadata::TO_ONE) {
  590. $fieldType = AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION;
  591. } else {
  592. $fieldType = AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION;
  593. }
  594. }
  595. // Validate if PathExpression is one of the expected types
  596. $expectedType = $pathExpression->expectedType;
  597. if ( ! ($expectedType & $fieldType)) {
  598. // We need to recognize which was expected type(s)
  599. $expectedStringTypes = array();
  600. // Validate state field type
  601. if ($expectedType & AST\PathExpression::TYPE_STATE_FIELD) {
  602. $expectedStringTypes[] = 'StateFieldPathExpression';
  603. }
  604. // Validate single valued association (*-to-one)
  605. if ($expectedType & AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION) {
  606. $expectedStringTypes[] = 'SingleValuedAssociationField';
  607. }
  608. // Validate single valued association (*-to-many)
  609. if ($expectedType & AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION) {
  610. $expectedStringTypes[] = 'CollectionValuedAssociationField';
  611. }
  612. // Build the error message
  613. $semanticalError = 'Invalid PathExpression. ';
  614. if (count($expectedStringTypes) == 1) {
  615. $semanticalError .= 'Must be a ' . $expectedStringTypes[0] . '.';
  616. } else {
  617. $semanticalError .= implode(' or ', $expectedStringTypes) . ' expected.';
  618. }
  619. $this->semanticalError($semanticalError, $deferredItem['token']);
  620. }
  621. // We need to force the type in PathExpression
  622. $pathExpression->type = $fieldType;
  623. }
  624. }
  625. /**
  626. * QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement
  627. *
  628. * @return \Doctrine\ORM\Query\AST\SelectStatement |
  629. * \Doctrine\ORM\Query\AST\UpdateStatement |
  630. * \Doctrine\ORM\Query\AST\DeleteStatement
  631. */
  632. public function QueryLanguage()
  633. {
  634. $this->_lexer->moveNext();
  635. switch ($this->_lexer->lookahead['type']) {
  636. case Lexer::T_SELECT:
  637. $statement = $this->SelectStatement();
  638. break;
  639. case Lexer::T_UPDATE:
  640. $statement = $this->UpdateStatement();
  641. break;
  642. case Lexer::T_DELETE:
  643. $statement = $this->DeleteStatement();
  644. break;
  645. default:
  646. $this->syntaxError('SELECT, UPDATE or DELETE');
  647. break;
  648. }
  649. // Check for end of string
  650. if ($this->_lexer->lookahead !== null) {
  651. $this->syntaxError('end of string');
  652. }
  653. return $statement;
  654. }
  655. /**
  656. * SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
  657. *
  658. * @return \Doctrine\ORM\Query\AST\SelectStatement
  659. */
  660. public function SelectStatement()
  661. {
  662. $selectStatement = new AST\SelectStatement($this->SelectClause(), $this->FromClause());
  663. $selectStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE)
  664. ? $this->WhereClause() : null;
  665. $selectStatement->groupByClause = $this->_lexer->isNextToken(Lexer::T_GROUP)
  666. ? $this->GroupByClause() : null;
  667. $selectStatement->havingClause = $this->_lexer->isNextToken(Lexer::T_HAVING)
  668. ? $this->HavingClause() : null;
  669. $selectStatement->orderByClause = $this->_lexer->isNextToken(Lexer::T_ORDER)
  670. ? $this->OrderByClause() : null;
  671. return $selectStatement;
  672. }
  673. /**
  674. * UpdateStatement ::= UpdateClause [WhereClause]
  675. *
  676. * @return \Doctrine\ORM\Query\AST\UpdateStatement
  677. */
  678. public function UpdateStatement()
  679. {
  680. $updateStatement = new AST\UpdateStatement($this->UpdateClause());
  681. $updateStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE)
  682. ? $this->WhereClause() : null;
  683. return $updateStatement;
  684. }
  685. /**
  686. * DeleteStatement ::= DeleteClause [WhereClause]
  687. *
  688. * @return \Doctrine\ORM\Query\AST\DeleteStatement
  689. */
  690. public function DeleteStatement()
  691. {
  692. $deleteStatement = new AST\DeleteStatement($this->DeleteClause());
  693. $deleteStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE)
  694. ? $this->WhereClause() : null;
  695. return $deleteStatement;
  696. }
  697. /**
  698. * IdentificationVariable ::= identifier
  699. *
  700. * @return string
  701. */
  702. public function IdentificationVariable()
  703. {
  704. $this->match(Lexer::T_IDENTIFIER);
  705. $identVariable = $this->_lexer->token['value'];
  706. $this->_deferredIdentificationVariables[] = array(
  707. 'expression' => $identVariable,
  708. 'nestingLevel' => $this->_nestingLevel,
  709. 'token' => $this->_lexer->token,
  710. );
  711. return $identVariable;
  712. }
  713. /**
  714. * AliasIdentificationVariable = identifier
  715. *
  716. * @return string
  717. */
  718. public function AliasIdentificationVariable()
  719. {
  720. $this->match(Lexer::T_IDENTIFIER);
  721. $aliasIdentVariable = $this->_lexer->token['value'];
  722. $exists = isset($this->_queryComponents[$aliasIdentVariable]);
  723. if ($exists) {
  724. $this->semanticalError(
  725. "'$aliasIdentVariable' is already defined.", $this->_lexer->token
  726. );
  727. }
  728. return $aliasIdentVariable;
  729. }
  730. /**
  731. * AbstractSchemaName ::= identifier
  732. *
  733. * @return string
  734. */
  735. public function AbstractSchemaName()
  736. {
  737. $this->match(Lexer::T_IDENTIFIER);
  738. $schemaName = ltrim($this->_lexer->token['value'], '\\');
  739. if (strrpos($schemaName, ':') !== false) {
  740. list($namespaceAlias, $simpleClassName) = explode(':', $schemaName);
  741. $schemaName = $this->_em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
  742. }
  743. $exists = class_exists($schemaName, true);
  744. if ( ! $exists) {
  745. $this->semanticalError("Class '$schemaName' is not defined.", $this->_lexer->token);
  746. }
  747. return $schemaName;
  748. }
  749. /**
  750. * AliasResultVariable ::= identifier
  751. *
  752. * @return string
  753. */
  754. public function AliasResultVariable()
  755. {
  756. $this->match(Lexer::T_IDENTIFIER);
  757. $resultVariable = $this->_lexer->token['value'];
  758. $exists = isset($this->_queryComponents[$resultVariable]);
  759. if ($exists) {
  760. $this->semanticalError(
  761. "'$resultVariable' is already defined.", $this->_lexer->token
  762. );
  763. }
  764. return $resultVariable;
  765. }
  766. /**
  767. * ResultVariable ::= identifier
  768. *
  769. * @return string
  770. */
  771. public function ResultVariable()
  772. {
  773. $this->match(Lexer::T_IDENTIFIER);
  774. $resultVariable = $this->_lexer->token['value'];
  775. // Defer ResultVariable validation
  776. $this->_deferredResultVariables[] = array(
  777. 'expression' => $resultVariable,
  778. 'nestingLevel' => $this->_nestingLevel,
  779. 'token' => $this->_lexer->token,
  780. );
  781. return $resultVariable;
  782. }
  783. /**
  784. * JoinAssociationPathExpression ::= IdentificationVariable "." (CollectionValuedAssociationField | SingleValuedAssociationField)
  785. *
  786. * @return \Doctrine\ORM\Query\AST\JoinAssociationPathExpression
  787. */
  788. public function JoinAssociationPathExpression()
  789. {
  790. $token = $this->_lexer->lookahead;
  791. $identVariable = $this->IdentificationVariable();
  792. if (!isset($this->_queryComponents[$identVariable])) {
  793. $this->semanticalError('Identification Variable ' . $identVariable .' used in join path expression but was not defined before.');
  794. }
  795. $this->match(Lexer::T_DOT);
  796. $this->match(Lexer::T_IDENTIFIER);
  797. $field = $this->_lexer->token['value'];
  798. // Validate association field
  799. $qComp = $this->_queryComponents[$identVariable];
  800. $class = $qComp['metadata'];
  801. if ( ! isset($class->associationMappings[$field])) {
  802. $this->semanticalError('Class ' . $class->name . ' has no association named ' . $field);
  803. }
  804. return new AST\JoinAssociationPathExpression($identVariable, $field);
  805. }
  806. /**
  807. * Parses an arbitrary path expression and defers semantical validation
  808. * based on expected types.
  809. *
  810. * PathExpression ::= IdentificationVariable "." identifier
  811. *
  812. * @param integer $expectedTypes
  813. * @return \Doctrine\ORM\Query\AST\PathExpression
  814. */
  815. public function PathExpression($expectedTypes)
  816. {
  817. $token = $this->_lexer->lookahead;
  818. $identVariable = $this->IdentificationVariable();
  819. $field = null;
  820. if ($this->_lexer->isNextToken(Lexer::T_DOT)) {
  821. $this->match(Lexer::T_DOT);
  822. $this->match(Lexer::T_IDENTIFIER);
  823. $field = $this->_lexer->token['value'];
  824. }
  825. // Creating AST node
  826. $pathExpr = new AST\PathExpression($expectedTypes, $identVariable, $field);
  827. // Defer PathExpression validation if requested to be defered
  828. $this->_deferredPathExpressions[] = array(
  829. 'expression' => $pathExpr,
  830. 'nestingLevel' => $this->_nestingLevel,
  831. 'token' => $this->_lexer->token,
  832. );
  833. return $pathExpr;
  834. }
  835. /**
  836. * AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression
  837. *
  838. * @return \Doctrine\ORM\Query\AST\PathExpression
  839. */
  840. public function AssociationPathExpression()
  841. {
  842. return $this->PathExpression(
  843. AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION |
  844. AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION
  845. );
  846. }
  847. /**
  848. * SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression
  849. *
  850. * @return \Doctrine\ORM\Query\AST\PathExpression
  851. */
  852. public function SingleValuedPathExpression()
  853. {
  854. return $this->PathExpression(
  855. AST\PathExpression::TYPE_STATE_FIELD |
  856. AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION
  857. );
  858. }
  859. /**
  860. * StateFieldPathExpression ::= IdentificationVariable "." StateField
  861. *
  862. * @return \Doctrine\ORM\Query\AST\PathExpression
  863. */
  864. public function StateFieldPathExpression()
  865. {
  866. return $this->PathExpression(AST\PathExpression::TYPE_STATE_FIELD);
  867. }
  868. /**
  869. * SingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField
  870. *
  871. * @return \Doctrine\ORM\Query\AST\PathExpression
  872. */
  873. public function SingleValuedAssociationPathExpression()
  874. {
  875. return $this->PathExpression(AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION);
  876. }
  877. /**
  878. * CollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField
  879. *
  880. * @return \Doctrine\ORM\Query\AST\PathExpression
  881. */
  882. public function CollectionValuedPathExpression()
  883. {
  884. return $this->PathExpression(AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION);
  885. }
  886. /**
  887. * SelectClause ::= "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression}
  888. *
  889. * @return \Doctrine\ORM\Query\AST\SelectClause
  890. */
  891. public function SelectClause()
  892. {
  893. $isDistinct = false;
  894. $this->match(Lexer::T_SELECT);
  895. // Check for DISTINCT
  896. if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) {
  897. $this->match(Lexer::T_DISTINCT);
  898. $isDistinct = true;
  899. }
  900. // Process SelectExpressions (1..N)
  901. $selectExpressions = array();
  902. $selectExpressions[] = $this->SelectExpression();
  903. while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
  904. $this->match(Lexer::T_COMMA);
  905. $selectExpressions[] = $this->SelectExpression();
  906. }
  907. return new AST\SelectClause($selectExpressions, $isDistinct);
  908. }
  909. /**
  910. * SimpleSelectClause ::= "SELECT" ["DISTINCT"] SimpleSelectExpression
  911. *
  912. * @return \Doctrine\ORM\Query\AST\SimpleSelectClause
  913. */
  914. public function SimpleSelectClause()
  915. {
  916. $isDistinct = false;
  917. $this->match(Lexer::T_SELECT);
  918. if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) {
  919. $this->match(Lexer::T_DISTINCT);
  920. $isDistinct = true;
  921. }
  922. return new AST\SimpleSelectClause($this->SimpleSelectExpression(), $isDistinct);
  923. }
  924. /**
  925. * UpdateClause ::= "UPDATE" AbstractSchemaName ["AS"] AliasIdentificationVariable "SET" UpdateItem {"," UpdateItem}*
  926. *
  927. * @return \Doctrine\ORM\Query\AST\UpdateClause
  928. */
  929. public function UpdateClause()
  930. {
  931. $this->match(Lexer::T_UPDATE);
  932. $token = $this->_lexer->lookahead;
  933. $abstractSchemaName = $this->AbstractSchemaName();
  934. if ($this->_lexer->isNextToken(Lexer::T_AS)) {
  935. $this->match(Lexer::T_AS);
  936. }
  937. $aliasIdentificationVariable = $this->AliasIdentificationVariable();
  938. $class = $this->_em->getClassMetadata($abstractSchemaName);
  939. // Building queryComponent
  940. $queryComponent = array(
  941. 'metadata' => $class,
  942. 'parent' => null,
  943. 'relation' => null,
  944. 'map' => null,
  945. 'nestingLevel' => $this->_nestingLevel,
  946. 'token' => $token,
  947. );
  948. $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent;
  949. $this->match(Lexer::T_SET);
  950. $updateItems = array();
  951. $updateItems[] = $this->UpdateItem();
  952. while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
  953. $this->match(Lexer::T_COMMA);
  954. $updateItems[] = $this->UpdateItem();
  955. }
  956. $updateClause = new AST\UpdateClause($abstractSchemaName, $updateItems);
  957. $updateClause->aliasIdentificationVariable = $aliasIdentificationVariable;
  958. return $updateClause;
  959. }
  960. /**
  961. * DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName ["AS"] AliasIdentificationVariable
  962. *
  963. * @return \Doctrine\ORM\Query\AST\DeleteClause
  964. */
  965. public function DeleteClause()
  966. {
  967. $this->match(Lexer::T_DELETE);
  968. if ($this->_lexer->isNextToken(Lexer::T_FROM)) {
  969. $this->match(Lexer::T_FROM);
  970. }
  971. $token = $this->_lexer->lookahead;
  972. $deleteClause = new AST\DeleteClause($this->AbstractSchemaName());
  973. if ($this->_lexer->isNextToken(Lexer::T_AS)) {
  974. $this->match(Lexer::T_AS);
  975. }
  976. $aliasIdentificationVariable = $this->AliasIdentificationVariable();
  977. $deleteClause->aliasIdentificationVariable = $aliasIdentificationVariable;
  978. $class = $this->_em->getClassMetadata($deleteClause->abstractSchemaName);
  979. // Building queryComponent
  980. $queryComponent = array(
  981. 'metadata' => $class,
  982. 'parent' => null,
  983. 'relation' => null,
  984. 'map' => null,
  985. 'nestingLevel' => $this->_nestingLevel,
  986. 'token' => $token,
  987. );
  988. $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent;
  989. return $deleteClause;
  990. }
  991. /**
  992. * FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}*
  993. *
  994. * @return \Doctrine\ORM\Query\AST\FromClause
  995. */
  996. public function FromClause()
  997. {
  998. $this->match(Lexer::T_FROM);
  999. $identificationVariableDeclarations = array();
  1000. $identificationVariableDeclarations[] = $this->IdentificationVariableDeclaration();
  1001. while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
  1002. $this->match(Lexer::T_COMMA);
  1003. $identificationVariableDeclarations[] = $this->IdentificationVariableDeclaration();
  1004. }
  1005. return new AST\FromClause($identificationVariableDeclarations);
  1006. }
  1007. /**
  1008. * SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}*
  1009. *
  1010. * @return \Doctrine\ORM\Query\AST\SubselectFromClause
  1011. */
  1012. public function SubselectFromClause()
  1013. {
  1014. $this->match(Lexer::T_FROM);
  1015. $identificationVariables = array();
  1016. $identificationVariables[] = $this->SubselectIdentificationVariableDeclaration();
  1017. while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
  1018. $this->match(Lexer::T_COMMA);
  1019. $identificationVariables[] = $this->SubselectIdentificationVariableDeclaration();
  1020. }
  1021. return new AST\SubselectFromClause($identificationVariables);
  1022. }
  1023. /**
  1024. * WhereClause ::= "WHERE" ConditionalExpression
  1025. *
  1026. * @return \Doctrine\ORM\Query\AST\WhereClause
  1027. */
  1028. public function WhereClause()
  1029. {
  1030. $this->match(Lexer::T_WHERE);
  1031. return new AST\WhereClause($this->ConditionalExpression());
  1032. }
  1033. /**
  1034. * HavingClause ::= "HAVING" ConditionalExpression
  1035. *
  1036. * @return \Doctrine\ORM\Query\AST\HavingClause
  1037. */
  1038. public function HavingClause()
  1039. {
  1040. $this->match(Lexer::T_HAVING);
  1041. return new AST\HavingClause($this->ConditionalExpression());
  1042. }
  1043. /**
  1044. * GroupByClause ::= "GROUP" "BY" GroupByItem {"," GroupByItem}*
  1045. *
  1046. * @return \Doctrine\ORM\Query\AST\GroupByClause
  1047. */
  1048. public function GroupByClause()
  1049. {
  1050. $this->match(Lexer::T_GROUP);
  1051. $this->match(Lexer::T_BY);
  1052. $groupByItems = array($this->GroupByItem());
  1053. while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
  1054. $this->match(Lexer::T_COMMA);
  1055. $groupByItems[] = $this->GroupByItem();
  1056. }
  1057. return new AST\GroupByClause($groupByItems);
  1058. }
  1059. /**
  1060. * OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}*
  1061. *
  1062. * @return \Doctrine\ORM\Query\AST\OrderByClause
  1063. */
  1064. public function OrderByClause()
  1065. {
  1066. $this->match(Lexer::T_ORDER);
  1067. $this->match(Lexer::T_BY);
  1068. $orderByItems = array();
  1069. $orderByItems[] = $this->OrderByItem();
  1070. while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
  1071. $this->match(Lexer::T_COMMA);
  1072. $orderByItems[] = $this->OrderByItem();
  1073. }
  1074. return new AST\OrderByClause($orderByItems);
  1075. }
  1076. /**
  1077. * Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
  1078. *
  1079. * @return \Doctrine\ORM\Query\AST\Subselect
  1080. */
  1081. public function Subselect()
  1082. {
  1083. // Increase query nesting level
  1084. $this->_nestingLevel++;
  1085. $subselect = new AST\Subselect($this->SimpleSelectClause(), $this->SubselectFromClause());
  1086. $subselect->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE)
  1087. ? $this->WhereClause() : null;
  1088. $subselect->groupByClause = $this->_lexer->isNextToken(Lexer::T_GROUP)
  1089. ? $this->GroupByClause() : null;
  1090. $subselect->havingClause = $this->_lexer->isNextToken(Lexer::T_HAVING)
  1091. ? $this->HavingClause() : null;
  1092. $subselect->orderByClause = $this->_lexer->isNextToken(Lexer::T_ORDER)
  1093. ? $this->OrderByClause() : null;
  1094. // Decrease query nesting level
  1095. $this->_nestingLevel--;
  1096. return $subselect;
  1097. }
  1098. /**
  1099. * UpdateItem ::= SingleValuedPathExpression "=" NewValue
  1100. *
  1101. * @return \Doctrine\ORM\Query\AST\UpdateItem
  1102. */
  1103. public function UpdateItem()
  1104. {
  1105. $pathExpr = $this->SingleValuedPathExpression();
  1106. $this->match(Lexer::T_EQUALS);
  1107. $updateItem = new AST\UpdateItem($pathExpr, $this->NewValue());
  1108. return $updateItem;
  1109. }
  1110. /**
  1111. * GroupByItem ::= IdentificationVariable | SingleValuedPathExpression
  1112. *
  1113. * @return string | \Doctrine\ORM\Query\AST\PathExpression
  1114. */
  1115. public function GroupByItem()
  1116. {
  1117. // We need to check if we are in a IdentificationVariable or SingleValuedPathExpression
  1118. $glimpse = $this->_lexer->glimpse();
  1119. if ($glimpse['type'] != Lexer::T_DOT) {
  1120. $token = $this->_lexer->lookahead;
  1121. $identVariable = $this->IdentificationVariable();
  1122. if (!isset($this->_queryComponents[$identVariable])) {
  1123. $this->semanticalError('Cannot group by undefined identification variable.');
  1124. }
  1125. return $identVariable;
  1126. }
  1127. return $this->SingleValuedPathExpression();
  1128. }
  1129. /**
  1130. * OrderByItem ::= (ResultVariable | StateFieldPathExpression) ["ASC" | "DESC"]
  1131. *
  1132. * @todo Post 2.0 release. Support general SingleValuedPathExpression instead
  1133. * of only StateFieldPathExpression.
  1134. *
  1135. * @return \Doctrine\ORM\Query\AST\OrderByItem
  1136. */
  1137. public function OrderByItem()
  1138. {
  1139. $type = 'ASC';
  1140. // We need to check if we are in a ResultVariable or StateFieldPathExpression
  1141. $glimpse = $this->_lexer->glimpse();
  1142. if ($glimpse['type'] != Lexer::T_DOT) {
  1143. $token = $this->_lexer->lookahead;
  1144. $expr = $this->ResultVariable();
  1145. } else {
  1146. $expr = $this->StateFieldPathExpression();
  1147. }
  1148. $item = new AST\OrderByItem($expr);
  1149. if ($this->_lexer->isNextToken(Lexer::T_ASC)) {
  1150. $this->match(Lexer::T_ASC);
  1151. } else if ($this->_lexer->isNextToken(Lexer::T_DESC)) {
  1152. $this->match(Lexer::T_DESC);
  1153. $type = 'DESC';
  1154. }
  1155. $item->type = $type;
  1156. return $item;
  1157. }
  1158. /**
  1159. * NewValue ::= SimpleArithmeticExpression | StringPrimary | DatetimePrimary | BooleanPrimary |
  1160. * EnumPrimary | SimpleEntityExpression | "NULL"
  1161. *
  1162. * NOTE: Since it is not possible to correctly recognize individual types, here is the full
  1163. * grammar that needs to be supported:
  1164. *
  1165. * NewValue ::= SimpleArithmeticExpression | "NULL"
  1166. *
  1167. * SimpleArithmeticExpression covers all *Primary grammar rules and also SimplEntityExpression
  1168. */
  1169. public function NewValue()
  1170. {
  1171. if ($this->_lexer->isNextToken(Lexer::T_NULL)) {
  1172. $this->match(Lexer::T_NULL);
  1173. return null;
  1174. } else if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
  1175. $this->match(Lexer::T_INPUT_PARAMETER);
  1176. return new AST\InputParameter($this->_lexer->token['value']);
  1177. }
  1178. return $this->SimpleArithmeticExpression();
  1179. }
  1180. /**
  1181. * IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}*
  1182. *
  1183. * @return \Doctrine\ORM\Query\AST\IdentificationVariableDeclaration
  1184. */
  1185. public function IdentificationVariableDeclaration()
  1186. {
  1187. $rangeVariableDeclaration = $this->RangeVariableDeclaration();
  1188. $indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) ? $this->IndexBy() : null;
  1189. $joinVariableDeclarations = array();
  1190. while (
  1191. $this->_lexer->isNextToken(Lexer::T_LEFT) ||
  1192. $this->_lexer->isNextToken(Lexer::T_INNER) ||
  1193. $this->_lexer->isNextToken(Lexer::T_JOIN)
  1194. ) {
  1195. $joinVariableDeclarations[] = $this->JoinVariableDeclaration();
  1196. }
  1197. return new AST\IdentificationVariableDeclaration(
  1198. $rangeVariableDeclaration, $indexBy, $joinVariableDeclarations
  1199. );
  1200. }
  1201. /**
  1202. * SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration | (AssociationPathExpression ["AS"] AliasIdentificationVariable)
  1203. *
  1204. * @return \Doctrine\ORM\Query\AST\SubselectIdentificationVariableDeclaration |
  1205. * \Doctrine\ORM\Query\AST\IdentificationVariableDeclaration
  1206. */
  1207. public function SubselectIdentificationVariableDeclaration()
  1208. {
  1209. $glimpse = $this->_lexer->glimpse();
  1210. /* NOT YET IMPLEMENTED!
  1211. if ($glimpse['type'] == Lexer::T_DOT) {
  1212. $subselectIdVarDecl = new AST\SubselectIdentificationVariableDeclaration();
  1213. $subselectIdVarDecl->associationPathExpression = $this->AssociationPathExpression();
  1214. $this->match(Lexer::T_AS);
  1215. $subselectIdVarDecl->aliasIdentificationVariable = $this->AliasIdentificationVariable();
  1216. return $subselectIdVarDecl;
  1217. }
  1218. */
  1219. return $this->IdentificationVariableDeclaration();
  1220. }
  1221. /**
  1222. * JoinVariableDeclaration ::= Join [IndexBy]
  1223. *
  1224. * @return \Doctrine\ORM\Query\AST\JoinVariableDeclaration
  1225. */
  1226. public function JoinVariableDeclaration()
  1227. {
  1228. $join = $this->Join();
  1229. $indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX)
  1230. ? $this->IndexBy() : null;
  1231. return new AST\JoinVariableDeclaration($join, $indexBy);
  1232. }
  1233. /**
  1234. * RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable
  1235. *
  1236. * @return \Doctrine\ORM\Query\AST\RangeVariableDeclaration
  1237. */
  1238. public function RangeVariableDeclaration()
  1239. {
  1240. $abstractSchemaName = $this->AbstractSchemaName();
  1241. if ($this->_lexer->isNextToken(Lexer::T_AS)) {
  1242. $this->match(Lexer::T_AS);
  1243. }
  1244. $token = $this->_lexer->lookahead;
  1245. $aliasIdentificationVariable = $this->AliasIdentificationVariable();
  1246. $classMetadata = $this->_em->getClassMetadata($abstractSchemaName);
  1247. // Building queryComponent
  1248. $queryComponent = array(
  1249. 'metadata' => $classMetadata,
  1250. 'parent' => null,
  1251. 'relation' => null,
  1252. 'map' => null,
  1253. 'nestingLevel' => $this->_nestingLevel,
  1254. 'token' => $token
  1255. );
  1256. $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent;
  1257. return new AST\RangeVariableDeclaration($abstractSchemaName, $aliasIdentificationVariable);
  1258. }
  1259. /**
  1260. * PartialObjectExpression ::= "PARTIAL" IdentificationVariable "." PartialFieldSet
  1261. * PartialFieldSet ::= "{" SimpleStateField {"," SimpleStateField}* "}"
  1262. *
  1263. * @return array
  1264. */
  1265. public function PartialObjectExpression()
  1266. {
  1267. $this->match(Lexer::T_PARTIAL);
  1268. $partialFieldSet = array();
  1269. $identificationVariable = $this->IdentificationVariable();
  1270. $this->match(Lexer::T_DOT);
  1271. $this->match(Lexer::T_OPEN_CURLY_BRACE);
  1272. $this->match(Lexer::T_IDENTIFIER);
  1273. $partialFieldSet[] = $this->_lexer->token['value'];
  1274. while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
  1275. $this->match(Lexer::T_COMMA);
  1276. $this->match(Lexer::T_IDENTIFIER);
  1277. $partialFieldSet[] = $this->_lexer->token['value'];
  1278. }
  1279. $this->match(Lexer::T_CLOSE_CURLY_BRACE);
  1280. $partialObjectExpression = new AST\PartialObjectExpression($identificationVariable, $partialFieldSet);
  1281. // Defer PartialObjectExpression validation
  1282. $this->_deferredPartialObjectExpressions[] = array(
  1283. 'expression' => $partialObjectExpression,
  1284. 'nestingLevel' => $this->_nestingLevel,
  1285. 'token' => $this->_lexer->token,
  1286. );
  1287. return $partialObjectExpression;
  1288. }
  1289. /**
  1290. * Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression
  1291. * ["AS"] AliasIdentificationVariable ["WITH" ConditionalExpression]
  1292. *
  1293. * @return \Doctrine\ORM\Query\AST\Join
  1294. */
  1295. public function Join()
  1296. {
  1297. // Check Join type
  1298. $joinType = AST\Join::JOIN_TYPE_INNER;
  1299. if ($this->_lexer->isNextToken(Lexer::T_LEFT)) {
  1300. $this->match(Lexer::T_LEFT);
  1301. // Possible LEFT OUTER join
  1302. if ($this->_lexer->isNextToken(Lexer::T_OUTER)) {
  1303. $this->match(Lexer::T_OUTER);
  1304. $joinType = AST\Join::JOIN_TYPE_LEFTOUTER;
  1305. } else {
  1306. $joinType = AST\Join::JOIN_TYPE_LEFT;
  1307. }
  1308. } else if ($this->_lexer->isNextToken(Lexer::T_INNER)) {
  1309. $this->match(Lexer::T_INNER);
  1310. }
  1311. $this->match(Lexer::T_JOIN);
  1312. $joinPathExpression = $this->JoinAssociationPathExpression();
  1313. if ($this->_lexer->isNextToken(Lexer::T_AS)) {
  1314. $this->match(Lexer::T_AS);
  1315. }
  1316. $token = $this->_lexer->lookahead;
  1317. $aliasIdentificationVariable = $this->AliasIdentificationVariable();
  1318. // Verify that the association exists.
  1319. $parentClass = $this->_queryComponents[$joinPathExpression->identificationVariable]['metadata'];
  1320. $assocField = $joinPathExpression->associationField;
  1321. if ( ! $parentClass->hasAssociation($assocField)) {
  1322. $this->semanticalError(
  1323. "Class " . $parentClass->name . " has no association named '$assocField'."
  1324. );
  1325. }
  1326. $targetClassName = $parentClass->associationMappings[$assocField]['targetEntity'];
  1327. // Building queryComponent
  1328. $joinQueryComponent = array(
  1329. 'metadata' => $this->_em->getClassMetadata($targetClassName),
  1330. 'parent' => $joinPathExpression->identificationVariable,
  1331. 'relation' => $parentClass->getAssociationMapping($assocField),
  1332. 'map' => null,
  1333. 'nestingLevel' => $this->_nestingLevel,
  1334. 'token' => $token
  1335. );
  1336. $this->_queryComponents[$aliasIdentificationVariable] = $joinQueryComponent;
  1337. // Create AST node
  1338. $join = new AST\Join($joinType, $joinPathExpression, $aliasIdentificationVariable);
  1339. // Check for ad-hoc Join conditions
  1340. if ($this->_lexer->isNextToken(Lexer::T_WITH)) {
  1341. $this->match(Lexer::T_WITH);
  1342. $join->conditionalExpression = $this->ConditionalExpression();
  1343. }
  1344. return $join;
  1345. }
  1346. /**
  1347. * IndexBy ::= "INDEX" "BY" StateFieldPathExpression
  1348. *
  1349. * @return \Doctrine\ORM\Query\AST\IndexBy
  1350. */
  1351. public function IndexBy()
  1352. {
  1353. $this->match(Lexer::T_INDEX);
  1354. $this->match(Lexer::T_BY);
  1355. $pathExpr = $this->StateFieldPathExpression();
  1356. // Add the INDEX BY info to the query component
  1357. $this->_queryComponents[$pathExpr->identificationVariable]['map'] = $pathExpr->field;
  1358. return new AST\IndexBy($pathExpr);
  1359. }
  1360. /**
  1361. * ScalarExpression ::= SimpleArithmeticExpression | StringPrimary | DateTimePrimary |
  1362. * StateFieldPathExpression | BooleanPrimary | CaseExpression |
  1363. * EntityTypeExpression
  1364. *
  1365. * @return mixed One of the possible expressions or subexpressions.
  1366. */
  1367. public function ScalarExpression()
  1368. {
  1369. $lookahead = $this->_lexer->lookahead['type'];
  1370. if ($lookahead === Lexer::T_IDENTIFIER) {
  1371. $this->_lexer->peek(); // lookahead => '.'
  1372. $this->_lexer->peek(); // lookahead => token after '.'
  1373. $peek = $this->_lexer->peek(); // lookahead => token after the token after the '.'
  1374. $this->_lexer->resetPeek();
  1375. if ($this->_isMathOperator($peek)) {
  1376. return $this->SimpleArithmeticExpression();
  1377. }
  1378. return $this->StateFieldPathExpression();
  1379. } else if ($lookahead == Lexer::T_INTEGER || $lookahead == Lexer::T_FLOAT) {
  1380. return $this->SimpleArithmeticExpression();
  1381. } else if ($lookahead == Lexer::T_CASE || $lookahead == Lexer::T_COALESCE || $lookahead == Lexer::T_NULLIF) {
  1382. // Since NULLIF and COALESCE can be identified as a function,
  1383. // we need to check if before check for FunctionDeclaration
  1384. return $this->CaseExpression();
  1385. } else if ($this->_isFunction() || $this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
  1386. // We may be in an ArithmeticExpression (find the matching ")" and inspect for Math operator)
  1387. $this->_lexer->peek(); // "("
  1388. $peek = $this->_peekBeyondClosingParenthesis();
  1389. if ($this->_isMathOperator($peek)) {
  1390. return $this->SimpleArithmeticExpression();
  1391. }
  1392. if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
  1393. return $this->AggregateExpression();
  1394. } else {
  1395. return $this->FunctionDeclaration();
  1396. }
  1397. } else if ($lookahead == Lexer::T_STRING) {
  1398. return $this->StringPrimary();
  1399. } else if ($lookahead == Lexer::T_INPUT_PARAMETER) {
  1400. return $this->InputParameter();
  1401. } else if ($lookahead == Lexer::T_TRUE || $lookahead == Lexer::T_FALSE) {
  1402. $this->match($lookahead);
  1403. return new AST\Literal(AST\Literal::BOOLEAN, $this->_lexer->token['value']);
  1404. } else {
  1405. $this->syntaxError();
  1406. }
  1407. }
  1408. public function CaseExpression()
  1409. {
  1410. $lookahead = $this->_lexer->lookahead['type'];
  1411. // if "CASE" "WHEN" => GeneralCaseExpression
  1412. // else if "CASE" => SimpleCaseExpression
  1413. // [DONE] else if "COALESCE" => CoalesceExpression
  1414. // [DONE] else if "NULLIF" => NullifExpression
  1415. switch ($lookahead) {
  1416. case Lexer::T_NULLIF:
  1417. return $this->NullIfExpression();
  1418. case Lexer::T_COALESCE:
  1419. return $this->CoalesceExpression();
  1420. default:
  1421. $this->semanticalError('CaseExpression not yet supported.');
  1422. return null;
  1423. }
  1424. }
  1425. /**
  1426. * CoalesceExpression ::= "COALESCE" "(" ScalarExpression {"," ScalarExpression}* ")"
  1427. *
  1428. * @return \Doctrine\ORM\Query\AST\CoalesceExpression
  1429. */
  1430. public function CoalesceExpression()
  1431. {
  1432. $this->match(Lexer::T_COALESCE);
  1433. $this->match(Lexer::T_OPEN_PARENTHESIS);
  1434. // Process ScalarExpressions (1..N)
  1435. $scalarExpressions = array();
  1436. $scalarExpressions[] = $this->ScalarExpression();
  1437. while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
  1438. $this->match(Lexer::T_COMMA);
  1439. $scalarExpressions[] = $this->ScalarExpression();
  1440. }
  1441. $this->match(Lexer::T_CLOSE_PARENTHESIS);
  1442. return new AST\CoalesceExpression($scalarExpressions);
  1443. }
  1444. /**
  1445. * NullIfExpression ::= "NULLIF" "(" ScalarExpression "," ScalarExpression ")"
  1446. *
  1447. * @return \Doctrine\ORM\Query\AST\ExistsExpression
  1448. */
  1449. public function NullIfExpression()
  1450. {
  1451. $this->match(Lexer::T_NULLIF);
  1452. $this->match(Lexer::T_OPEN_PARENTHESIS);
  1453. $firstExpression = $this->ScalarExpression();
  1454. $this->match(Lexer::T_COMMA);
  1455. $secondExpression = $this->ScalarExpression();
  1456. $this->match(Lexer::T_CLOSE_PARENTHESIS);
  1457. return new AST\NullIfExpression($firstExpression, $secondExpression);
  1458. }
  1459. /**
  1460. * SelectExpression ::=
  1461. * IdentificationVariable | StateFieldPathExpression |
  1462. * (AggregateExpression | "(" Subselect ")" | ScalarExpression) [["AS"] AliasResultVariable]
  1463. *
  1464. * @return \Doctrine\ORM\Query\AST\SelectExpression
  1465. */
  1466. public function SelectExpression()
  1467. {
  1468. $expression = null;
  1469. $identVariable = null;
  1470. $fieldAliasIdentificationVariable = null;
  1471. $peek = $this->_lexer->glimpse();
  1472. $supportsAlias = true;
  1473. if ($peek['value'] != '(' && $this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) {
  1474. if ($peek['value'] == '.') {
  1475. // ScalarExpression
  1476. $expression = $this->ScalarExpression();
  1477. } else {
  1478. $supportsAlias = false;
  1479. $expression = $identVariable = $this->IdentificationVariable();
  1480. }
  1481. } else if ($this->_lexer->lookahead['value'] == '(') {
  1482. if ($peek['type'] == Lexer::T_SELECT) {
  1483. // Subselect
  1484. $this->match(Lexer::T_OPEN_PARENTHESIS);
  1485. $expression = $this->Subselect();
  1486. $this->match(Lexer::T_CLOSE_PARENTHESIS);
  1487. } else {
  1488. // Shortcut: ScalarExpression => SimpleArithmeticExpression
  1489. $expression = $this->SimpleArithmeticExpression();
  1490. }
  1491. } else if ($this->_isFunction()) {
  1492. $this->_lexer->peek(); // "("
  1493. $lookaheadType = $this->_lexer->lookahead['type'];
  1494. $beyond = $this->_peekBeyondClosingParenthesis();
  1495. if ($this->_isMathOperator($beyond)) {
  1496. $expression = $this->ScalarExpression();
  1497. } else if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
  1498. $expression = $this->AggregateExpression();
  1499. } else if (in_array ($lookaheadType, array(Lexer::T_CASE, Lexer::T_COALESCE, Lexer::T_NULLIF))) {
  1500. $expression = $this->CaseExpression();
  1501. } else {
  1502. // Shortcut: ScalarExpression => Function
  1503. $expression = $this->FunctionDeclaration();
  1504. }
  1505. } else if ($this->_lexer->lookahead['type'] == Lexer::T_PARTIAL) {
  1506. $supportsAlias = false;
  1507. $expression = $this->PartialObjectExpression();
  1508. $identVariable = $expression->identificationVariable;
  1509. } else if ($this->_lexer->lookahead['type'] == Lexer::T_INTEGER ||
  1510. $this->_lexer->lookahead['type'] == Lexer::T_FLOAT ||
  1511. $this->_lexer->lookahead['type'] == Lexer::T_STRING) {
  1512. // Shortcut: ScalarExpression => SimpleArithmeticExpression
  1513. $expression = $this->SimpleArithmeticExpression();
  1514. } else {
  1515. $this->syntaxError('IdentificationVariable | StateFieldPathExpression'
  1516. . ' | AggregateExpression | "(" Subselect ")" | ScalarExpression',
  1517. $this->_lexer->lookahead);
  1518. }
  1519. if ($supportsAlias) {
  1520. if ($this->_lexer->isNextToken(Lexer::T_AS)) {
  1521. $this->match(Lexer::T_AS);
  1522. }
  1523. if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
  1524. $token = $this->_lexer->lookahead;
  1525. $fieldAliasIdentificationVariable = $this->AliasResultVariable();
  1526. // Include AliasResultVariable in query components.
  1527. $this->_queryComponents[$fieldAliasIdentificationVariable] = array(
  1528. 'resultVariable' => $expression,
  1529. 'nestingLevel' => $this->_nestingLevel,
  1530. 'token' => $token,
  1531. );
  1532. }
  1533. }
  1534. $expr = new AST\SelectExpression($expression, $fieldAliasIdentificationVariable);
  1535. if (!$supportsAlias) {
  1536. $this->_identVariableExpressions[$identVariable] = $expr;
  1537. }
  1538. return $expr;
  1539. }
  1540. /**
  1541. * SimpleSelectExpression ::=
  1542. * StateFieldPathExpression | IdentificationVariable |
  1543. * ((AggregateExpression | "(" Subselect ")" | ScalarExpression) [["AS"] AliasResultVariable])
  1544. *
  1545. * @return \Doctrine\ORM\Query\AST\SimpleSelectExpression
  1546. */
  1547. public function SimpleSelectExpression()
  1548. {
  1549. $peek = $this->_lexer->glimpse();
  1550. if ($peek['value'] != '(' && $this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) {
  1551. // SingleValuedPathExpression | IdentificationVariable
  1552. if ($peek['value'] == '.') {
  1553. $expression = $this->StateFieldPathExpression();
  1554. } else {
  1555. $expression = $this->IdentificationVariable();
  1556. }
  1557. return new AST\SimpleSelectExpression($expression);
  1558. } else if ($this->_lexer->lookahead['value'] == '(') {
  1559. if ($peek['type'] == Lexer::T_SELECT) {
  1560. // Subselect
  1561. $this->match(Lexer::T_OPEN_PARENTHESIS);
  1562. $expression = $this->Subselect();
  1563. $this->match(Lexer::T_CLOSE_PARENTHESIS);
  1564. } else {
  1565. // Shortcut: ScalarExpression => SimpleArithmeticExpression
  1566. $expression = $this->SimpleArithmeticExpression();
  1567. }
  1568. return new AST\SimpleSelectExpression($expression);
  1569. }
  1570. $this->_lexer->peek();
  1571. $expression = $this->ScalarExpression();
  1572. $expr = new AST\SimpleSelectExpression($expression);
  1573. if ($this->_lexer->isNextToken(Lexer::T_AS)) {
  1574. $this->match(Lexer::T_AS);
  1575. }
  1576. if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
  1577. $token = $this->_lexer->lookahead;
  1578. $resultVariable = $this->AliasResultVariable();
  1579. $expr->fieldIdentificationVariable = $resultVariable;
  1580. // Include AliasResultVariable in query components.
  1581. $this->_queryComponents[$resultVariable] = array(
  1582. 'resultvariable' => $expr,
  1583. 'nestingLevel' => $this->_nestingLevel,
  1584. 'token' => $token,
  1585. );
  1586. }
  1587. return $expr;
  1588. }
  1589. /**
  1590. * ConditionalExpression ::= ConditionalTerm {"OR" ConditionalTerm}*
  1591. *
  1592. * @return \Doctrine\ORM\Query\AST\ConditionalExpression
  1593. */
  1594. public function ConditionalExpression()
  1595. {
  1596. $conditionalTerms = array();
  1597. $conditionalTerms[] = $this->ConditionalTerm();
  1598. while ($this->_lexer->isNextToken(Lexer::T_OR)) {
  1599. $this->match(Lexer::T_OR);
  1600. $conditionalTerms[] = $this->ConditionalTerm();
  1601. }
  1602. // Phase 1 AST optimization: Prevent AST\ConditionalExpression
  1603. // if only one AST\ConditionalTerm is defined
  1604. if (count($conditionalTerms) == 1) {
  1605. return $conditionalTerms[0];
  1606. }
  1607. return new AST\ConditionalExpression($conditionalTerms);
  1608. }
  1609. /**
  1610. * ConditionalTerm ::= ConditionalFactor {"AND" ConditionalFactor}*
  1611. *
  1612. * @return \Doctrine\ORM\Query\AST\ConditionalTerm
  1613. */
  1614. public function ConditionalTerm()
  1615. {
  1616. $conditionalFactors = array();
  1617. $conditionalFactors[] = $this->ConditionalFactor();
  1618. while ($this->_lexer->isNextToken(Lexer::T_AND)) {
  1619. $this->match(Lexer::T_AND);
  1620. $conditionalFactors[] = $this->ConditionalFactor();
  1621. }
  1622. // Phase 1 AST optimization: Prevent AST\ConditionalTerm
  1623. // if only one AST\ConditionalFactor is defined
  1624. if (count($conditionalFactors) == 1) {
  1625. return $conditionalFactors[0];
  1626. }
  1627. return new AST\ConditionalTerm($conditionalFactors);
  1628. }
  1629. /**
  1630. * ConditionalFactor ::= ["NOT"] ConditionalPrimary
  1631. *
  1632. * @return \Doctrine\ORM\Query\AST\ConditionalFactor
  1633. */
  1634. public function ConditionalFactor()
  1635. {
  1636. $not = false;
  1637. if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
  1638. $this->match(Lexer::T_NOT);
  1639. $not = true;
  1640. }
  1641. $conditionalPrimary = $this->ConditionalPrimary();
  1642. // Phase 1 AST optimization: Prevent AST\ConditionalFactor
  1643. // if only one AST\ConditionalPrimary is defined
  1644. if ( ! $not) {
  1645. return $conditionalPrimary;
  1646. }
  1647. $conditionalFactor = new AST\ConditionalFactor($conditionalPrimary);
  1648. $conditionalFactor->not = $not;
  1649. return $conditionalFactor;
  1650. }
  1651. /**
  1652. * ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")"
  1653. *
  1654. * @return \Doctrine\ORM\Query\AST\ConditionalPrimary
  1655. */
  1656. public function ConditionalPrimary()
  1657. {
  1658. $condPrimary = new AST\ConditionalPrimary;
  1659. if ($this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
  1660. // Peek beyond the matching closing paranthesis ')'
  1661. $peek = $this->_peekBeyondClosingParenthesis();
  1662. if (in_array($peek['value'], array("=", "<", "<=", "<>", ">", ">=", "!=")) ||
  1663. $peek['type'] === Lexer::T_NOT ||
  1664. $peek['type'] === Lexer::T_BETWEEN ||
  1665. $peek['type'] === Lexer::T_LIKE ||
  1666. $peek['type'] === Lexer::T_IN ||
  1667. $peek['type'] === Lexer::T_IS ||
  1668. $peek['type'] === Lexer::T_EXISTS) {
  1669. $condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression();
  1670. } else {
  1671. $this->match(Lexer::T_OPEN_PARENTHESIS);
  1672. $condPrimary->conditionalExpression = $this->ConditionalExpression();
  1673. $this->match(Lexer::T_CLOSE_PARENTHESIS);
  1674. }
  1675. } else {
  1676. $condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression();
  1677. }
  1678. return $condPrimary;
  1679. }
  1680. /**
  1681. * SimpleConditionalExpression ::=
  1682. * ComparisonExpression | BetweenExpression | LikeExpression |
  1683. * InExpression | NullComparisonExpression | ExistsExpression |
  1684. * EmptyCollectionComparisonExpression | CollectionMemberExpression |
  1685. * InstanceOfExpression
  1686. */
  1687. public function SimpleConditionalExpression()
  1688. {
  1689. if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
  1690. $token = $this->_lexer->glimpse();
  1691. } else {
  1692. $token = $this->_lexer->lookahead;
  1693. }
  1694. if ($token['type'] === Lexer::T_EXISTS) {
  1695. return $this->ExistsExpression();
  1696. }
  1697. $peek = $this->_lexer->glimpse();
  1698. if ($token['type'] === Lexer::T_IDENTIFIER || $token['type'] === Lexer::T_INPUT_PARAMETER) {
  1699. if ($peek['value'] == '(') {
  1700. // Peek beyond the matching closing paranthesis ')'
  1701. $this->_lexer->peek();
  1702. $token = $this->_peekBeyondClosingParenthesis();
  1703. } else {
  1704. // Peek beyond the PathExpression (or InputParameter)
  1705. $peek = $this->_lexer->peek();
  1706. while ($peek['value'] === '.') {
  1707. $this->_lexer->peek();
  1708. $peek = $this->_lexer->peek();
  1709. }
  1710. // Also peek beyond a NOT if there is one
  1711. if ($peek['type'] === Lexer::T_NOT) {
  1712. $peek = $this->_lexer->peek();
  1713. }
  1714. $token = $peek;
  1715. // We need to go even further in case of IS (differenciate between NULL and EMPTY)
  1716. $lookahead = $this->_lexer->peek();
  1717. // Also peek beyond a NOT if there is one
  1718. if ($lookahead['type'] === Lexer::T_NOT) {
  1719. $lookahead = $this->_lexer->peek();
  1720. }
  1721. $this->_lexer->resetPeek();
  1722. }
  1723. }
  1724. switch ($token['type']) {
  1725. case Lexer::T_BETWEEN:
  1726. return $this->BetweenExpression();
  1727. case Lexer::T_LIKE:
  1728. return $this->LikeExpression();
  1729. case Lexer::T_IN:
  1730. return $this->InExpression();
  1731. case Lexer::T_INSTANCE:
  1732. return $this->InstanceOfExpression();
  1733. case Lexer::T_IS:
  1734. if ($lookahead['type'] == Lexer::T_NULL) {
  1735. return $this->NullComparisonExpression();
  1736. }
  1737. return $this->EmptyCollectionComparisonExpression();
  1738. case Lexer::T_MEMBER:
  1739. return $this->CollectionMemberExpression();
  1740. default:
  1741. return $this->ComparisonExpression();
  1742. }
  1743. }
  1744. /**
  1745. * EmptyCollectionComparisonExpression ::= CollectionValuedPathExpression "IS" ["NOT"] "EMPTY"
  1746. *
  1747. * @return \Doctrine\ORM\Query\AST\EmptyCollectionComparisonExpression
  1748. */
  1749. public function EmptyCollectionComparisonExpression()
  1750. {
  1751. $emptyColletionCompExpr = new AST\EmptyCollectionComparisonExpression(
  1752. $this->CollectionValuedPathExpression()
  1753. );
  1754. $this->match(Lexer::T_IS);
  1755. if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
  1756. $this->match(Lexer::T_NOT);
  1757. $emptyColletionCompExpr->not = true;
  1758. }
  1759. $this->match(Lexer::T_EMPTY);
  1760. return $emptyColletionCompExpr;
  1761. }
  1762. /**
  1763. * CollectionMemberExpression ::= EntityExpression ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpression
  1764. *
  1765. * EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression
  1766. * SimpleEntityExpression ::= IdentificationVariable | InputParameter
  1767. *
  1768. * @return \Doctrine\ORM\Query\AST\CollectionMemberExpression
  1769. */
  1770. public function CollectionMemberExpression()
  1771. {
  1772. $not = false;
  1773. $entityExpr = $this->EntityExpression();
  1774. if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
  1775. $not = true;
  1776. $this->match(Lexer::T_NOT);
  1777. }
  1778. $this->match(Lexer::T_MEMBER);
  1779. if ($this->_lexer->isNextToken(Lexer::T_OF)) {
  1780. $this->match(Lexer::T_OF);
  1781. }
  1782. $collMemberExpr = new AST\CollectionMemberExpression(
  1783. $entityExpr, $this->CollectionValuedPathExpression()
  1784. );
  1785. $collMemberExpr->not = $not;
  1786. return $collMemberExpr;
  1787. }
  1788. /**
  1789. * Literal ::= string | char | integer | float | boolean
  1790. *
  1791. * @return string
  1792. */
  1793. public function Literal()
  1794. {
  1795. switch ($this->_lexer->lookahead['type']) {
  1796. case Lexer::T_STRING:
  1797. $this->match(Lexer::T_STRING);
  1798. return new AST\Literal(AST\Literal::STRING, $this->_lexer->token['value']);
  1799. case Lexer::T_INTEGER:
  1800. case Lexer::T_FLOAT:
  1801. $this->match(
  1802. $this->_lexer->isNextToken(Lexer::T_INTEGER) ? Lexer::T_INTEGER : Lexer::T_FLOAT
  1803. );
  1804. return new AST\Literal(AST\Literal::NUMERIC, $this->_lexer->token['value']);
  1805. case Lexer::T_TRUE:
  1806. case Lexer::T_FALSE:
  1807. $this->match(
  1808. $this->_lexer->isNextToken(Lexer::T_TRUE) ? Lexer::T_TRUE : Lexer::T_FALSE
  1809. );
  1810. return new AST\Literal(AST\Literal::BOOLEAN, $this->_lexer->token['value']);
  1811. default:
  1812. $this->syntaxError('Literal');
  1813. }
  1814. }
  1815. /**
  1816. * InParameter ::= Literal | InputParameter
  1817. *
  1818. * @return string | \Doctrine\ORM\Query\AST\InputParameter
  1819. */
  1820. public function InParameter()
  1821. {
  1822. if ($this->_lexer->lookahead['type'] == Lexer::T_INPUT_PARAMETER) {
  1823. return $this->InputParameter();
  1824. }
  1825. return $this->Literal();
  1826. }
  1827. /**
  1828. * InputParameter ::= PositionalParameter | NamedParameter
  1829. *
  1830. * @return \Doctrine\ORM\Query\AST\InputParameter
  1831. */
  1832. public function InputParameter()
  1833. {
  1834. $this->match(Lexer::T_INPUT_PARAMETER);
  1835. return new AST\InputParameter($this->_lexer->token['value']);
  1836. }
  1837. /**
  1838. * ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")"
  1839. *
  1840. * @return \Doctrine\ORM\Query\AST\ArithmeticExpression
  1841. */
  1842. public function ArithmeticExpression()
  1843. {
  1844. $expr = new AST\ArithmeticExpression;
  1845. if ($this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
  1846. $peek = $this->_lexer->glimpse();
  1847. if ($peek['type'] === Lexer::T_SELECT) {
  1848. $this->match(Lexer::T_OPEN_PARENTHESIS);
  1849. $expr->subselect = $this->Subselect();
  1850. $this->match(Lexer::T_CLOSE_PARENTHESIS);
  1851. return $expr;
  1852. }
  1853. }
  1854. $expr->simpleArithmeticExpression = $this->SimpleArithmeticExpression();
  1855. return $expr;
  1856. }
  1857. /**
  1858. * SimpleArithmeticExpression ::= ArithmeticTerm {("+" | "-") ArithmeticTerm}*
  1859. *
  1860. * @return \Doctrine\ORM\Query\AST\SimpleArithmeticExpression
  1861. */
  1862. public function SimpleArithmeticExpression()
  1863. {
  1864. $terms = array();
  1865. $terms[] = $this->ArithmeticTerm();
  1866. while (($isPlus = $this->_lexer->isNextToken(Lexer::T_PLUS)) || $this->_lexer->isNextToken(Lexer::T_MINUS)) {
  1867. $this->match(($isPlus) ? Lexer::T_PLUS : Lexer::T_MINUS);
  1868. $terms[] = $this->_lexer->token['value'];
  1869. $terms[] = $this->ArithmeticTerm();
  1870. }
  1871. // Phase 1 AST optimization: Prevent AST\SimpleArithmeticExpression
  1872. // if only one AST\ArithmeticTerm is defined
  1873. if (count($terms) == 1) {
  1874. return $terms[0];
  1875. }
  1876. return new AST\SimpleArithmeticExpression($terms);
  1877. }
  1878. /**
  1879. * ArithmeticTerm ::= ArithmeticFactor {("*" | "/") ArithmeticFactor}*
  1880. *
  1881. * @return \Doctrine\ORM\Query\AST\ArithmeticTerm
  1882. */
  1883. public function ArithmeticTerm()
  1884. {
  1885. $factors = array();
  1886. $factors[] = $this->ArithmeticFactor();
  1887. while (($isMult = $this->_lexer->isNextToken(Lexer::T_MULTIPLY)) || $this->_lexer->isNextToken(Lexer::T_DIVIDE)) {
  1888. $this->match(($isMult) ? Lexer::T_MULTIPLY : Lexer::T_DIVIDE);
  1889. $factors[] = $this->_lexer->token['value'];
  1890. $factors[] = $this->ArithmeticFactor();
  1891. }
  1892. // Phase 1 AST optimization: Prevent AST\ArithmeticTerm
  1893. // if only one AST\ArithmeticFactor is defined
  1894. if (count($factors) == 1) {
  1895. return $factors[0];
  1896. }
  1897. return new AST\ArithmeticTerm($factors);
  1898. }
  1899. /**
  1900. * ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary
  1901. *
  1902. * @return \Doctrine\ORM\Query\AST\ArithmeticFactor
  1903. */
  1904. public function ArithmeticFactor()
  1905. {
  1906. $sign = null;
  1907. if (($isPlus = $this->_lexer->isNextToken(Lexer::T_PLUS)) || $this->_lexer->isNextToken(Lexer::T_MINUS)) {
  1908. $this->match(($isPlus) ? Lexer::T_PLUS : Lexer::T_MINUS);
  1909. $sign = $isPlus;
  1910. }
  1911. $primary = $this->ArithmeticPrimary();
  1912. // Phase 1 AST optimization: Prevent AST\ArithmeticFactor
  1913. // if only one AST\ArithmeticPrimary is defined
  1914. if ($sign === null) {
  1915. return $primary;
  1916. }
  1917. return new AST\ArithmeticFactor($primary, $sign);
  1918. }
  1919. /**
  1920. * ArithmeticPrimary ::= SingleValuedPathExpression | Literal | "(" SimpleArithmeticExpression ")"
  1921. * | FunctionsReturningNumerics | AggregateExpression | FunctionsReturningStrings
  1922. * | FunctionsReturningDatetime | IdentificationVariable | ResultVariable
  1923. */
  1924. public function ArithmeticPrimary()
  1925. {
  1926. if ($this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
  1927. $this->match(Lexer::T_OPEN_PARENTHESIS);
  1928. $expr = $this->SimpleArithmeticExpression();
  1929. $this->match(Lexer::T_CLOSE_PARENTHESIS);
  1930. return $expr;
  1931. }
  1932. switch ($this->_lexer->lookahead['type']) {
  1933. case Lexer::T_IDENTIFIER:
  1934. $peek = $this->_lexer->glimpse();
  1935. if ($peek['value'] == '(') {
  1936. return $this->FunctionDeclaration();
  1937. }
  1938. if ($peek['value'] == '.') {
  1939. return $this->SingleValuedPathExpression();
  1940. }
  1941. if (isset($this->_queryComponents[$this->_lexer->lookahead['value']]['resultVariable'])) {
  1942. return $this->ResultVariable();
  1943. }
  1944. return $this->StateFieldPathExpression();
  1945. case Lexer::T_INPUT_PARAMETER:
  1946. return $this->InputParameter();
  1947. default:
  1948. $peek = $this->_lexer->glimpse();
  1949. if ($peek['value'] == '(') {
  1950. if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
  1951. return $this->AggregateExpression();
  1952. }
  1953. return $this->FunctionDeclaration();
  1954. } else {
  1955. return $this->Literal();
  1956. }
  1957. }
  1958. }
  1959. /**
  1960. * StringExpression ::= StringPrimary | "(" Subselect ")"
  1961. *
  1962. * @return \Doctrine\ORM\Query\AST\StringPrimary |
  1963. * \Doctrine]ORM\Query\AST\Subselect
  1964. */
  1965. public function StringExpression()
  1966. {
  1967. if ($this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
  1968. $peek = $this->_lexer->glimpse();
  1969. if ($peek['type'] === Lexer::T_SELECT) {
  1970. $this->match(Lexer::T_OPEN_PARENTHESIS);
  1971. $expr = $this->Subselect();
  1972. $this->match(Lexer::T_CLOSE_PARENTHESIS);
  1973. return $expr;
  1974. }
  1975. }
  1976. return $this->StringPrimary();
  1977. }
  1978. /**
  1979. * StringPrimary ::= StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression
  1980. */
  1981. public function StringPrimary()
  1982. {
  1983. if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
  1984. $peek = $this->_lexer->glimpse();
  1985. if ($peek['value'] == '.') {
  1986. return $this->StateFieldPathExpression();
  1987. } else if ($peek['value'] == '(') {
  1988. // do NOT directly go to FunctionsReturningString() because it doesnt check for custom functions.
  1989. return $this->FunctionDeclaration();
  1990. } else {
  1991. $this->syntaxError("'.' or '('");
  1992. }
  1993. } else if ($this->_lexer->isNextToken(Lexer::T_STRING)) {
  1994. $this->match(Lexer::T_STRING);
  1995. return $this->_lexer->token['value'];
  1996. } else if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
  1997. return $this->InputParameter();
  1998. } else if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
  1999. return $this->AggregateExpression();
  2000. }
  2001. $this->syntaxError('StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression');
  2002. }
  2003. /**
  2004. * EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression
  2005. *
  2006. * @return \Doctrine\ORM\Query\AST\SingleValuedAssociationPathExpression |
  2007. * \Doctrine\ORM\Query\AST\SimpleEntityExpression
  2008. */
  2009. public function EntityExpression()
  2010. {
  2011. $glimpse = $this->_lexer->glimpse();
  2012. if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER) && $glimpse['value'] === '.') {
  2013. return $this->SingleValuedAssociationPathExpression();
  2014. }
  2015. return $this->SimpleEntityExpression();
  2016. }
  2017. /**
  2018. * SimpleEntityExpression ::= IdentificationVariable | InputParameter
  2019. *
  2020. * @return string | \Doctrine\ORM\Query\AST\InputParameter
  2021. */
  2022. public function SimpleEntityExpression()
  2023. {
  2024. if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
  2025. return $this->InputParameter();
  2026. }
  2027. return $this->IdentificationVariable();
  2028. }
  2029. /**
  2030. * AggregateExpression ::=
  2031. * ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" |
  2032. * "COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedPathExpression) ")"
  2033. *
  2034. * @return \Doctrine\ORM\Query\AST\AggregateExpression
  2035. */
  2036. public function AggregateExpression()
  2037. {
  2038. $isDistinct = false;
  2039. $functionName = '';
  2040. if ($this->_lexer->isNextToken(Lexer::T_COUNT)) {
  2041. $this->match(Lexer::T_COUNT);
  2042. $functionName = $this->_lexer->token['value'];
  2043. $this->match(Lexer::T_OPEN_PARENTHESIS);
  2044. if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) {
  2045. $this->match(Lexer::T_DISTINCT);
  2046. $isDistinct = true;
  2047. }
  2048. $pathExp = $this->SingleValuedPathExpression();
  2049. $this->match(Lexer::T_CLOSE_PARENTHESIS);
  2050. } else {
  2051. if ($this->_lexer->isNextToken(Lexer::T_AVG)) {
  2052. $this->match(Lexer::T_AVG);
  2053. } else if ($this->_lexer->isNextToken(Lexer::T_MAX)) {
  2054. $this->match(Lexer::T_MAX);
  2055. } else if ($this->_lexer->isNextToken(Lexer::T_MIN)) {
  2056. $this->match(Lexer::T_MIN);
  2057. } else if ($this->_lexer->isNextToken(Lexer::T_SUM)) {
  2058. $this->match(Lexer::T_SUM);
  2059. } else {
  2060. $this->syntaxError('One of: MAX, MIN, AVG, SUM, COUNT');
  2061. }
  2062. $functionName = $this->_lexer->token['value'];
  2063. $this->match(Lexer::T_OPEN_PARENTHESIS);
  2064. $pathExp = $this->SimpleArithmeticExpression();
  2065. $this->match(Lexer::T_CLOSE_PARENTHESIS);
  2066. }
  2067. return new AST\AggregateExpression($functionName, $pathExp, $isDistinct);
  2068. }
  2069. /**
  2070. * QuantifiedExpression ::= ("ALL" | "ANY" | "SOME") "(" Subselect ")"
  2071. *
  2072. * @return \Doctrine\ORM\Query\AST\QuantifiedExpression
  2073. */
  2074. public function QuantifiedExpression()
  2075. {
  2076. $type = '';
  2077. if ($this->_lexer->isNextToken(Lexer::T_ALL)) {
  2078. $this->match(Lexer::T_ALL);
  2079. $type = 'ALL';
  2080. } else if ($this->_lexer->isNextToken(Lexer::T_ANY)) {
  2081. $this->match(Lexer::T_ANY);
  2082. $type = 'ANY';
  2083. } else if ($this->_lexer->isNextToken(Lexer::T_SOME)) {
  2084. $this->match(Lexer::T_SOME);
  2085. $type = 'SOME';
  2086. } else {
  2087. $this->syntaxError('ALL, ANY or SOME');
  2088. }
  2089. $this->match(Lexer::T_OPEN_PARENTHESIS);
  2090. $qExpr = new AST\QuantifiedExpression($this->Subselect());
  2091. $qExpr->type = $type;
  2092. $this->match(Lexer::T_CLOSE_PARENTHESIS);
  2093. return $qExpr;
  2094. }
  2095. /**
  2096. * BetweenExpression ::= ArithmeticExpression ["NOT"] "BETWEEN" ArithmeticExpression "AND" ArithmeticExpression
  2097. *
  2098. * @return \Doctrine\ORM\Query\AST\BetweenExpression
  2099. */
  2100. public function BetweenExpression()
  2101. {
  2102. $not = false;
  2103. $arithExpr1 = $this->ArithmeticExpression();
  2104. if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
  2105. $this->match(Lexer::T_NOT);
  2106. $not = true;
  2107. }
  2108. $this->match(Lexer::T_BETWEEN);
  2109. $arithExpr2 = $this->ArithmeticExpression();
  2110. $this->match(Lexer::T_AND);
  2111. $arithExpr3 = $this->ArithmeticExpression();
  2112. $betweenExpr = new AST\BetweenExpression($arithExpr1, $arithExpr2, $arithExpr3);
  2113. $betweenExpr->not = $not;
  2114. return $betweenExpr;
  2115. }
  2116. /**
  2117. * ComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression )
  2118. *
  2119. * @return \Doctrine\ORM\Query\AST\ComparisonExpression
  2120. */
  2121. public function ComparisonExpression()
  2122. {
  2123. $peek = $this->_lexer->glimpse();
  2124. $leftExpr = $this->ArithmeticExpression();
  2125. $operator = $this->ComparisonOperator();
  2126. if ($this->_isNextAllAnySome()) {
  2127. $rightExpr = $this->QuantifiedExpression();
  2128. } else {
  2129. $rightExpr = $this->ArithmeticExpression();
  2130. }
  2131. return new AST\ComparisonExpression($leftExpr, $operator, $rightExpr);
  2132. }
  2133. /**
  2134. * InExpression ::= SingleValuedPathExpression ["NOT"] "IN" "(" (InParameter {"," InParameter}* | Subselect) ")"
  2135. *
  2136. * @return \Doctrine\ORM\Query\AST\InExpression
  2137. */
  2138. public function InExpression()
  2139. {
  2140. $inExpression = new AST\InExpression($this->SingleValuedPathExpression());
  2141. if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
  2142. $this->match(Lexer::T_NOT);
  2143. $inExpression->not = true;
  2144. }
  2145. $this->match(Lexer::T_IN);
  2146. $this->match(Lexer::T_OPEN_PARENTHESIS);
  2147. if ($this->_lexer->isNextToken(Lexer::T_SELECT)) {
  2148. $inExpression->subselect = $this->Subselect();
  2149. } else {
  2150. $literals = array();
  2151. $literals[] = $this->InParameter();
  2152. while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
  2153. $this->match(Lexer::T_COMMA);
  2154. $literals[] = $this->InParameter();
  2155. }
  2156. $inExpression->literals = $literals;
  2157. }
  2158. $this->match(Lexer::T_CLOSE_PARENTHESIS);
  2159. return $inExpression;
  2160. }
  2161. /**
  2162. * InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (AbstractSchemaName | InputParameter)
  2163. *
  2164. * @return \Doctrine\ORM\Query\AST\InstanceOfExpression
  2165. */
  2166. public function InstanceOfExpression()
  2167. {
  2168. $instanceOfExpression = new AST\InstanceOfExpression($this->IdentificationVariable());
  2169. if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
  2170. $this->match(Lexer::T_NOT);
  2171. $instanceOfExpression->not = true;
  2172. }
  2173. $this->match(Lexer::T_INSTANCE);
  2174. if ($this->_lexer->isNextToken(Lexer::T_OF)) {
  2175. $this->match(Lexer::T_OF);
  2176. }
  2177. if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
  2178. $this->match(Lexer::T_INPUT_PARAMETER);
  2179. $exprValue = new AST\InputParameter($this->_lexer->token['value']);
  2180. } else {
  2181. $exprValue = $this->AliasIdentificationVariable();
  2182. }
  2183. $instanceOfExpression->value = $exprValue;
  2184. return $instanceOfExpression;
  2185. }
  2186. /**
  2187. * LikeExpression ::= StringExpression ["NOT"] "LIKE" (string | input_parameter) ["ESCAPE" char]
  2188. *
  2189. * @return \Doctrine\ORM\Query\AST\LikeExpression
  2190. */
  2191. public function LikeExpression()
  2192. {
  2193. $stringExpr = $this->StringExpression();
  2194. $not = false;
  2195. if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
  2196. $this->match(Lexer::T_NOT);
  2197. $not = true;
  2198. }
  2199. $this->match(Lexer::T_LIKE);
  2200. if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
  2201. $this->match(Lexer::T_INPUT_PARAMETER);
  2202. $stringPattern = new AST\InputParameter($this->_lexer->token['value']);
  2203. } else {
  2204. $this->match(Lexer::T_STRING);
  2205. $stringPattern = $this->_lexer->token['value'];
  2206. }
  2207. $escapeChar = null;
  2208. if ($this->_lexer->lookahead['type'] === Lexer::T_ESCAPE) {
  2209. $this->match(Lexer::T_ESCAPE);
  2210. $this->match(Lexer::T_STRING);
  2211. $escapeChar = $this->_lexer->token['value'];
  2212. }
  2213. $likeExpr = new AST\LikeExpression($stringExpr, $stringPattern, $escapeChar);
  2214. $likeExpr->not = $not;
  2215. return $likeExpr;
  2216. }
  2217. /**
  2218. * NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL"
  2219. *
  2220. * @return \Doctrine\ORM\Query\AST\NullComparisonExpression
  2221. */
  2222. public function NullComparisonExpression()
  2223. {
  2224. if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
  2225. $this->match(Lexer::T_INPUT_PARAMETER);
  2226. $expr = new AST\InputParameter($this->_lexer->token['value']);
  2227. } else {
  2228. $expr = $this->SingleValuedPathExpression();
  2229. }
  2230. $nullCompExpr = new AST\NullComparisonExpression($expr);
  2231. $this->match(Lexer::T_IS);
  2232. if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
  2233. $this->match(Lexer::T_NOT);
  2234. $nullCompExpr->not = true;
  2235. }
  2236. $this->match(Lexer::T_NULL);
  2237. return $nullCompExpr;
  2238. }
  2239. /**
  2240. * ExistsExpression ::= ["NOT"] "EXISTS" "(" Subselect ")"
  2241. *
  2242. * @return \Doctrine\ORM\Query\AST\ExistsExpression
  2243. */
  2244. public function ExistsExpression()
  2245. {
  2246. $not = false;
  2247. if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
  2248. $this->match(Lexer::T_NOT);
  2249. $not = true;
  2250. }
  2251. $this->match(Lexer::T_EXISTS);
  2252. $this->match(Lexer::T_OPEN_PARENTHESIS);
  2253. $existsExpression = new AST\ExistsExpression($this->Subselect());
  2254. $existsExpression->not = $not;
  2255. $this->match(Lexer::T_CLOSE_PARENTHESIS);
  2256. return $existsExpression;
  2257. }
  2258. /**
  2259. * ComparisonOperator ::= "=" | "<" | "<=" | "<>" | ">" | ">=" | "!="
  2260. *
  2261. * @return string
  2262. */
  2263. public function ComparisonOperator()
  2264. {
  2265. switch ($this->_lexer->lookahead['value']) {
  2266. case '=':
  2267. $this->match(Lexer::T_EQUALS);
  2268. return '=';
  2269. case '<':
  2270. $this->match(Lexer::T_LOWER_THAN);
  2271. $operator = '<';
  2272. if ($this->_lexer->isNextToken(Lexer::T_EQUALS)) {
  2273. $this->match(Lexer::T_EQUALS);
  2274. $operator .= '=';
  2275. } else if ($this->_lexer->isNextToken(Lexer::T_GREATER_THAN)) {
  2276. $this->match(Lexer::T_GREATER_THAN);
  2277. $operator .= '>';
  2278. }
  2279. return $operator;
  2280. case '>':
  2281. $this->match(Lexer::T_GREATER_THAN);
  2282. $operator = '>';
  2283. if ($this->_lexer->isNextToken(Lexer::T_EQUALS)) {
  2284. $this->match(Lexer::T_EQUALS);
  2285. $operator .= '=';
  2286. }
  2287. return $operator;
  2288. case '!':
  2289. $this->match(Lexer::T_NEGATE);
  2290. $this->match(Lexer::T_EQUALS);
  2291. return '<>';
  2292. default:
  2293. $this->syntaxError('=, <, <=, <>, >, >=, !=');
  2294. }
  2295. }
  2296. /**
  2297. * FunctionDeclaration ::= FunctionsReturningStrings | FunctionsReturningNumerics | FunctionsReturningDatetime
  2298. */
  2299. public function FunctionDeclaration()
  2300. {
  2301. $token = $this->_lexer->lookahead;
  2302. $funcName = strtolower($token['value']);
  2303. // Check for built-in functions first!
  2304. if (isset(self::$_STRING_FUNCTIONS[$funcName])) {
  2305. return $this->FunctionsReturningStrings();
  2306. } else if (isset(self::$_NUMERIC_FUNCTIONS[$funcName])) {
  2307. return $this->FunctionsReturningNumerics();
  2308. } else if (isset(self::$_DATETIME_FUNCTIONS[$funcName])) {
  2309. return $this->FunctionsReturningDatetime();
  2310. }
  2311. // Check for custom functions afterwards
  2312. $config = $this->_em->getConfiguration();
  2313. if ($config->getCustomStringFunction($funcName) !== null) {
  2314. return $this->CustomFunctionsReturningStrings();
  2315. } else if ($config->getCustomNumericFunction($funcName) !== null) {
  2316. return $this->CustomFunctionsReturningNumerics();
  2317. } else if ($config->getCustomDatetimeFunction($funcName) !== null) {
  2318. return $this->CustomFunctionsReturningDatetime();
  2319. }
  2320. $this->syntaxError('known function', $token);
  2321. }
  2322. /**
  2323. * FunctionsReturningNumerics ::=
  2324. * "LENGTH" "(" StringPrimary ")" |
  2325. * "LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" |
  2326. * "ABS" "(" SimpleArithmeticExpression ")" |
  2327. * "SQRT" "(" SimpleArithmeticExpression ")" |
  2328. * "MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")" |
  2329. * "SIZE" "(" CollectionValuedPathExpression ")"
  2330. */
  2331. public function FunctionsReturningNumerics()
  2332. {
  2333. $funcNameLower = strtolower($this->_lexer->lookahead['value']);
  2334. $funcClass = self::$_NUMERIC_FUNCTIONS[$funcNameLower];
  2335. $function = new $funcClass($funcNameLower);
  2336. $function->parse($this);
  2337. return $function;
  2338. }
  2339. public function CustomFunctionsReturningNumerics()
  2340. {
  2341. $funcName = strtolower($this->_lexer->lookahead['value']);
  2342. // getCustomNumericFunction is case-insensitive
  2343. $funcClass = $this->_em->getConfiguration()->getCustomNumericFunction($funcName);
  2344. $function = new $funcClass($funcName);
  2345. $function->parse($this);
  2346. return $function;
  2347. }
  2348. /**
  2349. * FunctionsReturningDateTime ::= "CURRENT_DATE" | "CURRENT_TIME" | "CURRENT_TIMESTAMP"
  2350. */
  2351. public function FunctionsReturningDatetime()
  2352. {
  2353. $funcNameLower = strtolower($this->_lexer->lookahead['value']);
  2354. $funcClass = self::$_DATETIME_FUNCTIONS[$funcNameLower];
  2355. $function = new $funcClass($funcNameLower);
  2356. $function->parse($this);
  2357. return $function;
  2358. }
  2359. public function CustomFunctionsReturningDatetime()
  2360. {
  2361. $funcName = $this->_lexer->lookahead['value'];
  2362. // getCustomDatetimeFunction is case-insensitive
  2363. $funcClass = $this->_em->getConfiguration()->getCustomDatetimeFunction($funcName);
  2364. $function = new $funcClass($funcName);
  2365. $function->parse($this);
  2366. return $function;
  2367. }
  2368. /**
  2369. * FunctionsReturningStrings ::=
  2370. * "CONCAT" "(" StringPrimary "," StringPrimary ")" |
  2371. * "SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" |
  2372. * "TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")" |
  2373. * "LOWER" "(" StringPrimary ")" |
  2374. * "UPPER" "(" StringPrimary ")"
  2375. */
  2376. public function FunctionsReturningStrings()
  2377. {
  2378. $funcNameLower = strtolower($this->_lexer->lookahead['value']);
  2379. $funcClass = self::$_STRING_FUNCTIONS[$funcNameLower];
  2380. $function = new $funcClass($funcNameLower);
  2381. $function->parse($this);
  2382. return $function;
  2383. }
  2384. public function CustomFunctionsReturningStrings()
  2385. {
  2386. $funcName = $this->_lexer->lookahead['value'];
  2387. // getCustomStringFunction is case-insensitive
  2388. $funcClass = $this->_em->getConfiguration()->getCustomStringFunction($funcName);
  2389. $function = new $funcClass($funcName);
  2390. $function->parse($this);
  2391. return $function;
  2392. }
  2393. }