expression.class.inc.php 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527
  1. <?php
  2. // Copyright (c) 2010-2017 Combodo SARL
  3. //
  4. // This file is part of iTop.
  5. //
  6. // iTop is free software; you can redistribute it and/or modify
  7. // it under the terms of the GNU Affero General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // iTop is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU Affero General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU Affero General Public License
  17. // along with iTop. If not, see <http://www.gnu.org/licenses/>
  18. //
  19. class MissingQueryArgument extends CoreException
  20. {
  21. }
  22. abstract class Expression
  23. {
  24. /**
  25. * Perform a deep clone (as opposed to "clone" which does copy a reference to the underlying objects)
  26. **/
  27. public function DeepClone()
  28. {
  29. return unserialize(serialize($this));
  30. }
  31. // recursive translation of identifiers
  32. abstract public function GetUnresolvedFields($sAlias, &$aUnresolved);
  33. abstract public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true);
  34. // recursive rendering (aArgs used as input by default, or used as output if bRetrofitParams set to True
  35. abstract public function Render(&$aArgs = null, $bRetrofitParams = false);
  36. /**
  37. * Recursively browse the expression tree
  38. * @param Closure $callback
  39. * @return mixed
  40. */
  41. abstract public function Browse(Closure $callback);
  42. abstract public function ApplyParameters($aArgs);
  43. // recursively builds an array of class => fieldname
  44. abstract public function ListRequiredFields();
  45. // recursively list field parents ($aTable = array of sParent => dummy)
  46. abstract public function CollectUsedParents(&$aTable);
  47. abstract public function IsTrue();
  48. // recursively builds an array of [classAlias][fieldName] => value
  49. abstract public function ListConstantFields();
  50. public function RequiresField($sClass, $sFieldName)
  51. {
  52. // #@# todo - optimize : this is called quite often when building a single query !
  53. $aRequired = $this->ListRequiredFields();
  54. if (!in_array($sClass.'.'.$sFieldName, $aRequired)) return false;
  55. return true;
  56. }
  57. public function serialize()
  58. {
  59. return base64_encode($this->Render());
  60. }
  61. static public function unserialize($sValue)
  62. {
  63. return self::FromOQL(base64_decode($sValue));
  64. }
  65. /**
  66. * @param $sConditionExpr
  67. * @return Expression
  68. */
  69. static public function FromOQL($sConditionExpr)
  70. {
  71. static $aCache = array();
  72. if (array_key_exists($sConditionExpr, $aCache))
  73. {
  74. return $aCache[$sConditionExpr];
  75. }
  76. $oOql = new OqlInterpreter($sConditionExpr);
  77. $oExpression = $oOql->ParseExpression();
  78. $aCache[$sConditionExpr] = $oExpression;
  79. return $oExpression;
  80. }
  81. static public function FromSQL($sSQL)
  82. {
  83. $oSql = new SQLExpression($sSQL);
  84. return $oSql;
  85. }
  86. /**
  87. * @param Expression $oExpr
  88. * @return Expression
  89. */
  90. public function LogAnd(Expression $oExpr)
  91. {
  92. if ($this->IsTrue()) return clone $oExpr;
  93. if ($oExpr->IsTrue()) return clone $this;
  94. return new BinaryExpression($this, 'AND', $oExpr);
  95. }
  96. /**
  97. * @param Expression $oExpr
  98. * @return Expression
  99. */
  100. public function LogOr(Expression $oExpr)
  101. {
  102. return new BinaryExpression($this, 'OR', $oExpr);
  103. }
  104. abstract public function RenameParam($sOldName, $sNewName);
  105. abstract public function RenameAlias($sOldName, $sNewName);
  106. /**
  107. * Make the most relevant label, given the value of the expression
  108. *
  109. * @param DBSearch oFilter The context in which this expression has been used
  110. * @param string sValue The value returned by the query, for this expression
  111. * @param string sDefault The default value if no relevant label could be computed
  112. * @return The label
  113. */
  114. public function MakeValueLabel($oFilter, $sValue, $sDefault)
  115. {
  116. return $sDefault;
  117. }
  118. }
  119. class SQLExpression extends Expression
  120. {
  121. protected $m_sSQL;
  122. public function __construct($sSQL)
  123. {
  124. $this->m_sSQL = $sSQL;
  125. }
  126. public function IsTrue()
  127. {
  128. return false;
  129. }
  130. // recursive rendering
  131. public function Render(&$aArgs = null, $bRetrofitParams = false)
  132. {
  133. return $this->m_sSQL;
  134. }
  135. public function Browse(Closure $callback)
  136. {
  137. $callback($this);
  138. }
  139. public function ApplyParameters($aArgs)
  140. {
  141. }
  142. public function GetUnresolvedFields($sAlias, &$aUnresolved)
  143. {
  144. }
  145. public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
  146. {
  147. return clone $this;
  148. }
  149. public function ListRequiredFields()
  150. {
  151. return array();
  152. }
  153. public function CollectUsedParents(&$aTable)
  154. {
  155. }
  156. public function ListConstantFields()
  157. {
  158. return array();
  159. }
  160. public function RenameParam($sOldName, $sNewName)
  161. {
  162. // Do nothing, since there is nothing to rename
  163. }
  164. public function RenameAlias($sOldName, $sNewName)
  165. {
  166. // Do nothing, since there is nothing to rename
  167. }
  168. }
  169. class BinaryExpression extends Expression
  170. {
  171. protected $m_oLeftExpr; // filter code or an SQL expression (later?)
  172. protected $m_oRightExpr;
  173. protected $m_sOperator;
  174. public function __construct($oLeftExpr, $sOperator, $oRightExpr)
  175. {
  176. if (!is_object($oLeftExpr))
  177. {
  178. throw new CoreException('Expecting an Expression object on the left hand', array('found_type' => gettype($oLeftExpr)));
  179. }
  180. if (!is_object($oRightExpr))
  181. {
  182. throw new CoreException('Expecting an Expression object on the right hand', array('found_type' => gettype($oRightExpr)));
  183. }
  184. if (!$oLeftExpr instanceof Expression)
  185. {
  186. throw new CoreException('Expecting an Expression object on the left hand', array('found_class' => get_class($oLeftExpr)));
  187. }
  188. if (!$oRightExpr instanceof Expression)
  189. {
  190. throw new CoreException('Expecting an Expression object on the right hand', array('found_class' => get_class($oRightExpr)));
  191. }
  192. $this->m_oLeftExpr = $oLeftExpr;
  193. $this->m_oRightExpr = $oRightExpr;
  194. $this->m_sOperator = $sOperator;
  195. }
  196. public function IsTrue()
  197. {
  198. // return true if we are certain that it will be true
  199. if ($this->m_sOperator == 'AND')
  200. {
  201. if ($this->m_oLeftExpr->IsTrue() && $this->m_oRightExpr->IsTrue()) return true;
  202. }
  203. elseif ($this->m_sOperator == 'OR')
  204. {
  205. if ($this->m_oLeftExpr->IsTrue() || $this->m_oRightExpr->IsTrue()) return true;
  206. }
  207. return false;
  208. }
  209. public function GetLeftExpr()
  210. {
  211. return $this->m_oLeftExpr;
  212. }
  213. public function GetRightExpr()
  214. {
  215. return $this->m_oRightExpr;
  216. }
  217. public function GetOperator()
  218. {
  219. return $this->m_sOperator;
  220. }
  221. // recursive rendering
  222. public function Render(&$aArgs = null, $bRetrofitParams = false)
  223. {
  224. $sOperator = $this->GetOperator();
  225. $sLeft = $this->GetLeftExpr()->Render($aArgs, $bRetrofitParams);
  226. $sRight = $this->GetRightExpr()->Render($aArgs, $bRetrofitParams);
  227. return "($sLeft $sOperator $sRight)";
  228. }
  229. public function Browse(Closure $callback)
  230. {
  231. $callback($this);
  232. $this->m_oLeftExpr->Browse($callback);
  233. $this->m_oRightExpr->Browse($callback);
  234. }
  235. public function ApplyParameters($aArgs)
  236. {
  237. if ($this->m_oLeftExpr instanceof VariableExpression)
  238. {
  239. $this->m_oLeftExpr = $this->m_oLeftExpr->GetAsScalar($aArgs);
  240. }
  241. else //if ($this->m_oLeftExpr instanceof Expression)
  242. {
  243. $this->m_oLeftExpr->ApplyParameters($aArgs);
  244. }
  245. if ($this->m_oRightExpr instanceof VariableExpression)
  246. {
  247. $this->m_oRightExpr = $this->m_oRightExpr->GetAsScalar($aArgs);
  248. }
  249. else //if ($this->m_oRightExpr instanceof Expression)
  250. {
  251. $this->m_oRightExpr->ApplyParameters($aArgs);
  252. }
  253. }
  254. public function GetUnresolvedFields($sAlias, &$aUnresolved)
  255. {
  256. $this->GetLeftExpr()->GetUnresolvedFields($sAlias, $aUnresolved);
  257. $this->GetRightExpr()->GetUnresolvedFields($sAlias, $aUnresolved);
  258. }
  259. public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
  260. {
  261. $oLeft = $this->GetLeftExpr()->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
  262. $oRight = $this->GetRightExpr()->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
  263. return new BinaryExpression($oLeft, $this->GetOperator(), $oRight);
  264. }
  265. public function ListRequiredFields()
  266. {
  267. $aLeft = $this->GetLeftExpr()->ListRequiredFields();
  268. $aRight = $this->GetRightExpr()->ListRequiredFields();
  269. return array_merge($aLeft, $aRight);
  270. }
  271. public function CollectUsedParents(&$aTable)
  272. {
  273. $this->GetLeftExpr()->CollectUsedParents($aTable);
  274. $this->GetRightExpr()->CollectUsedParents($aTable);
  275. }
  276. /**
  277. * List all constant expression of the form <field> = <scalar> or <field> = :<variable>
  278. * Could be extended to support <field> = <function><constant_expression>
  279. */
  280. public function ListConstantFields()
  281. {
  282. $aResult = array();
  283. if ($this->m_sOperator == '=')
  284. {
  285. if (($this->m_oLeftExpr instanceof FieldExpression) && ($this->m_oRightExpr instanceof ScalarExpression))
  286. {
  287. $aResult[$this->m_oLeftExpr->GetParent()][$this->m_oLeftExpr->GetName()] = $this->m_oRightExpr;
  288. }
  289. else if (($this->m_oRightExpr instanceof FieldExpression) && ($this->m_oLeftExpr instanceof ScalarExpression))
  290. {
  291. $aResult[$this->m_oRightExpr->GetParent()][$this->m_oRightExpr->GetName()] = $this->m_oLeftExpr;
  292. }
  293. else if (($this->m_oLeftExpr instanceof FieldExpression) && ($this->m_oRightExpr instanceof VariableExpression))
  294. {
  295. $aResult[$this->m_oLeftExpr->GetParent()][$this->m_oLeftExpr->GetName()] = $this->m_oRightExpr;
  296. }
  297. else if (($this->m_oRightExpr instanceof FieldExpression) && ($this->m_oLeftExpr instanceof VariableExpression))
  298. {
  299. $aResult[$this->m_oRightExpr->GetParent()][$this->m_oRightExpr->GetName()] = $this->m_oLeftExpr;
  300. }
  301. }
  302. else if ($this->m_sOperator == 'AND')
  303. {
  304. // Strictly, this should be done only for the AND operator
  305. $aResult = array_merge_recursive($this->m_oRightExpr->ListConstantFields(), $this->m_oLeftExpr->ListConstantFields());
  306. }
  307. return $aResult;
  308. }
  309. public function RenameParam($sOldName, $sNewName)
  310. {
  311. $this->GetLeftExpr()->RenameParam($sOldName, $sNewName);
  312. $this->GetRightExpr()->RenameParam($sOldName, $sNewName);
  313. }
  314. public function RenameAlias($sOldName, $sNewName)
  315. {
  316. $this->GetLeftExpr()->RenameAlias($sOldName, $sNewName);
  317. $this->GetRightExpr()->RenameAlias($sOldName, $sNewName);
  318. }
  319. }
  320. class UnaryExpression extends Expression
  321. {
  322. protected $m_value;
  323. public function __construct($value)
  324. {
  325. $this->m_value = $value;
  326. }
  327. public function IsTrue()
  328. {
  329. // return true if we are certain that it will be true
  330. return ($this->m_value == 1);
  331. }
  332. public function GetValue()
  333. {
  334. return $this->m_value;
  335. }
  336. // recursive rendering
  337. public function Render(&$aArgs = null, $bRetrofitParams = false)
  338. {
  339. return CMDBSource::Quote($this->m_value);
  340. }
  341. public function Browse(Closure $callback)
  342. {
  343. $callback($this);
  344. }
  345. public function ApplyParameters($aArgs)
  346. {
  347. }
  348. public function GetUnresolvedFields($sAlias, &$aUnresolved)
  349. {
  350. }
  351. public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
  352. {
  353. return clone $this;
  354. }
  355. public function ListRequiredFields()
  356. {
  357. return array();
  358. }
  359. public function CollectUsedParents(&$aTable)
  360. {
  361. }
  362. public function ListConstantFields()
  363. {
  364. return array();
  365. }
  366. public function RenameParam($sOldName, $sNewName)
  367. {
  368. // Do nothing
  369. // really ? what about :param{$iParamIndex} ??
  370. }
  371. public function RenameAlias($sOldName, $sNewName)
  372. {
  373. // Do nothing
  374. }
  375. }
  376. class ScalarExpression extends UnaryExpression
  377. {
  378. public function __construct($value)
  379. {
  380. if (!is_scalar($value) && !is_null($value) && (!$value instanceof OqlHexValue))
  381. {
  382. throw new CoreException('Attempt to create a scalar expression from a non scalar', array('var_type'=>gettype($value)));
  383. }
  384. parent::__construct($value);
  385. }
  386. // recursive rendering
  387. public function Render(&$aArgs = null, $bRetrofitParams = false)
  388. {
  389. if (is_null($this->m_value))
  390. {
  391. $sRet = 'NULL';
  392. }
  393. else
  394. {
  395. $sRet = CMDBSource::Quote($this->m_value);
  396. }
  397. return $sRet;
  398. }
  399. public function GetAsScalar($aArgs)
  400. {
  401. return clone $this;
  402. }
  403. }
  404. class TrueExpression extends ScalarExpression
  405. {
  406. public function __construct()
  407. {
  408. parent::__construct(1);
  409. }
  410. public function IsTrue()
  411. {
  412. return true;
  413. }
  414. }
  415. class FalseExpression extends ScalarExpression
  416. {
  417. public function __construct()
  418. {
  419. parent::__construct(0);
  420. }
  421. public function IsTrue()
  422. {
  423. return false;
  424. }
  425. }
  426. class FieldExpression extends UnaryExpression
  427. {
  428. protected $m_sParent;
  429. protected $m_sName;
  430. public function __construct($sName, $sParent = '')
  431. {
  432. parent::__construct("$sParent.$sName");
  433. $this->m_sParent = $sParent;
  434. $this->m_sName = $sName;
  435. }
  436. public function IsTrue()
  437. {
  438. // return true if we are certain that it will be true
  439. return false;
  440. }
  441. public function GetParent() {return $this->m_sParent;}
  442. public function GetName() {return $this->m_sName;}
  443. public function SetParent($sParent)
  444. {
  445. $this->m_sParent = $sParent;
  446. $this->m_value = $sParent.'.'.$this->m_sName;
  447. }
  448. // recursive rendering
  449. public function Render(&$aArgs = null, $bRetrofitParams = false)
  450. {
  451. if (empty($this->m_sParent))
  452. {
  453. return "`{$this->m_sName}`";
  454. }
  455. return "`{$this->m_sParent}`.`{$this->m_sName}`";
  456. }
  457. public function ListRequiredFields()
  458. {
  459. return array($this->m_sParent.'.'.$this->m_sName);
  460. }
  461. public function CollectUsedParents(&$aTable)
  462. {
  463. $aTable[$this->m_sParent] = true;
  464. }
  465. public function GetUnresolvedFields($sAlias, &$aUnresolved)
  466. {
  467. if ($this->m_sParent == $sAlias)
  468. {
  469. // Add a reference to the field
  470. $aUnresolved[$this->m_sName] = $this;
  471. }
  472. elseif ($sAlias == '')
  473. {
  474. // An empty alias means "any alias"
  475. // In such a case, the results are indexed differently
  476. $aUnresolved[$this->m_sParent][$this->m_sName] = $this;
  477. }
  478. }
  479. public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
  480. {
  481. if (!array_key_exists($this->m_sParent, $aTranslationData))
  482. {
  483. if ($bMatchAll) throw new CoreException('Unknown parent id in translation table', array('parent_id' => $this->m_sParent, 'translation_table' => array_keys($aTranslationData)));
  484. return clone $this;
  485. }
  486. if (!array_key_exists($this->m_sName, $aTranslationData[$this->m_sParent]))
  487. {
  488. if (!array_key_exists('*', $aTranslationData[$this->m_sParent]))
  489. {
  490. // #@# debug - if ($bMatchAll) MyHelpers::var_dump_html($aTranslationData, true);
  491. if ($bMatchAll) throw new CoreException('Unknown name in translation table', array('name' => $this->m_sName, 'parent_id' => $this->m_sParent, 'translation_table' => array_keys($aTranslationData[$this->m_sParent])));
  492. return clone $this;
  493. }
  494. $sNewParent = $aTranslationData[$this->m_sParent]['*'];
  495. $sNewName = $this->m_sName;
  496. if ($bMarkFieldsAsResolved)
  497. {
  498. $oRet = new FieldExpressionResolved($sNewName, $sNewParent);
  499. }
  500. else
  501. {
  502. $oRet = new FieldExpression($sNewName, $sNewParent);
  503. }
  504. }
  505. else
  506. {
  507. $oRet = $aTranslationData[$this->m_sParent][$this->m_sName];
  508. }
  509. return $oRet;
  510. }
  511. /**
  512. * Make the most relevant label, given the value of the expression
  513. *
  514. * @param DBSearch oFilter The context in which this expression has been used
  515. * @param string sValue The value returned by the query, for this expression
  516. * @param string sDefault The default value if no relevant label could be computed
  517. * @return The label
  518. */
  519. public function MakeValueLabel($oFilter, $sValue, $sDefault)
  520. {
  521. $sAttCode = $this->GetName();
  522. $sParentAlias = $this->GetParent();
  523. $aSelectedClasses = $oFilter->GetSelectedClasses();
  524. $sClass = $aSelectedClasses[$sParentAlias];
  525. $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
  526. // Set a default value for the general case
  527. $sRes = $oAttDef->GetAsHtml($sValue);
  528. // Exceptions...
  529. if ($oAttDef->IsExternalKey())
  530. {
  531. $sObjClass = $oAttDef->GetTargetClass();
  532. $iObjKey = (int)$sValue;
  533. if ($iObjKey > 0)
  534. {
  535. $oObject = MetaModel::GetObjectWithArchive($sObjClass, $iObjKey);
  536. $sRes = $oObject->GetHyperlink();
  537. }
  538. else
  539. {
  540. // Undefined
  541. $sRes = DBObject::MakeHyperLink($sObjClass, 0);
  542. }
  543. }
  544. elseif ($oAttDef->IsExternalField())
  545. {
  546. if (is_null($sValue))
  547. {
  548. $sRes = Dict::S('UI:UndefinedObject');
  549. }
  550. }
  551. return $sRes;
  552. }
  553. public function RenameAlias($sOldName, $sNewName)
  554. {
  555. if ($this->m_sParent == $sOldName)
  556. {
  557. $this->m_sParent = $sNewName;
  558. }
  559. }
  560. }
  561. // Has been resolved into an SQL expression
  562. class FieldExpressionResolved extends FieldExpression
  563. {
  564. public function GetUnresolvedFields($sAlias, &$aUnresolved)
  565. {
  566. }
  567. public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
  568. {
  569. return clone $this;
  570. }
  571. }
  572. class VariableExpression extends UnaryExpression
  573. {
  574. protected $m_sName;
  575. public function __construct($sName)
  576. {
  577. parent::__construct($sName);
  578. $this->m_sName = $sName;
  579. }
  580. public function IsTrue()
  581. {
  582. // return true if we are certain that it will be true
  583. return false;
  584. }
  585. public function GetName() {return $this->m_sName;}
  586. // recursive rendering
  587. public function Render(&$aArgs = null, $bRetrofitParams = false)
  588. {
  589. if (is_null($aArgs))
  590. {
  591. return ':'.$this->m_sName;
  592. }
  593. elseif (array_key_exists($this->m_sName, $aArgs))
  594. {
  595. $res = CMDBSource::Quote($aArgs[$this->m_sName]);
  596. if (is_array($res))
  597. {
  598. $res = implode(', ', $res);
  599. }
  600. return $res;
  601. }
  602. elseif (($iPos = strpos($this->m_sName, '->')) !== false)
  603. {
  604. $sParamName = substr($this->m_sName, 0, $iPos);
  605. if (array_key_exists($sParamName.'->object()', $aArgs))
  606. {
  607. $sAttCode = substr($this->m_sName, $iPos + 2);
  608. $oObj = $aArgs[$sParamName.'->object()'];
  609. if ($sAttCode == 'id')
  610. {
  611. return CMDBSource::Quote($oObj->GetKey());
  612. }
  613. return CMDBSource::Quote($oObj->Get($sAttCode));
  614. }
  615. }
  616. if ($bRetrofitParams)
  617. {
  618. $aArgs[$this->m_sName] = null;
  619. return ':'.$this->m_sName;
  620. }
  621. else
  622. {
  623. throw new MissingQueryArgument('Missing query argument', array('expecting'=>$this->m_sName, 'available'=>array_keys($aArgs)));
  624. }
  625. }
  626. public function RenameParam($sOldName, $sNewName)
  627. {
  628. if ($this->m_sName == $sOldName)
  629. {
  630. $this->m_sName = $sNewName;
  631. }
  632. }
  633. public function GetAsScalar($aArgs)
  634. {
  635. $oRet = null;
  636. if (array_key_exists($this->m_sName, $aArgs))
  637. {
  638. $oRet = new ScalarExpression($aArgs[$this->m_sName]);
  639. }
  640. elseif (($iPos = strpos($this->m_sName, '->')) !== false)
  641. {
  642. $sParamName = substr($this->m_sName, 0, $iPos);
  643. if (array_key_exists($sParamName.'->object()', $aArgs))
  644. {
  645. $sAttCode = substr($this->m_sName, $iPos + 2);
  646. $oObj = $aArgs[$sParamName.'->object()'];
  647. if ($sAttCode == 'id')
  648. {
  649. $oRet = new ScalarExpression($oObj->GetKey());
  650. }
  651. elseif (MetaModel::IsValidAttCode(get_class($oObj), $sAttCode))
  652. {
  653. $oRet = new ScalarExpression($oObj->Get($sAttCode));
  654. }
  655. else
  656. {
  657. throw new CoreException("Query argument {$this->m_sName} not matching any attribute of class ".get_class($oObj));
  658. }
  659. }
  660. }
  661. if (is_null($oRet))
  662. {
  663. throw new MissingQueryArgument('Missing query argument', array('expecting'=>$this->m_sName, 'available'=>array_keys($aArgs)));
  664. }
  665. return $oRet;
  666. }
  667. }
  668. // Temporary, until we implement functions and expression casting!
  669. // ... or until we implement a real full text search based in the MATCH() expression
  670. class ListExpression extends Expression
  671. {
  672. protected $m_aExpressions;
  673. public function __construct($aExpressions)
  674. {
  675. $this->m_aExpressions = $aExpressions;
  676. }
  677. public static function FromScalars($aScalars)
  678. {
  679. $aExpressions = array();
  680. foreach($aScalars as $value)
  681. {
  682. $aExpressions[] = new ScalarExpression($value);
  683. }
  684. return new ListExpression($aExpressions);
  685. }
  686. public function IsTrue()
  687. {
  688. // return true if we are certain that it will be true
  689. return false;
  690. }
  691. public function GetItems()
  692. {
  693. return $this->m_aExpressions;
  694. }
  695. // recursive rendering
  696. public function Render(&$aArgs = null, $bRetrofitParams = false)
  697. {
  698. $aRes = array();
  699. foreach ($this->m_aExpressions as $oExpr)
  700. {
  701. $aRes[] = $oExpr->Render($aArgs, $bRetrofitParams);
  702. }
  703. return '('.implode(', ', $aRes).')';
  704. }
  705. public function Browse(Closure $callback)
  706. {
  707. $callback($this);
  708. foreach ($this->m_aExpressions as $oExpr)
  709. {
  710. $oExpr->Browse($callback);
  711. }
  712. }
  713. public function ApplyParameters($aArgs)
  714. {
  715. $aRes = array();
  716. foreach ($this->m_aExpressions as $idx => $oExpr)
  717. {
  718. if ($oExpr instanceof VariableExpression)
  719. {
  720. $this->m_aExpressions[$idx] = $oExpr->GetAsScalar();
  721. }
  722. else
  723. {
  724. $oExpr->ApplyParameters($aArgs);
  725. }
  726. }
  727. }
  728. public function GetUnresolvedFields($sAlias, &$aUnresolved)
  729. {
  730. foreach ($this->m_aExpressions as $oExpr)
  731. {
  732. $oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
  733. }
  734. }
  735. public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
  736. {
  737. $aRes = array();
  738. foreach ($this->m_aExpressions as $oExpr)
  739. {
  740. $aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
  741. }
  742. return new ListExpression($aRes);
  743. }
  744. public function ListRequiredFields()
  745. {
  746. $aRes = array();
  747. foreach ($this->m_aExpressions as $oExpr)
  748. {
  749. $aRes = array_merge($aRes, $oExpr->ListRequiredFields());
  750. }
  751. return $aRes;
  752. }
  753. public function CollectUsedParents(&$aTable)
  754. {
  755. foreach ($this->m_aExpressions as $oExpr)
  756. {
  757. $oExpr->CollectUsedParents($aTable);
  758. }
  759. }
  760. public function ListConstantFields()
  761. {
  762. $aRes = array();
  763. foreach ($this->m_aExpressions as $oExpr)
  764. {
  765. $aRes = array_merge($aRes, $oExpr->ListConstantFields());
  766. }
  767. return $aRes;
  768. }
  769. public function RenameParam($sOldName, $sNewName)
  770. {
  771. $aRes = array();
  772. foreach ($this->m_aExpressions as $key => $oExpr)
  773. {
  774. $this->m_aExpressions[$key] = $oExpr->RenameParam($sOldName, $sNewName);
  775. }
  776. }
  777. public function RenameAlias($sOldName, $sNewName)
  778. {
  779. $aRes = array();
  780. foreach ($this->m_aExpressions as $key => $oExpr)
  781. {
  782. $oExpr->RenameAlias($sOldName, $sNewName);
  783. }
  784. }
  785. }
  786. class FunctionExpression extends Expression
  787. {
  788. protected $m_sVerb;
  789. protected $m_aArgs; // array of expressions
  790. public function __construct($sVerb, $aArgExpressions)
  791. {
  792. $this->m_sVerb = $sVerb;
  793. $this->m_aArgs = $aArgExpressions;
  794. }
  795. public function IsTrue()
  796. {
  797. // return true if we are certain that it will be true
  798. return false;
  799. }
  800. public function GetVerb()
  801. {
  802. return $this->m_sVerb;
  803. }
  804. public function GetArgs()
  805. {
  806. return $this->m_aArgs;
  807. }
  808. // recursive rendering
  809. public function Render(&$aArgs = null, $bRetrofitParams = false)
  810. {
  811. $aRes = array();
  812. foreach ($this->m_aArgs as $iPos => $oExpr)
  813. {
  814. $aRes[] = $oExpr->Render($aArgs, $bRetrofitParams);
  815. }
  816. return $this->m_sVerb.'('.implode(', ', $aRes).')';
  817. }
  818. public function Browse(Closure $callback)
  819. {
  820. $callback($this);
  821. foreach ($this->m_aArgs as $iPos => $oExpr)
  822. {
  823. $oExpr->Browse($callback);
  824. }
  825. }
  826. public function ApplyParameters($aArgs)
  827. {
  828. $aRes = array();
  829. foreach ($this->m_aArgs as $idx => $oExpr)
  830. {
  831. if ($oExpr instanceof VariableExpression)
  832. {
  833. $this->m_aArgs[$idx] = $oExpr->GetAsScalar($aArgs);
  834. }
  835. else
  836. {
  837. $oExpr->ApplyParameters($aArgs);
  838. }
  839. }
  840. }
  841. public function GetUnresolvedFields($sAlias, &$aUnresolved)
  842. {
  843. foreach ($this->m_aArgs as $oExpr)
  844. {
  845. $oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
  846. }
  847. }
  848. public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
  849. {
  850. $aRes = array();
  851. foreach ($this->m_aArgs as $oExpr)
  852. {
  853. $aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
  854. }
  855. return new FunctionExpression($this->m_sVerb, $aRes);
  856. }
  857. public function ListRequiredFields()
  858. {
  859. $aRes = array();
  860. foreach ($this->m_aArgs as $oExpr)
  861. {
  862. $aRes = array_merge($aRes, $oExpr->ListRequiredFields());
  863. }
  864. return $aRes;
  865. }
  866. public function CollectUsedParents(&$aTable)
  867. {
  868. foreach ($this->m_aArgs as $oExpr)
  869. {
  870. $oExpr->CollectUsedParents($aTable);
  871. }
  872. }
  873. public function ListConstantFields()
  874. {
  875. $aRes = array();
  876. foreach ($this->m_aArgs as $oExpr)
  877. {
  878. $aRes = array_merge($aRes, $oExpr->ListConstantFields());
  879. }
  880. return $aRes;
  881. }
  882. public function RenameParam($sOldName, $sNewName)
  883. {
  884. foreach ($this->m_aArgs as $key => $oExpr)
  885. {
  886. $this->m_aArgs[$key] = $oExpr->RenameParam($sOldName, $sNewName);
  887. }
  888. }
  889. public function RenameAlias($sOldName, $sNewName)
  890. {
  891. foreach ($this->m_aArgs as $key => $oExpr)
  892. {
  893. $oExpr->RenameAlias($sOldName, $sNewName);
  894. }
  895. }
  896. /**
  897. * Make the most relevant label, given the value of the expression
  898. *
  899. * @param DBSearch oFilter The context in which this expression has been used
  900. * @param string sValue The value returned by the query, for this expression
  901. * @param string sDefault The default value if no relevant label could be computed
  902. * @return The label
  903. */
  904. public function MakeValueLabel($oFilter, $sValue, $sDefault)
  905. {
  906. static $aWeekDayToString = null;
  907. if (is_null($aWeekDayToString))
  908. {
  909. // Init the correspondance table
  910. $aWeekDayToString = array(
  911. 0 => Dict::S('DayOfWeek-Sunday'),
  912. 1 => Dict::S('DayOfWeek-Monday'),
  913. 2 => Dict::S('DayOfWeek-Tuesday'),
  914. 3 => Dict::S('DayOfWeek-Wednesday'),
  915. 4 => Dict::S('DayOfWeek-Thursday'),
  916. 5 => Dict::S('DayOfWeek-Friday'),
  917. 6 => Dict::S('DayOfWeek-Saturday')
  918. );
  919. }
  920. static $aMonthToString = null;
  921. if (is_null($aMonthToString))
  922. {
  923. // Init the correspondance table
  924. $aMonthToString = array(
  925. 1 => Dict::S('Month-01'),
  926. 2 => Dict::S('Month-02'),
  927. 3 => Dict::S('Month-03'),
  928. 4 => Dict::S('Month-04'),
  929. 5 => Dict::S('Month-05'),
  930. 6 => Dict::S('Month-06'),
  931. 7 => Dict::S('Month-07'),
  932. 8 => Dict::S('Month-08'),
  933. 9 => Dict::S('Month-09'),
  934. 10 => Dict::S('Month-10'),
  935. 11 => Dict::S('Month-11'),
  936. 12 => Dict::S('Month-12'),
  937. );
  938. }
  939. $sRes = $sDefault;
  940. if (strtolower($this->m_sVerb) == 'date_format')
  941. {
  942. $oFormatExpr = $this->m_aArgs[1];
  943. if ($oFormatExpr->Render() == "'%w'")
  944. {
  945. if (isset($aWeekDayToString[(int)$sValue]))
  946. {
  947. $sRes = $aWeekDayToString[(int)$sValue];
  948. }
  949. }
  950. elseif ($oFormatExpr->Render() == "'%Y-%m'")
  951. {
  952. // yyyy-mm => "yyyy month"
  953. $iMonth = (int) substr($sValue, -2); // the two last chars
  954. $sRes = substr($sValue, 0, 4).' '.$aMonthToString[$iMonth];
  955. }
  956. elseif ($oFormatExpr->Render() == "'%Y-%m-%d'")
  957. {
  958. // yyyy-mm-dd => "month d"
  959. $iMonth = (int) substr($sValue, 5, 2);
  960. $sRes = $aMonthToString[$iMonth].' '.(int)substr($sValue, -2);
  961. }
  962. }
  963. return $sRes;
  964. }
  965. }
  966. class IntervalExpression extends Expression
  967. {
  968. protected $m_oValue; // expression
  969. protected $m_sUnit;
  970. public function __construct($oValue, $sUnit)
  971. {
  972. $this->m_oValue = $oValue;
  973. $this->m_sUnit = $sUnit;
  974. }
  975. public function IsTrue()
  976. {
  977. // return true if we are certain that it will be true
  978. return false;
  979. }
  980. public function GetValue()
  981. {
  982. return $this->m_oValue;
  983. }
  984. public function GetUnit()
  985. {
  986. return $this->m_sUnit;
  987. }
  988. // recursive rendering
  989. public function Render(&$aArgs = null, $bRetrofitParams = false)
  990. {
  991. return 'INTERVAL '.$this->m_oValue->Render($aArgs, $bRetrofitParams).' '.$this->m_sUnit;
  992. }
  993. public function Browse(Closure $callback)
  994. {
  995. $callback($this);
  996. $this->m_oValue->Browse($callback);
  997. }
  998. public function ApplyParameters($aArgs)
  999. {
  1000. if ($this->m_oValue instanceof VariableExpression)
  1001. {
  1002. $this->m_oValue = $this->m_oValue->GetAsScalar($aArgs);
  1003. }
  1004. else
  1005. {
  1006. $this->m_oValue->ApplyParameters($aArgs);
  1007. }
  1008. }
  1009. public function GetUnresolvedFields($sAlias, &$aUnresolved)
  1010. {
  1011. $this->m_oValue->GetUnresolvedFields($sAlias, $aUnresolved);
  1012. }
  1013. public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
  1014. {
  1015. return new IntervalExpression($this->m_oValue->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved), $this->m_sUnit);
  1016. }
  1017. public function ListRequiredFields()
  1018. {
  1019. return array();
  1020. }
  1021. public function CollectUsedParents(&$aTable)
  1022. {
  1023. }
  1024. public function ListConstantFields()
  1025. {
  1026. return array();
  1027. }
  1028. public function RenameParam($sOldName, $sNewName)
  1029. {
  1030. $this->m_oValue->RenameParam($sOldName, $sNewName);
  1031. }
  1032. public function RenameAlias($sOldName, $sNewName)
  1033. {
  1034. $this->m_oValue->RenameAlias($sOldName, $sNewName);
  1035. }
  1036. }
  1037. class CharConcatExpression extends Expression
  1038. {
  1039. protected $m_aExpressions;
  1040. public function __construct($aExpressions)
  1041. {
  1042. $this->m_aExpressions = $aExpressions;
  1043. }
  1044. public function IsTrue()
  1045. {
  1046. // return true if we are certain that it will be true
  1047. return false;
  1048. }
  1049. public function GetItems()
  1050. {
  1051. return $this->m_aExpressions;
  1052. }
  1053. // recursive rendering
  1054. public function Render(&$aArgs = null, $bRetrofitParams = false)
  1055. {
  1056. $aRes = array();
  1057. foreach ($this->m_aExpressions as $oExpr)
  1058. {
  1059. $sCol = $oExpr->Render($aArgs, $bRetrofitParams);
  1060. // Concat will be globally NULL if one single argument is null !
  1061. $aRes[] = "COALESCE($sCol, '')";
  1062. }
  1063. return "CAST(CONCAT(".implode(', ', $aRes).") AS CHAR)";
  1064. }
  1065. public function Browse(Closure $callback)
  1066. {
  1067. $callback($this);
  1068. foreach ($this->m_aExpressions as $oExpr)
  1069. {
  1070. $oExpr->Browse($callback);
  1071. }
  1072. }
  1073. public function ApplyParameters($aArgs)
  1074. {
  1075. $aRes = array();
  1076. foreach ($this->m_aExpressions as $idx => $oExpr)
  1077. {
  1078. if ($oExpr instanceof VariableExpression)
  1079. {
  1080. $this->m_aExpressions[$idx] = $oExpr->GetAsScalar();
  1081. }
  1082. else
  1083. {
  1084. $this->m_aExpressions->ApplyParameters($aArgs);
  1085. }
  1086. }
  1087. }
  1088. public function GetUnresolvedFields($sAlias, &$aUnresolved)
  1089. {
  1090. foreach ($this->m_aExpressions as $oExpr)
  1091. {
  1092. $oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
  1093. }
  1094. }
  1095. public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
  1096. {
  1097. $aRes = array();
  1098. foreach ($this->m_aExpressions as $oExpr)
  1099. {
  1100. $aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
  1101. }
  1102. return new CharConcatExpression($aRes);
  1103. }
  1104. public function ListRequiredFields()
  1105. {
  1106. $aRes = array();
  1107. foreach ($this->m_aExpressions as $oExpr)
  1108. {
  1109. $aRes = array_merge($aRes, $oExpr->ListRequiredFields());
  1110. }
  1111. return $aRes;
  1112. }
  1113. public function CollectUsedParents(&$aTable)
  1114. {
  1115. foreach ($this->m_aExpressions as $oExpr)
  1116. {
  1117. $oExpr->CollectUsedParents($aTable);
  1118. }
  1119. }
  1120. public function ListConstantFields()
  1121. {
  1122. $aRes = array();
  1123. foreach ($this->m_aExpressions as $oExpr)
  1124. {
  1125. $aRes = array_merge($aRes, $oExpr->ListConstantFields());
  1126. }
  1127. return $aRes;
  1128. }
  1129. public function RenameParam($sOldName, $sNewName)
  1130. {
  1131. foreach ($this->m_aExpressions as $key => $oExpr)
  1132. {
  1133. $this->m_aExpressions[$key] = $oExpr->RenameParam($sOldName, $sNewName);
  1134. }
  1135. }
  1136. public function RenameAlias($sOldName, $sNewName)
  1137. {
  1138. foreach ($this->m_aExpressions as $key => $oExpr)
  1139. {
  1140. $oExpr->RenameAlias($sOldName, $sNewName);
  1141. }
  1142. }
  1143. }
  1144. class CharConcatWSExpression extends CharConcatExpression
  1145. {
  1146. protected $m_separator;
  1147. public function __construct($separator, $aExpressions)
  1148. {
  1149. $this->m_separator = $separator;
  1150. parent::__construct($aExpressions);
  1151. }
  1152. // recursive rendering
  1153. public function Render(&$aArgs = null, $bRetrofitParams = false)
  1154. {
  1155. $aRes = array();
  1156. foreach ($this->m_aExpressions as $oExpr)
  1157. {
  1158. $sCol = $oExpr->Render($aArgs, $bRetrofitParams);
  1159. // Concat will be globally NULL if one single argument is null !
  1160. $aRes[] = "COALESCE($sCol, '')";
  1161. }
  1162. $sSep = CMDBSource::Quote($this->m_separator);
  1163. return "CAST(CONCAT_WS($sSep, ".implode(', ', $aRes).") AS CHAR)";
  1164. }
  1165. public function Browse(Closure $callback)
  1166. {
  1167. $callback($this);
  1168. foreach ($this->m_aExpressions as $oExpr)
  1169. {
  1170. $oExpr->Browse($callback);
  1171. }
  1172. }
  1173. public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
  1174. {
  1175. $aRes = array();
  1176. foreach ($this->m_aExpressions as $oExpr)
  1177. {
  1178. $aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
  1179. }
  1180. return new CharConcatWSExpression($this->m_separator, $aRes);
  1181. }
  1182. }
  1183. class QueryBuilderExpressions
  1184. {
  1185. /**
  1186. * @var Expression
  1187. */
  1188. protected $m_oConditionExpr;
  1189. /**
  1190. * @var Expression[]
  1191. */
  1192. protected $m_aSelectExpr;
  1193. /**
  1194. * @var Expression[]
  1195. */
  1196. protected $m_aGroupByExpr;
  1197. /**
  1198. * @var Expression[]
  1199. */
  1200. protected $m_aJoinFields;
  1201. /**
  1202. * @var string[]
  1203. */
  1204. protected $m_aClassIds;
  1205. public function __construct(DBObjectSearch $oSearch, $aGroupByExpr = null)
  1206. {
  1207. $this->m_oConditionExpr = $oSearch->GetCriteria();
  1208. if (!$oSearch->GetShowObsoleteData())
  1209. {
  1210. foreach ($oSearch->GetSelectedClasses() as $sAlias => $sClass)
  1211. {
  1212. if (MetaModel::IsObsoletable($sClass))
  1213. {
  1214. $oNotObsolete = new BinaryExpression(new FieldExpression('obsolescence_flag', $sAlias), '=', new ScalarExpression(0));
  1215. $this->m_oConditionExpr = $this->m_oConditionExpr->LogAnd($oNotObsolete);
  1216. }
  1217. }
  1218. }
  1219. $this->m_aSelectExpr = array();
  1220. $this->m_aGroupByExpr = $aGroupByExpr;
  1221. $this->m_aJoinFields = array();
  1222. $this->m_aClassIds = array();
  1223. foreach($oSearch->GetJoinedClasses() as $sClassAlias => $sClass)
  1224. {
  1225. $this->m_aClassIds[$sClassAlias] = new FieldExpression('id', $sClassAlias);
  1226. }
  1227. }
  1228. public function GetSelect()
  1229. {
  1230. return $this->m_aSelectExpr;
  1231. }
  1232. public function GetGroupBy()
  1233. {
  1234. return $this->m_aGroupByExpr;
  1235. }
  1236. public function GetCondition()
  1237. {
  1238. return $this->m_oConditionExpr;
  1239. }
  1240. /**
  1241. * @return Expression|mixed
  1242. */
  1243. public function PopJoinField()
  1244. {
  1245. return array_pop($this->m_aJoinFields);
  1246. }
  1247. /**
  1248. * @param string $sAttAlias
  1249. * @param Expression $oExpression
  1250. */
  1251. public function AddSelect($sAttAlias, Expression $oExpression)
  1252. {
  1253. $this->m_aSelectExpr[$sAttAlias] = $oExpression;
  1254. }
  1255. /**
  1256. * @param Expression $oExpression
  1257. */
  1258. public function AddCondition(Expression $oExpression)
  1259. {
  1260. $this->m_oConditionExpr = $this->m_oConditionExpr->LogAnd($oExpression);
  1261. }
  1262. /**
  1263. * @param Expression $oExpression
  1264. */
  1265. public function PushJoinField(Expression $oExpression)
  1266. {
  1267. array_push($this->m_aJoinFields, $oExpression);
  1268. }
  1269. /**
  1270. * Get tables representing the queried objects
  1271. * Could be further optimized: when the first join is an outer join, then the rest can be omitted
  1272. */
  1273. public function GetMandatoryTables(&$aTables = null)
  1274. {
  1275. if (is_null($aTables)) $aTables = array();
  1276. foreach($this->m_aClassIds as $sClass => $oExpression)
  1277. {
  1278. $oExpression->CollectUsedParents($aTables);
  1279. }
  1280. }
  1281. public function GetUnresolvedFields($sAlias, &$aUnresolved)
  1282. {
  1283. $this->m_oConditionExpr->GetUnresolvedFields($sAlias, $aUnresolved);
  1284. foreach($this->m_aSelectExpr as $sColAlias => $oExpr)
  1285. {
  1286. $oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
  1287. }
  1288. if ($this->m_aGroupByExpr)
  1289. {
  1290. foreach($this->m_aGroupByExpr as $sColAlias => $oExpr)
  1291. {
  1292. $oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
  1293. }
  1294. }
  1295. foreach($this->m_aJoinFields as $oExpression)
  1296. {
  1297. $oExpression->GetUnresolvedFields($sAlias, $aUnresolved);
  1298. }
  1299. }
  1300. public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
  1301. {
  1302. $this->m_oConditionExpr = $this->m_oConditionExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
  1303. foreach($this->m_aSelectExpr as $sColAlias => $oExpr)
  1304. {
  1305. $this->m_aSelectExpr[$sColAlias] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
  1306. }
  1307. if ($this->m_aGroupByExpr)
  1308. {
  1309. foreach($this->m_aGroupByExpr as $sColAlias => $oExpr)
  1310. {
  1311. $this->m_aGroupByExpr[$sColAlias] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
  1312. }
  1313. }
  1314. foreach($this->m_aJoinFields as $index => $oExpression)
  1315. {
  1316. $this->m_aJoinFields[$index] = $oExpression->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
  1317. }
  1318. foreach($this->m_aClassIds as $sClass => $oExpression)
  1319. {
  1320. $this->m_aClassIds[$sClass] = $oExpression->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
  1321. }
  1322. }
  1323. public function RenameParam($sOldName, $sNewName)
  1324. {
  1325. $this->m_oConditionExpr->RenameParam($sOldName, $sNewName);
  1326. foreach($this->m_aSelectExpr as $sColAlias => $oExpr)
  1327. {
  1328. $this->m_aSelectExpr[$sColAlias] = $oExpr->RenameParam($sOldName, $sNewName);
  1329. }
  1330. if ($this->m_aGroupByExpr)
  1331. {
  1332. foreach($this->m_aGroupByExpr as $sColAlias => $oExpr)
  1333. {
  1334. $this->m_aGroupByExpr[$sColAlias] = $oExpr->RenameParam($sOldName, $sNewName);
  1335. }
  1336. }
  1337. foreach($this->m_aJoinFields as $index => $oExpression)
  1338. {
  1339. $this->m_aJoinFields[$index] = $oExpression->RenameParam($sOldName, $sNewName);
  1340. }
  1341. }
  1342. }