PageRenderTime 57ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/runtime/lib/query/Join.php

https://github.com/1989gaurav/Propel
PHP | 560 lines | 485 code | 13 blank | 62 comment | 10 complexity | 9728d05dad3bb7d6baa37bd18bfd5f3a MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the Propel package.
  4. * For the full copyright and license information, please view the LICENSE
  5. * file that was distributed with this source code.
  6. *
  7. * @license MIT License
  8. */
  9. /**
  10. * Data object to describe a join between two tables, for example
  11. * <pre>
  12. * table_a LEFT JOIN table_b ON table_a.id = table_b.a_id
  13. * </pre>
  14. *
  15. * @author Francois Zaninotto (Propel)
  16. * @author Hans Lellelid <hans@xmpl.org> (Propel)
  17. * @author Kaspars Jaudzems <kaspars.jaudzems@inbox.lv> (Propel)
  18. * @author Frank Y. Kim <frank.kim@clearink.com> (Torque)
  19. * @author John D. McNally <jmcnally@collab.net> (Torque)
  20. * @author Brett McLaughlin <bmclaugh@algx.net> (Torque)
  21. * @author Eric Dobbs <eric@dobbse.net> (Torque)
  22. * @author Henning P. Schmiedehausen <hps@intermeta.de> (Torque)
  23. * @author Sam Joseph <sam@neurogrid.com> (Torque)
  24. * @package propel.runtime.query
  25. */
  26. class Join
  27. {
  28. // default comparison type
  29. const EQUAL = "=";
  30. const INNER_JOIN = 'INNER JOIN';
  31. // the left parts of the join condition
  32. protected $left = array();
  33. // the right parts of the join condition
  34. protected $right = array();
  35. // the comparison operators for each pair of columns in the join condition
  36. protected $operator = array();
  37. // the type of the join (LEFT JOIN, ...)
  38. protected $joinType;
  39. // the number of conditions in the join
  40. protected $count = 0;
  41. // the database adapter
  42. protected $db;
  43. protected $leftTableName;
  44. protected $rightTableName;
  45. protected $leftTableAlias;
  46. protected $rightTableAlias;
  47. protected $joinCondition;
  48. /**
  49. * Constructor
  50. * Use it preferably with no arguments, and then use addCondition() and setJoinType()
  51. * Syntax with arguments used mainly for backwards compatibility
  52. *
  53. * @param string $leftColumn The left column of the join condition
  54. * (may contain an alias name)
  55. * @param string $rightColumn The right column of the join condition
  56. * (may contain an alias name)
  57. * @param string $joinType The type of the join. Valid join types are null (implicit join),
  58. * Criteria::LEFT_JOIN, Criteria::RIGHT_JOIN, and Criteria::INNER_JOIN
  59. */
  60. public function __construct($leftColumn = null, $rightColumn = null, $joinType = null)
  61. {
  62. if (null !== $leftColumn) {
  63. if (is_array($leftColumn)) {
  64. // join with multiple conditions
  65. $this->addConditions($leftColumn, $rightColumn);
  66. } else {
  67. // simple join
  68. $this->addCondition($leftColumn, $rightColumn);
  69. }
  70. }
  71. if (null !== $joinType) {
  72. $this->setJoinType($joinType);
  73. }
  74. }
  75. /**
  76. * Join condition definition.
  77. * Warning: doesn't support table aliases. Use the explicit methods to use aliases.
  78. *
  79. * @param string $left The left column of the join condition
  80. * (may contain an alias name)
  81. * @param string $right The right column of the join condition
  82. * (may contain an alias name)
  83. * @param string $operator The comparison operator of the join condition, default Join::EQUAL
  84. */
  85. public function addCondition($left, $right, $operator = self::EQUAL)
  86. {
  87. if ($pos = strrpos($left, '.')) {
  88. list($this->leftTableName, $this->left[]) = explode('.', $left);
  89. } else {
  90. $this->left[] = $left;
  91. }
  92. if ($pos = strrpos($right, '.')) {
  93. list($this->rightTableName, $this->right[]) = explode('.', $right);
  94. } else {
  95. $this->right[] = $right;
  96. }
  97. $this->operator[] = $operator;
  98. $this->count++;
  99. }
  100. /**
  101. * Join condition definition, for several conditions
  102. *
  103. * @param array $lefts The left columns of the join condition
  104. * @param array $rights The right columns of the join condition
  105. * @param array $operators The comparison operators of the join condition, default Join::EQUAL
  106. */
  107. public function addConditions($lefts, $rights, $operators = array())
  108. {
  109. if (count($lefts) != count($rights) ) {
  110. throw new PropelException("Unable to create join because the left column count isn't equal to the right column count");
  111. }
  112. foreach ($lefts as $key => $left) {
  113. $this->addCondition($left, $rights[$key], isset($operators[$key]) ? $operators[$key] : self::EQUAL);
  114. }
  115. }
  116. /**
  117. * Join condition definition.
  118. * @example
  119. * <code>
  120. * $join = new Join();
  121. * $join->setJoinType(Criteria::LEFT_JOIN);
  122. * $join->addExplicitCondition('book', 'AUTHOR_ID', null, 'author', 'ID', 'a', Join::EQUAL);
  123. * echo $join->getClause();
  124. * // LEFT JOIN author a ON (book.AUTHOR_ID=a.ID)
  125. * </code>
  126. *
  127. * @param string $leftTableName
  128. * @param string $leftColumnName
  129. * @param string $leftTableAlias
  130. * @param string $rightTableName
  131. * @param string $rightColumnName
  132. * @param string $rightTableAlias
  133. * @param string $operator The comparison operator of the join condition, default Join::EQUAL
  134. */
  135. public function addExplicitCondition($leftTableName, $leftColumnName, $leftTableAlias = null, $rightTableName, $rightColumnName, $rightTableAlias = null, $operator = self::EQUAL)
  136. {
  137. $this->leftTableName = $leftTableName;
  138. $this->leftTableAlias = $leftTableAlias;
  139. $this->rightTableName = $rightTableName;
  140. $this->rightTableAlias = $rightTableAlias;
  141. $this->left []= $leftColumnName;
  142. $this->right []= $rightColumnName;
  143. $this->operator []= $operator;
  144. $this->count++;
  145. }
  146. /**
  147. * Retrieve the number of conditions in the join
  148. *
  149. * @return integer The number of conditions in the join
  150. */
  151. public function countConditions()
  152. {
  153. return $this->count;
  154. }
  155. /**
  156. * Return an array of the join conditions
  157. *
  158. * @return array An array of arrays representing (left, comparison, right) for each condition
  159. */
  160. public function getConditions()
  161. {
  162. $conditions = array();
  163. for ($i=0; $i < $this->count; $i++) {
  164. $conditions[] = array(
  165. 'left' => $this->getLeftColumn($i),
  166. 'operator' => $this->getOperator($i),
  167. 'right' => $this->getRightColumn($i)
  168. );
  169. }
  170. return $conditions;
  171. }
  172. /**
  173. * @param string $operator the comparison operator for the join condition
  174. */
  175. public function addOperator($operator = null)
  176. {
  177. $this->operator []= $operator;
  178. }
  179. /**
  180. * @return the comparison operator for the join condition
  181. */
  182. public function getOperator($index = 0)
  183. {
  184. return $this->operator[$index];
  185. }
  186. public function getOperators()
  187. {
  188. return $this->operator;
  189. }
  190. /**
  191. * Set the join type
  192. *
  193. * @param string $joinType The type of the join. Valid join types are
  194. * null (adding the join condition to the where clause),
  195. * Criteria::LEFT_JOIN(), Criteria::RIGHT_JOIN(), and Criteria::INNER_JOIN()
  196. */
  197. public function setJoinType($joinType = null)
  198. {
  199. $this->joinType = $joinType;
  200. }
  201. /**
  202. * Get the join type
  203. *
  204. * @return string The type of the join, i.e. Criteria::LEFT_JOIN(), ...,
  205. * or null for adding the join condition to the where Clause
  206. */
  207. public function getJoinType()
  208. {
  209. return null === $this->joinType ? self::INNER_JOIN : $this->joinType;
  210. }
  211. /**
  212. * Add a left column name to the join condition
  213. *
  214. * @example
  215. * <code>
  216. * $join->setLeftTableName('book');
  217. * $join->addLeftColumnName('AUTHOR_ID');
  218. * </code>
  219. * @param string $left The name of the left column to add
  220. */
  221. public function addLeftColumnName($left)
  222. {
  223. $this->left []= $left;
  224. }
  225. /**
  226. * Get the fully qualified name of the left column of the join condition
  227. *
  228. * @example
  229. * <code>
  230. * $join->addCondition('book.AUTHOR_ID', 'author.ID');
  231. * echo $join->getLeftColumn(); // 'book.AUTHOR_ID'
  232. * </code>
  233. * @param integer $index The number of the condition to use
  234. * @return string
  235. */
  236. public function getLeftColumn($index = 0)
  237. {
  238. $tableName = $this->getLeftTableAliasOrName();
  239. return $tableName ? $tableName . '.' . $this->left[$index] : $this->left[$index];
  240. }
  241. /**
  242. * Get the left column name of the join condition
  243. *
  244. * @example
  245. * <code>
  246. * $join->addCondition('book.AUTHOR_ID', 'author.ID');
  247. * echo $join->getLeftColumnName(); // 'AUTHOR_ID'
  248. * </code>
  249. * @param integer $index The number of the condition to use
  250. * @return string
  251. */
  252. public function getLeftColumnName($index = 0)
  253. {
  254. return $this->left[$index];
  255. }
  256. /**
  257. * Get the list of all the names of left columns of the join condition
  258. * @return array
  259. */
  260. public function getLeftColumns()
  261. {
  262. $columns = array();
  263. foreach ($this->left as $index => $column) {
  264. $columns []= $this->getLeftColumn($index);
  265. }
  266. return $columns;
  267. }
  268. public function setLeftTableName($leftTableName)
  269. {
  270. $this->leftTableName = $leftTableName;
  271. return $this;
  272. }
  273. public function getLeftTableName()
  274. {
  275. return $this->leftTableName;
  276. }
  277. public function setLeftTableAlias($leftTableAlias)
  278. {
  279. $this->leftTableAlias = $leftTableAlias;
  280. return $this;
  281. }
  282. public function getLeftTableAlias()
  283. {
  284. return $this->leftTableAlias;
  285. }
  286. public function hasLeftTableAlias()
  287. {
  288. return null !== $this->leftTableAlias;
  289. }
  290. public function getLeftTableAliasOrName()
  291. {
  292. return $this->leftTableAlias ? $this->leftTableAlias : $this->leftTableName;
  293. }
  294. public function getLeftTableWithAlias()
  295. {
  296. return $this->leftTableAlias ? $this->leftTableName . ' ' . $this->leftTableAlias : $this->leftTableName;
  297. }
  298. /**
  299. * Add a right column name to the join condition
  300. *
  301. * @example
  302. * <code>
  303. * $join->setRightTableName('author');
  304. * $join->addRightColumnName('ID');
  305. * </code>
  306. * @param string $right The name of the right column to add
  307. */
  308. public function addRightColumnName($right)
  309. {
  310. $this->right []= $right;
  311. }
  312. /**
  313. * Get the fully qualified name of the right column of the join condition
  314. *
  315. * @example
  316. * <code>
  317. * $join->addCondition('book.AUTHOR_ID', 'author.ID');
  318. * echo $join->getLeftColumn(); // 'author.ID'
  319. * </code>
  320. * @param integer $index The number of the condition to use
  321. * @return string
  322. */
  323. public function getRightColumn($index = 0)
  324. {
  325. $tableName = $this->getRightTableAliasOrName();
  326. return $tableName ? $tableName . '.' . $this->right[$index] : $this->right[$index];
  327. }
  328. /**
  329. * Get the right column name of the join condition
  330. *
  331. * @example
  332. * <code>
  333. * $join->addCondition('book.AUTHOR_ID', 'author.ID');
  334. * echo $join->getLeftColumn(); // 'ID'
  335. * </code>
  336. * @param integer $index The number of the condition to use
  337. * @return string
  338. */
  339. public function getRightColumnName($index = 0)
  340. {
  341. return $this->right[$index];
  342. }
  343. /**
  344. * @return all right columns of the join condition
  345. */
  346. public function getRightColumns()
  347. {
  348. $columns = array();
  349. foreach ($this->right as $index => $column) {
  350. $columns []= $this->getRightColumn($index);
  351. }
  352. return $columns;
  353. }
  354. public function setRightTableName($rightTableName)
  355. {
  356. $this->rightTableName = $rightTableName;
  357. return $this;
  358. }
  359. public function getRightTableName()
  360. {
  361. return $this->rightTableName;
  362. }
  363. public function setRightTableAlias($rightTableAlias)
  364. {
  365. $this->rightTableAlias = $rightTableAlias;
  366. return $this;
  367. }
  368. public function getRightTableAlias()
  369. {
  370. return $this->rightTableAlias;
  371. }
  372. public function hasRightTableAlias()
  373. {
  374. return null !== $this->rightTableAlias;
  375. }
  376. public function getRightTableAliasOrName()
  377. {
  378. return $this->rightTableAlias ? $this->rightTableAlias : $this->rightTableName;
  379. }
  380. public function getRightTableWithAlias()
  381. {
  382. return $this->rightTableAlias ? $this->rightTableName . ' ' . $this->rightTableAlias : $this->rightTableName;
  383. }
  384. /**
  385. * Get the value of db.
  386. * The DBAdapter which might be used to get db specific
  387. * variations of sql.
  388. * @return DBAdapter value of db.
  389. */
  390. public function getDB()
  391. {
  392. return $this->db;
  393. }
  394. /**
  395. * Set the value of db.
  396. * The DBAdapter might be used to get db specific variations of sql.
  397. * @param DBAdapter $db Value to assign to db.
  398. * @return void
  399. */
  400. public function setDB(DBAdapter $db)
  401. {
  402. $this->db = $db;
  403. }
  404. /**
  405. * Set a custom join condition
  406. *
  407. * @param Criterion $joinCondition a Join condition
  408. */
  409. public function setJoinCondition(Criterion $joinCondition)
  410. {
  411. $this->joinCondition = $joinCondition;
  412. }
  413. /**
  414. * Get the custom join condition, if previously set
  415. *
  416. * @return Criterion
  417. */
  418. public function getJoinCondition()
  419. {
  420. return $this->joinCondition;
  421. }
  422. /**
  423. * Set the custom join condition Criterion based on the conditions of this join
  424. *
  425. * @param Criteria $c A Criteria object to get Criterions from
  426. */
  427. public function buildJoinCondition(Criteria $c)
  428. {
  429. $joinCondition = null;
  430. for ($i=0; $i < $this->count; $i++) {
  431. $criterion = $c->getNewCriterion($this->getLeftColumn($i), $this->getLeftColumn($i) . $this->getOperator($i) . $this->getRightColumn($i), Criteria::CUSTOM);
  432. if (null === $joinCondition) {
  433. $joinCondition = $criterion;
  434. } else {
  435. $joinCondition = $joinCondition->addAnd($criterion);
  436. }
  437. }
  438. $this->joinCondition = $joinCondition;
  439. }
  440. /**
  441. * Get the join clause for this Join.
  442. * If the join condition needs binding, uses the passed params array.
  443. * @example
  444. * <code>
  445. * $join = new Join();
  446. * $join->addExplicitCondition('book', 'AUTHOR_ID', null, 'author', 'ID');
  447. * $params = array();
  448. * echo $j->getClause($params);
  449. * // 'LEFT JOIN author ON (book.AUTHOR_ID=author.ID)'
  450. * </code>
  451. *
  452. * @param array &$params
  453. *
  454. * @return string SQL join clause with join condition
  455. */
  456. public function getClause(&$params)
  457. {
  458. if (null === $this->joinCondition) {
  459. $conditions = array();
  460. for ($i=0; $i < $this->count; $i++) {
  461. $conditions []= $this->getLeftColumn($i) . $this->getOperator($i) . $this->getRightColumn($i);
  462. }
  463. $joinCondition = sprintf('(%s)', implode($conditions, ' AND '));
  464. } else {
  465. $joinCondition = '';
  466. $this->getJoinCondition()->appendPsTo($joinCondition, $params);
  467. }
  468. $rightTableName = $this->getRightTableWithAlias();
  469. if (null !== $this->db && $this->db->useQuoteIdentifier()) {
  470. $rightTableName = $this->db->quoteIdentifierTable($rightTableName);
  471. }
  472. return sprintf('%s %s ON %s',
  473. $this->getJoinType(),
  474. $rightTableName,
  475. $joinCondition
  476. );
  477. }
  478. public function equals($join)
  479. {
  480. return $join !== null
  481. && $join instanceof Join
  482. && $this->joinType == $join->getJoinType()
  483. && $this->getConditions() == $join->getConditions();
  484. }
  485. /**
  486. * Returns a String representation of the class,
  487. *
  488. * @return string A String representation of the class
  489. */
  490. public function toString()
  491. {
  492. $params = array();
  493. return $this->getClause($params);
  494. }
  495. public function __toString()
  496. {
  497. return $this->toString();
  498. }
  499. }