PageRenderTime 41ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/runtime/lib/query/ModelCriterion.php

https://github.com/1989gaurav/Propel
PHP | 283 lines | 163 code | 24 blank | 96 comment | 29 complexity | 59d00e556db00007e50a8dfbe05b5e95 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. * This is an "inner" class that describes an object in the criteria.
  11. *
  12. * @author Francois
  13. * @version $Revision$
  14. * @package propel.runtime.query
  15. */
  16. class ModelCriterion extends Criterion
  17. {
  18. protected $clause = '';
  19. /**
  20. * Create a new instance.
  21. *
  22. * @param Criteria $parent The outer class (this is an "inner" class).
  23. * @param ColumnMap $column A Column object to help escaping the value
  24. * @param mixed $value
  25. * @param string $comparison, among ModelCriteria::MODEL_CLAUSE
  26. * @param string $clause A simple pseudo-SQL clause, e.g. 'foo.BAR LIKE ?'
  27. */
  28. public function __construct(Criteria $outer, $column, $value = null, $comparison = ModelCriteria::MODEL_CLAUSE, $clause)
  29. {
  30. $this->value = $value;
  31. if ($column instanceof ColumnMap) {
  32. $this->column = $column->getName();
  33. $this->table = $column->getTable()->getName();
  34. } else {
  35. $dotPos = strrpos($column,'.');
  36. if ($dotPos === false) {
  37. // no dot => aliased column
  38. $this->table = null;
  39. $this->column = $column;
  40. } else {
  41. $this->table = substr($column, 0, $dotPos);
  42. $this->column = substr($column, $dotPos+1, strlen($column));
  43. }
  44. }
  45. $this->comparison = ($comparison === null ? Criteria::EQUAL : $comparison);
  46. $this->clause = $clause;
  47. $this->init($outer);
  48. }
  49. public function getClause()
  50. {
  51. return $this->clause;
  52. }
  53. /**
  54. * Figure out which MocelCriterion method to use
  55. * to build the prepared statement and parameters using to the Criterion comparison
  56. * and call it to append the prepared statement and the parameters of the current clause.
  57. * For performance reasons, this method tests the cases of parent::dispatchPsHandling()
  58. * first, and that is not possible through inheritance ; that's why the parent
  59. * code is duplicated here.
  60. *
  61. * @param string &$sb The string that will receive the Prepared Statement
  62. * @param array $params A list to which Prepared Statement parameters will be appended
  63. */
  64. protected function dispatchPsHandling(&$sb, array &$params)
  65. {
  66. switch ($this->comparison) {
  67. case Criteria::CUSTOM:
  68. // custom expression with no parameter binding
  69. $this->appendCustomToPs($sb, $params);
  70. break;
  71. case Criteria::IN:
  72. case Criteria::NOT_IN:
  73. // table.column IN (?, ?) or table.column NOT IN (?, ?)
  74. $this->appendInToPs($sb, $params);
  75. break;
  76. case Criteria::LIKE:
  77. case Criteria::NOT_LIKE:
  78. case Criteria::ILIKE:
  79. case Criteria::NOT_ILIKE:
  80. // table.column LIKE ? or table.column NOT LIKE ? (or ILIKE for Postgres)
  81. $this->appendLikeToPs($sb, $params);
  82. break;
  83. case ModelCriteria::MODEL_CLAUSE:
  84. // regular model clause, e.g. 'book.TITLE = ?'
  85. $this->appendModelClauseToPs($sb, $params);
  86. break;
  87. case ModelCriteria::MODEL_CLAUSE_LIKE:
  88. // regular model clause, e.g. 'book.TITLE = ?'
  89. $this->appendModelClauseLikeToPs($sb, $params);
  90. break;
  91. case ModelCriteria::MODEL_CLAUSE_SEVERAL:
  92. // Ternary model clause, e.G 'book.ID BETWEEN ? AND ?'
  93. $this->appendModelClauseSeveralToPs($sb, $params);
  94. break;
  95. case ModelCriteria::MODEL_CLAUSE_ARRAY:
  96. // IN or NOT IN model clause, e.g. 'book.TITLE NOT IN ?'
  97. $this->appendModelClauseArrayToPs($sb, $params);
  98. break;
  99. default:
  100. // table.column = ? or table.column >= ? etc. (traditional expressions, the default)
  101. $this->appendBasicToPs($sb, $params);
  102. }
  103. }
  104. /**
  105. * Appends a Prepared Statement representation of the ModelCriterion onto the buffer
  106. * For regular model clauses, e.g. 'book.TITLE = ?'
  107. *
  108. * @param string &$sb The string that will receive the Prepared Statement
  109. * @param array $params A list to which Prepared Statement parameters will be appended
  110. */
  111. public function appendModelClauseToPs(&$sb, array &$params)
  112. {
  113. if ($this->value !== null) {
  114. $params[] = array('table' => $this->realtable, 'column' => $this->column, 'value' => $this->value);
  115. $sb .= str_replace('?', ':p'.count($params), $this->clause);
  116. } else {
  117. $sb .= $this->clause;
  118. }
  119. }
  120. /**
  121. * Appends a Prepared Statement representation of the ModelCriterion onto the buffer
  122. * For LIKE model clauses, e.g. 'book.TITLE LIKE ?'
  123. * Handles case insensitivity for VARCHAR columns
  124. *
  125. * @param string &$sb The string that will receive the Prepared Statement
  126. * @param array $params A list to which Prepared Statement parameters will be appended
  127. */
  128. public function appendModelClauseLikeToPs(&$sb, array &$params)
  129. {
  130. // LIKE is case insensitive in mySQL and SQLite, but not in PostGres
  131. // If the column is case insensitive, use ILIKE / NOT ILIKE instead of LIKE / NOT LIKE
  132. if ($this->ignoreStringCase && $this->getDb() instanceof DBPostgres) {
  133. $this->clause = preg_replace('/LIKE \?$/i', 'ILIKE ?', $this->clause);
  134. }
  135. $this->appendModelClauseToPs($sb, $params);
  136. }
  137. /**
  138. * Appends a Prepared Statement representation of the ModelCriterion onto the buffer
  139. * For ternary model clauses, e.G 'book.ID BETWEEN ? AND ?'
  140. *
  141. * @param string &$sb The string that will receive the Prepared Statement
  142. * @param array $params A list to which Prepared Statement parameters will be appended
  143. */
  144. public function appendModelClauseSeveralToPs(&$sb, array &$params)
  145. {
  146. $clause = $this->clause;
  147. foreach ((array) $this->value as $value) {
  148. if ($value === null) {
  149. // FIXME we eventually need to translate a BETWEEN to
  150. // something like WHERE (col < :p1 OR :p1 IS NULL) AND (col < :p2 OR :p2 IS NULL)
  151. // in order to support null values
  152. throw new PropelException('Null values are not supported inside BETWEEN clauses');
  153. }
  154. $params[] = array('table' => $this->realtable, 'column' => $this->column, 'value' => $value);
  155. $clause = self::strReplaceOnce('?', ':p'.count($params), $clause);
  156. }
  157. $sb .= $clause;
  158. }
  159. /**
  160. * Appends a Prepared Statement representation of the ModelCriterion onto the buffer
  161. * For IN or NOT IN model clauses, e.g. 'book.TITLE NOT IN ?'
  162. *
  163. * @param string &$sb The string that will receive the Prepared Statement
  164. * @param array $params A list to which Prepared Statement parameters will be appended
  165. */
  166. public function appendModelClauseArrayToPs(&$sb, array &$params)
  167. {
  168. $_bindParams = array(); // the param names used in query building
  169. $_idxstart = count($params);
  170. $valuesLength = 0;
  171. foreach ( (array) $this->value as $value ) {
  172. $valuesLength++; // increment this first to correct for wanting bind params to start with :p1
  173. $params[] = array('table' => $this->realtable, 'column' => $this->column, 'value' => $value);
  174. $_bindParams[] = ':p'.($_idxstart + $valuesLength);
  175. }
  176. if ($valuesLength !== 0) {
  177. $sb .= str_replace('?', '(' . implode(',', $_bindParams) . ')', $this->clause);
  178. } else {
  179. $sb .= (stripos($this->clause, ' NOT IN ') === false) ? "1<>1" : "1=1";
  180. }
  181. unset ( $value, $valuesLength );
  182. }
  183. /**
  184. * This method checks another Criteria to see if they contain
  185. * the same attributes and hashtable entries.
  186. * @return boolean
  187. */
  188. public function equals($obj)
  189. {
  190. // TODO: optimize me with early outs
  191. if ($this === $obj) {
  192. return true;
  193. }
  194. if (($obj === null) || !($obj instanceof ModelCriterion)) {
  195. return false;
  196. }
  197. $crit = $obj;
  198. $isEquiv = ( ( ($this->table === null && $crit->getTable() === null)
  199. || ( $this->table !== null && $this->table === $crit->getTable() )
  200. )
  201. && $this->clause === $crit->getClause()
  202. && $this->column === $crit->getColumn()
  203. && $this->comparison === $crit->getComparison());
  204. // check chained criterion
  205. $clausesLength = count($this->clauses);
  206. $isEquiv &= (count($crit->getClauses()) == $clausesLength);
  207. $critConjunctions = $crit->getConjunctions();
  208. $critClauses = $crit->getClauses();
  209. for ($i=0; $i < $clausesLength && $isEquiv; $i++) {
  210. $isEquiv &= ($this->conjunctions[$i] === $critConjunctions[$i]);
  211. $isEquiv &= ($this->clauses[$i] === $critClauses[$i]);
  212. }
  213. if ($isEquiv) {
  214. $isEquiv &= $this->value === $crit->getValue();
  215. }
  216. return $isEquiv;
  217. }
  218. /**
  219. * Returns a hash code value for the object.
  220. */
  221. public function hashCode()
  222. {
  223. $h = crc32(serialize($this->value)) ^ crc32($this->comparison) ^ crc32($this->clause);
  224. if ($this->table !== null) {
  225. $h ^= crc32($this->table);
  226. }
  227. if ($this->column !== null) {
  228. $h ^= crc32($this->column);
  229. }
  230. foreach ( $this->clauses as $clause ) {
  231. // TODO: i KNOW there is a php incompatibility with the following line
  232. // but i dont remember what it is, someone care to look it up and
  233. // replace it if it doesnt bother us?
  234. // $clause->appendPsTo($sb='',$params=array());
  235. $sb = '';
  236. $params = array();
  237. $clause->appendPsTo($sb,$params);
  238. $h ^= crc32(serialize(array($sb,$params)));
  239. unset ( $sb, $params );
  240. }
  241. return $h;
  242. }
  243. /**
  244. * Replace only once
  245. * taken from http://www.php.net/manual/en/function.str-replace.php
  246. *
  247. */
  248. protected static function strReplaceOnce($search, $replace, $subject)
  249. {
  250. $firstChar = strpos($subject, $search);
  251. if($firstChar !== false) {
  252. $beforeStr = substr($subject,0,$firstChar);
  253. $afterStr = substr($subject, $firstChar + strlen($search));
  254. return $beforeStr.$replace.$afterStr;
  255. } else {
  256. return $subject;
  257. }
  258. }
  259. }