/runtime/lib/query/ModelCriteria.php
PHP | 1613 lines | 715 code | 146 blank | 752 comment | 95 complexity | cf6de279f23db334a43e0fdc6e48c0de MD5 | raw file
- <?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
- */
- /**
- * This class extends the Criteria by adding runtime introspection abilities
- * in order to ease the building of queries.
- *
- * A ModelCriteria requires additional information to be initialized.
- * Using a model name and tablemaps, a ModelCriteria can do more powerful things than a simple Criteria
- *
- * magic methods:
- *
- * @method ModelCriteria leftJoin($relation) Adds a LEFT JOIN clause to the query
- * @method ModelCriteria rightJoin($relation) Adds a RIGHT JOIN clause to the query
- * @method ModelCriteria innerJoin($relation) Adds a INNER JOIN clause to the query
- *
- * @author François Zaninotto
- * @version $Revision$
- * @package propel.runtime.query
- */
- class ModelCriteria extends Criteria
- {
- const MODEL_CLAUSE = "MODEL CLAUSE";
- const MODEL_CLAUSE_ARRAY = "MODEL CLAUSE ARRAY";
- const MODEL_CLAUSE_LIKE = "MODEL CLAUSE LIKE";
- const MODEL_CLAUSE_SEVERAL = "MODEL CLAUSE SEVERAL";
- const FORMAT_STATEMENT = 'PropelStatementFormatter';
- const FORMAT_ARRAY = 'PropelArrayFormatter';
- const FORMAT_OBJECT = 'PropelObjectFormatter';
- const FORMAT_ON_DEMAND = 'PropelOnDemandFormatter';
- protected $modelName;
- protected $modelPeerName;
- protected $modelAlias;
- protected $useAliasInSQL = false;
- protected $tableMap;
- protected $primaryCriteria;
- protected $formatter;
- protected $defaultFormatterClass = ModelCriteria::FORMAT_OBJECT;
- protected $with = array();
- protected $isWithOneToMany = false;
- protected $previousJoin = null; // this is introduced to prevent useQuery->join from going wrong
- protected $isKeepQuery = true; // whether to clone the current object before termination methods
- protected $select = null; // this is for the select method
- /**
- * Creates a new instance with the default capacity which corresponds to
- * the specified database.
- *
- * @param string $dbName The dabase name
- * @param string $modelName The phpName of a model, e.g. 'Book'
- * @param string $modelAlias The alias for the model in this query, e.g. 'b'
- */
- public function __construct($dbName = null, $modelName, $modelAlias = null)
- {
- $this->setDbName($dbName);
- $this->originalDbName = $dbName;
- $this->modelName = $modelName;
- $this->modelPeerName = constant($this->modelName . '::PEER');
- $this->modelAlias = $modelAlias;
- $this->tableMap = Propel::getDatabaseMap($this->getDbName())->getTableByPhpName($this->modelName);
- }
- /**
- * Returns the name of the class for this model criteria
- *
- * @return string
- */
- public function getModelName()
- {
- return $this->modelName;
- }
- /**
- * Sets the alias for the model in this query
- *
- * @param string $modelAlias The model alias
- * @param boolean $useAliasInSQL Whether to use the alias in the SQL code (false by default)
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function setModelAlias($modelAlias, $useAliasInSQL = false)
- {
- if ($useAliasInSQL) {
- $this->addAlias($modelAlias, $this->tableMap->getName());
- $this->useAliasInSQL = true;
- }
- $this->modelAlias = $modelAlias;
- return $this;
- }
- /**
- * Returns the alias of the main class for this model criteria
- *
- * @return string The model alias
- */
- public function getModelAlias()
- {
- return $this->modelAlias;
- }
- /**
- * Return the string to use in a clause as a model prefix for the main model
- *
- * @return string The model alias if it exists, the model name if not
- */
- public function getModelAliasOrName()
- {
- return $this->modelAlias ? $this->modelAlias : $this->modelName;
- }
- /**
- * Returns the name of the Peer class for this model criteria
- *
- * @return string
- */
- public function getModelPeerName()
- {
- return $this->modelPeerName;
- }
- /**
- * Returns the TabkleMap object for this Criteria
- *
- * @return TableMap
- */
- public function getTableMap()
- {
- return $this->tableMap;
- }
- /**
- * Sets the formatter to use for the find() output
- * Formatters must extend PropelFormatter
- * Use the ModelCriteria constants for class names:
- * <code>
- * $c->setFormatter(ModelCriteria::FORMAT_ARRAY);
- * </code>
- *
- * @param string|PropelFormatter $formatter a formatter class name, or a formatter instance
- * @return ModelCriteria The current object, for fluid interface
- */
- public function setFormatter($formatter)
- {
- if(is_string($formatter)) {
- $formatter = new $formatter();
- }
- if (!$formatter instanceof PropelFormatter) {
- throw new PropelException('setFormatter() only accepts classes extending PropelFormatter');
- }
- $this->formatter = $formatter;
- return $this;
- }
- /**
- * Gets the formatter to use for the find() output
- * Defaults to an instance of ModelCriteria::$defaultFormatterClass, i.e. PropelObjectsFormatter
- *
- * @return PropelFormatter
- */
- public function getFormatter()
- {
- if (null === $this->formatter) {
- $formatterClass = $this->defaultFormatterClass;
- $this->formatter = new $formatterClass();
- }
- return $this->formatter;
- }
- /**
- * Adds a condition on a column based on a pseudo SQL clause
- * but keeps it for later use with combine()
- * Until combine() is called, the condition is not added to the query
- * Uses introspection to translate the column phpName into a fully qualified name
- * <code>
- * $c->condition('cond1', 'b.Title = ?', 'foo');
- * </code>
- *
- * @see Criteria::add()
- *
- * @param string $conditionName A name to store the condition for a later combination with combine()
- * @param string $clause The pseudo SQL clause, e.g. 'AuthorId = ?'
- * @param mixed $value A value for the condition
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function condition($conditionName, $clause, $value = null)
- {
- $this->addCond($conditionName, $this->getCriterionForClause($clause, $value), null, null);
- return $this;
- }
- /**
- * Adds a condition on a column based on a column phpName and a value
- * Uses introspection to translate the column phpName into a fully qualified name
- * Warning: recognizes only the phpNames of the main Model (not joined tables)
- * <code>
- * $c->filterBy('Title', 'foo');
- * </code>
- *
- * @see Criteria::add()
- *
- * @param string $column A string representing thecolumn phpName, e.g. 'AuthorId'
- * @param mixed $value A value for the condition
- * @param string $comparison What to use for the column comparison, defaults to Criteria::EQUAL
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function filterBy($column, $value, $comparison = Criteria::EQUAL)
- {
- return $this->add($this->getRealColumnName($column), $value, $comparison);
- }
- /**
- * Adds a list of conditions on the columns of the current model
- * Uses introspection to translate the column phpName into a fully qualified name
- * Warning: recognizes only the phpNames of the main Model (not joined tables)
- * <code>
- * $c->filterByArray(array(
- * 'Title' => 'War And Peace',
- * 'Publisher' => $publisher
- * ));
- * </code>
- *
- * @see filterBy()
- *
- * @param mixed $conditions An array of conditions, using column phpNames as key
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function filterByArray($conditions)
- {
- foreach ($conditions as $column => $args) {
- call_user_func_array(array($this, 'filterBy' . $column), (array) $args);
- }
- return $this;
- }
- /**
- * Adds a condition on a column based on a pseudo SQL clause
- * Uses introspection to translate the column phpName into a fully qualified name
- * <code>
- * // simple clause
- * $c->where('b.Title = ?', 'foo');
- * // named conditions
- * $c->condition('cond1', 'b.Title = ?', 'foo');
- * $c->condition('cond2', 'b.ISBN = ?', 12345);
- * $c->where(array('cond1', 'cond2'), Criteria::LOGICAL_OR);
- * </code>
- *
- * @see Criteria::add()
- *
- * @param mixed $clause A string representing the pseudo SQL clause, e.g. 'Book.AuthorId = ?'
- * Or an array of condition names
- * @param mixed $value A value for the condition
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function where($clause, $value = null)
- {
- if (is_array($clause)) {
- // where(array('cond1', 'cond2'), Criteria::LOGICAL_OR)
- $criterion = $this->getCriterionForConditions($clause, $value);
- } else {
- // where('Book.AuthorId = ?', 12)
- $criterion = $this->getCriterionForClause($clause, $value);
- }
- $this->addUsingOperator($criterion, null, null);
- return $this;
- }
- /**
- * Adds a condition on a column based on a pseudo SQL clause
- * Uses introspection to translate the column phpName into a fully qualified name
- * <code>
- * // simple clause
- * $c->orWhere('b.Title = ?', 'foo');
- * // named conditions
- * $c->condition('cond1', 'b.Title = ?', 'foo');
- * $c->condition('cond2', 'b.ISBN = ?', 12345);
- * $c->orWhere(array('cond1', 'cond2'), Criteria::LOGICAL_OR);
- * </code>
- *
- * @see Criteria::addOr()
- * @deprecated Use _or()->where() instead
- *
- * @param string $clause The pseudo SQL clause, e.g. 'AuthorId = ?'
- * @param mixed $value A value for the condition
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function orWhere($clause, $value = null)
- {
- return $this
- ->_or()
- ->where($clause, $value);
- }
- /**
- * Adds a having condition on a column based on a pseudo SQL clause
- * Uses introspection to translate the column phpName into a fully qualified name
- * <code>
- * // simple clause
- * $c->having('b.Title = ?', 'foo');
- * // named conditions
- * $c->condition('cond1', 'b.Title = ?', 'foo');
- * $c->condition('cond2', 'b.ISBN = ?', 12345);
- * $c->having(array('cond1', 'cond2'), Criteria::LOGICAL_OR);
- * </code>
- *
- * @see Criteria::addHaving()
- *
- * @param mixed $clause A string representing the pseudo SQL clause, e.g. 'Book.AuthorId = ?'
- * Or an array of condition names
- * @param mixed $value A value for the condition
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function having($clause, $value = null)
- {
- if (is_array($clause)) {
- // having(array('cond1', 'cond2'), Criteria::LOGICAL_OR)
- $criterion = $this->getCriterionForConditions($clause, $value);
- } else {
- // having('Book.AuthorId = ?', 12)
- $criterion = $this->getCriterionForClause($clause, $value);
- }
- $this->addHaving($criterion);
- return $this;
- }
- /**
- * Adds an ORDER BY clause to the query
- * Usability layer on top of Criteria::addAscendingOrderByColumn() and Criteria::addDescendingOrderByColumn()
- * Infers $column and $order from $columnName and some optional arguments
- * Examples:
- * $c->orderBy('Book.CreatedAt')
- * => $c->addAscendingOrderByColumn(BookPeer::CREATED_AT)
- * $c->orderBy('Book.CategoryId', 'desc')
- * => $c->addDescendingOrderByColumn(BookPeer::CATEGORY_ID)
- *
- * @param string $columnName The column to order by
- * @param string $order The sorting order. Criteria::ASC by default, also accepts Criteria::DESC
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function orderBy($columnName, $order = Criteria::ASC)
- {
- list($column, $realColumnName) = $this->getColumnFromName($columnName, false);
- $order = strtoupper($order);
- switch ($order) {
- case Criteria::ASC:
- $this->addAscendingOrderByColumn($realColumnName);
- break;
- case Criteria::DESC:
- $this->addDescendingOrderByColumn($realColumnName);
- break;
- default:
- throw new PropelException('ModelCriteria::orderBy() only accepts Criteria::ASC or Criteria::DESC as argument');
- }
- return $this;
- }
- /**
- * Adds a GROUB BY clause to the query
- * Usability layer on top of Criteria::addGroupByColumn()
- * Infers $column $columnName
- * Examples:
- * $c->groupBy('Book.AuthorId')
- * => $c->addGroupByColumn(BookPeer::AUTHOR_ID)
- *
- * @param string $columnName The column to group by
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function groupBy($columnName)
- {
- list($column, $realColumnName) = $this->getColumnFromName($columnName, false);
- $this->addGroupByColumn($realColumnName);
- return $this;
- }
- /**
- * Adds a GROUB BY clause for all columns of a model to the query
- * Examples:
- * $c->groupBy('Book');
- * => $c->addGroupByColumn(BookPeer::ID);
- * => $c->addGroupByColumn(BookPeer::TITLE);
- * => $c->addGroupByColumn(BookPeer::AUTHOR_ID);
- * => $c->addGroupByColumn(BookPeer::PUBLISHER_ID);
- *
- * @param string $class The class name or alias
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function groupByClass($class)
- {
- if ($class == $this->getModelAliasOrName()) {
- // column of the Criteria's model
- $tableMap = $this->getTableMap();
- } elseif (isset($this->joins[$class])) {
- // column of a relations's model
- $tableMap = $this->joins[$class]->getTableMap();
- } else {
- throw new PropelException('Unknown model or alias ' . $class);
- }
- foreach ($tableMap->getColumns() as $column) {
- if (isset($this->aliases[$class])) {
- $this->addGroupByColumn($class . '.' . $column->getName());
- } else {
- $this->addGroupByColumn($column->getFullyQualifiedName());
- }
- }
- return $this;
- }
- /**
- * Adds a DISTINCT clause to the query
- * Alias for Criteria::setDistinct()
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function distinct()
- {
- $this->setDistinct();
- return $this;
- }
- /**
- * Adds a LIMIT clause (or its subselect equivalent) to the query
- * Alias for Criteria:::setLimit()
- *
- * @param int $limit Maximum number of results to return by the query
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function limit($limit)
- {
- $this->setLimit($limit);
- return $this;
- }
- /**
- * Adds an OFFSET clause (or its subselect equivalent) to the query
- * Alias for of Criteria::setOffset()
- *
- * @param int $offset Offset of the first result to return
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function offset($offset)
- {
- $this->setOffset($offset);
- return $this;
- }
- /**
- * Makes the ModelCriteria return a string, array, or PropelArrayCollection
- * Examples:
- * ArticleQuery::create()->select('Name')->find();
- * => PropelArrayCollection Object ('Foo', 'Bar')
- *
- * ArticleQuery::create()->select('Name')->findOne();
- * => string 'Foo'
- *
- * ArticleQuery::create()->select(array('Id', 'Name'))->find();
- * => PropelArrayCollection Object (
- * array('Id' => 1, 'Name' => 'Foo'),
- * array('Id' => 2, 'Name' => 'Bar')
- * )
- *
- * ArticleQuery::create()->select(array('Id', 'Name'))->findOne();
- * => array('Id' => 1, 'Name' => 'Foo')
- *
- * @param mixed $columnArray A list of column names (e.g. array('Title', 'Category.Name', 'c.Content')) or a single column name (e.g. 'Name')
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function select($columnArray)
- {
- if (!count($columnArray) || $columnArray == '') {
- throw new PropelException('You must ask for at least one column');
- }
- if ($columnArray == '*') {
- $columnArray = array();
- foreach (call_user_func(array($this->modelPeerName, 'getFieldNames'), BasePeer::TYPE_PHPNAME) as $column) {
- $columnArray []= $this->modelName . '.' . $column;
- }
- }
- $this->select = $columnArray;
- return $this;
- }
- /**
- * Retrieves the columns defined by a previous call to select().
- * @see select()
- *
- * @return array|string A list of column names (e.g. array('Title', 'Category.Name', 'c.Content')) or a single column name (e.g. 'Name')
- */
- public function getSelect()
- {
- return $this->select;
- }
- protected function configureSelectColumns()
- {
- if (is_null($this->select)) {
- // leave early
- return;
- }
- // select() needs the PropelSimpleArrayFormatter
- $this->setFormatter('PropelSimpleArrayFormatter');
- // clear only the selectColumns, clearSelectColumns() clears asColumns too
- $this->selectColumns = array();
- // We need to set the primary table name, since in the case that there are no WHERE columns
- // it will be impossible for the BasePeer::createSelectSql() method to determine which
- // tables go into the FROM clause.
- if (!$this->selectQueries) {
- $this->setPrimaryTableName(constant($this->modelPeerName . '::TABLE_NAME'));
- }
- // Add requested columns which are not withColumns
- $columnNames = is_array($this->select) ? $this->select : array($this->select);
- foreach ($columnNames as $columnName) {
- // check if the column was added by a withColumn, if not add it
- if (!array_key_exists($columnName, $this->getAsColumns())) {
- $column = $this->getColumnFromName($columnName);
- // always put quotes around the columnName to be safe, we strip them in the formatter
- $this->addAsColumn('"' . $columnName . '"', $column[1]);
- }
- }
- }
- /**
- * This method returns the previousJoin for this ModelCriteria,
- * by default this is null, but after useQuery this is set the to the join of that use
- *
- * @return Join the previousJoin for this ModelCriteria
- */
- public function getPreviousJoin()
- {
- return $this->previousJoin;
- }
- /**
- * This method sets the previousJoin for this ModelCriteria,
- * by default this is null, but after useQuery this is set the to the join of that use
- *
- * @param Join $previousJoin The previousJoin for this ModelCriteria
- */
- public function setPreviousJoin(Join $previousJoin)
- {
- $this->previousJoin = $previousJoin;
- }
- /**
- * This method returns an already defined join clause from the query
- *
- * @param string $name The name of the join clause
- *
- * @return Join A join object
- */
- public function getJoin($name)
- {
- return $this->joins[$name];
- }
- /**
- * Adds a JOIN clause to the query
- * Infers the ON clause from a relation name
- * Uses the Propel table maps, based on the schema, to guess the related columns
- * Beware that the default JOIN operator is INNER JOIN, while Criteria defaults to WHERE
- * Examples:
- * <code>
- * $c->join('Book.Author');
- * => $c->addJoin(BookPeer::AUTHOR_ID, AuthorPeer::ID, Criteria::INNER_JOIN);
- * $c->join('Book.Author', Criteria::RIGHT_JOIN);
- * => $c->addJoin(BookPeer::AUTHOR_ID, AuthorPeer::ID, Criteria::RIGHT_JOIN);
- * $c->join('Book.Author a', Criteria::RIGHT_JOIN);
- * => $c->addAlias('a', AuthorPeer::TABLE_NAME);
- * => $c->addJoin(BookPeer::AUTHOR_ID, 'a.ID', Criteria::RIGHT_JOIN);
- * </code>
- *
- * @param string $relation Relation to use for the join
- * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join'
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function join($relation, $joinType = Criteria::INNER_JOIN)
- {
- // relation looks like '$leftName.$relationName $relationAlias'
- list($fullName, $relationAlias) = self::getClassAndAlias($relation);
- if (strpos($fullName, '.') === false) {
- // simple relation name, refers to the current table
- $leftName = $this->getModelAliasOrName();
- $relationName = $fullName;
- $previousJoin = $this->getPreviousJoin();
- $tableMap = $this->getTableMap();
- } else {
- list($leftName, $relationName) = explode('.', $fullName);
- // find the TableMap for the left table using the $leftName
- if ($leftName == $this->getModelAliasOrName()) {
- $previousJoin = $this->getPreviousJoin();
- $tableMap = $this->getTableMap();
- } elseif (isset($this->joins[$leftName])) {
- $previousJoin = $this->joins[$leftName];
- $tableMap = $previousJoin->getTableMap();
- } else {
- throw new PropelException('Unknown table or alias ' . $leftName);
- }
- }
- $leftTableAlias = isset($this->aliases[$leftName]) ? $leftName : null;
- // find the RelationMap in the TableMap using the $relationName
- if(!$tableMap->hasRelation($relationName)) {
- throw new PropelException('Unknown relation ' . $relationName . ' on the ' . $leftName .' table');
- }
- $relationMap = $tableMap->getRelation($relationName);
- // create a ModelJoin object for this join
- $join = new ModelJoin();
- $join->setJoinType($joinType);
- if(null !== $previousJoin) {
- $join->setPreviousJoin($previousJoin);
- }
- $join->setRelationMap($relationMap, $leftTableAlias, $relationAlias);
- // add the ModelJoin to the current object
- if($relationAlias !== null) {
- $this->addAlias($relationAlias, $relationMap->getRightTable()->getName());
- $this->addJoinObject($join, $relationAlias);
- } else {
- $this->addJoinObject($join, $relationName);
- }
- return $this;
- }
- /**
- * Add another condition to an already added join
- * @example
- * <code>
- * $query->join('Book.Author');
- * $query->addJoinCondition('Author', 'Book.Title LIKE ?', 'foo%');
- * </code>
- *
- * @param string $name The relation name or alias on which the join was created
- * @param string $clause SQL clause, may contain column and table phpNames
- * @param mixed $value An optional value to bind to the clause
- * @param string $operator The operator to use to add the condition. Defaults to 'AND'
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function addJoinCondition($name, $clause, $value = null, $operator = null)
- {
- if (!isset($this->joins[$name])) {
- throw new PropelException(sprintf('Adding a condition to a nonexistent join, %s. Try calling join() first.', $name));
- }
- $join = $this->joins[$name];
- if (!$join->getJoinCondition() instanceof Criterion) {
- $join->buildJoinCondition($this);
- }
- $criterion = $this->getCriterionForClause($clause, $value);
- $method = $operator === Criteria::LOGICAL_OR ? 'addOr' : 'addAnd';
- $join->getJoinCondition()->$method($criterion);
- return $this;
- }
- /**
- * Replace the condition of an already added join
- * @example
- * <code>
- * $query->join('Book.Author');
- * $query->condition('cond1', 'Book.AuthorId = Author.Id')
- * $query->condition('cond2', 'Book.Title LIKE ?', 'War%')
- * $query->combine(array('cond1', 'cond2'), 'and', 'cond3')
- * $query->setJoinCondition('Author', 'cond3');
- * </code>
- *
- * @param string $name The relation name or alias on which the join was created
- * @param mixed $condition A Criterion object, or a condition name
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function setJoinCondition($name, $condition)
- {
- if (!isset($this->joins[$name])) {
- throw new PropelException(sprintf('Setting a condition to a nonexistent join, %s. Try calling join() first.', $name));
- }
- if ($condition instanceof Criterion) {
- $this->getJoin($name)->setJoinCondition($condition);
- } elseif (isset($this->namedCriterions[$condition])) {
- $this->getJoin($name)->setJoinCondition($this->namedCriterions[$condition]);
- } else {
- throw new PropelException(sprintf('Cannot add condition %s on join %s. setJoinCondition() expects either a Criterion, or a condition added by way of condition()', $condition, $name));
- }
- return $this;
- }
- /**
- * Add a join object to the Criteria
- * @see Criteria::addJoinObject()
- * @param Join $join A join object
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function addJoinObject(Join $join, $name = null)
- {
- if (!in_array($join, $this->joins)) { // compare equality, NOT identity
- if (null === $name) {
- $this->joins[] = $join;
- } else {
- $this->joins[$name] = $join;
- }
- }
- return $this;
- }
- /**
- * Adds a JOIN clause to the query and hydrates the related objects
- * Shortcut for $c->join()->with()
- * <code>
- * $c->joinWith('Book.Author');
- * => $c->join('Book.Author');
- * => $c->with('Author');
- * $c->joinWith('Book.Author a', Criteria::RIGHT_JOIN);
- * => $c->join('Book.Author a', Criteria::RIGHT_JOIN);
- * => $c->with('a');
- * </code>
- *
- * @param string $relation Relation to use for the join
- * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join'
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function joinWith($relation, $joinType = Criteria::INNER_JOIN)
- {
- $this->join($relation, $joinType);
- $this->with(self::getRelationName($relation));
- return $this;
- }
- /**
- * Adds a relation to hydrate together with the main object
- * The relation must be initialized via a join() prior to calling with()
- * Examples:
- * <code>
- * $c->join('Book.Author');
- * $c->with('Author');
- *
- * $c->join('Book.Author a', Criteria::RIGHT_JOIN);
- * $c->with('a');
- * </code>
- * WARNING: on a one-to-many relationship, the use of with() combined with limit()
- * will return a wrong number of results for the related objects
- *
- * @param string $relation Relation to use for the join
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function with($relation)
- {
- if (!isset($this->joins[$relation])) {
- throw new PropelException('Unknown relation name or alias ' . $relation);
- }
- $join = $this->joins[$relation];
- if ($join->getRelationMap()->getType() == RelationMap::MANY_TO_MANY) {
- throw new PropelException('with() does not allow hydration for many-to-many relationships');
- } elseif ($join->getRelationMap()->getType() == RelationMap::ONE_TO_MANY) {
- // For performance reasons, the formatters will use a special routine in this case
- $this->isWithOneToMany = true;
- }
- // check that the columns of the main class are already added (but only if this isn't a useQuery)
- if (!$this->hasSelectClause() && !$this->getPrimaryCriteria()) {
- $this->addSelfSelectColumns();
- }
- // add the columns of the related class
- $this->addRelationSelectColumns($relation);
- // list the join for later hydration in the formatter
- $this->with[$relation] = new ModelWith($join);
- return $this;
- }
- /**
- * Gets the array of ModelWith specifying which objects must be hydrated
- * together with the main object.
- *
- * @see with()
- * @return array
- */
- public function getWith()
- {
- return $this->with;
- }
- /**
- * Sets the array of ModelWith specifying which objects must be hydrated
- * together with the main object.
- *
- * @param array
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function setWith($with)
- {
- $this->with = $with;
- return $this;
- }
- public function isWithOneToMany()
- {
- return $this->isWithOneToMany;
- }
- /**
- * Adds a supplementary column to the select clause
- * These columns can later be retrieved from the hydrated objects using getVirtualColumn()
- *
- * @param string $clause The SQL clause with object model column names
- * e.g. 'UPPER(Author.FirstName)'
- * @param string $name Optional alias for the added column
- * If no alias is provided, the clause is used as a column alias
- * This alias is used for retrieving the column via BaseObject::getVirtualColumn($alias)
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function withColumn($clause, $name = null)
- {
- if (null === $name) {
- $name = str_replace(array('.', '(', ')'), '', $clause);
- }
- $clause = trim($clause);
- $this->replaceNames($clause);
- // check that the columns of the main class are already added (if this is the primary ModelCriteria)
- if (!$this->hasSelectClause() && !$this->getPrimaryCriteria()) {
- $this->addSelfSelectColumns();
- }
- $this->addAsColumn($name, $clause);
- return $this;
- }
- /**
- * Initializes a secondary ModelCriteria object, to be later merged with the current object
- *
- * @see ModelCriteria::endUse()
- * @param string $relationName Relation name or alias
- * @param string $secondCriteriaClass Classname for the ModelCriteria to be used
- *
- * @return ModelCriteria The secondary criteria object
- */
- public function useQuery($relationName, $secondaryCriteriaClass = null)
- {
- if (!isset($this->joins[$relationName])) {
- throw new PropelException('Unknown class or alias ' . $relationName);
- }
- $className = $this->joins[$relationName]->getTableMap()->getPhpName();
- if (null === $secondaryCriteriaClass) {
- $secondaryCriteria = PropelQuery::from($className);
- } else {
- $secondaryCriteria = new $secondaryCriteriaClass();
- }
- if ($className != $relationName) {
- $secondaryCriteria->setModelAlias($relationName, $relationName == $this->joins[$relationName]->getRelationMap()->getName() ? false : true);
- }
- $secondaryCriteria->setPrimaryCriteria($this, $this->joins[$relationName]);
- return $secondaryCriteria;
- }
- /**
- * Finalizes a secondary criteria and merges it with its primary Criteria
- *
- * @see Criteria::mergeWith()
- *
- * @return ModelCriteria The primary criteria object
- */
- public function endUse()
- {
- if (isset($this->aliases[$this->modelAlias])) {
- $this->removeAlias($this->modelAlias);
- }
- $primaryCriteria = $this->getPrimaryCriteria();
- $primaryCriteria->mergeWith($this);
- return $primaryCriteria;
- }
- /**
- * Add the content of a Criteria to the current Criteria
- * In case of conflict, the current Criteria keeps its properties
- * @see Criteria::mergeWith()
- *
- * @param Criteria $criteria The criteria to read properties from
- * @param string $operator The logical operator used to combine conditions
- * Defaults to Criteria::LOGICAL_AND, also accapts Criteria::LOGICAL_OR
- *
- * @return ModelCriteria The primary criteria object
- */
- public function mergeWith(Criteria $criteria, $operator = null)
- {
- parent::mergeWith($criteria, $operator);
- // merge with
- if ($criteria instanceof ModelCriteria) {
- $this->with = array_merge($this->getWith(), $criteria->getWith());
- }
- return $this;
- }
- /**
- * Clear the conditions to allow the reuse of the query object.
- * The ModelCriteria's Model and alias 'all the properties set by construct) will remain.
- *
- * @return ModelCriteria The primary criteria object
- */
- public function clear()
- {
- parent::clear();
- $this->with = array();
- $this->primaryCriteria = null;
- $this->formatter=null;
- return $this;
- }
- /**
- * Sets the primary Criteria for this secondary Criteria
- *
- * @param ModelCriteria $criteria The primary criteria
- * @param Join $previousJoin The previousJoin for this ModelCriteria
- */
- public function setPrimaryCriteria(ModelCriteria $criteria, Join $previousJoin)
- {
- $this->primaryCriteria = $criteria;
- $this->setPreviousJoin($previousJoin);
- }
- /**
- * Gets the primary criteria for this secondary Criteria
- *
- * @return ModelCriteria The primary criteria
- */
- public function getPrimaryCriteria()
- {
- return $this->primaryCriteria;
- }
- /**
- * Adds a Criteria as subQuery in the From Clause.
- *
- * @see Criteria::addSelectQuery()
- *
- * @param Criteria $subQueryCriteria Criteria to build the subquery from
- * @param string $alias alias for the subQuery
- * @param boolean $addAliasAndSelectColumns Set to false if you want to manually add the aliased select columns
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function addSelectQuery(Criteria $subQueryCriteria, $alias = null, $addAliasAndSelectColumns = true)
- {
- if (!$subQueryCriteria->hasSelectClause()) {
- $subQueryCriteria->addSelfSelectColumns();
- }
- parent::addSelectQuery($subQueryCriteria, $alias);
- if ($addAliasAndSelectColumns) {
- // give this query-model same alias as subquery
- if (null === $alias) {
- end($this->selectQueries);
- $alias = key($this->selectQueries);
- }
- $this->setModelAlias($alias, true);
- // so we can add selfSelectColumns
- $this->addSelfSelectColumns();
- }
- return $this;
- }
- /**
- * Adds the select columns for a the current table
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function addSelfSelectColumns()
- {
- call_user_func(array($this->modelPeerName, 'addSelectColumns'), $this, $this->useAliasInSQL ? $this->modelAlias : null);
- return $this;
- }
- /**
- * Adds the select columns for a relation
- *
- * @param string $relation The relation name or alias, as defined in join()
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function addRelationSelectColumns($relation)
- {
- $join = $this->joins[$relation];
- call_user_func(array($join->getTableMap()->getPeerClassname(), 'addSelectColumns'), $this, $join->getRelationAlias());
- return $this;
- }
- /**
- * Returns the class and alias of a string representing a model or a relation
- * e.g. 'Book b' => array('Book', 'b')
- * e.g. 'Book' => array('Book', null)
- *
- * @param string $class The classname to explode
- *
- * @return array list($className, $aliasName)
- */
- public static function getClassAndAlias($class)
- {
- if(strpos($class, ' ') !== false) {
- list($class, $alias) = explode(' ', $class);
- } else {
- $alias = null;
- }
- return array($class, $alias);
- }
- /**
- * Returns the name of a relation from a string.
- * The input looks like '$leftName.$relationName $relationAlias'
- *
- * @param string $relation Relation to use for the join
- * @return string the relationName used in the join
- */
- public static function getRelationName($relation)
- {
- // get the relationName
- list($fullName, $relationAlias) = self::getClassAndAlias($relation);
- if ($relationAlias) {
- $relationName = $relationAlias;
- } elseif (false === strpos($fullName, '.')) {
- $relationName = $fullName;
- } else {
- list($leftName, $relationName) = explode('.', $fullName);
- }
- return $relationName;
- }
- /**
- * Triggers the automated cloning on termination.
- * By default, temrination methods don't clone the current object,
- * even though they modify it. If the query must be reused after termination,
- * you must call this method prior to temrination.
- *
- * @param boolean $isKeepQuery
- *
- * @return ModelCriteria The current object, for fluid interface
- */
- public function keepQuery($isKeepQuery = true)
- {
- $this->isKeepQuery = (bool) $isKeepQuery;
- return $this;
- }
- /**
- * Checks whether the automated cloning on termination is enabled.
- *
- * @return boolean true if cloning must be done before termination
- */
- public function isKeepQuery()
- {
- return $this->isKeepQuery;
- }
- /**
- * Code to execute before every SELECT statement
- *
- * @param PropelPDO $con The connection object used by the query
- */
- protected function basePreSelect(PropelPDO $con)
- {
- return $this->preSelect($con);
- }
- protected function preSelect(PropelPDO $con)
- {
- }
- /**
- * Issue a SELECT query based on the current ModelCriteria
- * and format the list of results with the current formatter
- * By default, returns an array of model objects
- *
- * @param PropelPDO $con an optional connection object
- *
- * @return PropelObjectCollection|array|mixed the list of results, formatted by the current formatter
- */
- public function find($con = null)
- {
- $criteria = $this->isKeepQuery() ? clone $this : $this;
- $stmt = $criteria->getSelectStatement($con);
- return $criteria->getFormatter()->init($criteria)->format($stmt);
- }
- /**
- * Issue a SELECT ... LIMIT 1 query based on the current ModelCriteria
- * and format the result with the current formatter
- * By default, returns a model object
- *
- * @param PropelPDO $con an optional connection object
- *
- * @return mixed the result, formatted by the current formatter
- */
- public function findOne($con = null)
- {
- $criteria = $this->isKeepQuery() ? clone $this : $this;
- $criteria->limit(1);
- $stmt = $criteria->getSelectStatement($con);
- return $criteria->getFormatter()->init($criteria)->formatOne($stmt);
- }
- /**
- * Issue a SELECT ... LIMIT 1 query based on the current ModelCriteria
- * and format the result with the current formatter
- * By default, returns a model object
- *
- * @param PropelPDO $con an optional connection object
- *
- * @return mixed the result, formatted by the current formatter
- */
- public function findOneOrCreate($con = null)
- {
- $criteria = $this->isKeepQuery() ? clone $this : $this;
- $criteria->limit(1);
- if (!$ret = $criteria->findOne($con)) {
- $class = $this->getModelName();
- $obj = new $class();
- foreach ($this->keys() as $key) {
- $obj->setByName($key, $this->getValue($key), BasePeer::TYPE_COLNAME);
- }
- $ret = $this->getFormatter()->formatRecord($obj);
- }
- return $ret;
- }
- /**
- * Find object by primary key
- * Behaves differently if the model has simple or composite primary key
- * <code>
- * // simple primary key
- * $book = $c->findPk(12, $con);
- * // composite primary key
- * $bookOpinion = $c->findPk(array(34, 634), $con);
- * </code>
- * @param mixed $key Primary key to use for the query
- * @param PropelPDO $con an optional connection object
- *
- * @return mixed the result, formatted by the current formatter
- */
- public function findPk($key, $con = null)
- {
- $pkCols = $this->getTableMap()->getPrimaryKeyColumns();
- if (count($pkCols) == 1) {
- // simple primary key
- $pkCol = $pkCols[0];
- $this->add($pkCol->getFullyQualifiedName(), $key);
- return $this->findOne($con);
- } else {
- // composite primary key
- foreach ($pkCols as $pkCol) {
- $keyPart = array_shift($key);
- $this->add($pkCol->getFullyQualifiedName(), $keyPart);
- }
- return $this->findOne($con);
- }
- }
- /**
- * Find objects by primary key
- * Behaves differently if the model has simple or composite primary key
- * <code>
- * // simple primary key
- * $books = $c->findPks(array(12, 56, 832), $con);
- * // composite primary key
- * $bookOpinion = $c->findPks(array(array(34, 634), array(45, 518), array(34, 765)), $con);
- * </code>
- * @param array $keys Primary keys to use for the query
- * @param PropelPDO $con an optional connection object
- *
- * @return mixed the list of results, formatted by the current formatter
- */
- public function findPks($keys, $con = null)
- {
- $pkCols = $this->getTableMap()->getPrimaryKeyColumns();
- if (count($pkCols) == 1) {
- // simple primary key
- $pkCol = array_shift($pkCols);
- $this->add($pkCol->getFullyQualifiedName(), $keys, Criteria::IN);
- } else {
- // composite primary key
- throw new PropelException('Multiple object retrieval is not implemented for composite primary keys');
- }
- return $this->find($con);
- }
- protected function getSelectStatement($con = null)
- {
- $dbMap = Propel::getDatabaseMap($this->getDbName());
- $db = Propel::getDB($this->getDbName());
- if ($con === null) {
- $con = Propel::getConnection($this->getDbName(), Propel::CONNECTION_READ);
- }
- // check that the columns of the main class are already added (if this is the primary ModelCriteria)
- if (!$this->hasSelectClause() && !$this->getPrimaryCriteria()) {
- $this->addSelfSelectColumns();
- }
- $this->configureSelectColumns();
- try {
- $this->basePreSelect($con);
- $params = array();
- $sql = BasePeer::createSelectSql($this, $params);
- $stmt = $con->prepare($sql);
- $db->bindValues($stmt, $params, $dbMap);
- $stmt->execute();
- } catch (Exception $e) {
- if (isset($stmt)) {
- $stmt = null; // close
- }
- Propel::log($e->getMessage(), Propel::LOG_ERR);
- throw new PropelException(sprintf('Unable to execute SELECT statement [%s]', $sql), $e);
- }
- return $stmt;
- }
- /**
- * Apply a condition on a column and issues the SELECT query
- *
- * @see filterBy()
- * @see find()
- *
- * @param string $column A string representing the column phpName, e.g. 'AuthorId'
- * @param mixed $value A value for the condition
- * @param PropelPDO $con An optional connection object
- *
- * @return mixed the list of results, formatted by the current formatter
- */
- public function findBy($column, $value, $con = null)
- {
- $method = 'filterBy' . $column;
- $this->$method($value);
- return $this->find($con);
- }
- /**
- * Apply a list of conditions on columns and issues the SELECT query
- * <code>
- * $c->findByArray(array(
- * 'Title' => 'War And Peace',
- * 'Publisher' => $publisher
- * ), $con);
- * </code>
- *
- * @see filterByArray()
- * @see find()
- *
- * @param mixed $conditions An array of conditions, using column phpNames as key
- * @param PropelPDO $con an optional connection object
- *
- * @return mixed the list of results, formatted by the current formatter
- */
- public function findByArray($conditions, $con = null)
- {
- $this->filterByArray($conditions);
- return $this->find($con);
- }
- /**
- * Apply a condition on a column and issues the SELECT ... LIMIT 1 query
- *
- * @see filterBy()
- * @see findOne()
- *
- * @param mixed $column A string representing thecolumn phpName, e.g. 'AuthorId'
- * @param mixed $value A value for the condition
- * @param PropelPDO $con an optional connection object
- *
- * @return mixed the result, formatted by the current formatter
- */
- public function findOneBy($column, $value, $con = null)
- {
- $method = 'filterBy' . $column;
- $this->$method($value);
- return $this->findOne($con);
- }
- /**
- * Apply a list of conditions on columns and issues the SELECT ... LIMIT 1 query
- * <code>
- * $c->findOneByArray(array(
- * 'Title' => 'War And Peace',
- * 'Publisher' => $publisher
- * ), $con);
- * </code>
- *
- * @see filterByArray()
- * @see findOne()
- *
- * @param mixed $conditions An array of conditions, using column phpNames as key
- * @param PropelPDO $con an optional connection object
- *
- * @return mixed the list of results, formatted by the current formatter
- */
- public function findOneByArray($conditions, $con = null)
- {
- $this->filterByArray($conditions);
- return $this->findOne($con);
- }
- /**
- * Issue a SELECT COUNT(*) query based on the current ModelCriteria
- *
- * @param PropelPDO $con an optional connection object
- *
- * @return integer the number of results
- */
- public function count($con = null)
- {
- if ($con === null) {
- $con = Propel::getConnection($this->getDbName(), Propel::CONNECTION_READ);
- }
- $criteria = $this->isKeepQuery() ? clone $this : $this;
- $criteria->setDbName($this->getDbName()); // Set the correct dbName
- $criteria->clearOrderByColumns(); // ORDER BY won't ever affect the count
- // We need to set the primary table name, since in the case that there are no WHERE columns
- // it will be impossible for the BasePeer::createSelectSql() method to determine which
- // tables go into the FROM clause.
- $criteria->setPrimaryTableName(constant($this->modelPeerName.'::TABLE_NAME'));
- $stmt = $criteria->getCountStatement($con);
- if ($row = $stmt->fetch(PDO::FETCH_NUM)) {
- $count = (int) $row[0];
- } else {
- $count = 0; // no rows returned; we infer that means 0 matches.
- }
- $stmt->closeCursor();
- return $count;
- }
- protected function getCountStatement($con = null)
- {
- $dbMap = Propel::getDatabaseMap($this->getDbName());
- $db = Propel::getDB($this->getDbName());
- if ($con === null) {
- $con = Propel::getConnection($this->getDbName(), Propel::CONNECTION_READ);
- }
- // check that the columns of the main class are already added (if this is the primary ModelCriteria)
- if (!$this->hasSelectClause() && !$this->getPrimaryCriteria()) {
- $this->addSelfSelectColumns();
- }
- $this->configureSelectColumns();
- $needsComplexCount = $this->getGroupByColumns()
- || $this->getOffset()
- || $this->getLimit()
- || $this->getHaving()
- || in_array(Criteria::DISTINCT, $this->getSelectModifiers());
- try {
- $this->basePreSelect($con);
- $params = array();
- if ($needsComplexCount) {
- if (BasePeer::needsSelectAliases($this)) {
- if ($this->getHaving()) {
- throw new PropelException('Propel cannot create a COUNT query when using HAVING and duplicate column names in the SELECT part');
- }
- $db->turnSelectColumnsToAliases($this);
- }
- $selectSql = BasePeer::createSelectSql($this, $params);
- $sql = 'SELECT COUNT(*) FROM (' . $selectSql . ') propelmatch4cnt';
- } else {
- // Replace SELECT columns with COUNT(*)
- $this->clearSelectColumns()->addSelectColumn('COUNT(*)');
- $sql = BasePeer::createSelectSql($this, $params);
- }
- $stmt = $con->prepare($sql);
- $db->bindValues($stmt, $params, $dbMap);
- $stmt->execute();
- } catch (PropelException $e) {
- if ($stmt) {
- $stmt = null; // close
- }
- Propel::log($e->getMessage(), Propel::LOG_ERR);
- throw new PropelException(sprintf('Unable to execute COUNT statement [%s]', $sql), $e);
- }
- return $stmt;
- }
- /**
- * Issue a SELECT query based on the current ModelCriteria
- * and uses a page and a maximum number of results per page
- * to compute an offet and a limit.
- *
- * @param int $page number of the page to start the pager on. Page 1 means no offset
- * @param int $maxPerPage maximum number of results per page. Determines the limit
- * @param PropelPDO $con an optional connection object
- *
- * @return PropelModelPager a pager object, supporting iteration
- */
- public function paginate($page = 1, $maxPerPage = 10, $con = null)
- {
- $criteria = $this->isKeepQuery() ? clone $this : $this;
- $pager = new PropelModelPager($criteria, $maxPerPage);
- $pager->setPage($page);
- $pager->init($con);
- return $pager;
- }
- /**
- * Code to execute before every DELETE statement
- *
- * @param PropelPDO $con The connection object used by the query
- */
- protected function basePreDelete(PropelPDO $con)
- {
- return $this->preDelete($con);
- }
- protected function preDelete(PropelPDO $con)
- {
- }
- /**
- * Code to execute after every DELETE statement
- *
- * @param int $affectedRows the number of deleted rows
- * @param PropelPDO $con The connection object used by the query
- */
- protected function basePostDelete($affectedRows, PropelPDO $con)
- {
- return $this->postDelete($affectedRows, $con);
- }
- protected function postDelete($affectedRows, PropelPDO $con)
- {
- }
- /**
- * Issue a DELETE query based on the current ModelCriteria
- * An optional hook on basePreDelete() can prevent the actual deletion
- *
- * @param PropelPDO $con an optional connection object
- *
- * @return integer the number of deleted rows
- */
- public function delete($con = null)
- {
- if (count($this->getMap()) == 0) {
- throw new PropelException('delete() expects a Criteria with at least one condition. Use deleteAll() to delete all the rows of a table');
- }
- if ($con === null) {
- $con = Propel::getConnection($this->getDbName(), Propel::CONNECTION_WRITE);
- }
- $criteria = $this->isKeepQuery() ? clone $this : $this;
- $criteria->setDbName($this->getDbName());
- $con->beginTransaction();
- try {
- if(!$affectedRows = $criteria->basePreDelete($con)) {
- $affectedRows = $criteria->doDelete($con);
- }
- $criteria->basePostDelete($affectedRows, $con);
- $con->commit();
- } catch (PropelException $e) {
- $con->rollback();
- throw $e;
- }
- return $affectedRows;
- }
- /**
- * Issue a DELETE query based on the current ModelCriteria
- * This method is called by ModelCriteria::delete() inside a transaction
- *
- * @param PropelPDO $con a connection object
- *
- * @return integer the number of deleted rows
- */
- public function doDelete($con)
- {
- $affectedRows = call_user_func(array($this->modelPeerName, 'doDelete'), $this, $con);
- return $affectedRows;
- }
- /**
- * Issue a DELETE query based on the current ModelCriteria deleting all rows in the table
- * An optional hook on basePreDelete() can prevent the actual deletion
- *
- * @param PropelPDO $con an optional connection object
- *
- * @return integer the number of deleted rows
- */
- public function deleteAll($con = null)
- {
- if ($con === null) {
- $con = Propel::getConnection($this->getDbName(), Propel::CONNECTION_WRITE);
- }
- $con->beginTransaction();
- try {
- if(!$affectedRows = $this->basePreDelete($con)) {
- $affectedRows = $this->doDeleteAll($con);
- }
- $this->basePostDelete($affectedRows, $con);
- $con->commit();
- return $affectedRows;
- } catch (PropelException $e) {
- $con->rollBack();
- throw $e;
- }
- return $affectedRows;
- }
- /**
- * Issue a DELETE query based on the current ModelCriteria deleting all rows in the table
- * This method is called by ModelCriteria::deleteAll() inside a transaction
- *
- * @param PropelPDO $con a connection object
- *
- * @return integer the number of deleted rows
- */
- public function doDeleteAll($con)
- {
- $affectedRows = call_user_func(array($this->modelPeerName, 'doDeleteAll'), $con);
- return $affectedRows;
- }
- /**
- * Code to execute before every UPDATE statement
- *
- * @param array $values The associatiove array of columns and values for the update
- * @param PropelPDO $con The connection object used by the query
- * @param boolean $forceIndividualSaves If false (default), the resulting call is a BasePeer::doUpdate(), ortherwise it is a series of save() calls on all the found objects
- */
- protected function basePreUpdate(&$values, PropelPDO $con, $forceIndividualSaves = false)
- {
- return $this->preUpdate($values, $con, $forceIndividualSaves);
- }
- protected function preUpdate(&$values, PropelPDO $con, $forceIndividualSaves = false)
- {
- }
- /**
- * Code to execute after every UPDATE statement
- *
- * @param int $affectedRows the number of updated rows
- * @param PropelPDO $con The connection object used by the query
- */
- protected function basePostUpdate($affectedRows, PropelPDO