/library/Doctrine/Doctrine/Query/Abstract.php
PHP | 2162 lines | 1135 code | 208 blank | 819 comment | 133 complexity | cd09e94e643c03d2c5c34c46630c8d60 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- <?php
- /*
- * $Id: Query.php 1393 2007-05-19 17:49:16Z zYne $
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * This software consists of voluntary contributions made by many individuals
- * and is licensed under the LGPL. For more information, see
- * <http://www.phpdoctrine.org>.
- */
-
- /**
- * Doctrine_Query_Abstract
- *
- * @package Doctrine
- * @subpackage Query
- * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
- * @link www.phpdoctrine.org
- * @since 1.0
- * @version $Revision: 1393 $
- * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
- * @todo See {@link Doctrine_Query}
- */
- abstract class Doctrine_Query_Abstract
- {
- /**
- * QUERY TYPE CONSTANTS
- */
-
- /**
- * constant for SELECT queries
- */
- const SELECT = 0;
-
- /**
- * constant for DELETE queries
- */
- const DELETE = 1;
-
- /**
- * constant for UPDATE queries
- */
- const UPDATE = 2;
-
- /**
- * constant for INSERT queries
- */
- const INSERT = 3;
-
- /**
- * constant for CREATE queries
- */
- const CREATE = 4;
-
- /** @todo document the query states (and the transitions between them). */
- /**
- * A query object is in CLEAN state when it has NO unparsed/unprocessed DQL parts.
- */
- const STATE_CLEAN = 1;
-
- /**
- * A query object is in state DIRTY when it has DQL parts that have not yet been
- * parsed/processed.
- */
- const STATE_DIRTY = 2;
-
- /**
- * A query is in DIRECT state when ... ?
- */
- const STATE_DIRECT = 3;
-
- /**
- * A query object is on LOCKED state when ... ?
- */
- const STATE_LOCKED = 4;
-
- /**
- * @var array Table alias map. Keys are SQL aliases and values DQL aliases.
- */
- protected $_tableAliasMap = array();
-
- /**
- * @var Doctrine_View The view object used by this query, if any.
- */
- protected $_view;
-
- /**
- * @var integer $_state The current state of this query.
- */
- protected $_state = Doctrine_Query::STATE_CLEAN;
-
- /**
- * @var array $params The parameters of this query.
- */
- protected $_params = array('join' => array(),
- 'where' => array(),
- 'set' => array(),
- 'having' => array());
-
- /* Caching properties */
- /**
- * @var Doctrine_Cache_Interface The cache driver used for caching result sets.
- */
- protected $_resultCache;
- /**
- * @var boolean $_expireResultCache A boolean value that indicates whether or not
- * expire the result cache.
- */
- protected $_expireResultCache = false;
- protected $_resultCacheTTL;
-
- /**
- * @var Doctrine_Cache_Interface The cache driver used for caching queries.
- */
- protected $_queryCache;
- protected $_expireQueryCache = false;
- protected $_queryCacheTTL;
-
-
- /**
- * @var Doctrine_Connection The connection used by this query object.
- */
- protected $_conn;
-
-
- /**
- * @var array $_sqlParts The SQL query string parts. Filled during the DQL parsing process.
- */
- protected $_sqlParts = array(
- 'select' => array(),
- 'distinct' => false,
- 'forUpdate' => false,
- 'from' => array(),
- 'set' => array(),
- 'join' => array(),
- 'where' => array(),
- 'groupby' => array(),
- 'having' => array(),
- 'orderby' => array(),
- 'limit' => false,
- 'offset' => false,
- );
-
- /**
- * @var array $_dqlParts an array containing all DQL query parts
- */
- protected $_dqlParts = array(
- 'from' => array(),
- 'select' => array(),
- 'forUpdate' => false,
- 'set' => array(),
- 'join' => array(),
- 'where' => array(),
- 'groupby' => array(),
- 'having' => array(),
- 'orderby' => array(),
- 'limit' => array(),
- 'offset' => array(),
- );
-
-
- /**
- * @var array $_queryComponents Two dimensional array containing the components of this query,
- * informations about their relations and other related information.
- * The components are constructed during query parsing.
- *
- * Keys are component aliases and values the following:
- *
- * table table object associated with given alias
- *
- * relation the relation object owned by the parent
- *
- * parent the alias of the parent
- *
- * agg the aggregates of this component
- *
- * map the name of the column / aggregate value this
- * component is mapped to a collection
- */
- protected $_queryComponents = array();
-
- /**
- * @var integer $type the query type
- *
- * @see Doctrine_Query::* constants
- */
- protected $_type = self::SELECT;
-
- /**
- * @var Doctrine_Hydrator The hydrator object used to hydrate query results.
- */
- protected $_hydrator;
-
- /**
- * @var Doctrine_Query_Tokenizer The tokenizer that is used during the query parsing process.
- */
- protected $_tokenizer;
-
- /**
- * @var Doctrine_Query_Parser The parser that is used for query parsing.
- */
- protected $_parser;
-
- /**
- * @var array $_tableAliasSeeds A simple array keys representing table aliases and values
- * table alias seeds. The seeds are used for generating short table
- * aliases.
- */
- protected $_tableAliasSeeds = array();
-
- /**
- * @var array $_options an array of options
- */
- protected $_options = array(
- 'hydrationMode' => Doctrine::HYDRATE_RECORD
- );
-
- /**
- * @var boolean
- */
- protected $_isLimitSubqueryUsed = false;
-
- /**
- * @var array components used in the DQL statement
- */
- protected $_components;
-
- /**
- * @var bool Boolean variable for whether or not the preQuery process has been executed
- */
- protected $_preQueried = false;
-
- /**
- * Constructor.
- *
- * @param Doctrine_Connection The connection object the query will use.
- * @param Doctrine_Hydrator_Abstract The hydrator that will be used for generating result sets.
- */
- public function __construct(Doctrine_Connection $connection = null,
- Doctrine_Hydrator_Abstract $hydrator = null)
- {
- if ($connection === null) {
- $connection = Doctrine_Manager::getInstance()->getCurrentConnection();
- }
- if ($hydrator === null) {
- $hydrator = new Doctrine_Hydrator();
- }
- $this->_conn = $connection;
- $this->_hydrator = $hydrator;
- $this->_tokenizer = new Doctrine_Query_Tokenizer();
- $this->_resultCacheTTL = $this->_conn->getAttribute(Doctrine::ATTR_RESULT_CACHE_LIFESPAN);
- $this->_queryCacheTTL = $this->_conn->getAttribute(Doctrine::ATTR_QUERY_CACHE_LIFESPAN);
- }
-
- /**
- * setOption
- *
- * @param string $name option name
- * @param string $value option value
- * @return Doctrine_Query this object
- */
- public function setOption($name, $value)
- {
- if ( ! isset($this->_options[$name])) {
- throw new Doctrine_Query_Exception('Unknown option ' . $name);
- }
- $this->_options[$name] = $value;
- }
-
- /**
- * hasTableAlias
- * whether or not this object has given tableAlias
- *
- * @param string $tableAlias the table alias to be checked
- * @return boolean true if this object has given alias, otherwise false
- * @deprecated
- */
- public function hasTableAlias($sqlTableAlias)
- {
- return $this->hasSqlTableAlias($sqlTableAlias);
- }
-
- /**
- * hasSqlTableAlias
- * whether or not this object has given tableAlias
- *
- * @param string $tableAlias the table alias to be checked
- * @return boolean true if this object has given alias, otherwise false
- */
- public function hasSqlTableAlias($sqlTableAlias)
- {
- return (isset($this->_tableAliasMap[$sqlTableAlias]));
- }
-
- /**
- * getTableAliases
- * returns all table aliases
- *
- * @return array table aliases as an array
- * @deprecated
- */
- public function getTableAliases()
- {
- return $this->getTableAliasMap();
- }
-
- /**
- * getTableAliasMap
- * returns all table aliases
- *
- * @return array table aliases as an array
- */
- public function getTableAliasMap()
- {
- return $this->_tableAliasMap;
- }
-
- /**
- * getDql
- * returns the DQL query that is represented by this query object.
- *
- * the query is built from $_dqlParts
- *
- * @return string the DQL query
- */
- public function getDql()
- {
- $q = '';
- if ($this->_type == self::SELECT) {
- $q .= ( ! empty($this->_dqlParts['select'])) ? 'SELECT ' . implode(', ', $this->_dqlParts['select']) : '';
- $q .= ( ! empty($this->_dqlParts['from'])) ? ' FROM ' . implode(' ', $this->_dqlParts['from']) : '';
- } else if ($this->_type == self::DELETE) {
- $q .= 'DELETE';
- $q .= ( ! empty($this->_dqlParts['from'])) ? ' FROM ' . implode(' ', $this->_dqlParts['from']) : '';
- } else if ($this->_type == self::UPDATE) {
- $q .= 'UPDATE ';
- $q .= ( ! empty($this->_dqlParts['from'])) ? implode(' ', $this->_dqlParts['from']) : '';
- $q .= ( ! empty($this->_dqlParts['set'])) ? ' SET ' . implode(' ', $this->_dqlParts['set']) : '';
- }
- $q .= ( ! empty($this->_dqlParts['where'])) ? ' WHERE ' . implode(' ', $this->_dqlParts['where']) : '';
- $q .= ( ! empty($this->_dqlParts['groupby'])) ? ' GROUP BY ' . implode(', ', $this->_dqlParts['groupby']) : '';
- $q .= ( ! empty($this->_dqlParts['having'])) ? ' HAVING ' . implode(' AND ', $this->_dqlParts['having']) : '';
- $q .= ( ! empty($this->_dqlParts['orderby'])) ? ' ORDER BY ' . implode(', ', $this->_dqlParts['orderby']) : '';
- $q .= ( ! empty($this->_dqlParts['limit'])) ? ' LIMIT ' . implode(' ', $this->_dqlParts['limit']) : '';
- $q .= ( ! empty($this->_dqlParts['offset'])) ? ' OFFSET ' . implode(' ', $this->_dqlParts['offset']) : '';
-
- return $q;
- }
-
-
-
- /**
- * getQueryPart
- * gets a query part from the query part array
- *
- * @param string $name the name of the query part to be set
- * @param string $part query part string
- * @throws Doctrine_Query_Exception if trying to set unknown query part
- * @return Doctrine_Query_Abstract this object
- * @deprecated
- */
- public function getQueryPart($part)
- {
- return $this->getSqlQueryPart($part);
- }
-
- /**
- * getSqlQueryPart
- * gets an SQL query part from the SQL query part array
- *
- * @param string $name the name of the query part to be set
- * @param string $part query part string
- * @throws Doctrine_Query_Exception if trying to set unknown query part
- * @return Doctrine_Hydrate this object
- */
- public function getSqlQueryPart($part)
- {
- if ( ! isset($this->_sqlParts[$part])) {
- throw new Doctrine_Query_Exception('Unknown SQL query part ' . $part);
- }
- return $this->_sqlParts[$part];
- }
-
- /**
- * setQueryPart
- * sets a query part in the query part array
- *
- * @param string $name the name of the query part to be set
- * @param string $part query part string
- * @throws Doctrine_Query_Exception if trying to set unknown query part
- * @return Doctrine_Hydrate this object
- * @deprecated
- */
- public function setQueryPart($name, $part)
- {
- return $this->setSqlQueryPart($name, $part);
- }
-
- /**
- * setSqlQueryPart
- * sets an SQL query part in the SQL query part array
- *
- * @param string $name the name of the query part to be set
- * @param string $part query part string
- * @throws Doctrine_Query_Exception if trying to set unknown query part
- * @return Doctrine_Hydrate this object
- */
- public function setSqlQueryPart($name, $part)
- {
- if ( ! isset($this->_sqlParts[$name])) {
- throw new Doctrine_Query_Exception('Unknown query part ' . $name);
- }
-
- if ($name !== 'limit' && $name !== 'offset') {
- if (is_array($part)) {
- $this->_sqlParts[$name] = $part;
- } else {
- $this->_sqlParts[$name] = array($part);
- }
- } else {
- $this->_sqlParts[$name] = $part;
- }
-
- return $this;
- }
-
- /**
- * addQueryPart
- * adds a query part in the query part array
- *
- * @param string $name the name of the query part to be added
- * @param string $part query part string
- * @throws Doctrine_Query_Exception if trying to add unknown query part
- * @return Doctrine_Hydrate this object
- * @deprecated
- */
- public function addQueryPart($name, $part)
- {
- return $this->addSqlQueryPart($name, $part);
- }
-
- /**
- * addSqlQueryPart
- * adds an SQL query part to the SQL query part array
- *
- * @param string $name the name of the query part to be added
- * @param string $part query part string
- * @throws Doctrine_Query_Exception if trying to add unknown query part
- * @return Doctrine_Hydrate this object
- */
- public function addSqlQueryPart($name, $part)
- {
- if ( ! isset($this->_sqlParts[$name])) {
- throw new Doctrine_Query_Exception('Unknown query part ' . $name);
- }
- if (is_array($part)) {
- $this->_sqlParts[$name] = array_merge($this->_sqlParts[$name], $part);
- } else {
- $this->_sqlParts[$name][] = $part;
- }
- return $this;
- }
-
- /**
- * removeQueryPart
- * removes a query part from the query part array
- *
- * @param string $name the name of the query part to be removed
- * @throws Doctrine_Query_Exception if trying to remove unknown query part
- * @return Doctrine_Hydrate this object
- * @deprecated
- */
- public function removeQueryPart($name)
- {
- return $this->removeSqlQueryPart($name);
- }
-
- /**
- * removeSqlQueryPart
- * removes a query part from the query part array
- *
- * @param string $name the name of the query part to be removed
- * @throws Doctrine_Query_Exception if trying to remove unknown query part
- * @return Doctrine_Hydrate this object
- */
- public function removeSqlQueryPart($name)
- {
- if ( ! isset($this->_sqlParts[$name])) {
- throw new Doctrine_Query_Exception('Unknown query part ' . $name);
- }
-
- if ($name == 'limit' || $name == 'offset') {
- $this->_sqlParts[$name] = false;
- } else {
- $this->_sqlParts[$name] = array();
- }
-
- return $this;
- }
-
- /**
- * removeDqlQueryPart
- * removes a dql query part from the dql query part array
- *
- * @param string $name the name of the query part to be removed
- * @throws Doctrine_Query_Exception if trying to remove unknown query part
- * @return Doctrine_Hydrate this object
- */
- public function removeDqlQueryPart($name)
- {
- if ( ! isset($this->_dqlParts[$name])) {
- throw new Doctrine_Query_Exception('Unknown query part ' . $name);
- }
-
- if ($name == 'limit' || $name == 'offset') {
- $this->_dqlParts[$name] = false;
- } else {
- $this->_dqlParts[$name] = array();
- }
-
- return $this;
- }
-
- /**
- * getParams
- *
- * @return array
- */
- public function getParams($params = array())
- {
- return array_merge((array) $params, $this->_params['join'], $this->_params['set'], $this->_params['where'], $this->_params['having']);
- }
-
- /**
- * Get the raw array of parameters
- *
- * @return array
- */
- public function getRawParams()
- {
- return $this->_params;
- }
-
- /**
- * setParams
- *
- * @param array $params
- */
- public function setParams(array $params = array())
- {
- $this->_params = $params;
- }
-
- /**
- * setView
- * sets a database view this query object uses
- * this method should only be called internally by doctrine
- *
- * @param Doctrine_View $view database view
- * @return void
- */
- public function setView(Doctrine_View $view)
- {
- $this->_view = $view;
- }
-
- /**
- * getView
- * returns the view associated with this query object (if any)
- *
- * @return Doctrine_View the view associated with this query object
- */
- public function getView()
- {
- return $this->_view;
- }
-
- /**
- * limitSubqueryUsed
- *
- * @return boolean
- */
- public function isLimitSubqueryUsed()
- {
- return $this->_isLimitSubqueryUsed;
- }
-
- /**
- * Returns the inheritance condition for the passed componentAlias
- * If no component alias is specified it defaults to the root component
- *
- * This function is used to append a SQL condition to models which have inheritance mapping
- * The condition is applied to the FROM component in the WHERE, but the condition is applied to
- * JOINS in the ON condition and not the WHERE
- *
- * @return string $str SQL condition string
- */
- public function getInheritanceCondition($componentAlias)
- {
- $map = $this->_queryComponents[$componentAlias]['table']->inheritanceMap;
-
- // No inheritance map so lets just return
- if (empty($map)) {
- return;
- }
-
- $tableAlias = $this->getSqlTableAlias($componentAlias);
-
- if ($this->_type !== Doctrine_Query::SELECT) {
- $tableAlias = '';
- } else {
- $tableAlias .= '.';
- }
-
- $field = key($map);
- $value = current($map);
- $identifier = $this->_conn->quoteIdentifier($tableAlias . $field);
-
- return $identifier . ' = ' . $this->_conn->quote($value);;
- }
-
- /**
- * getTableAlias
- * some database such as Oracle need the identifier lengths to be < ~30 chars
- * hence Doctrine creates as short identifier aliases as possible
- *
- * this method is used for the creation of short table aliases, its also
- * smart enough to check if an alias already exists for given component (componentAlias)
- *
- * @param string $componentAlias the alias for the query component to search table alias for
- * @param string $tableName the table name from which the table alias is being created
- * @return string the generated / fetched short alias
- * @deprecated
- */
- public function getTableAlias($componentAlias, $tableName = null)
- {
- return $this->getSqlTableAlias($componentAlias, $tableName);
- }
-
- /**
- * getSqlTableAlias
- * some database such as Oracle need the identifier lengths to be < ~30 chars
- * hence Doctrine creates as short identifier aliases as possible
- *
- * this method is used for the creation of short table aliases, its also
- * smart enough to check if an alias already exists for given component (componentAlias)
- *
- * @param string $componentAlias the alias for the query component to search table alias for
- * @param string $tableName the table name from which the table alias is being created
- * @return string the generated / fetched short alias
- */
- public function getSqlTableAlias($componentAlias, $tableName = null)
- {
- $alias = array_search($componentAlias, $this->_tableAliasMap);
-
- if ($alias !== false) {
- return $alias;
- }
-
- if ($tableName === null) {
- throw new Doctrine_Query_Exception("Couldn't get short alias for " . $componentAlias);
- }
-
- return $this->generateTableAlias($componentAlias, $tableName);
- }
-
- /**
- * generateNewTableAlias
- * generates a new alias from given table alias
- *
- * @param string $tableAlias table alias from which to generate the new alias from
- * @return string the created table alias
- * @deprecated
- */
- public function generateNewTableAlias($oldAlias)
- {
- return $this->generateNewSqlTableAlias($oldAlias);
- }
-
- /**
- * generateNewSqlTableAlias
- * generates a new alias from given table alias
- *
- * @param string $tableAlias table alias from which to generate the new alias from
- * @return string the created table alias
- */
- public function generateNewSqlTableAlias($oldAlias)
- {
- if (isset($this->_tableAliasMap[$oldAlias])) {
- // generate a new alias
- $name = substr($oldAlias, 0, 1);
- $i = ((int) substr($oldAlias, 1));
-
- // Fix #1530: It was reaching unexistent seeds index
- if ( ! isset($this->_tableAliasSeeds[$name])) {
- $this->_tableAliasSeeds[$name] = 1;
- }
-
- $newIndex = ($this->_tableAliasSeeds[$name] + (($i == 0) ? 1 : $i));
-
- return $name . $newIndex;
- }
-
- return $oldAlias;
- }
-
- /**
- * getTableAliasSeed
- * returns the alias seed for given table alias
- *
- * @param string $tableAlias table alias that identifies the alias seed
- * @return integer table alias seed
- * @deprecated
- */
- public function getTableAliasSeed($sqlTableAlias)
- {
- return $this->getSqlTableAliasSeed($sqlTableAlias);
- }
-
- /**
- * getSqlTableAliasSeed
- * returns the alias seed for given table alias
- *
- * @param string $tableAlias table alias that identifies the alias seed
- * @return integer table alias seed
- */
- public function getSqlTableAliasSeed($sqlTableAlias)
- {
- if ( ! isset($this->_tableAliasSeeds[$sqlTableAlias])) {
- return 0;
- }
- return $this->_tableAliasSeeds[$sqlTableAlias];
- }
-
- /**
- * hasAliasDeclaration
- * whether or not this object has a declaration for given component alias
- *
- * @param string $componentAlias the component alias the retrieve the declaration from
- * @return boolean
- */
- public function hasAliasDeclaration($componentAlias)
- {
- return isset($this->_queryComponents[$componentAlias]);
- }
-
- /**
- * getAliasDeclaration
- * get the declaration for given component alias
- *
- * @param string $componentAlias the component alias the retrieve the declaration from
- * @return array the alias declaration
- * @deprecated
- */
- public function getAliasDeclaration($componentAlias)
- {
- return $this->getQueryComponent($componentAlias);
- }
-
- /**
- * getQueryComponent
- * get the declaration for given component alias
- *
- * @param string $componentAlias the component alias the retrieve the declaration from
- * @return array the alias declaration
- */
- public function getQueryComponent($componentAlias)
- {
- if ( ! isset($this->_queryComponents[$componentAlias])) {
- throw new Doctrine_Query_Exception('Unknown component alias ' . $componentAlias);
- }
-
- return $this->_queryComponents[$componentAlias];
- }
-
- /**
- * copyAliases
- * copy aliases from another Hydrate object
- *
- * this method is needed by DQL subqueries which need the aliases
- * of the parent query
- *
- * @param Doctrine_Hydrate $query the query object from which the
- * aliases are copied from
- * @return Doctrine_Hydrate this object
- */
- public function copySubqueryInfo(Doctrine_Query_Abstract $query)
- {
- $this->_params =& $query->_params;
- $this->_tableAliasMap =& $query->_tableAliasMap;
- $this->_queryComponents =& $query->_queryComponents;
- $this->_tableAliasSeeds = $query->_tableAliasSeeds;
- return $this;
- }
-
- /**
- * getRootAlias
- * returns the alias of the the root component
- *
- * @return array
- */
- public function getRootAlias()
- {
- if ( ! $this->_queryComponents) {
- $this->getSql();
- }
- reset($this->_queryComponents);
-
- return key($this->_queryComponents);
- }
-
- /**
- * getRootDeclaration
- * returns the root declaration
- *
- * @return array
- */
- public function getRootDeclaration()
- {
- $map = reset($this->_queryComponents);
- return $map;
- }
-
- /**
- * getRoot
- * returns the root component for this object
- *
- * @return Doctrine_Table root components table
- */
- public function getRoot()
- {
- $map = reset($this->_queryComponents);
-
- if ( ! isset($map['table'])) {
- throw new Doctrine_Query_Exception('Root component not initialized.');
- }
-
- return $map['table'];
- }
-
- /**
- * generateTableAlias
- * generates a table alias from given table name and associates
- * it with given component alias
- *
- * @param string $componentAlias the component alias to be associated with generated table alias
- * @param string $tableName the table name from which to generate the table alias
- * @return string the generated table alias
- * @deprecated
- */
- public function generateTableAlias($componentAlias, $tableName)
- {
- return $this->generateSqlTableAlias($componentAlias, $tableName);
- }
-
- /**
- * generateSqlTableAlias
- * generates a table alias from given table name and associates
- * it with given component alias
- *
- * @param string $componentAlias the component alias to be associated with generated table alias
- * @param string $tableName the table name from which to generate the table alias
- * @return string the generated table alias
- */
- public function generateSqlTableAlias($componentAlias, $tableName)
- {
- preg_match('/([^_])/', $tableName, $matches);
- $char = strtolower($matches[0]);
-
- $alias = $char;
-
- if ( ! isset($this->_tableAliasSeeds[$alias])) {
- $this->_tableAliasSeeds[$alias] = 1;
- }
-
- while (isset($this->_tableAliasMap[$alias])) {
- if ( ! isset($this->_tableAliasSeeds[$alias])) {
- $this->_tableAliasSeeds[$alias] = 1;
- }
- $alias = $char . ++$this->_tableAliasSeeds[$alias];
- }
-
- $this->_tableAliasMap[$alias] = $componentAlias;
-
- return $alias;
- }
-
- /**
- * getComponentAlias
- * get component alias associated with given table alias
- *
- * @param string $sqlTableAlias the SQL table alias that identifies the component alias
- * @return string component alias
- */
- public function getComponentAlias($sqlTableAlias)
- {
- $sqlTableAlias = trim($sqlTableAlias, '[]`"');
- if ( ! isset($this->_tableAliasMap[$sqlTableAlias])) {
- throw new Doctrine_Query_Exception('Unknown table alias ' . $sqlTableAlias);
- }
- return $this->_tableAliasMap[$sqlTableAlias];
- }
-
- /**
- * calculateQueryCacheHash
- * calculate hash key for query cache
- *
- * @return string the hash
- */
- public function calculateQueryCacheHash()
- {
- $dql = $this->getDql();
- $hash = md5($dql . 'DOCTRINE_QUERY_CACHE_SALT');
- return $hash;
- }
-
- /**
- * calculateResultCacheHash
- * calculate hash key for result cache
- *
- * @param array $params
- * @return string the hash
- */
- public function calculateResultCacheHash($params = array())
- {
- $dql = $this->getDql();
- $params = $this->getParams($params);
- $conn = $this->getConnection();
- $hash = md5($conn->getName() . $conn->getOption('dsn') . $dql . var_export($params, true));
- return $hash;
- }
-
- /**
- * _execute
- *
- * @param array $params
- * @return PDOStatement The executed PDOStatement.
- */
- protected function _execute($params)
- {
- $params = $this->_conn->convertBooleans($params);
-
- if ( ! $this->_view) {
- if ($this->_queryCache !== false && ($this->_queryCache || $this->_conn->getAttribute(Doctrine::ATTR_QUERY_CACHE))) {
- $queryCacheDriver = $this->getQueryCacheDriver();
- $hash = $this->calculateQueryCacheHash();
- $cached = $queryCacheDriver->fetch($hash);
-
- if ($cached) {
- $query = $this->_constructQueryFromCache($cached);
- } else {
- $query = $this->getSqlQuery($params);
- // Check again because getSqlQuery() above could have flipped the _queryCache flag
- // if this query contains the limit sub query algorithm we don't need to cache it
- if ($this->_queryCache !== false && ($this->_queryCache || $this->_conn->getAttribute(Doctrine::ATTR_QUERY_CACHE))) {
- $serializedQuery = $this->getCachedForm($query);
- $queryCacheDriver->save($hash, $serializedQuery, $this->getQueryCacheLifeSpan());
- }
- }
- } else {
- $query = $this->getSqlQuery($params);
- }
- } else {
- $query = $this->_view->getSelectSql();
- }
-
- if ($this->isLimitSubqueryUsed() &&
- $this->_conn->getAttribute(Doctrine::ATTR_DRIVER_NAME) !== 'mysql') {
- $params = array_merge($params, $params);
- }
-
- if ($this->_type !== self::SELECT) {
- return $this->_conn->exec($query, $params);
- }
-
- $stmt = $this->_conn->execute($query, $params);
- return $stmt;
- }
-
- /**
- * execute
- * executes the query and populates the data set
- *
- * @param array $params
- * @return Doctrine_Collection the root collection
- */
- public function execute($params = array(), $hydrationMode = null)
- {
- if (empty($this->_dqlParts['from']) && empty($this->_sqlParts['from'])) {
- throw new Doctrine_Query_Exception('You must have at least one component specified in your from.');
- }
-
- $preQueryParams = $this->getParams($params);
-
- $this->_preQuery($preQueryParams);
-
- if ($hydrationMode !== null) {
- $this->_hydrator->setHydrationMode($hydrationMode);
- }
-
- $params = $this->getParams($params);
-
- if ($this->_resultCache && $this->_type == self::SELECT) {
- $cacheDriver = $this->getResultCacheDriver();
- $hash = $this->calculateResultCacheHash($params);
- $cached = ($this->_expireResultCache) ? false : $cacheDriver->fetch($hash);
-
- if ($cached === false) {
- // cache miss
- $stmt = $this->_execute($params);
- $this->_hydrator->setQueryComponents($this->_queryComponents);
- $result = $this->_hydrator->hydrateResultSet($stmt, $this->_tableAliasMap);
-
- $cached = $this->getCachedForm($result);
- $cacheDriver->save($hash, $cached, $this->getResultCacheLifeSpan());
- } else {
- $result = $this->_constructQueryFromCache($cached);
- }
- } else {
- $stmt = $this->_execute($params);
-
- if (is_integer($stmt)) {
- $result = $stmt;
- } else {
- $this->_hydrator->setQueryComponents($this->_queryComponents);
- $result = $this->_hydrator->hydrateResultSet($stmt, $this->_tableAliasMap);
- }
- }
-
- return $result;
- }
-
- /**
- * Get the dql call back for this query
- *
- * @return array $callback
- */
- protected function _getDqlCallback()
- {
- $callback = false;
- if ( ! empty($this->_dqlParts['from'])) {
- switch ($this->_type) {
- case self::DELETE:
- $callback = array(
- 'callback' => 'preDqlDelete',
- 'const' => Doctrine_Event::RECORD_DQL_DELETE
- );
- break;
- case self::UPDATE:
- $callback = array(
- 'callback' => 'preDqlUpdate',
- 'const' => Doctrine_Event::RECORD_DQL_UPDATE
- );
- break;
- case self::SELECT:
- $callback = array(
- 'callback' => 'preDqlSelect',
- 'const' => Doctrine_Event::RECORD_DQL_SELECT
- );
- break;
- }
- }
-
- return $callback;
- }
-
- /**
- * Pre query method which invokes the pre*Query() methods on the model instance or any attached
- * record listeners
- *
- * @return void
- */
- protected function _preQuery($params = array())
- {
- if ( ! $this->_preQueried && $this->getConnection()->getAttribute('use_dql_callbacks')) {
- $this->_preQueried = true;
-
- $callback = $this->_getDqlCallback();
-
- // if there is no callback for the query type, then we can return early
- if ( ! $callback) {
- return;
- }
-
- foreach ($this->_getDqlCallbackComponents($params) as $alias => $component) {
- $table = $component['table'];
- $record = $table->getRecordInstance();
-
- // Trigger preDql*() callback event
- $params = array('component' => $component, 'alias' => $alias);
- $event = new Doctrine_Event($record, $callback['const'], $this, $params);
-
- $record->$callback['callback']($event);
- $table->getRecordListener()->$callback['callback']($event);
- }
- }
-
- // Invoke preQuery() hook on Doctrine_Query for child classes which implement this hook
- $this->preQuery();
- }
-
- /**
- * Returns an array of components to execute the query callbacks for
- *
- * @param array $params
- * @return array $components
- */
- protected function _getDqlCallbackComponents($params = array())
- {
- $componentsBefore = array();
- if ($this->isSubquery()) {
- $componentsBefore = $this->getQueryComponents();
- }
-
- $copy = $this->copy();
- $copy->getSqlQuery($params);
- $componentsAfter = $copy->getQueryComponents();
-
- if ($componentsBefore !== $componentsAfter) {
- return array_diff($componentsAfter, $componentsBefore);
- } else {
- return $componentsAfter;
- }
- }
-
- /**
- * Blank hook methods which can be implemented in Doctrine_Query child classes
- *
- * @return void
- */
- public function preQuery()
- {
- }
-
- /**
- * Constructs the query from the cached form.
- *
- * @param string The cached query, in a serialized form.
- * @return array The custom component that was cached together with the essential
- * query data. This can be either a result set (result caching)
- * or an SQL query string (query caching).
- */
- protected function _constructQueryFromCache($cached)
- {
- $cached = unserialize($cached);
- $this->_tableAliasMap = $cached[2];
- $customComponent = $cached[0];
-
- $queryComponents = array();
- $cachedComponents = $cached[1];
- foreach ($cachedComponents as $alias => $components) {
- $e = explode('.', $components[0]);
- if (count($e) === 1) {
- $queryComponents[$alias]['table'] = $this->_conn->getTable($e[0]);
- } else {
- $queryComponents[$alias]['parent'] = $e[0];
- $queryComponents[$alias]['relation'] = $queryComponents[$e[0]]['table']->getRelation($e[1]);
- $queryComponents[$alias]['table'] = $queryComponents[$alias]['relation']->getTable();
- }
- if (isset($components[1])) {
- $queryComponents[$alias]['agg'] = $components[1];
- }
- if (isset($components[2])) {
- $queryComponents[$alias]['map'] = $components[2];
- }
- }
- $this->_queryComponents = $queryComponents;
-
- return $customComponent;
- }
-
- /**
- * getCachedForm
- * returns the cached form of this query for given resultSet
- *
- * @param array $resultSet
- * @return string serialized string representation of this query
- */
- public function getCachedForm($customComponent = null)
- {
- $componentInfo = array();
-
- foreach ($this->getQueryComponents() as $alias => $components) {
- if ( ! isset($components['parent'])) {
- $componentInfo[$alias][] = $components['table']->getComponentName();
- } else {
- $componentInfo[$alias][] = $components['parent'] . '.' . $components['relation']->getAlias();
- }
- if (isset($components['agg'])) {
- $componentInfo[$alias][] = $components['agg'];
- }
- if (isset($components['map'])) {
- $componentInfo[$alias][] = $components['map'];
- }
- }
-
- if ($customComponent instanceof Doctrine_Collection) {
- foreach ($customComponent as $record) {
- $record->serializeReferences(true);
- }
- }
-
- return serialize(array($customComponent, $componentInfo, $this->getTableAliasMap()));
- }
-
- /**
- * addSelect
- * adds fields to the SELECT part of the query
- *
- * @param string $select Query SELECT part
- * @return Doctrine_Query
- */
- public function addSelect($select)
- {
- return $this->_addDqlQueryPart('select', $select, true);
- }
-
- /**
- * addTableAlias
- * adds an alias for table and associates it with given component alias
- *
- * @param string $componentAlias the alias for the query component associated with given tableAlias
- * @param string $tableAlias the table alias to be added
- * @return Doctrine_Hydrate
- * @deprecated
- */
- public function addTableAlias($tableAlias, $componentAlias)
- {
- return $this->addSqlTableAlias($tableAlias, $componentAlias);
- }
-
- /**
- * addSqlTableAlias
- * adds an SQL table alias and associates it a component alias
- *
- * @param string $componentAlias the alias for the query component associated with given tableAlias
- * @param string $tableAlias the table alias to be added
- * @return Doctrine_Query_Abstract
- */
- public function addSqlTableAlias($sqlTableAlias, $componentAlias)
- {
- $this->_tableAliasMap[$sqlTableAlias] = $componentAlias;
- return $this;
- }
-
- /**
- * addFrom
- * adds fields to the FROM part of the query
- *
- * @param string $from Query FROM part
- * @return Doctrine_Query
- */
- public function addFrom($from)
- {
- return $this->_addDqlQueryPart('from', $from, true);
- }
-
- /**
- * addWhere
- * adds conditions to the WHERE part of the query
- *
- * @param string $where Query WHERE part
- * @param mixed $params an array of parameters or a simple scalar
- * @return Doctrine_Query
- */
- public function addWhere($where, $params = array())
- {
- return $this->andWhere($where, $params);
- }
-
-
- /**
- * Adds conditions to the WHERE part of the query
- *
- * @param string $where Query WHERE part
- * @param mixed $params An array of parameters or a simple scalar
- * @return Doctrine_Query
- */
- public function andWhere($where, $params = array())
- {
- if (is_array($params)) {
- $this->_params['where'] = array_merge($this->_params['where'], $params);
- } else {
- $this->_params['where'][] = $params;
- }
-
- if ($this->_hasDqlQueryPart('where')) {
- $this->_addDqlQueryPart('where', 'AND', true);
- }
-
- return $this->_addDqlQueryPart('where', $where, true);
- }
-
-
- /**
- * Adds conditions to the WHERE part of the query
- *
- * @param string $where Query WHERE part
- * @param mixed $params An array of parameters or a simple scalar
- * @return Doctrine_Query
- */
- public function orWhere($where, $params = array())
- {
- if (is_array($params)) {
- $this->_params['where'] = array_merge($this->_params['where'], $params);
- } else {
- $this->_params['where'][] = $params;
- }
-
- if ($this->_hasDqlQueryPart('where')) {
- $this->_addDqlQueryPart('where', 'OR', true);
- }
-
- return $this->_addDqlQueryPart('where', $where, true);
- }
-
-
- /**
- * whereIn
- * adds IN condition to the query WHERE part
- *
- * @param string $expr the operand of the IN
- * @param mixed $params an array of parameters or a simple scalar
- * @param boolean $not whether or not to use NOT in front of IN
- * @return Doctrine_Query
- */
- public function whereIn($expr, $params = array(), $not = false)
- {
- return $this->andWhereIn($expr, $params, $not);
- }
-
-
- /**
- * Adds IN condition to the query WHERE part
- *
- * @param string $expr The operand of the IN
- * @param mixed $params An array of parameters or a simple scalar
- * @param boolean $not Whether or not to use NOT in front of IN
- * @return Doctrine_Query
- */
- public function andWhereIn($expr, $params = array(), $not = false)
- {
- // if there's no params, return (else we'll get a WHERE IN (), invalid SQL)
- if ( ! count($params)) {
- return $this;
- }
-
- if ($this->_hasDqlQueryPart('where')) {
- $this->_addDqlQueryPart('where', 'AND', true);
- }
-
- return $this->_addDqlQueryPart('where', $this->_processWhereIn($expr, $params, $not), true);
- }
-
-
- /**
- * Adds IN condition to the query WHERE part
- *
- * @param string $expr The operand of the IN
- * @param mixed $params An array of parameters or a simple scalar
- * @param boolean $not Whether or not to use NOT in front of IN
- * @return Doctrine_Query
- */
- public function orWhereIn($expr, $params = array(), $not = false)
- {
- // if there's no params, return (else we'll get a WHERE IN (), invalid SQL)
- if ( ! count($params)) {
- return $this;
- }
-
- if ($this->_hasDqlQueryPart('where')) {
- $this->_addDqlQueryPart('where', 'OR', true);
- }
-
- return $this->_addDqlQueryPart('where', $this->_processWhereIn($expr, $params, $not), true);
- }
-
-
- /**
- * @nodoc
- */
- protected function _processWhereIn($expr, $params = array(), $not = false)
- {
- $params = (array) $params;
-
- // if there's no params, return (else we'll get a WHERE IN (), invalid SQL)
- if ( ! count($params)) {
- return $this;
- }
-
- $a = array();
- foreach ($params as $k => $value) {
- if ($value instanceof Doctrine_Expression) {
- $value = $value->getSql();
- unset($params[$k]);
- } else {
- $value = '?';
- }
- $a[] = $value;
- }
-
- $this->_params['where'] = array_merge($this->_params['where'], $params);
-
- return $expr . ($not === true ? ' NOT ':'') . ' IN (' . implode(', ', $a) . ')';
- }
-
-
- /**
- * whereNotIn
- * adds NOT IN condition to the query WHERE part
- *
- * @param string $expr the operand of the NOT IN
- * @param mixed $params an array of parameters or a simple scalar
- * @return Doctrine_Query
- */
- public function whereNotIn($expr, $params = array())
- {
- return $this->whereIn($expr, $params, true);
- }
-
-
- /**
- * Adds NOT IN condition to the query WHERE part
- *
- * @param string $expr The operand of the NOT IN
- * @param mixed $params An array of parameters or a simple scalar
- * @return Doctrine_Query
- */
- public function andWhereNotIn($expr, $params = array())
- {
- return $this->andWhereIn($expr, $params, true);
- }
-
-
- /**
- * Adds NOT IN condition to the query WHERE part
- *
- * @param string $expr The operand of the NOT IN
- * @param mixed $params An array of parameters or a simple scalar
- * @return Doctrine_Query
- */
- public function orWhereNotIn($expr, $params = array())
- {
- return $this->orWhereIn($expr, $params, true);
- }
-
- /**
- * addGroupBy
- * adds fields to the GROUP BY part of the query
- *
- * @param string $groupby Query GROUP BY part
- * @return Doctrine_Query
- */
- public function addGroupBy($groupby)
- {
- return $this->_addDqlQueryPart('groupby', $groupby, true);
- }
-
- /**
- * addHaving
- * adds conditions to the HAVING part of the query
- *
- * @param string $having Query HAVING part
- * @param mixed $params an array of parameters or a simple scalar
- * @return Doctrine_Query
- */
- public function addHaving($having, $params = array())
- {
- if (is_array($params)) {
- $this->_params['having'] = array_merge($this->_params['having'], $params);
- } else {
- $this->_params['having'][] = $params;
- }
- return $this->_addDqlQueryPart('having', $having, true);
- }
-
- /**
- * addOrderBy
- * adds fields to the ORDER BY part of the query
- *
- * @param string $orderby Query ORDER BY part
- * @return Doctrine_Query
- */
- public function addOrderBy($orderby)
- {
- return $this->_addDqlQueryPart('orderby', $orderby, true);
- }
-
- /**
- * select
- * sets the SELECT part of the query
- *
- * @param string $select Query SELECT part
- * @return Doctrine_Query
- */
- public function select($select)
- {
- return $this->_addDqlQueryPart('select', $select);
- }
-
- /**
- * distinct
- * Makes the query SELECT DISTINCT.
- *
- * @param bool $flag Whether or not the SELECT is DISTINCT (default true).
- * @return Doctrine_Query
- */
- public function distinct($flag = true)
- {
- $this->_sqlParts['distinct'] = (bool) $flag;
- return $this;
- }
-
- /**
- * forUpdate
- * Makes the query SELECT FOR UPDATE.
- …
Large files files are truncated, but you can click here to view the full file