Parser.php 108 KB

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