Permalink
Browse files

Merge pull request #282 from fzaninotto/specialized_criterions

Specialized criterions
  • Loading branch information...
willdurand committed Jul 30, 2012
2 parents ec60c07 + ab1ffa3 commit eaeca7409ce811c2b0d7087c461f08041bdd4fff
@@ -16,6 +16,7 @@
use Propel\Runtime\Query\Criteria;
use Propel\Runtime\Exception\PropelException;
use Propel\Runtime\Adapter\AdapterInterface;
+use Propel\Runtime\Map\ColumnMap;
/**
* This is an "inner" class that describes an object in the criteria.
@@ -29,7 +30,7 @@
const UND = " AND ";
const ODER = " OR ";
- /** Value of the CO. */
+ /** Value of the criterion */
protected $value;
/**
@@ -38,31 +39,43 @@
*/
protected $comparison;
- /** Table name. */
+ /**
+ * Table name
+ * @var string
+ */
protected $table;
- /** Real table name */
+ /**
+ * Real table name
+ * @var string
+ */
protected $realtable;
- /** Column name. */
+ /**
+ * Column name
+ * @var string
+ */
protected $column;
/**
- * The DBAdaptor which might be used to get db specific
+ * The DBAdapter which might be used to get db specific
* variations of sql.
*/
protected $db;
/**
- * other connected criteria and their conjunctions.
+ * Other connected criterons
+ * @var [AbstractCriterion]
*/
protected $clauses = array();
+ /**
+ * Operators for connected criterions
+ * Only self::UND and self::ODER are accepted
+ * @var [String]
+ */
protected $conjunctions = array();
- /** "Parent" Criteria class */
- protected $parent;
-
/**
* Create a new instance.
*
@@ -74,15 +87,7 @@
public function __construct(Criteria $outer, $column, $value, $comparison = null)
{
$this->value = $value;
- $dotPos = strrpos($column, '.');
- if (false === $dotPos) {
- // no dot => aliased column
- $this->table = null;
- $this->column = $column;
- } else {
- $this->table = substr($column, 0, $dotPos);
- $this->column = substr($column, $dotPos + 1);
- }
+ $this->setColumn($column);
$this->comparison = (null === $comparison) ? Criteria::EQUAL : $comparison;
$this->init($outer);
}
@@ -93,7 +98,6 @@ public function __construct(Criteria $outer, $column, $value, $comparison = null
*/
public function init(Criteria $criteria)
{
- // init $this->db
try {
$db = Propel::getServiceContainer()->getAdapter($criteria->getDbName());
$this->setAdapter($db);
@@ -106,7 +110,27 @@ public function init(Criteria $criteria)
// init $this->realtable
$realtable = $criteria->getTableForAlias($this->table);
$this->realtable = $realtable ? $realtable : $this->table;
+ }
+ /**
+ * Set the $column and $table properties based on a column name or object
+ */
+ protected function setColumn($column)
+ {
+ if ($column instanceof ColumnMap) {
+ $this->column = $column->getName();
+ $this->table = $column->getTable()->getName();
+ } else {
+ $dotPos = strrpos($column,'.');
+ if ($dotPos === false) {
+ // no dot => aliased column
+ $this->table = null;
+ $this->column = $column;
+ } else {
+ $this->table = substr($column, 0, $dotPos);
+ $this->column = substr($column, $dotPos+1, strlen($column));
+ }
+ }
}
/**
@@ -240,10 +264,12 @@ public function addOr(AbstractCriterion $criterion)
*/
public function appendPsTo(&$sb, array &$params)
{
+ if (!$this->clauses) {
+ return $this->appendPsForUniqueClauseTo($sb, $params);
+ }
+ // if there are sub criterions, they must be combined to this criterion
$sb .= str_repeat ( '(', count($this->clauses) );
-
$this->appendPsForUniqueClauseTo($sb, $params);
-
foreach ($this->clauses as $key => $clause) {
$sb .= $this->conjunctions[$key];
$clause->appendPsTo($sb, $params);
@@ -301,36 +327,6 @@ public function equals($obj)
return $isEquiv;
}
- /**
- * Returns a hash code value for the object.
- */
- public function hashCode()
- {
- $h = crc32(serialize($this->value)) ^ crc32($this->comparison);
-
- if (null !== $this->table) {
- $h ^= crc32($this->table);
- }
-
- if (null !== $this->column) {
- $h ^= crc32($this->column);
- }
-
- foreach ($this->clauses as $clause) {
- // TODO: i KNOW there is a php incompatibility with the following line
- // but i don't remember what it is, someone care to look it up and
- // replace it if it doesn't bother us?
- // $clause->appendPsTo($sb='',$params=array());
- $sb = '';
- $params = array();
- $clause->appendPsTo($sb,$params);
- $h ^= crc32(serialize(array($sb,$params)));
- unset ($sb, $params);
- }
-
- return $h;
- }
-
/**
* Get all tables from nested criterion objects
* @return array
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * This file is part of the Propel package.
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @license MIT License
+ */
+
+namespace Propel\Runtime\Query\Criterion;
+
+use Propel\Runtime\Query\Criteria;
+
+/**
+ * This is an "inner" class that describes an object in the criteria.
+ *
+ * @author Francois
+ */
+Abstract class AbstractModelCriterion extends AbstractCriterion
+{
+ protected $clause = '';
+
+ /**
+ * Create a new instance.
+ *
+ * @param Criteria $outer The outer class (this is an "inner" class).
+ * @param string $clause A simple pseudo-SQL clause, e.g. 'foo.BAR LIKE ?'
+ * @param ColumnMap $column A Column object to help escaping the value
+ * @param mixed $value
+ * @param string $tableAlias optional table alias
+ */
+ public function __construct(Criteria $outer, $clause, $column, $value = null, $tableAlias = null)
+ {
+ $this->value = $value;
+ $this->setColumn($column);
+ if ($tableAlias) {
+ $this->table = $tableAlias;
+ }
+ $this->clause = $clause;
+ $this->init($outer);
+ }
+
+ public function getClause()
+ {
+ return $this->clause;
+ }
+
+ /**
+ * This method checks another Criteria to see if they contain
+ * the same attributes and hashtable entries.
+ * @return boolean
+ */
+ public function equals($obj)
+ {
+ // TODO: optimize me with early outs
+ if ($this === $obj) {
+ return true;
+ }
+
+ if (null === $obj || !($obj instanceof AbstractModelCriterion)) {
+ return false;
+ }
+
+ $crit = $obj;
+
+ $isEquiv = (((null === $this->table && null === $crit->getTable())
+ || (null !== $this->table && $crit->getTable() === $this->table)
+ )
+ && $this->clause === $crit->getClause()
+ && $this->column === $crit->getColumn()
+ && $this->comparison === $crit->getComparison());
+
+ // check chained criterion
+
+ $clausesLength = count($this->clauses);
+ $isEquiv &= (count($crit->getClauses()) == $clausesLength);
+ $critConjunctions = $crit->getConjunctions();
+ $critClauses = $crit->getClauses();
+ for ($i = 0; $i < $clausesLength && $isEquiv; $i++) {
+ $isEquiv &= ($this->conjunctions[$i] === $critConjunctions[$i]);
+ $isEquiv &= ($this->clauses[$i] === $critClauses[$i]);
+ }
+
+ if ($isEquiv) {
+ $isEquiv &= $this->value === $crit->getValue();
+ }
+
+ return $isEquiv;
+ }
+}
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * This file is part of the Propel package.
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @license MIT License
+ */
+
+namespace Propel\Runtime\Query\Criterion;
+
+use Propel\Runtime\Query\Criterion\Exception\InvalidClauseException;
+
+/**
+ * Specialized ModelCriterion used for traditional expressions,
+ * e.g. table.column = ? or table.column >= ? etc.
+ */
+class BasicModelCriterion extends AbstractModelCriterion
+{
+ /**
+ * Appends a Prepared Statement representation of the ModelCriterion onto the buffer
+ *
+ * @param string &$sb The string that will receive the Prepared Statement
+ * @param array $params A list to which Prepared Statement parameters will be appended
+ */
+ protected function appendPsForUniqueClauseTo(&$sb, array &$params)
+ {
+ if (null !== $this->value) {
+ if (!strpos($this->clause, '?')) {
+ throw new InvalidClauseException('A clause must contain a question mark in order to be bound to a value');
+ }
+ $params[] = array(
+ 'table' => $this->realtable,
+ 'column' => $this->column,
+ 'value' => $this->value
+ );
+ $sb .= str_replace('?', ':p'.count($params), $this->clause);
+ } else {
+ $sb .= $this->clause;
+ }
+ }
+
+}
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * This file is part of the Propel package.
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @license MIT License
+ */
+
+namespace Propel\Runtime\Query\Criterion;
+
+/**
+ * Specialized ModelCriterion used for IN or NOT IN model clauses,
+ * e.g. 'book.TITLE NOT IN ?'
+ */
+class InModelCriterion extends AbstractModelCriterion
+{
+ /**
+ * Appends a Prepared Statement representation of the ModelCriterion onto the buffer
+ *
+ * @param string &$sb The string that will receive the Prepared Statement
+ * @param array $params A list to which Prepared Statement parameters will be appended
+ */
+ protected function appendPsForUniqueClauseTo(&$sb, array &$params)
+ {
+ $bindParams = array(); // the param names used in query building
+ $index = count($params);
+ foreach ((array) $this->value as $value) {
+ $params[] = array(
+ 'table' => $this->realtable,
+ 'column' => $this->column,
+ 'value' => $value
+ );
+ $index++; // increment this first to correct for wanting bind params to start with :p1
+ $bindParams[] = ':p' . $index;
+ }
+ if (count($bindParams)) {
+ $sb .= str_replace('?', '(' . implode(',', $bindParams) . ')', $this->clause);
+ } else {
+ $sb .= (stripos($this->clause, ' NOT IN ') === false) ? "1<>1" : "1=1";
+ }
+ unset($value, $valuesLength);
+ }
+
+}
Oops, something went wrong.

0 comments on commit eaeca74

Please sign in to comment.