Commit ee46dba3 authored by romanb's avatar romanb

[2.0] Moved code between Query and AbstractQuery. Added first NativeQuery...

[2.0] Moved code between Query and AbstractQuery. Added first NativeQuery implementation. Hydration work and code movements for discriminator column usage. Started implementing Single Table Inheritance.
parent 67ba9661
......@@ -31,8 +31,9 @@ use \ArrayIterator;
* A Collection is a thin wrapper around a php array. Think of it as an OO version
* of a plain array.
*
* @author Roman S. Borschel
* @author Roman S. Borschel <roman@code-factory.org>
* @since 2.0
* @todo Consider extending ArrayObject
*/
class Collection implements Countable, IteratorAggregate, ArrayAccess
{
......
......@@ -49,9 +49,8 @@ interface Statement
public function bindColumn($column, &$param, $type = null);
/**
* bindValue
* Binds a value to a corresponding named or question mark
* placeholder in the SQL statement that was use to prepare the statement.
* Binds a value to a corresponding named or positional
* placeholder in the SQL statement that was used to prepare the statement.
*
* @param mixed $param Parameter identifier. For a prepared statement using named placeholders,
* this will be a parameter name of the form :name. For a prepared statement
......@@ -65,7 +64,6 @@ interface Statement
public function bindValue($param, $value, $type = null);
/**
* bindParam
* Binds a PHP variable to a corresponding named or question mark placeholder in the
* SQL statement that was use to prepare the statement. Unlike PDOStatement->bindValue(),
* the variable is bound as a reference and will only be evaluated at the time
......
......@@ -36,8 +36,11 @@ abstract class Type
}
abstract public function getSqlDeclaration(array $fieldDeclaration, \Doctrine\DBAL\Platforms\AbstractPlatform $platform);
abstract public function getName();
//abstract public function getTypeCode();
/**
* Factory method to create type instances.
* Type instances are implemented as flyweights.
......
<?php
/*
* $Id: Abstract.php 1393 2008-03-06 17:49:16Z guilhermeblanco $
*
......@@ -35,78 +34,27 @@ namespace Doctrine\ORM;
*/
abstract class AbstractQuery
{
/* Hydration mode constants */
/**
* QUERY TYPE CONSTANTS
* Hydrates an object graph. This is the default behavior.
*/
const HYDRATE_OBJECT = 1;
/**
* Constant for SELECT queries.
* Hydrates an array graph.
*/
const SELECT = 0;
const HYDRATE_ARRAY = 2;
/**
* Constant for DELETE queries.
* Hydrates a flat, rectangular result set with scalar values.
*/
const DELETE = 1;
const HYDRATE_SCALAR = 3;
/**
* Constant for UPDATE queries.
* Hydrates a single scalar value.
*/
const UPDATE = 2;
const HYDRATE_SINGLE_SCALAR = 4;
/**
* @todo [TODO] Remove these ones (INSERT and CREATE)?
* Hydrates nothing.
*/
/**
* Constant for INSERT queries.
*/
//const INSERT = 3;
/**
* Constant for CREATE queries.
*/
//const CREATE = 4;
/**
* 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. This is automatically defined as DIRTY when addDqlQueryPart
* is called.
*/
const STATE_DIRTY = 2;
/**
* @todo [TODO] Remove these ones (DIRECT and LOCKED)?
*/
/**
* A query is in DIRECT state when ... ?
*/
//const STATE_DIRECT = 3;
/**
* A query object is on LOCKED state when ... ?
*/
//const STATE_LOCKED = 4;
/**
* @var integer $type Query type.
*
* @see Query::* constants
*/
protected $_type = self::SELECT;
/**
* @var integer $_state The current state of this query.
*/
protected $_state = self::STATE_CLEAN;
const HYDRATE_NONE = 5;
/**
* @var array $params Parameters of this query.
......@@ -121,894 +69,464 @@ abstract class AbstractQuery
protected $_enumParams = array();
/**
* @var array $_dqlParts An array containing all DQL query parts.
* @see Query::free that initializes this property
* The user-specified ResultSetMapping to use.
*
* @var ResultSetMapping
*/
protected $_dqlParts = array();
protected $_resultSetMapping;
/**
* @var string $_dql Cached DQL query.
* @var Doctrine\ORM\EntityManager The entity manager used by this query object.
*/
protected $_dql = null;
protected $_em;
/**
* Frees the resources used by the query object. It especially breaks a
* cyclic reference between the query object and it's parsers. This enables
* PHP's current GC to reclaim the memory.
* This method can therefore be used to reduce memory usage when creating a lot
* of query objects during a request.
*/
public function free()
{
/**
* @todo [TODO] What about "forUpdate" support? Remove it?
*/
$this->_dqlParts = array(
'select' => array(),
'distinct' => false,
'forUpdate' => false,
'from' => array(),
'join' => array(),
'set' => array(),
'where' => array(),
'groupby' => array(),
'having' => array(),
'orderby' => array(),
'limit' => array(),
'offset' => array(),
);
$this->_params = array(
'join' => array(),
'set' => array(),
'where' => array(),
'having' => array()
);
$this->_enumParams = array();
$this->_dql = null;
$this->_state = self::STATE_CLEAN;
}
/**
* Defines a complete DQL
*
* @param string $dqlQuery DQL Query
*/
public function setDql($dqlQuery)
{
$this->free();
if ($dqlQuery !== null) {
$this->_dql = $dqlQuery;
$this->_state = self::STATE_DIRTY;
}
}
/**
* Returns the DQL query that is represented by this query object.
* A set of query hints.
*
* @return string DQL query
* @var array
*/
public function getDql()
{
if ($this->_dql !== null) {
return $this->_dql;
}
$dql = '';
switch ($this->_type) {
case self::DELETE:
$dql = $this->_getDqlForDelete();
break;
case self::UPDATE:
$dql = $this->_getDqlForUpdate();
break;
protected $_hints = array();
/**
* @todo [TODO] Remove these ones (INSERT and CREATE)?
* @var integer The hydration mode.
*/
/*
case self::INSERT:
break;
case self::CREATE:
break;
*/
case self::SELECT:
default:
$dql = $this->_getDqlForSelect();
break;
}
return $dql;
}
protected $_hydrationMode = self::HYDRATE_OBJECT;
/**
* Builds the DQL of DELETE
*/
protected function _getDqlForDelete()
{
/*
* BNF:
*
* DeleteStatement = DeleteClause [WhereClause] [OrderByClause] [LimitClause] [OffsetClause]
* DeleteClause = "DELETE" "FROM" RangeVariableDeclaration
* WhereClause = "WHERE" ConditionalExpression
* OrderByClause = "ORDER" "BY" OrderByItem {"," OrderByItem}
* LimitClause = "LIMIT" integer
* OffsetClause = "OFFSET" integer
* The locally set cache driver used for caching result sets of this query.
*
* @var CacheDriver
*/
return 'DELETE'
. $this->_getReducedDqlQueryPart('from', array('pre' => ' FROM ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('where', array('pre' => ' WHERE ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('orderby', array('pre' => ' ORDER BY ', 'separator' => ', '))
. $this->_getReducedDqlQueryPart('limit', array('pre' => ' LIMIT ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('offset', array('pre' => ' OFFSET ', 'separator' => ' '));
}
protected $_resultCache;
/**
* Builds the DQL of UPDATE
* @var boolean Boolean value that indicates whether or not expire the result cache.
*/
protected function _getDqlForUpdate()
{
/*
* BNF:
*
* UpdateStatement = UpdateClause [WhereClause] [OrderByClause] [LimitClause] [OffsetClause]
* UpdateClause = "UPDATE" RangeVariableDeclaration "SET" UpdateItem {"," UpdateItem}
* WhereClause = "WHERE" ConditionalExpression
* OrderByClause = "ORDER" "BY" OrderByItem {"," OrderByItem}
* LimitClause = "LIMIT" integer
* OffsetClause = "OFFSET" integer
*
*/
return 'UPDATE'
. $this->_getReducedDqlQueryPart('from', array('pre' => ' FROM ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('where', array('pre' => ' SET ', 'separator' => ', '))
. $this->_getReducedDqlQueryPart('where', array('pre' => ' WHERE ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('orderby', array('pre' => ' ORDER BY ', 'separator' => ', '))
. $this->_getReducedDqlQueryPart('limit', array('pre' => ' LIMIT ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('offset', array('pre' => ' OFFSET ', 'separator' => ' '));
}
protected $_expireResultCache = false;
/**
* Builds the DQL of SELECT
*/
protected function _getDqlForSelect()
{
/*
* BNF:
*
* SelectStatement = [SelectClause] FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] [LimitClause] [OffsetClause]
* SelectClause = "SELECT" ["ALL" | "DISTINCT"] SelectExpression {"," SelectExpression}
* FromClause = "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}
* WhereClause = "WHERE" ConditionalExpression
* GroupByClause = "GROUP" "BY" GroupByItem {"," GroupByItem}
* HavingClause = "HAVING" ConditionalExpression
* OrderByClause = "ORDER" "BY" OrderByItem {"," OrderByItem}
* LimitClause = "LIMIT" integer
* OffsetClause = "OFFSET" integer
*
*/
/**
* @todo [TODO] What about "ALL" support?
* @var int Result Cache lifetime.
*/
return 'SELECT'
. (($this->getDqlQueryPart('distinct') === true) ? ' DISTINCT' : '')
. $this->_getReducedDqlQueryPart('select', array('pre' => ' ', 'separator' => ', ', 'empty' => ' *'))
. $this->_getReducedDqlQueryPart('from', array('pre' => ' FROM ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('where', array('pre' => ' WHERE ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('groupby', array('pre' => ' GROUP BY ', 'separator' => ', '))
. $this->_getReducedDqlQueryPart('having', array('pre' => ' HAVING ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('orderby', array('pre' => ' ORDER BY ', 'separator' => ', '))
. $this->_getReducedDqlQueryPart('limit', array('pre' => ' LIMIT ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('offset', array('pre' => ' OFFSET ', 'separator' => ' '));
}
protected $_resultCacheTTL;
/**
* @nodoc
* Initializes a new instance of a class derived from <tt>AbstractQuery</tt>.
*
* @param Doctrine\ORM\EntityManager $entityManager
*/
protected function _getReducedDqlQueryPart($queryPartName, $options = array())
public function __construct(EntityManager $entityManager)
{
if (empty($this->_dqlParts[$queryPartName])) {
return (isset($options['empty']) ? $options['empty'] : '');
}
$str = (isset($options['pre']) ? $options['pre'] : '');
$str .= implode($options['separator'], $this->getDqlQueryPart($queryPartName));
$str .= (isset($options['post']) ? $options['post'] : '');
return $str;
$this->_em = $entityManager;
$this->free();
}
/**
* Returns the type of this query object
* By default the type is Doctrine_ORM_Query_Abstract::SELECT but if update() or delete()
* are being called the type is Doctrine_ORM_Query_Abstract::UPDATE and Doctrine_ORM_Query_Abstract::DELETE,
* respectively.
*
* @see Doctrine_ORM_Query_Abstract::SELECT
* @see Doctrine_ORM_Query_Abstract::UPDATE
* @see Doctrine_ORM_Query_Abstract::DELETE
* Retrieves the associated EntityManager of this Query instance.
*
* @return integer Return the query type
* @return Doctrine\ORM\EntityManager
*/
public function getType()
public function getEntityManager()
{
return $this->_type;
return $this->_em;
}
/**
* Returns the state of this query object
* By default the type is Doctrine_ORM_Query_Abstract::STATE_CLEAN but if it appears any unprocessed DQL
* part, it is switched to Doctrine_ORM_Query_Abstract::STATE_DIRTY.
*
* @see Doctrine_ORM_Query_Abstract::STATE_CLEAN
* @see Doctrine_ORM_Query_Abstract::STATE_DIRTY
*
* @return integer Return the query state
* Frees the resources used by the query object. It especially breaks a
* cyclic reference between the query object and it's parsers. This enables
* PHP's current GC to reclaim the memory.
* This method can therefore be used to reduce memory usage when creating a lot
* of query objects during a request.
*/
public function getState()
public function free()
{
return $this->_state;
$this->_params = array();
$this->_enumParams = array();
}
/**
* Adds fields to the SELECT part of the query
* Set enumerated parameters
*
* @param string $select Query SELECT part
* @return Doctrine_ORM_Query
* @param array $enumParams Enum parameters.
*/
public function select($select = '', $override = false)
protected function _setEnumParams($enumParams = array())
{
if ($select === '') {
return $this;
}
return $this->_addDqlQueryPart('select', $select, ! $override);
$this->_enumParams = $enumParams;
}
/**
* Makes the query SELECT DISTINCT.
* Get all enumerated parameters
*
* @param bool $flag Whether or not the SELECT is DISTINCT (default true).
* @return Doctrine_ORM_Query
* @return array All enumerated parameters
*/
public function distinct($flag = true)
public function getEnumParams()
{
$this->_dqlParts['distinct'] = (bool) $flag;
return $this;
return $this->_enumParams;
}
/**
* Makes the query SELECT FOR UPDATE.
*
* @param bool $flag Whether or not the SELECT is FOR UPDATE (default true).
* @return Doctrine_ORM_Query
* Convert ENUM parameters to their integer equivalents
*
* @todo [TODO] What about "forUpdate" support? Remove it?
* @param $params Parameters to be converted
* @return array Converted parameters array
*/
public function forUpdate($flag = true)
public function convertEnums($params)
{
return $this->_addDqlQueryPart('forUpdate', (bool) $flag);
foreach ($this->_enumParams as $key => $values) {
if (isset($params[$key]) && ! empty($values)) {
$params[$key] = $values[0]->enumIndex($values[1], $params[$key]);
}
}
return $params;
}
/**
* Sets the query type to DELETE
* Get all defined parameters
*
* @return Doctrine_ORM_Query
* @return array Defined parameters
*/
public function delete()
public function getParams($params = array())
{
$this->_type = self::DELETE;
return $this;
return array_merge($this->_params, $params);
}
/**
* Sets the UPDATE part of the query
* setParams
*
* @param string $update Query UPDATE part
* @return Doctrine_ORM_Query
* @param array $params
*/
public function update($update)
{
$this->_type = self::UPDATE;
return $this->_addDqlQueryPart('from', $update);
public function setParams(array $params = array()) {
$this->_params = $params;
}
/**
* Sets the SET part of the query
* Gets the SQL query that corresponds to this query object.
* The returned SQL syntax depends on the connection driver that is used
* by this query object at the time of this method call.
*
* @param mixed $key UPDATE keys. Accepts either a string (requiring then $value or $params to be defined)
* or an array of $key => $value pairs.
* @param string $value UPDATE key value. Optional argument, but required if $key is a string.
* @return Doctrine_ORM_Query
* @return string SQL query
*/
public function set($key, $value = null, $params = null)
{
if (is_array($key)) {
foreach ($key as $k => $v) {
$this->set($k, '?', array($v));
}
return $this;
} else {
if ($params !== null) {
if (is_array($params)) {
$this->_params['set'] = array_merge($this->_params['set'], $params);
} else {
$this->_params['set'][] = $params;
}
}
if ($value === null) {
throw \Doctrine\Common\DoctrineException::updateMe( 'Cannot try to set \''.$key.'\' without a value.' );
}
return $this->_addDqlQueryPart('set', $key . ' = ' . $value, true);
}
}
abstract public function getSql();
/**
* Adds fields to the FROM part of the query
* Sets a query parameter.
*
* @param string $from Query FROM part
* @return Doctrine_ORM_Query
* @param string|integer $key
* @param mixed $value
*/
public function from($from, $override = false)
public function setParameter($key, $value)
{
return $this->_addDqlQueryPart('from', $from, ! $override);
$this->_params[$key] = $value;
}
/**
* Appends an INNER JOIN to the FROM part of the query
* Sets a collection of query parameters.
*
* @param string $join Query INNER JOIN
* @param mixed $params Optional JOIN params (array of parameters or a simple scalar)
* @return Doctrine_ORM_Query
* @param array $params
*/
public function innerJoin($join, $params = array())
public function setParameters(array $params)
{
if (is_array($params)) {
$this->_params['join'] = array_merge($this->_params['join'], $params);
} else {
$this->_params['join'][] = $params;
foreach ($params as $key => $value) {
$this->setParameter($key, $value);
}
return $this->_addDqlQueryPart('from', 'INNER JOIN ' . $join, true);
}
/**
* Appends an INNER JOIN to the FROM part of the query
* Sets the ResultSetMapping that should be used for hydration.
*
* @param string $join Query INNER JOIN
* @param mixed $params Optional JOIN params (array of parameters or a simple scalar)
* @return Doctrine_ORM_Query
* @param ResultSetMapping $rsm
*/
public function join($join, $params = array())
public function setResultSetMapping($rsm)
{
return $this->innerJoin($join, $params);
$this->_resultSetMapping = $rsm;
}
/**
* Appends a LEFT JOIN to the FROM part of the query
* Defines a cache driver to be used for caching result sets.
*
* @param string $join Query LEFT JOIN
* @param mixed $params Optional JOIN params (array of parameters or a simple scalar)
* @return Doctrine_ORM_Query
* @param Doctrine\ORM\Cache\Cache $driver Cache driver
* @return Doctrine\ORM\Query
*/
public function leftJoin($join, $params = array())
public function setResultCache($resultCache = null)
{
if (is_array($params)) {
$this->_params['join'] = array_merge($this->_params['join'], $params);
} else {
$this->_params['join'][] = $params;
if ($resultCache !== null && ! ($resultCache instanceof \Doctrine\ORM\Cache\Cache)) {
throw DoctrineException::updateMe(
'Method setResultCache() accepts only an instance of Doctrine_Cache_Interface or null.'
);
}
return $this->_addDqlQueryPart('from', 'LEFT JOIN ' . $join, true);
$this->_resultCache = $resultCache;
return $this;
}
/**
* Adds conditions to the WHERE part of the query
* Returns the cache driver used for caching result sets.
*
* @param string $where Query WHERE part
* @param mixed $params An array of parameters or a simple scalar
* @return Doctrine_ORM_Query
* @return Doctrine_Cache_Interface Cache driver
*/
public function where($where, $params = array(), $override = false)
public function getResultCache()
{
if ($override) {
$this->_params['where'] = array();
}
if (is_array($params)) {
$this->_params['where'] = array_merge($this->_params['where'], $params);
if ($this->_resultCache instanceof \Doctrine\ORM\Cache\Cache) {
return $this->_resultCache;
} else {
$this->_params['where'][] = $params;
return $this->_em->getConfiguration()->getResultCacheImpl();
}
return $this->_addDqlQueryPart('where', $where, ! $override);
}
/**
* Adds conditions to the WHERE part of the query
* Defines how long the result cache will be active before expire.
*
* @param string $where Query WHERE part
* @param mixed $params An array of parameters or a simple scalar
* @return Doctrine_ORM_Query
* @param integer $timeToLive How long the cache entry is valid
* @return Doctrine\ORM\Query
*/
public function andWhere($where, $params = array(), $override = false)
public function setResultCacheLifetime($timeToLive)
{
if (count($this->getDqlQueryPart('where')) > 0) {
$this->_addDqlQueryPart('where', 'AND', true);
if ($timeToLive !== null) {
$timeToLive = (int) $timeToLive;
}
return $this->where($where, $params, $override);
}
$this->_resultCacheTTL = $timeToLive;
return $this;
}
/**
* Adds conditions to the WHERE part of the query
* Retrieves the lifetime of resultset cache.
*
* @param string $where Query WHERE part
* @param mixed $params An array of parameters or a simple scalar
* @return Doctrine_ORM_Query
* @return int
*/
public function orWhere($where, $params = array(), $override = false)
public function getResultCacheLifetime()
{
if (count($this->getDqlQueryPart('where')) > 0) {
$this->_addDqlQueryPart('where', 'OR', true);
}
return $this->where($where, $params, $override);
return $this->_resultCacheTTL;
}
/**
* Adds IN condition to the query WHERE part
* Defines if the resultset cache is active or not.
*
* @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
* @param boolean $expire Whether or not to force resultset cache expiration.
* @return Doctrine_ORM_Query
*/
public function whereIn($expr, $params = array(), $override = false, $not = false)
public function setExpireResultCache($expire = true)
{
$params = (array) $params;
$this->_expireResultCache = (bool) $expire;
// Must have at least one param, otherwise we'll get an empty IN () => invalid SQL
if ( ! count($params)) {
return $this;
}
list($sqlPart, $params) = $this->_processWhereInParams($params);
$where = $expr . ($not === true ? ' NOT' : '') . ' IN (' . $sqlPart . ')';
return $this->_returnWhereIn($where, $params, $override);
}
/**
* Adds NOT IN condition to the query WHERE part
* Retrieves if the resultset cache is active or not.
*
* @param string $expr The operand of the NOT IN
* @param mixed $params An array of parameters or a simple scalar
* @return Doctrine_ORM_Query
* @return bool
*/
public function whereNotIn($expr, $params = array(), $override = false)
public function getExpireResultCache()
{
return $this->whereIn($expr, $params, $override, true);
return $this->_expireResultCache;
}
/**
* Adds IN condition to the query WHERE part
* Defines the processing mode to be used during hydration process.
*
* @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_ORM_Query
* @param integer $hydrationMode Doctrine processing mode to be used during hydration process.
* One of the Query::HYDRATE_* constants.
* @return Doctrine\ORM\Query
*/
public function andWhereIn($expr, $params = array(), $override = false)
public function setHydrationMode($hydrationMode)
{
if (count($this->getDqlQueryPart('where')) > 0) {
$this->_addDqlQueryPart('where', 'AND', true);
}
return $this->whereIn($expr, $params, $override);
$this->_hydrationMode = $hydrationMode;
return $this;
}
/**
* Adds NOT IN condition to the query WHERE part
* Gets the hydration mode currently used by the query.
*
* @param string $expr The operand of the NOT IN
* @param mixed $params An array of parameters or a simple scalar
* @return Doctrine_ORM_Query
* @return integer
*/
public function andWhereNotIn($expr, $params = array(), $override = false)
public function getHydrationMode()
{
if (count($this->getDqlQueryPart('where')) > 0) {
$this->_addDqlQueryPart('where', 'AND', true);
}
return $this->whereIn($expr, $params, $override, true);
return $this->_hydrationMode;
}
/**
* Adds IN condition to the query WHERE part
* Gets the list of results for the query.
*
* @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_ORM_Query
*/
public function orWhereIn($expr, $params = array(), $override = false)
{
if (count($this->getDqlQueryPart('where')) > 0) {
$this->_addDqlQueryPart('where', 'OR', true);
}
return $this->whereIn($expr, $params, $override);
}
/**
* Adds NOT IN condition to the query WHERE part
* Alias for execute(array(), HYDRATE_OBJECT).
*
* @param string $expr The operand of the NOT IN
* @param mixed $params An array of parameters or a simple scalar
* @return Doctrine_ORM_Query
* @return Collection
*/
public function orWhereNotIn($expr, $params = array(), $override = false)
public function getResultList()
{
if (count($this->getDqlQueryPart('where')) > 0) {
$this->_addDqlQueryPart('where', 'OR', true);
return $this->execute(array(), self::HYDRATE_OBJECT);
}
return $this->whereIn($expr, $params, $override, true);
}
/**
* Adds fields to the GROUP BY part of the query
* Gets the array of results for the query.
*
* @param string $groupby Query GROUP BY part
* @return Doctrine_ORM_Query
*/
public function groupBy($groupby, $override = false)
{
return $this->_addDqlQueryPart('groupby', $groupby, ! $override);
}
/**
* Adds conditions to the HAVING part of the query
* Alias for execute(array(), HYDRATE_ARRAY).
*
* @param string $having Query HAVING part
* @param mixed $params An array of parameters or a simple scalar
* @return Doctrine_ORM_Query
* @return array
*/
public function having($having, $params = array(), $override = false)
public function getResultArray()
{
if ($override) {
$this->_params['having'] = array();
}
if (is_array($params)) {
$this->_params['having'] = array_merge($this->_params['having'], $params);
} else {
$this->_params['having'][] = $params;
return $this->execute(array(), self::HYDRATE_ARRAY);
}
return $this->_addDqlQueryPart('having', $having, true);
}
/**
* Adds conditions to the HAVING part of the query
* Gets the scalar results for the query.
*
* @param string $having Query HAVING part
* @param mixed $params An array of parameters or a simple scalar
* @return Doctrine_ORM_Query
* Alias for execute(array(), HYDRATE_SCALAR).
*
* @return array
*/
public function andHaving($having, $params = array(), $override = false)
public function getScalarResult()
{
if (count($this->getDqlQueryPart('having')) > 0) {
$this->_addDqlQueryPart('having', 'AND', true);
return $this->execute(array(), self::HYDRATE_SCALAR);
}
return $this->having($having, $params, $override);
}
/**
* Adds conditions to the HAVING part of the query
* Gets the single result of the query.
* Enforces the uniqueness of the result. If the result is not unique,
* a QueryException is thrown.
*
* @param string $having Query HAVING part
* @param mixed $params An array of parameters or a simple scalar
* @return Doctrine_ORM_Query
* @param integer $hydrationMode
* @return mixed
* @throws QueryException If the query result is not unique.
*/
public function orHaving($having, $params = array(), $override = false)
public function getSingleResult($hydrationMode = null)
{
if (count($this->getDqlQueryPart('having')) > 0) {
$this->_addDqlQueryPart('having', 'OR', true);
$result = $this->execute(array(), $hydrationMode);
if (is_array($result)) {
if (count($result) > 1) {
throw QueryException::nonUniqueResult();
}
return $this->having($having, $params, $override);
return array_shift($result);
} else if (is_object($result)) {
if (count($result) > 1) {
throw QueryException::nonUniqueResult();
}
/**
* Adds fields to the ORDER BY part of the query
*
* @param string $orderby Query ORDER BY part
* @return Doctrine_ORM_Query
*/
public function orderBy($orderby, $override = false)
{
return $this->_addDqlQueryPart('orderby', $orderby, ! $override);
return $result->getFirst();
}
/**
* Sets the Query query limit
*
* @param integer $limit Limit to be used for limiting the query results
* @return Doctrine_ORM_Query
*/
public function limit($limit)
{
return $this->_addDqlQueryPart('limit', $limit);
return $result;
}
/**
* Sets the Query query offset
* Gets the single scalar result of the query.
*
* @param integer $offset Offset to be used for paginating the query
* @return Doctrine_ORM_Query
*/
public function offset($offset)
{
return $this->_addDqlQueryPart('offset', $offset);
}
/**
* Set enumerated parameters
* Alias for getSingleResult(HYDRATE_SINGLE_SCALAR).
*
* @param array $enumParams Enum parameters.
* @return mixed
* @throws QueryException If the query result is not unique.
*/
protected function _setEnumParams($enumParams = array())
public function getSingleScalarResult()
{
$this->_enumParams = $enumParams;
return $this->getSingleResult(self::HYDRATE_SINGLE_SCALAR);
}
/**
* Get all enumerated parameters
* Sets an implementation-specific hint. If the hint name is not recognized,
* it is silently ignored.
*
* @return array All enumerated parameters
* @param string $name The name of the hint.
* @param mixed $value The value of the hint.
*/
public function getEnumParams()
public function setHint($name, $value)
{
return $this->_enumParams;
$this->_hints[$name] = $value;
}
/**
* Convert ENUM parameters to their integer equivalents
* Gets an implementation-specific hint. If the hint name is not recognized,
* FALSE is returned.
*
* @param $params Parameters to be converted
* @return array Converted parameters array
* @param string $name The name of the hint.
* @return mixed The value of the hint or FALSe, if the hint name is not recognized.
*/
public function convertEnums($params)
public function getHint($name)
{
foreach ($this->_enumParams as $key => $values) {
if (isset($params[$key]) && ! empty($values)) {
$params[$key] = $values[0]->enumIndex($values[1], $params[$key]);
}
}
return $params;
return isset($this->_hints[$name]) ? $this->_hints[$name] : false;
}
/**
* Get all defined parameters
* Executes the query and returns an IterableResult that can be used to incrementally
* iterated over the result.
*
* @return array Defined parameters
* @param array $params The query parameters.
* @param integer $hydrationMode The hydratio mode to use.
* @return IterableResult
*/
public function getParams($params = array())
public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_OBJECT)
{
return array_merge(
$this->_params['join'],
$this->_params['set'],
$this->_params['where'],
$this->_params['having'],
$params
return $this->_em->getHydrator($this->_hydrationMode)->iterate(
$this->_execute($params, $hydrationMode), $this->_resultSetMapping
);
}
/**
* setParams
* Executes the query.
*
* @param array $params
* @param string $params Parameters to be sent to query.
* @param integer $hydrationMode Doctrine processing mode to be used during hydration process.
* One of the Query::HYDRATE_* constants.
* @return mixed
*/
public function setParams(array $params = array()) {
$this->_params = $params;
public function execute($params = array(), $hydrationMode = null)
{
if ($this->_em->getUnitOfWork()->hasPendingInsertions()) {
$this->_em->flush();
}
/**
* Method to check if a arbitrary piece of DQL exists
*
* @param string $dql Arbitrary piece of DQL to check for
* @return boolean
*/
public function contains($dql)
{
return stripos($this->getDql(), $dql) === false ? false : true;
if ($hydrationMode !== null) {
$this->_hydrationMode = $hydrationMode;
}
$params = $this->getParams($params);
/**
* Retrieve a DQL part for internal purposes
*
* @param string $queryPartName The name of the query part.
* @return mixed Array related to query part or simple scalar
*/
public function getDqlQueryPart($queryPartName)
{
if ( ! isset($this->_dqlParts[$queryPartName])) {
throw \Doctrine\Common\DoctrineException::updateMe('Unknown DQL query part \'' . $queryPartName . '\'');
}
// Check result cache (Only for SELECT queries)
if ($this->_resultCache && $this->_type === self::SELECT) {
$cacheDriver = $this->getResultCacheDriver();
return $this->_dqlParts[$queryPartName];
}
// Calculate hash for DQL query.
$hash = md5($this->getDql() . var_export($params, true));
$cached = ($this->_expireResultCache) ? false : $cacheDriver->fetch($hash);
if ($cached === false) {
// Cache miss.
$result = $this->_doExecute($params);
$queryResult = CacheHandler::fromResultSet($this, $result);
$cacheDriver->save($hash, $queryResult->toCachedForm(), $this->_resultCacheTTL);
/**
* Adds a DQL part to the internal parts collection.
*
* @param string $queryPartName The name of the query part.
* @param string $queryPart The actual query part to add.
* @param boolean $append Whether to append $queryPart to already existing
* parts under the same $queryPartName. Defaults to FALSE
* (previously added parts with the same name get overridden).
* @return Doctrine_ORM_Query
*/
protected function _addDqlQueryPart($queryPartName, $queryPart, $append = false)
{
if ($append) {
$this->_dqlParts[$queryPartName][] = $queryPart;
return $result;
} else {
$this->_dqlParts[$queryPartName] = array($queryPart);
}
// Cache hit.
$queryResult = CacheHandler::fromCachedResult($this, $cached);
$this->_state = Doctrine_ORM_Query::STATE_DIRTY;
return $this;
return $queryResult->getResultSet();
}
/**
* Processes the WHERE IN () parameters and return an indexed array containing
* the sqlPart to be placed in SQL statement and the new parameters (that will be
* bound in SQL execution)
*
* @param array $params Parameters to be processed
* @return array
*/
protected function _processWhereInParams($params = array())
{
return array(
// [0] => sqlPart
implode(', ', array_map(array(&$this, '_processWhereInSqlPart'), $params)),
// [1] => params
array_filter($params, array(&$this, '_processWhereInParamItem')),
);
}
$stmt = $this->_doExecute($params);
/**
* @nodoc
*/
protected function _processWhereInSqlPart($value)
{
// [TODO] Add support to imbricated query (must deliver the hardest effort to Parser)
return ($value instanceof Doctrine_Expression) ? $value->getSql() : '?';
if (is_integer($stmt)) {
return $stmt;
}
/**
* @nodoc
*/
protected function _processWhereInParamItem($value)
{
// [TODO] Add support to imbricated query (must deliver the hardest effort to Parser)
return ( ! ($value instanceof Doctrine_Expression));
return $this->_em->getHydrator($this->_hydrationMode)->hydrateAll($stmt, $this->_resultSetMapping);
}
/**
* Processes a WHERE IN () and build defined stuff to add in DQL
*
* @param string $where The WHERE clause to be added
* @param array $params WHERE clause parameters
* @param mixed $appender Where this clause may be not be appended, or appended
* (two possible values: AND or OR)
* @return Doctrine_ORM_Query
* @nodoc
*/
protected function _returnWhereIn($where, $params = array(), $override = false)
protected function _prepareParams(array $params)
{
// Parameters inclusion
$this->_params['where'] = $override ? $params : array_merge($this->_params['where'], $params);
// WHERE clause definition
return $this->_addDqlQueryPart('where', $where, ! $override);
}
/**
* Gets the SQL query that corresponds to this query object.
* The returned SQL syntax depends on the connection driver that is used
* by this query object at the time of this method call.
*
* @return string SQL query
*/
abstract public function getSql();
// Convert boolean params
$params = $this->_em->getConnection()->getDatabasePlatform()->convertBooleans($params);
/**
* Sets a query parameter.
*
* @param string|integer $key
* @param mixed $value
*/
public function setParameter($key, $value)
{
$this->_params[$key] = $value;
// Convert enum params
return $this->convertEnums($params);
}
/**
* Sets a collection of query parameters.
* Executes the query and returns a reference to the resulting Statement object.
*
* @param array $params
* @param <type> $params
*/
public function setParameters(array $params)
{
foreach ($params as $key => $value) {
$this->setParameter($key, $value);
}
}
abstract protected function _doExecute(array $params);
}
......@@ -223,7 +223,7 @@ class EntityManager
}
/**
* Creates a query with the specified name.
* Creates a DQL query with the specified name.
*
* @todo Implementation.
* @throws DoctrineException If there is no query registered with the given name.
......@@ -234,11 +234,17 @@ class EntityManager
}
/**
* @todo Implementation.
* Creates a native SQL query.
*
* @param string $sql
* @return Query
*/
public function createNativeQuery($sql = "")
public function createNativeQuery($sql, \Doctrine\ORM\Query\ResultSetMapping $rsm)
{
//...
$query = new NativeQuery($this);
$query->setSql($sql);
$query->setResultSetMapping($rsm);
return $query;
}
/**
......
......@@ -24,7 +24,8 @@ namespace Doctrine\ORM\Internal\Hydration;
use \PDO;
/**
* Base class for all hydrators (ok, we got only 1 currently).
* Base class for all hydrators. A hydrator is a class that provides some form
* of transformation of an SQL result set into another structure.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
......@@ -50,11 +51,8 @@ abstract class AbstractHydrator
/** @var Statement The statement that provides the data to hydrate. */
protected $_stmt;
/** @var object The ParserResult instance that holds the necessary information for hydration. */
protected $_parserResult;
/**
* Initializes a new instance of a class derived from AbstractHydrator.
* Initializes a new instance of a class derived from <tt>AbstractHydrator</tt>.
*
* @param Doctrine\ORM\EntityManager $em The EntityManager to use.
*/
......@@ -68,13 +66,14 @@ abstract class AbstractHydrator
* Initiates a row-by-row hydration.
*
* @param object $stmt
* @param object $parserResult
* @param object $resultSetMapping
* @return IterableResult
*/
public function iterate($stmt, $parserResult)
public function iterate($stmt, $resultSetMapping)
{
$this->_stmt = $stmt;
$this->_prepare($parserResult);
$this->_resultSetMapping = $resultSetMapping;
$this->_prepare();
return new IterableResult($this);
}
......@@ -82,13 +81,14 @@ abstract class AbstractHydrator
* Hydrates all rows returned by the passed statement instance at once.
*
* @param object $stmt
* @param object $parserResult
* @param object $resultSetMapping
* @return mixed
*/
public function hydrateAll($stmt, $parserResult)
public function hydrateAll($stmt, $resultSetMapping)
{
$this->_stmt = $stmt;
$this->_prepare($parserResult);
$this->_resultSetMapping = $resultSetMapping;
$this->_prepare();
$result = $this->_hydrateAll();
$this->_cleanup();
return $result;
......@@ -115,14 +115,9 @@ abstract class AbstractHydrator
/**
* Excutes one-time preparation tasks once each time hydration is started
* through {@link hydrateAll} or {@link iterate()}.
*
* @param object $parserResult
*/
protected function _prepare($parserResult)
{
$this->_resultSetMapping = $parserResult->getResultSetMapping();
$this->_parserResult = $parserResult;
}
protected function _prepare()
{}
/**
* Excutes one-time cleanup tasks at the end of a hydration that was initiated
......@@ -131,7 +126,6 @@ abstract class AbstractHydrator
protected function _cleanup()
{
$this->_resultSetMapping = null;
$this->_parserResult = null;
$this->_stmt->closeCursor();
$this->_stmt = null;
}
......@@ -152,8 +146,6 @@ abstract class AbstractHydrator
/**
* Hydrates all rows from the current statement instance at once.
*
* @param object $parserResult
*/
abstract protected function _hydrateAll();
......@@ -180,21 +172,26 @@ abstract class AbstractHydrator
foreach ($data as $key => $value) {
// Parse each column name only once. Cache the results.
if ( ! isset($cache[$key])) {
if ($this->_isIgnoredName($key)) continue;
if ($this->_resultSetMapping->isScalarResult($key)) {
if ($this->_resultSetMapping->isIgnoredColumn($key)) {
$cache[$key] = false;
} else if ($this->_resultSetMapping->isScalarResult($key)) {
$cache[$key]['fieldName'] = $this->_resultSetMapping->getScalarAlias($key);
$cache[$key]['isScalar'] = true;
} else {
} else if ($this->_resultSetMapping->isFieldResult($key)) {
$classMetadata = $this->_resultSetMapping->getOwningClass($key);
$fieldName = $this->_resultSetMapping->getFieldName($key);
$classMetadata = $this->_lookupDeclaringClass($classMetadata, $fieldName);
//$fieldName = $classMetadata->getFieldNameForLowerColumnName($columnName);
$cache[$key]['fieldName'] = $fieldName;
$cache[$key]['isScalar'] = false;
$cache[$key]['type'] = $classMetadata->getTypeOfField($fieldName);
$cache[$key]['isIdentifier'] = $classMetadata->isIdentifier($fieldName);
$cache[$key]['dqlAlias'] = $this->_resultSetMapping->getEntityAlias($key);
} else {
// Discriminator column
$cache[$key]['isDiscriminator'] = true;
$cache[$key]['isScalar'] = false;
$cache[$key]['fieldName'] = $key;
$cache[$key]['dqlAlias'] = $this->_resultSetMapping->getEntityAlias($key);
}
}
......@@ -207,6 +204,11 @@ abstract class AbstractHydrator
$dqlAlias = $cache[$key]['dqlAlias'];
if (isset($cache[$key]['isDiscriminator'])) {
$rowData[$dqlAlias][$fieldName] = $value;
continue;
}
if ($cache[$key]['isIdentifier']) {
$id[$dqlAlias] .= '|' . $value;
}
......@@ -243,9 +245,10 @@ abstract class AbstractHydrator
foreach ($data as $key => $value) {
// Parse each column name only once. Cache the results.
if ( ! isset($cache[$key])) {
if ($this->_isIgnoredName($key)) continue;
if ($this->_resultSetMapping->isScalarResult($key)) {
if ($this->_resultSetMapping->isIgnoredColumn($key)) {
$cache[$key] = false;
continue;
} else if ($this->_resultSetMapping->isScalarResult($key)) {
$cache[$key]['fieldName'] = $this->_resultSetMapping->getScalarAlias($key);
$cache[$key]['isScalar'] = true;
} else {
......@@ -285,19 +288,6 @@ abstract class AbstractHydrator
$this->_resultSetMapping->getIndexByField($alias) : null;
}
/**
* Checks whether a name is ignored. Used during result set parsing to skip
* certain elements in the result set that do not have any meaning for the result.
* (I.e. ORACLE limit/offset emulation adds doctrine_rownum to the result set).
*
* @param string $name
* @return boolean
*/
private function _isIgnoredName($name)
{
return $name == 'doctrine_rownum';
}
/**
* Looks up the field name for a (lowercased) column name.
*
......@@ -319,14 +309,12 @@ abstract class AbstractHydrator
private function _lookupDeclaringClass($class, $fieldName)
{
if ($class->hasField($fieldName)) {
//return $class->getFieldNameForLowerColumnName($lcColumnName);
return $class;
}
foreach ($class->getSubclasses() as $subClass) {
$subClassMetadata = $this->_em->getClassMetadata($subClass);
if ($subClassMetadata->hasField($fieldName)) {
//return $subClassMetadata->getFieldNameForLowerColumnName($lcColumnName);
return $subClassMetadata;
}
}
......
......@@ -38,9 +38,8 @@ class ArrayHydrator extends AbstractHydrator
private $_resultCounter = 0;
/** @override */
protected function _prepare($parserResult)
protected function _prepare()
{
parent::_prepare($parserResult);
$this->_isSimpleQuery = $this->_resultSetMapping->getEntityResultCount() <= 1;
$this->_identifierMap = array();
$this->_resultPointers = array();
......@@ -98,7 +97,7 @@ class ArrayHydrator extends AbstractHydrator
// Get a reference to the right element in the result tree.
// This element will get the associated element attached.
if ($this->_parserResult->isMixedQuery() && isset($this->_rootAliases[$parent])) {
if ($this->_resultSetMapping->isMixedResult() && isset($this->_rootAliases[$parent])) {
$key = key(reset($this->_resultPointers));
// TODO: Exception if $key === null ?
$baseElement =& $this->_resultPointers[$parent][$key];
......@@ -155,14 +154,14 @@ class ArrayHydrator extends AbstractHydrator
if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
$element = $rowData[$dqlAlias];
if ($field = $this->_getCustomIndexField($dqlAlias)) {
if ($this->_parserResult->isMixedQuery()) {
if ($this->_resultSetMapping->isMixedResult()) {
$result[] = array($element[$field] => $element);
++$this->_resultCounter;
} else {
$result[$element[$field]] = $element;
}
} else {
if ($this->_parserResult->isMixedQuery()) {
if ($this->_resultSetMapping->isMixedResult()) {
$result[] = array($element);
++$this->_resultCounter;
} else {
......
......@@ -33,22 +33,24 @@ use Doctrine\Common\Collections\Collection;
*/
class ObjectHydrator extends AbstractHydrator
{
/* TOOD: Consider unifying _collections and _initializedRelations */
/** Collections initialized by the hydrator */
private $_collections = array();
/** Memory for initialized relations */
private $_initializedRelations = array();
private $_metadataMap = array();
private $_classMetadatas = array();
private $_rootAliases = array();
private $_isSimpleQuery = false;
private $_identifierMap = array();
private $_resultPointers = array();
private $_idTemplate = array();
private $_resultCounter = 0;
private $_discriminatorMap = array();
/** @override */
protected function _prepare($parserResult)
protected function _prepare()
{
parent::_prepare($parserResult);
$this->_isSimpleQuery = $this->_resultSetMapping->getEntityResultCount() <= 1;
$this->_identifierMap = array();
$this->_resultPointers = array();
......@@ -58,6 +60,14 @@ class ObjectHydrator extends AbstractHydrator
$this->_identifierMap[$dqlAlias] = array();
$this->_resultPointers[$dqlAlias] = array();
$this->_idTemplate[$dqlAlias] = '';
$this->_classMetadatas[$class->getClassName()] = $class;
if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) {
$this->_discriminatorMap[$class->getClassName()][$class->getDiscriminatorValue()] = $class->getClassName();
foreach (array_merge($class->getParentClasses(), $class->getSubclasses()) as $className) {
$value = $this->_em->getClassMetadata($className)->getDiscriminatorValue();
$this->_discriminatorMap[$class->getClassName()][$value] = $className;
}
}
}
}
......@@ -70,7 +80,7 @@ class ObjectHydrator extends AbstractHydrator
{
$s = microtime(true);
if ($this->_parserResult->isMixedQuery()) {
if ($this->_resultSetMapping->isMixedResult()) {
$result = array();
} else {
$result = new Collection;
......@@ -90,7 +100,7 @@ class ObjectHydrator extends AbstractHydrator
// Clean up
$this->_collections = array();
$this->_initializedRelations = array();
$this->_metadataMap = array();
$this->_classMetadatas = array();
$e = microtime(true);
echo 'Hydration took: ' . ($e - $s) . PHP_EOL;
......@@ -108,7 +118,7 @@ class ObjectHydrator extends AbstractHydrator
* @param string $dqlAlias
* @param boolean $oneToOne Whether it is a single-valued association or not.
*/
private function updateResultPointer(&$coll, $index, $dqlAlias, $oneToOne)
private function updateResultPointer(&$coll, $index, $dqlAlias/*, $oneToOne*/)
{
if ($coll === null) {
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
......@@ -132,6 +142,12 @@ class ObjectHydrator extends AbstractHydrator
}
}
/**
*
* @param <type> $component
* @return <type>
* @todo Consider inlining this method.
*/
private function getCollection($component)
{
$coll = new PersistentCollection($this->_em, $component);
......@@ -139,10 +155,16 @@ class ObjectHydrator extends AbstractHydrator
return $coll;
}
/**
*
* @param <type> $entity
* @param <type> $name
* @todo Consider inlining this method.
*/
private function initRelatedCollection($entity, $name)
{
$oid = spl_object_hash($entity);
$classMetadata = $this->_metadataMap[$oid];
$classMetadata = $this->_classMetadatas[get_class($entity)];
if ( ! isset($this->_initializedRelations[$oid][$name])) {
$relation = $classMetadata->getAssociationMapping($name);
$relatedClass = $this->_em->getClassMetadata($relation->getTargetEntityName());
......@@ -157,7 +179,7 @@ class ObjectHydrator extends AbstractHydrator
private function isIndexKeyInUse($entity, $assocField, $indexField)
{
return $this->_metadataMap[spl_object_hash($entity)]
return $this->_classMetadatas[get_class($entity)]
->getReflectionProperty($assocField)
->getValue($entity)
->containsKey($indexField);
......@@ -178,9 +200,11 @@ class ObjectHydrator extends AbstractHydrator
private function getEntity(array $data, $className)
{
if ($discrColumn = $this->_resultSetMapping->getDiscriminatorColumn($className)) {
$className = $this->_discriminatorMap[$className][$data[$discrColumn]];
unset($data[$discrColumn]);
}
$entity = $this->_uow->createEntity($className, $data);
$oid = spl_object_hash($entity);
$this->_metadataMap[$oid] = $this->_em->getClassMetadata($className);
return $entity;
}
......@@ -191,11 +215,13 @@ class ObjectHydrator extends AbstractHydrator
* @param <type> $property
* @param <type> $entity2
* @param <type> $indexField
* @todo Consider inlining this method. It's called only once and inlining can
* remove the need for the 2 get_class calls.
*/
private function addRelatedIndexedEntity($entity1, $property, $entity2, $indexField)
{
$classMetadata1 = $this->_metadataMap[spl_object_hash($entity1)];
$classMetadata2 = $this->_metadataMap[spl_object_hash($entity2)];
$classMetadata1 = $this->_classMetadatas[get_class($entity1)];
$classMetadata2 = $this->_classMetadatas[get_class($entity2)];
$indexValue = $classMetadata2->getReflectionProperty($indexField)->getValue($entity2);
$classMetadata1->getReflectionProperty($property)->getValue($entity1)->set($indexValue, $entity2);
}
......@@ -209,8 +235,10 @@ class ObjectHydrator extends AbstractHydrator
*/
private function addRelatedEntity($entity1, $property, $entity2)
{
$classMetadata1 = $this->_metadataMap[spl_object_hash($entity1)];
$classMetadata1->getReflectionProperty($property)->getValue($entity1)->add($entity2);
$this->_classMetadatas[get_class($entity1)]
->getReflectionProperty($property)
->getValue($entity1)
->add($entity2);
}
/**
......@@ -222,7 +250,7 @@ class ObjectHydrator extends AbstractHydrator
*/
private function isFieldSet($entity, $field)
{
return $this->_metadataMap[spl_object_hash($entity)]
return $this->_classMetadatas[get_class($entity)]
->getReflectionProperty($field)
->getValue($entity) !== null;
}
......@@ -237,12 +265,13 @@ class ObjectHydrator extends AbstractHydrator
private function setRelatedElement($entity1, $property, $entity2)
{
$oid = spl_object_hash($entity1);
$classMetadata1 = $this->_metadataMap[$oid];
$classMetadata1 = $this->_classMetadatas[get_class($entity1)];
$classMetadata1->getReflectionProperty($property)->setValue($entity1, $entity2);
$this->_uow->setOriginalEntityProperty($oid, $property, $entity2);
$relation = $classMetadata1->getAssociationMapping($property);
if ($relation->isOneToOne()) {
$targetClass = $this->_em->getClassMetadata($relation->getTargetEntityName());
//$targetClass = $this->_em->getClassMetadata($relation->getTargetEntityName());
$targetClass = $this->_classMetadatas[$relation->getTargetEntityName()];
if ($relation->isOwningSide()) {
// If there is an inverse mapping on the target class its bidirectional
if ($targetClass->hasInverseAssociationMapping($property)) {
......@@ -291,7 +320,7 @@ class ObjectHydrator extends AbstractHydrator
// Get a reference to the right element in the result tree.
// This element will get the associated element attached.
if ($this->_parserResult->isMixedQuery() && isset($this->_rootAliases[$parent])) {
if ($this->_resultSetMapping->isMixedResult() && isset($this->_rootAliases[$parent])) {
$key = key(reset($this->_resultPointers));
// TODO: Exception if $key === null ?
$baseElement =& $this->_resultPointers[$parent][$key];
......@@ -302,11 +331,11 @@ class ObjectHydrator extends AbstractHydrator
continue;
}
$oid = spl_object_hash($baseElement);
$parentClass = get_class($baseElement);
// Check the type of the relation (many or single-valued)
if ( ! $relation->isOneToOne()) {
$oneToOne = false;
//$oneToOne = false;
if (isset($nonemptyComponents[$dqlAlias])) {
$this->initRelatedCollection($baseElement, $relationAlias);
$indexExists = isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]);
......@@ -320,9 +349,10 @@ class ObjectHydrator extends AbstractHydrator
$this->addRelatedEntity($baseElement, $relationAlias, $element);
}
$this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] = $this->getLastKey(
$this->_metadataMap[$oid]
$this->_classMetadatas[$parentClass]
->getReflectionProperty($relationAlias)
->getValue($baseElement));
->getValue($baseElement)
);
}
} else if ( ! $this->isFieldSet($baseElement, $relationAlias)) {
$coll = new PersistentCollection($this->_em, $entityName);
......@@ -330,7 +360,7 @@ class ObjectHydrator extends AbstractHydrator
$this->setRelatedElement($baseElement, $relationAlias, $coll);
}
} else {
$oneToOne = true;
//$oneToOne = true;
if ( ! isset($nonemptyComponents[$dqlAlias]) &&
! $this->isFieldSet($baseElement, $relationAlias)) {
$this->setRelatedElement($baseElement, $relationAlias, null);
......@@ -340,12 +370,12 @@ class ObjectHydrator extends AbstractHydrator
}
}
$coll = $this->_metadataMap[$oid]
$coll = $this->_classMetadatas[$parentClass]
->getReflectionProperty($relationAlias)
->getValue($baseElement);
if ($coll !== null) {
$this->updateResultPointer($coll, $index, $dqlAlias, $oneToOne);
$this->updateResultPointer($coll, $index, $dqlAlias/*, $oneToOne*/);
}
} else {
// Its a root result element
......@@ -353,24 +383,22 @@ class ObjectHydrator extends AbstractHydrator
$this->_rootAliases[$dqlAlias] = true; // Mark as root alias
if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
$element = $this->_uow->createEntity($entityName, $rowData[$dqlAlias]);
$oid = spl_object_hash($element);
$this->_metadataMap[$oid] = $this->_em->getClassMetadata($entityName);
$element = $this->getEntity($rowData[$dqlAlias], $entityName);
if ($field = $this->_getCustomIndexField($dqlAlias)) {
if ($this->_parserResult->isMixedQuery()) {
if ($this->_resultSetMapping->isMixedResult()) {
$result[] = array(
$this->_metadataMap[$oid]
$this->_classMetadatas[$entityName]
->getReflectionProperty($field)
->getValue($element) => $element
);
++$this->_resultCounter;
} else {
$result->set($element, $this->_metadataMap[$oid]
$result->set($element, $this->_classMetadatas[$entityName]
->getReflectionProperty($field)
->getValue($element));
}
} else {
if ($this->_parserResult->isMixedQuery()) {
if ($this->_resultSetMapping->isMixedResult()) {
$result[] = array($element);
++$this->_resultCounter;
} else {
......@@ -381,7 +409,7 @@ class ObjectHydrator extends AbstractHydrator
} else {
$index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
}
$this->updateResultPointer($result, $index, $dqlAlias, false);
$this->updateResultPointer($result, $index, $dqlAlias/*, false*/);
//unset($rowData[$dqlAlias]);
}
}
......
<?php
/*
* $Id$
*
* 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.doctrine-project.org>.
*/
namespace Doctrine\ORM\Internal\Hydration;
......@@ -9,7 +28,7 @@ use \PDO;
* The created result is almost the same as a regular SQL result set, except
* that column names are mapped to field names and data type conversions.
*
* @author robo
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
*/
class ScalarHydrator extends AbstractHydrator
......
......@@ -273,7 +273,8 @@ final class ClassMetadata
* @var array
* @see _discriminatorColumn
*/
private $_discriminatorMap = array();
//private $_discriminatorMap = array();
private $_discriminatorValue;
/**
* The definition of the descriminator column used in JOINED and SINGLE_TABLE
......@@ -826,6 +827,20 @@ final class ClassMetadata
return isset($this->_columnNames[$fieldName]);
}
public function setValue($entity, $field, $value)
{
if (isset($this->_reflectionProperties[$field])) {
$this->_reflectionProperties[$field]->setValue($entity, $value);
}
}
public function setValueIfChanged($entity, $field, $value)
{
if (isset($this->_reflectionProperties[$field])) {
$this->_reflectionProperties[$field]->setValue($entity, $value);
}
}
/**
* Gets all field mappings.
*
......@@ -1500,25 +1515,25 @@ final class ClassMetadata
}
/**
* Sets the dsicriminator map used for mapping discriminator values to class names.
* Sets the dsicriminator value used by this class.
* Used for JOINED and SINGLE_TABLE inheritance mapping strategies.
*
* @param array $map
*/
public function setDiscriminatorMap(array $map)
public function setDiscriminatorValue($value)
{
$this->_discriminatorMap = $map;
$this->_discriminatorValue = $value;
}
/**
* Gets the discriminator map that maps discriminator values to class names.
* Gets the discriminator value of this class.
* Used for JOINED and SINGLE_TABLE inheritance mapping strategies.
*
* @return array
*/
public function getDiscriminatorMap()
public function getDiscriminatorValue()
{
return $this->_discriminatorMap;
return $this->_discriminatorValue;
}
/**
......
......@@ -126,7 +126,7 @@ class ClassMetadataFactory
$class = $this->_newClassMetadataInstance($className);
if ($parent) {
$class->setInheritanceType($parent->getInheritanceType());
$class->setDiscriminatorMap($parent->getDiscriminatorMap());
//$class->setDiscriminatorMap($parent->getDiscriminatorMap());
$class->setDiscriminatorColumn($parent->getDiscriminatorColumn());
$class->setIdGeneratorType($parent->getIdGeneratorType());
$this->_addInheritedFields($class, $parent);
......
......@@ -75,11 +75,16 @@ class AnnotationDriver
'length' => $discrColumnAnnot->length
));
}
/*
// Evaluate DoctrineDiscriminatorMap annotation
if ($discrMapAnnot = $annotClass->getAnnotation('DoctrineDiscriminatorMap')) {
$metadata->setDiscriminatorMap((array)$discrMapAnnot->value);
}
*/
// Evaluate DoctrineDiscriminatorMap annotation
if ($discrValueAnnot = $annotClass->getAnnotation('DoctrineDiscriminatorValue')) {
$metadata->setDiscriminatorValue($discrValueAnnot->value);
}
// Evaluate DoctrineSubClasses annotation
if ($subClassesAnnot = $annotClass->getAnnotation('DoctrineSubClasses')) {
......
......@@ -31,6 +31,7 @@ final class DoctrineDiscriminatorColumn extends \Addendum\Annotation {
public $length;
}
final class DoctrineDiscriminatorMap extends \Addendum\Annotation {}
final class DoctrineDiscriminatorValue extends \Addendum\Annotation {}
final class DoctrineSubClasses extends \Addendum\Annotation {}
final class DoctrineId extends \Addendum\Annotation {}
final class DoctrineGeneratedValue extends \Addendum\Annotation {
......
<?php
/*
* $Id$
*
* 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.doctrine-project.org>.
*/
namespace Doctrine\ORM;
......@@ -6,51 +25,60 @@ namespace Doctrine\ORM;
* Represents a native SQL query.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
*/
class NativeQuery
class NativeQuery extends AbstractQuery
{
private $_sql;
private $_conn;
private $_params = array();
public function __construct($sql, Connection $conn)
/**
* Initializes a new instance of the <tt>NativeQuery</tt> class that is bound
* to the given EntityManager.
*
* @param EntityManager $em
*/
public function __construct(EntityManager $em)
{
$this->_sql = $sql;
$this->_conn = $conn;
parent::__construct($em);
}
/*public function addScalar()
{
}*/
public function addEntity($alias, $className)
/**
* Sets the SQL of the query.
*
* @param string $sql
*/
public function setSql($sql)
{
$this->_entities[$alias] = $className;
$this->_sql = $sql;
}
public function addJoin($join)
/**
* Gets the SQL query/queries that correspond to this DQL query.
*
* @return mixed The built sql query or an array of all sql queries.
* @override
*/
public function getSql()
{
return $this->_sql;
}
public function setParameter($key, $value)
/**
* Executed the query.
*
* @param array $params
* @return Statement The Statement handle.
* @override
*/
protected function _doExecute(array $params)
{
$this->_params[$key] = $value;
}
// Assignments for Enums
//$this->_setEnumParams($this->_parserResult->getEnumParams());
// Converting parameters
$params = $this->_prepareParams($params);
public function execute(array $params)
{
if ($this->_entities) {
//...
} else {
return $this->_conn->execute($this->_sql, array_merge($this->_params, $params));
}
}
public function executeUpdate(array $params)
{
return $this->_conn->exec($this->_sql, array_merge($this->_params, $params));
// Executing the query and returning statement
return $this->_em->getConnection()->execute($this->_sql, $params);
}
}
\ No newline at end of file
......@@ -244,13 +244,5 @@ abstract class AbstractEntityPersister
$result[$columnName] = $type->convertToDatabaseValue($newVal, $this->_conn->getDatabasePlatform());
}
}
/*
// Populate the discriminator column on insert in JOINED & SINGLE_TABLE inheritance
if ($isInsert && ($this->_classMetadata->isInheritanceTypeJoined() ||
$this->_classMetadata->isInheritanceTypeSingleTable())) {
$discColumn = $this->_classMetadata->getDiscriminatorColumn();
$discMap = $this->_classMetadata->getDiscriminatorMap();
$result[$discColumn['name']] = array_search($this->_entityName, $discMap);
}*/
}
}
\ No newline at end of file
......@@ -18,8 +18,8 @@ class SingleTablePersister extends AbstractEntityPersister
// Populate the discriminator column
if ($isInsert) {
$discColumn = $this->_classMetadata->getDiscriminatorColumn();
$discMap = $this->_classMetadata->getDiscriminatorMap();
$result[$discColumn['name']] = array_search($this->_entityName, $discMap);
//$discMap = $this->_classMetadata->getDiscriminatorMap();
$result[$discColumn['name']] = $this->_classMetadata->getDiscriminatorValue(); //array_search($this->_entityName, $discMap);
}
}
......
......@@ -38,589 +38,943 @@ use Doctrine\ORM\Query\QueryException;
*/
class Query extends AbstractQuery
{
/* Hydration mode constants */
/**
* Hydrates an object graph. This is the default behavior.
* QUERY TYPE CONSTANTS
*/
const HYDRATE_OBJECT = 1;
/**
* Hydrates an array graph.
*/
const HYDRATE_ARRAY = 2;
/**
* Hydrates a flat, rectangular result set with scalar values.
*/
const HYDRATE_SCALAR = 3;
/**
* Hydrates a single scalar value.
* Constant for SELECT queries.
*/
const HYDRATE_SINGLE_SCALAR = 4;
const SELECT = 0;
/**
* Hydrates nothing.
* Constant for DELETE queries.
*/
const HYDRATE_NONE = 5;
const DELETE = 1;
/**
* @var Doctrine\ORM\EntityManager The entity manager used by this query object.
* Constant for UPDATE queries.
*/
protected $_em;
const UPDATE = 2;
/**
* @var integer The hydration mode.
* A query object is in CLEAN state when it has NO unparsed/unprocessed DQL parts.
*/
protected $_hydrationMode = self::HYDRATE_OBJECT;
const STATE_CLEAN = 1;
/**
* @var Doctrine\ORM\Query\ParserResult The parser result that holds DQL => SQL information.
* A query object is in state DIRTY when it has DQL parts that have not yet been
* parsed/processed. This is automatically defined as DIRTY when addDqlQueryPart
* is called.
*/
protected $_parserResult;
const STATE_DIRTY = 2;
/**
* A set of query hints.
* @var integer $type Query type.
*
* @var array
* @see Query::* constants
*/
protected $_hints = array();
// Caching Stuff
protected $_type = self::SELECT;
/**
* @var Doctrine_Cache_Interface The cache driver used for caching result sets.
* @var integer $_state The current state of this query.
*/
protected $_resultCache;
protected $_state = self::STATE_CLEAN;
/**
* @var boolean Boolean value that indicates whether or not expire the result cache.
* @var array $_dqlParts An array containing all DQL query parts.
* @see Query::free that initializes this property
*/
protected $_expireResultCache = false;
protected $_dqlParts = array();
/**
* @var int Result Cache lifetime.
* @var string $_dql Cached DQL query.
*/
protected $_resultCacheTTL;
protected $_dql = null;
/**
* @var Doctrine\ORM\Query\ParserResult The parser result that holds DQL => SQL information.
*/
protected $_parserResult;
/**
* @var Doctrine_Cache_Interface The cache driver used for caching queries.
*/
protected $_queryCache;
//protected $_queryCache;
/**
* @var boolean Boolean value that indicates whether or not expire the query cache.
*/
protected $_expireQueryCache = false;
//protected $_expireQueryCache = false;
/**
* @var int Query Cache lifetime.
*/
protected $_queryCacheTTL;
//protected $_queryCacheTTL;
// End of Caching Stuff
/**
* Initializes a new instance of the Query class.
* Initializes a new Query instance.
*
* @param Doctrine\ORM\EntityManager $entityManager
*/
public function __construct(EntityManager $entityManager)
{
$this->_em = $entityManager;
$this->free();
parent::__construct($entityManager);
}
/**
* Retrieves the associated EntityManager of this Query instance.
* Gets the SQL query/queries that correspond to this DQL query.
*
* @return Doctrine\ORM\EntityManager
* @return mixed The built sql query or an array of all sql queries.
* @override
*/
public function getEntityManager()
public function getSql()
{
return $this->_em;
return $this->parse()->getSqlExecutor()->getSqlStatements();
}
/**
* Convenience method to execute using array fetching as hydration mode.
* Parses the DQL query, if necessary, and stores the parser result.
*
* @param string $params
* @return array
* Note: Populates $this->_parserResult as a side-effect.
*
* @return Doctrine\ORM\Query\ParserResult
*/
public function fetchArray($params = array())
public function parse()
{
return $this->execute($params, self::HYDRATE_ARRAY);
if ($this->_state === self::STATE_DIRTY) {
$parser = new Parser($this);
$this->_parserResult = $parser->parse();
$this->_state = self::STATE_CLEAN;
}
return $this->_parserResult;
}
/**
* Convenience method to execute the query and return the first item
* of the collection.
* _execute
*
* @param string $params Parameters
* @param int $hydrationMode Hydration mode
* @return mixed Array or Doctrine\Common\Collection or false if no result.
* @param array $params
* @return PDOStatement The executed PDOStatement.
* @override
*/
public function fetchOne($params = array(), $hydrationMode = null)
protected function _doExecute(array $params)
{
$collection = $this->limit(1)->execute($params, $hydrationMode);
// If there is a CacheDriver associated to cache queries...
if ($queryCache = $this->_em->getConfiguration()->getQueryCacheImpl()) {
// Calculate hash for dql query.
$hash = md5($this->getDql() . 'DOCTRINE_QUERY_CACHE_SALT');
$cached = ($this->_expireQueryCache) ? false : $queryCache->fetch($hash);
if (count($collection) === 0) {
return false;
if ($cached === false) {
// Cache miss.
$executor = $this->parse()->getSqlExecutor();
$queryCache->save($hash, $this->_parserResult->toCachedForm(), null);
} else {
// Cache hit.
$this->_parserResult = CacheHandler::fromCachedQuery($this, $cached);
$executor = $this->_parserResult->getSqlExecutor();
}
} else {
$executor = $this->parse()->getSqlExecutor();
}
if ($collection instanceof Collection) {
return $collection->getFirst();
} else if (is_array($collection)) {
return array_shift($collection);
// Assignments for Enums
$this->_setEnumParams($this->_parserResult->getEnumParams());
// Converting parameters
$params = $this->_prepareParams($params);
if ( ! $this->_resultSetMapping) {
$this->_resultSetMapping = $this->_parserResult->getResultSetMapping();
}
return false;
// Executing the query and returning statement
return $executor->execute($this->_em->getConnection(), $params);
}
/**
* Query the database with DQL (Doctrine Query Language).
* Defines a cache driver to be used for caching queries.
*
* @param string $query The DQL query.
* @param array $params The query parameters.
* @param int $hydrationMode
* @return mixed
* @param Doctrine_Cache_Interface|null $driver Cache driver
* @return Doctrine_ORM_Query
*/
public function query($query, $params = array(), $hydrationMode = null)
/*public function setQueryCache($queryCache)
{
$this->setDql($query);
return $this->execute($params, $hydrationMode);
if ($queryCache !== null && ! ($queryCache instanceof \Doctrine\ORM\Cache\Cache)) {
throw DoctrineException::updateMe(
'Method setResultCache() accepts only an instance of Doctrine_ORM_Cache_Interface or null.'
);
}
$this->_queryCache = $queryCache;
return $this;
}*/
/**
* Gets the SQL query/queries that correspond to this DQL query.
* Returns the cache driver used for caching queries.
*
* @return mixed The built sql query or an array of all sql queries.
* @return Doctrine_Cache_Interface Cache driver
*/
public function getSql()
/*public function getQueryCache()
{
return $this->parse()->getSqlExecutor()->getSqlStatements();
if ($this->_queryCache instanceof \Doctrine\ORM\Cache\Cache) {
return $this->_queryCache;
} else {
return $this->_em->getConnection()->getQueryCacheDriver();
}
}*/
/**
* Parses the DQL query, if necessary, and stores the parser result.
* Defines how long the query cache will be active before expire.
*
* Note: Populates $this->_parserResult as a side-effect.
* @param integer $timeToLive How long the cache entry is valid
* @return Doctrine_ORM_Query
*/
/*public function setQueryCacheLifetime($timeToLive)
{
if ($timeToLive !== null) {
$timeToLive = (int) $timeToLive;
}
$this->_queryCacheTTL = $timeToLive;
return $this;
}*/
/**
* Retrieves the lifetime of resultset cache.
*
* @return Doctrine\ORM\Query\ParserResult
* @return int
*/
public function parse()
/*public function getQueryCacheLifetime()
{
if ($this->_state === self::STATE_DIRTY) {
$parser = new Parser($this);
$this->_parserResult = $parser->parse();
return $this->_queryCacheTTL;
}*/
/**
* Defines if the query cache is active or not.
*
* @param boolean $expire Whether or not to force query cache expiration.
* @return Doctrine_ORM_Query
*/
/*public function setExpireQueryCache($expire = true)
{
$this->_expireQueryCache = (bool) $expire;
return $this;
}*/
/**
* Retrieves if the query cache is active or not.
*
* @return bool
*/
/*public function getExpireQueryCache()
{
return $this->_expireQueryCache;
}*/
/**
* @override
*/
public function free()
{
parent::free();
$this->_dqlParts = array(
'select' => array(),
'distinct' => false,
'from' => array(),
'join' => array(),
'set' => array(),
'where' => array(),
'groupby' => array(),
'having' => array(),
'orderby' => array(),
'limit' => array(),
'offset' => array(),
);
$this->_dql = null;
$this->_state = self::STATE_CLEAN;
}
return $this->_parserResult;
/**
* Sets a DQL query string.
*
* @param string $dqlQuery DQL Query
*/
public function setDql($dqlQuery)
{
$this->free();
if ($dqlQuery !== null) {
$this->_dql = $dqlQuery;
$this->_state = self::STATE_DIRTY;
}
}
/**
* Executes the query.
* Returns the DQL query that is represented by this query object.
*
* @param string $params Parameters to be sent to query.
* @param integer $hydrationMode Doctrine processing mode to be used during hydration process.
* One of the Query::HYDRATE_* constants.
* @return mixed
* @return string DQL query
*/
public function execute($params = array(), $hydrationMode = null)
public function getDql()
{
if ($this->_em->getUnitOfWork()->hasPendingInsertions()) {
$this->_em->flush();
if ($this->_dql !== null) {
return $this->_dql;
}
if ($hydrationMode !== null) {
$this->_hydrationMode = $hydrationMode;
$dql = '';
switch ($this->_type) {
case self::DELETE:
$dql = $this->_getDqlForDelete();
break;
case self::UPDATE:
$dql = $this->_getDqlForUpdate();
break;
case self::SELECT:
default:
$dql = $this->_getDqlForSelect();
break;
}
$params = $this->getParams($params);
return $dql;
}
// Check result cache
if ($this->_resultCache && $this->_type === self::SELECT) { // Only executes if "SELECT"
$cacheDriver = $this->getResultCacheDriver();
/**
* Builds the DQL of DELETE
*/
protected function _getDqlForDelete()
{
/*
* BNF:
*
* DeleteStatement = DeleteClause [WhereClause] [OrderByClause] [LimitClause] [OffsetClause]
* DeleteClause = "DELETE" "FROM" RangeVariableDeclaration
* WhereClause = "WHERE" ConditionalExpression
* OrderByClause = "ORDER" "BY" OrderByItem {"," OrderByItem}
* LimitClause = "LIMIT" integer
* OffsetClause = "OFFSET" integer
*
*/
return 'DELETE'
. $this->_getReducedDqlQueryPart('from', array('pre' => ' FROM ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('where', array('pre' => ' WHERE ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('orderby', array('pre' => ' ORDER BY ', 'separator' => ', '))
. $this->_getReducedDqlQueryPart('limit', array('pre' => ' LIMIT ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('offset', array('pre' => ' OFFSET ', 'separator' => ' '));
}
// Calculate hash for dql query.
$hash = md5($this->getDql() . var_export($params, true));
$cached = ($this->_expireResultCache) ? false : $cacheDriver->fetch($hash);
if ($cached === false) {
// Cache does not exist, we have to create it.
$result = $this->_execute($params, self::HYDRATE_ARRAY);
$queryResult = CacheHandler::fromResultSet($this, $result);
$cacheDriver->save($hash, $queryResult->toCachedForm(), $this->_resultCacheTTL);
/**
* Builds the DQL of UPDATE
*/
protected function _getDqlForUpdate()
{
/*
* BNF:
*
* UpdateStatement = UpdateClause [WhereClause] [OrderByClause] [LimitClause] [OffsetClause]
* UpdateClause = "UPDATE" RangeVariableDeclaration "SET" UpdateItem {"," UpdateItem}
* WhereClause = "WHERE" ConditionalExpression
* OrderByClause = "ORDER" "BY" OrderByItem {"," OrderByItem}
* LimitClause = "LIMIT" integer
* OffsetClause = "OFFSET" integer
*
*/
return 'UPDATE'
. $this->_getReducedDqlQueryPart('from', array('pre' => ' FROM ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('where', array('pre' => ' SET ', 'separator' => ', '))
. $this->_getReducedDqlQueryPart('where', array('pre' => ' WHERE ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('orderby', array('pre' => ' ORDER BY ', 'separator' => ', '))
. $this->_getReducedDqlQueryPart('limit', array('pre' => ' LIMIT ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('offset', array('pre' => ' OFFSET ', 'separator' => ' '));
}
return $result;
} else {
// Cache exists, recover it and return the results.
$queryResult = CacheHandler::fromCachedResult($this, $cached);
return $queryResult->getResultSet();
/**
* Builds the DQL of SELECT
*/
protected function _getDqlForSelect()
{
/*
* BNF:
*
* SelectStatement = [SelectClause] FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] [LimitClause] [OffsetClause]
* SelectClause = "SELECT" ["ALL" | "DISTINCT"] SelectExpression {"," SelectExpression}
* FromClause = "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}
* WhereClause = "WHERE" ConditionalExpression
* GroupByClause = "GROUP" "BY" GroupByItem {"," GroupByItem}
* HavingClause = "HAVING" ConditionalExpression
* OrderByClause = "ORDER" "BY" OrderByItem {"," OrderByItem}
* LimitClause = "LIMIT" integer
* OffsetClause = "OFFSET" integer
*
*/
/**
* @todo [TODO] What about "ALL" support?
*/
return 'SELECT'
. (($this->getDqlQueryPart('distinct') === true) ? ' DISTINCT' : '')
. $this->_getReducedDqlQueryPart('select', array('pre' => ' ', 'separator' => ', ', 'empty' => ' *'))
. $this->_getReducedDqlQueryPart('from', array('pre' => ' FROM ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('where', array('pre' => ' WHERE ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('groupby', array('pre' => ' GROUP BY ', 'separator' => ', '))
. $this->_getReducedDqlQueryPart('having', array('pre' => ' HAVING ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('orderby', array('pre' => ' ORDER BY ', 'separator' => ', '))
. $this->_getReducedDqlQueryPart('limit', array('pre' => ' LIMIT ', 'separator' => ' '))
. $this->_getReducedDqlQueryPart('offset', array('pre' => ' OFFSET ', 'separator' => ' '));
}
/**
* @nodoc
*/
protected function _getReducedDqlQueryPart($queryPartName, $options = array())
{
if (empty($this->_dqlParts[$queryPartName])) {
return (isset($options['empty']) ? $options['empty'] : '');
}
$stmt = $this->_execute($params);
$str = (isset($options['pre']) ? $options['pre'] : '');
$str .= implode($options['separator'], $this->getDqlQueryPart($queryPartName));
$str .= (isset($options['post']) ? $options['post'] : '');
if (is_integer($stmt)) {
return $stmt;
return $str;
}
return $this->_em->getHydrator($this->_hydrationMode)->hydrateAll($stmt, $this->_parserResult);
/**
* Returns the type of this query object
* By default the type is Doctrine_ORM_Query_Abstract::SELECT but if update() or delete()
* are being called the type is Doctrine_ORM_Query_Abstract::UPDATE and Doctrine_ORM_Query_Abstract::DELETE,
* respectively.
*
* @see Doctrine_ORM_Query_Abstract::SELECT
* @see Doctrine_ORM_Query_Abstract::UPDATE
* @see Doctrine_ORM_Query_Abstract::DELETE
*
* @return integer Return the query type
*/
public function getType()
{
return $this->_type;
}
/**
* _execute
* Returns the state of this query object
* By default the type is Doctrine_ORM_Query_Abstract::STATE_CLEAN but if it appears any unprocessed DQL
* part, it is switched to Doctrine_ORM_Query_Abstract::STATE_DIRTY.
*
* @param array $params
* @return PDOStatement The executed PDOStatement.
* @see AbstractQuery::STATE_CLEAN
* @see AbstractQuery::STATE_DIRTY
*
* @return integer Return the query state
*/
protected function _execute(array $params)
public function getState()
{
// If there is a CacheDriver associated to cache queries...
if ($this->_queryCache || $this->_em->getConfiguration()->getQueryCacheImpl()) {
$queryCacheDriver = $this->getQueryCacheDriver();
return $this->_state;
}
// Calculate hash for dql query.
$hash = md5($this->getDql() . 'DOCTRINE_QUERY_CACHE_SALT');
$cached = ($this->_expireQueryCache) ? false : $queryCacheDriver->fetch($hash);
/**
* Adds fields to the SELECT part of the query
*
* @param string $select Query SELECT part
* @return Doctrine_ORM_Query
*/
public function select($select = '', $override = false)
{
if ($select === '') {
return $this;
}
if ($cached === false) {
// Cache does not exist, we have to create it.
$executor = $this->parse()->getSqlExecutor();
return $this->_addDqlQueryPart('select', $select, ! $override);
}
// To-be cached item is parserResult
$cacheDriver->save($hash, $this->_parserResult->toCachedForm(), $this->_queryCacheTTL);
} else {
// Cache exists, recover it and return the results.
$this->_parserResult = CacheHandler::fromCachedQuery($this, $cached);
/**
* Makes the query SELECT DISTINCT.
*
* @param bool $flag Whether or not the SELECT is DISTINCT (default true).
* @return Doctrine_ORM_Query
*/
public function distinct($flag = true)
{
$this->_dqlParts['distinct'] = (bool) $flag;
return $this;
}
$executor = $this->_parserResult->getSqlExecutor();
/**
* Sets the query type to DELETE
*
* @return Doctrine_ORM_Query
*/
public function delete()
{
$this->_type = self::DELETE;
return $this;
}
/**
* Sets the UPDATE part of the query
*
* @param string $update Query UPDATE part
* @return Doctrine_ORM_Query
*/
public function update($update)
{
$this->_type = self::UPDATE;
return $this->_addDqlQueryPart('from', $update);
}
/**
* Sets the SET part of the query
*
* @param mixed $key UPDATE keys. Accepts either a string (requiring then $value or $params to be defined)
* or an array of $key => $value pairs.
* @param string $value UPDATE key value. Optional argument, but required if $key is a string.
* @return Doctrine_ORM_Query
*/
public function set($key, $value = null, $params = null)
{
if (is_array($key)) {
foreach ($key as $k => $v) {
$this->set($k, '?', array($v));
}
return $this;
} else {
$executor = $this->parse()->getSqlExecutor();
if ($params !== null) {
if (is_array($params)) {
$this->_params['set'] = array_merge($this->_params['set'], $params);
} else {
$this->_params['set'][] = $params;
}
}
// Assignments for Enums
$this->_setEnumParams($this->_parserResult->getEnumParams());
if ($value === null) {
throw \Doctrine\Common\DoctrineException::updateMe( 'Cannot try to set \''.$key.'\' without a value.' );
}
// Converting parameters
$params = $this->_prepareParams($params);
return $this->_addDqlQueryPart('set', $key . ' = ' . $value, true);
}
}
// Executing the query and returning statement
return $executor->execute($this->_em->getConnection(), $params);
/**
* Adds fields to the FROM part of the query
*
* @param string $from Query FROM part
* @return Doctrine_ORM_Query
*/
public function from($from, $override = false)
{
return $this->_addDqlQueryPart('from', $from, ! $override);
}
/**
* @nodoc
* Appends an INNER JOIN to the FROM part of the query
*
* @param string $join Query INNER JOIN
* @param mixed $params Optional JOIN params (array of parameters or a simple scalar)
* @return Doctrine_ORM_Query
*/
protected function _prepareParams(array $params)
public function innerJoin($join, $params = array())
{
// Convert boolean params
$params = $this->_em->getConnection()->getDatabasePlatform()->convertBooleans($params);
if (is_array($params)) {
$this->_params['join'] = array_merge($this->_params['join'], $params);
} else {
$this->_params['join'][] = $params;
}
// Convert enum params
return $this->convertEnums($params);
return $this->_addDqlQueryPart('from', 'INNER JOIN ' . $join, true);
}
/**
* Defines a cache driver to be used for caching result sets.
* Appends an INNER JOIN to the FROM part of the query
*
* @param Doctrine\ORM\Cache\Cache $driver Cache driver
* @return Doctrine\ORM\Query
* @param string $join Query INNER JOIN
* @param mixed $params Optional JOIN params (array of parameters or a simple scalar)
* @return Doctrine_ORM_Query
*/
public function setResultCache($resultCache)
public function join($join, $params = array())
{
if ($resultCache !== null && ! ($resultCache instanceof \Doctrine\ORM\Cache\Cache)) {
throw DoctrineException::updateMe(
'Method setResultCache() accepts only an instance of Doctrine_Cache_Interface or null.'
);
return $this->innerJoin($join, $params);
}
$this->_resultCache = $resultCache;
return $this;
/**
* Appends a LEFT JOIN to the FROM part of the query
*
* @param string $join Query LEFT JOIN
* @param mixed $params Optional JOIN params (array of parameters or a simple scalar)
* @return Doctrine_ORM_Query
*/
public function leftJoin($join, $params = array())
{
if (is_array($params)) {
$this->_params['join'] = array_merge($this->_params['join'], $params);
} else {
$this->_params['join'][] = $params;
}
return $this->_addDqlQueryPart('from', 'LEFT JOIN ' . $join, true);
}
/**
* Returns the cache driver used for caching result sets.
* Adds conditions to the WHERE part of the query
*
* @return Doctrine_Cache_Interface Cache driver
* @param string $where Query WHERE part
* @param mixed $params An array of parameters or a simple scalar
* @return Doctrine_ORM_Query
*/
public function getResultCache()
public function where($where, $params = array(), $override = false)
{
if ($this->_resultCache instanceof \Doctrine\ORM\Cache\Cache) {
return $this->_resultCache;
if ($override) {
$this->_params['where'] = array();
}
if (is_array($params)) {
$this->_params['where'] = array_merge($this->_params['where'], $params);
} else {
return $this->_em->getConnection()->getResultCacheDriver();
$this->_params['where'][] = $params;
}
return $this->_addDqlQueryPart('where', $where, ! $override);
}
/**
* Defines how long the result cache will be active before expire.
* Adds conditions to the WHERE part of the query
*
* @param integer $timeToLive How long the cache entry is valid
* @return Doctrine\ORM\Query
* @param string $where Query WHERE part
* @param mixed $params An array of parameters or a simple scalar
* @return Doctrine_ORM_Query
*/
public function setResultCacheLifetime($timeToLive)
public function andWhere($where, $params = array(), $override = false)
{
if ($timeToLive !== null) {
$timeToLive = (int) $timeToLive;
if (count($this->getDqlQueryPart('where')) > 0) {
$this->_addDqlQueryPart('where', 'AND', true);
}
$this->_resultCacheTTL = $timeToLive;
return $this;
return $this->where($where, $params, $override);
}
/**
* Retrieves the lifetime of resultset cache.
* Adds conditions to the WHERE part of the query
*
* @return int
* @param string $where Query WHERE part
* @param mixed $params An array of parameters or a simple scalar
* @return Doctrine_ORM_Query
*/
public function getResultCacheLifetime()
public function orWhere($where, $params = array(), $override = false)
{
return $this->_resultCacheTTL;
if (count($this->getDqlQueryPart('where')) > 0) {
$this->_addDqlQueryPart('where', 'OR', true);
}
return $this->where($where, $params, $override);
}
/**
* Defines if the resultset cache is active or not.
* Adds IN condition to the query WHERE part
*
* @param boolean $expire Whether or not to force resultset cache expiration.
* @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_ORM_Query
*/
public function setExpireResultCache($expire = true)
public function whereIn($expr, $params = array(), $override = false, $not = false)
{
$this->_expireResultCache = (bool) $expire;
$params = (array) $params;
// Must have at least one param, otherwise we'll get an empty IN () => invalid SQL
if ( ! count($params)) {
return $this;
}
list($sqlPart, $params) = $this->_processWhereInParams($params);
$where = $expr . ($not === true ? ' NOT' : '') . ' IN (' . $sqlPart . ')';
return $this->_returnWhereIn($where, $params, $override);
}
/**
* Retrieves if the resultset cache is active or not.
* Adds NOT IN condition to the query WHERE part
*
* @return bool
* @param string $expr The operand of the NOT IN
* @param mixed $params An array of parameters or a simple scalar
* @return Doctrine_ORM_Query
*/
public function getExpireResultCache()
public function whereNotIn($expr, $params = array(), $override = false)
{
return $this->_expireResultCache;
return $this->whereIn($expr, $params, $override, true);
}
/**
* Defines a cache driver to be used for caching queries.
* Adds IN condition to the query WHERE part
*
* @param Doctrine_Cache_Interface|null $driver Cache driver
* @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_ORM_Query
*/
public function setQueryCache($queryCache)
public function andWhereIn($expr, $params = array(), $override = false)
{
if ($queryCache !== null && ! ($queryCache instanceof \Doctrine\ORM\Cache\Cache)) {
throw DoctrineException::updateMe(
'Method setResultCache() accepts only an instance of Doctrine_ORM_Cache_Interface or null.'
);
if (count($this->getDqlQueryPart('where')) > 0) {
$this->_addDqlQueryPart('where', 'AND', true);
}
$this->_queryCache = $queryCache;
return $this;
return $this->whereIn($expr, $params, $override);
}
/**
* Returns the cache driver used for caching queries.
* Adds NOT IN condition to the query WHERE part
*
* @return Doctrine_Cache_Interface Cache driver
* @param string $expr The operand of the NOT IN
* @param mixed $params An array of parameters or a simple scalar
* @return Doctrine_ORM_Query
*/
public function getQueryCache()
public function andWhereNotIn($expr, $params = array(), $override = false)
{
if ($this->_queryCache instanceof \Doctrine\ORM\Cache\Cache) {
return $this->_queryCache;
} else {
return $this->_em->getConnection()->getQueryCacheDriver();
if (count($this->getDqlQueryPart('where')) > 0) {
$this->_addDqlQueryPart('where', 'AND', true);
}
return $this->whereIn($expr, $params, $override, true);
}
/**
* Defines how long the query cache will be active before expire.
* Adds IN condition to the query WHERE part
*
* @param integer $timeToLive How long the cache entry is valid
* @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_ORM_Query
*/
public function setQueryCacheLifetime($timeToLive)
public function orWhereIn($expr, $params = array(), $override = false)
{
if ($timeToLive !== null) {
$timeToLive = (int) $timeToLive;
if (count($this->getDqlQueryPart('where')) > 0) {
$this->_addDqlQueryPart('where', 'OR', true);
}
$this->_queryCacheTTL = $timeToLive;
return $this->whereIn($expr, $params, $override);
}
return $this;
/**
* 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_ORM_Query
*/
public function orWhereNotIn($expr, $params = array(), $override = false)
{
if (count($this->getDqlQueryPart('where')) > 0) {
$this->_addDqlQueryPart('where', 'OR', true);
}
return $this->whereIn($expr, $params, $override, true);
}
/**
* Retrieves the lifetime of resultset cache.
* Adds fields to the GROUP BY part of the query
*
* @return int
* @param string $groupby Query GROUP BY part
* @return Doctrine_ORM_Query
*/
public function getQueryCacheLifetime()
public function groupBy($groupby, $override = false)
{
return $this->_queryCacheTTL;
return $this->_addDqlQueryPart('groupby', $groupby, ! $override);
}
/**
* Defines if the query cache is active or not.
* Adds conditions to the HAVING part of the query
*
* @param boolean $expire Whether or not to force query cache expiration.
* @param string $having Query HAVING part
* @param mixed $params An array of parameters or a simple scalar
* @return Doctrine_ORM_Query
*/
public function setExpireQueryCache($expire = true)
public function having($having, $params = array(), $override = false)
{
$this->_expireQueryCache = (bool) $expire;
if ($override) {
$this->_params['having'] = array();
}
return $this;
if (is_array($params)) {
$this->_params['having'] = array_merge($this->_params['having'], $params);
} else {
$this->_params['having'][] = $params;
}
return $this->_addDqlQueryPart('having', $having, true);
}
/**
* Retrieves if the query cache is active or not.
* Adds conditions to the HAVING part of the query
*
* @return bool
* @param string $having Query HAVING part
* @param mixed $params An array of parameters or a simple scalar
* @return Doctrine_ORM_Query
*/
public function getExpireQueryCache()
public function andHaving($having, $params = array(), $override = false)
{
return $this->_expireQueryCache;
if (count($this->getDqlQueryPart('having')) > 0) {
$this->_addDqlQueryPart('having', 'AND', true);
}
return $this->having($having, $params, $override);
}
/**
* Defines the processing mode to be used during hydration process.
* Adds conditions to the HAVING part of the query
*
* @param integer $hydrationMode Doctrine processing mode to be used during hydration process.
* One of the Query::HYDRATE_* constants.
* @return Doctrine\ORM\Query
* @param string $having Query HAVING part
* @param mixed $params An array of parameters or a simple scalar
* @return Doctrine_ORM_Query
*/
public function setHydrationMode($hydrationMode)
public function orHaving($having, $params = array(), $override = false)
{
$this->_hydrationMode = $hydrationMode;
return $this;
if (count($this->getDqlQueryPart('having')) > 0) {
$this->_addDqlQueryPart('having', 'OR', true);
}
return $this->having($having, $params, $override);
}
/**
* Gets the hydration mode currently used by the query.
* Adds fields to the ORDER BY part of the query
*
* @return integer
* @param string $orderby Query ORDER BY part
* @return Doctrine_ORM_Query
*/
public function getHydrationMode()
public function orderBy($orderby, $override = false)
{
return $this->_hydrationMode;
return $this->_addDqlQueryPart('orderby', $orderby, ! $override);
}
/**
* Gets the list of results for the query.
*
* Alias for execute(array(), HYDRATE_OBJECT).
* Sets the Query query limit
*
* @return Collection
* @param integer $limit Limit to be used for limiting the query results
* @return Doctrine_ORM_Query
*/
public function getResultList()
public function limit($limit)
{
return $this->execute(array(), self::HYDRATE_OBJECT);
return $this->_addDqlQueryPart('limit', $limit);
}
/**
* Gets the array of results for the query.
*
* Alias for execute(array(), HYDRATE_ARRAY).
* Sets the Query query offset
*
* @return array
* @param integer $offset Offset to be used for paginating the query
* @return Doctrine_ORM_Query
*/
public function getResultArray()
public function offset($offset)
{
return $this->execute(array(), self::HYDRATE_ARRAY);
return $this->_addDqlQueryPart('offset', $offset);
}
/**
* Gets the scalar results for the query.
*
* Alias for execute(array(), HYDRATE_SCALAR).
* Method to check if a arbitrary piece of DQL exists
*
* @return array
* @param string $dql Arbitrary piece of DQL to check for
* @return boolean
*/
public function getScalarResult()
public function contains($dql)
{
return $this->execute(array(), self::HYDRATE_SCALAR);
return stripos($this->getDql(), $dql) === false ? false : true;
}
/**
* Gets the single result of the query.
* Enforces the uniqueness of the result. If the result is not unique,
* a QueryException is thrown.
* Retrieve a DQL part for internal purposes
*
* @param integer $hydrationMode
* @return mixed
* @throws QueryException If the query result is not unique.
* @param string $queryPartName The name of the query part.
* @return mixed Array related to query part or simple scalar
*/
public function getSingleResult($hydrationMode = null)
public function getDqlQueryPart($queryPartName)
{
$result = $this->execute(array(), $hydrationMode);
if (is_array($result)) {
if (count($result) > 1) {
throw QueryException::nonUniqueResult();
if ( ! isset($this->_dqlParts[$queryPartName])) {
throw \Doctrine\Common\DoctrineException::updateMe('Unknown DQL query part \'' . $queryPartName . '\'');
}
return array_shift($result);
} else if (is_object($result)) {
if (count($result) > 1) {
throw QueryException::nonUniqueResult();
return $this->_dqlParts[$queryPartName];
}
return $result->getFirst();
/**
* Adds a DQL part to the internal parts collection.
*
* @param string $queryPartName The name of the query part.
* @param string $queryPart The actual query part to add.
* @param boolean $append Whether to append $queryPart to already existing
* parts under the same $queryPartName. Defaults to FALSE
* (previously added parts with the same name get overridden).
* @return Doctrine_ORM_Query
*/
protected function _addDqlQueryPart($queryPartName, $queryPart, $append = false)
{
if ($append) {
$this->_dqlParts[$queryPartName][] = $queryPart;
} else {
$this->_dqlParts[$queryPartName] = array($queryPart);
}
return $result;
$this->_state = Doctrine_ORM_Query::STATE_DIRTY;
return $this;
}
/**
* Gets the single scalar result of the query.
*
* Alias for getSingleResult(HYDRATE_SINGLE_SCALAR).
* Processes the WHERE IN () parameters and return an indexed array containing
* the sqlPart to be placed in SQL statement and the new parameters (that will be
* bound in SQL execution)
*
* @return mixed
* @throws QueryException If the query result is not unique.
* @param array $params Parameters to be processed
* @return array
*/
public function getSingleScalarResult()
protected function _processWhereInParams($params = array())
{
return $this->getSingleResult(self::HYDRATE_SINGLE_SCALAR);
return array(
// [0] => sqlPart
implode(', ', array_map(array(&$this, '_processWhereInSqlPart'), $params)),
// [1] => params
array_filter($params, array(&$this, '_processWhereInParamItem')),
);
}
/**
* Sets an implementation-specific hint. If the hint name is not recognized,
* it is silently ignored.
*
* @param string $name The name of the hint.
* @param mixed $value The value of the hint.
* @nodoc
*/
public function setHint($name, $value)
protected function _processWhereInSqlPart($value)
{
$this->_hints[$name] = $value;
// [TODO] Add support to imbricated query (must deliver the hardest effort to Parser)
return ($value instanceof Doctrine_Expression) ? $value->getSql() : '?';
}
/**
* Gets an implementation-specific hint. If the hint name is not recognized,
* FALSE is returned.
*
* @param string $name The name of the hint.
* @nodoc
*/
public function getHint($name)
protected function _processWhereInParamItem($value)
{
return isset($this->_hints[$name]) ? $this->_hints[$name] : false;
// [TODO] Add support to imbricated query (must deliver the hardest effort to Parser)
return ( ! ($value instanceof Doctrine_Expression));
}
/**
* Executes the query and returns an IterableResult that can be used to incrementally
* iterated over the result.
* Processes a WHERE IN () and build defined stuff to add in DQL
*
* @param array $params The query parameters.
* @param integer $hydrationMode The hydratio mode to use.
* @return IterableResult
* @param string $where The WHERE clause to be added
* @param array $params WHERE clause parameters
* @param mixed $appender Where this clause may be not be appended, or appended
* (two possible values: AND or OR)
* @return Doctrine_ORM_Query
*/
public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_OBJECT)
protected function _returnWhereIn($where, $params = array(), $override = false)
{
return $this->_em->getHydrator($this->_hydrationMode)->iterate(
$this->_execute($params, $hydrationMode), $this->_parserResult
);
// Parameters inclusion
$this->_params['where'] = $override ? $params : array_merge($this->_params['where'], $params);
// WHERE clause definition
return $this->_addDqlQueryPart('where', $where, ! $override);
}
}
\ No newline at end of file
......@@ -46,31 +46,6 @@ abstract class AbstractResult
*/
protected $_enumParams = array();
/**
* @var boolean
*/
protected $_isMixedQuery = false;
/**
* Gets whether the parsed query selects objects/arrays and scalar values
* at the same time.
*
* @return boolean
*/
public function isMixedQuery()
{
return $this->_isMixedQuery;
}
/**
* Sets whether the parsed query selects objects/arrays and scalar values
* at the same time.
*/
public function setMixedQuery($bool)
{
$this->_isMixedQuery = $bool;
}
/**
* Returns the enum parameters.
*
......
......@@ -16,7 +16,7 @@
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query\Exec;
......
......@@ -112,30 +112,12 @@ class Parser
*/
private $_query;
/**
* Whether the query is a SELECT query and contains scalar values in the result list
* as defined by the SelectExpressions.
*
* @var boolean
*/
private $_resultContainsScalars = false;
/**
* Whether the query is a SELECT query and contains properties in the result list
* as defined by the SelectExpressions.
*
* @var boolean
*/
private $_resultContainsProperties = false;
/**
* Map of declared classes in the parsed query.
* Maps the declared DQL alias (key) to the class name (value).
*
* @var array
*/
//private $_declaredClasses = array();
private $_queryComponents = array();
/**
......@@ -656,10 +638,6 @@ class Parser
$peek = $this->_lexer->glimpse();
// First we recognize for an IdentificationVariable (DQL class alias)
if ($peek['value'] != '.' && $peek['value'] != '(' && $this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) {
$this->_resultContainsProperties = true;
if ($this->_resultContainsScalars) {
$this->_parserResult->setMixedQuery(true);
}
$expression = $this->_IdentificationVariable();
} else if (($isFunction = $this->_isFunction()) !== false || $this->_isSubselect()) {
if ($isFunction) {
......@@ -680,15 +658,7 @@ class Parser
$this->match(Lexer::T_IDENTIFIER);
$fieldIdentificationVariable = $this->_lexer->token['value'];
}
$this->_resultContainsScalars = true;
if ($this->_resultContainsProperties) {
$this->_parserResult->setMixedQuery(true);
}
} else {
$this->_resultContainsProperties = true;
if ($this->_resultContainsScalars) {
$this->_parserResult->setMixedQuery(true);
}
//TODO: If hydration mode is OBJECT throw an exception ("partial object dangerous...")
// unless the doctrine.forcePartialLoad query hint is set
$expression = $this->_StateFieldPathExpression();
......
......@@ -29,6 +29,8 @@ namespace Doctrine\ORM\Query;
*/
class ResultSetMapping
{
/** Whether the result is mixed (contains scalar values together with field values). */
private $_isMixed = false;
/** Maps alias names to ClassMetadata descriptors. */
private $_aliasMap = array();
/** Maps alias names to related association mappings. */
......@@ -41,10 +43,12 @@ class ResultSetMapping
private $_scalarMappings = array();
/** Maps column names in the result set to the alias they belong to. */
private $_columnOwnerMap = array();
/** Maps discriminator columns in the result set to the class they represent. */
private $_discriminatorMap = array();
/** List of columns in the result set that are used as discriminator columns. */
private $_discriminatorColumns = array();
/** Maps alias names to field names that should be used for indexing. */
private $_indexByMap = array();
/** A list of columns that should be ignored/skipped during hydration. */
private $_ignoredColumns = array();
/**
*
......@@ -52,12 +56,21 @@ class ResultSetMapping
* @param <type> $alias The alias for this class. The alias must be unique within this ResultSetMapping.
* @param <type> $discriminatorColumn
*/
public function addEntityResult($class, $alias, $discriminatorColumn = null)
public function addEntityResult($class, $alias)
{
$this->_aliasMap[$alias] = $class;
if ($discriminatorColumn !== null) {
$this->_discriminatorMap[$discriminatorColumn] = $class;
}
public function setDiscriminatorColumn($className, $alias, $discrColumn)
{
$this->_discriminatorColumns[$className] = $discrColumn;
$this->_columnOwnerMap[$discrColumn] = $alias;
}
public function getDiscriminatorColumn($className)
{
return isset($this->_discriminatorColumns[$className]) ?
$this->_discriminatorColumns[$className] : null;
}
public function addIndexBy($alias, $fieldName)
......@@ -75,30 +88,38 @@ class ResultSetMapping
return $this->_indexByMap[$alias];
}
public function isFieldResult($columnName)
{
return isset($this->_fieldMappings[$columnName]);
}
public function addFieldResult($alias, $columnName, $fieldName)
{
$this->_fieldMappings[$columnName] = $fieldName;
$this->_columnOwnerMap[$columnName] = $alias;
if ( ! $this->_isMixed && $this->_scalarMappings) {
$this->_isMixed = true;
}
}
public function addJoinedEntityResult($class, $alias, $parentAlias, $relation, $discriminatorColumn = null)
public function addJoinedEntityResult($class, $alias, $parentAlias, $relation)
{
$this->_aliasMap[$alias] = $class;
$this->_parentAliasMap[$alias] = $parentAlias;
$this->_relationMap[$alias] = $relation;
if ($discriminatorColumn !== null) {
$this->_discriminatorMap[$discriminatorColumn] = $class;
}
}
public function isDiscriminatorColumn($columnName)
/*public function isDiscriminatorColumn($columnName)
{
return isset($this->_discriminatorMap[$columnName]);
}
}*/
public function addScalarResult($columnName, $alias)
{
$this->_scalarMappings[$columnName] = $alias;
if ( ! $this->_isMixed && $this->_fieldMappings) {
$this->_isMixed = true;
}
}
/**
......@@ -115,9 +136,6 @@ class ResultSetMapping
*/
public function getClass($alias)
{
if ( ! isset($this->_aliasMap[$alias])) {
var_dump($alias); die();
}
return $this->_aliasMap[$alias];
}
......@@ -192,5 +210,20 @@ class ResultSetMapping
{
return count($this->_aliasMap);
}
public function isMixedResult()
{
return $this->_isMixed;
}
public function addIgnoredColumn($columnName)
{
$this->_ignoredColumns[$columnName] = true;
}
public function isIgnoredColumn($columnName)
{
return isset($this->_ignoredColumns[$columnName]);
}
}
......@@ -64,20 +64,12 @@ class SqlWalker
$this->_em = $query->getEntityManager();
$this->_parserResult = $parserResult;
$this->_queryComponents = $queryComponents;
/*$sqlToDqlAliasMap = array(Parser::SCALAR_QUERYCOMPONENT_ALIAS => Parser::SCALAR_QUERYCOMPONENT_ALIAS);
foreach ($parserResult->getQueryComponents() as $dqlAlias => $qComp) {
$sqlAlias = $this->generateSqlTableAlias($qComp['metadata']->getTableName());
$sqlToDqlAliasMap[$sqlAlias] = $dqlAlias;
}
// SQL => DQL alias stored in ParserResult, needed for hydration.
$parserResult->setTableAliasMap($sqlToDqlAliasMap);*/
// DQL => SQL alias stored only locally, needed for SQL construction.
//$this->_dqlToSqlAliasMap = array_flip($sqlToDqlAliasMap);
// In a mixed query we start alias counting for scalars with 1 since
// index 0 will hold the object.
if ($parserResult->isMixedQuery()) {
/*if ($parserResult->isMixedQuery()) {
$this->_scalarResultCounter = 1;
}
}*/
}
public function getConnection()
......@@ -99,7 +91,6 @@ class SqlWalker
$sql .= $AST->getHavingClause() ? $this->walkHavingClause($AST->getHavingClause()) : '';
$sql .= $AST->getOrderByClause() ? $this->walkOrderByClause($AST->getOrderByClause()) : '';
//... more clauses
return $sql;
}
......@@ -113,16 +104,6 @@ class SqlWalker
$sql = 'SELECT ' . (($selectClause->isDistinct()) ? 'DISTINCT ' : '')
. implode(', ', array_map(array($this, 'walkSelectExpression'),
$selectClause->getSelectExpressions()));
// Append discriminator columns
/*if ($this->_query->getHydrationMode() == \Doctrine\ORM\Query::HYDRATE_OBJECT) {
foreach ($this->_selectedClasses as $dqlAlias => $class) {
if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) {
$tblAlias = $this->_dqlToSqlAliasMap[$dqlAlias];
$discrColumn = $class->getDiscriminatorColumn();
$sql .= ", $tblAlias." . $discrColumn['name'] . ' AS discr__' . $discrColumn['name'];
}
}
}*/
foreach ($this->_selectedClasses as $dqlAlias => $class) {
if ($this->_queryComponents[$dqlAlias]['relation'] === null) {
......@@ -134,6 +115,15 @@ class SqlWalker
$this->_queryComponents[$dqlAlias]['relation']
);
}
//if ($this->_query->getHydrationMode() == \Doctrine\ORM\Query::HYDRATE_OBJECT) {
if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) {
$tblAlias = $this->getSqlTableAlias($class->getTableName());
$discrColumn = $class->getDiscriminatorColumn();
$columnAlias = $this->getSqlColumnAlias($discrColumn['name']);
$sql .= ", $tblAlias." . $discrColumn['name'] . ' AS ' . $columnAlias;
$this->_resultSetMapping->setDiscriminatorColumn($class->getClassName(), $dqlAlias, $columnAlias);
}
//}
}
return $sql;
......
......@@ -1173,15 +1173,6 @@ class UnitOfWork implements PropertyChangedListener
*/
public function createEntity($className, array $data, $query = null)
{
// Infer the correct class to instantiate
$class = $this->_em->getClassMetadata($className);
$discCol = $class->getDiscriminatorColumn();
if ($discCol) {
$discMap = $class->getDiscriminatorMap();
if (isset($data[$discCol['name']], $discMap[$data[$discCol['name']]])) {
$className = $discMap[$data[$discCol['name']]];
}
}
$class = $this->_em->getClassMetadata($className);
$id = array();
......@@ -1232,11 +1223,12 @@ class UnitOfWork implements PropertyChangedListener
private function _mergeData($entity, array $data, $class, $overrideLocalChanges = false) {
if ($overrideLocalChanges) {
foreach ($data as $field => $value) {
$class->getReflectionProperty($field)->setValue($entity, $value);
$class->setValue($entity, $field, $value);
}
} else {
$oid = spl_object_hash($entity);
foreach ($data as $field => $value) {
if ($class->hasField($field)) {
$currentValue = $class->getReflectionProperty($field)->getValue($entity);
if ( ! isset($this->_originalEntityData[$oid][$field]) ||
$currentValue == $this->_originalEntityData[$oid][$field]) {
......@@ -1245,6 +1237,7 @@ class UnitOfWork implements PropertyChangedListener
}
}
}
}
/**
* Gets the identity map of the UnitOfWork.
......
......@@ -5,12 +5,6 @@ namespace Doctrine\Tests\Models\Forum;
/**
* @DoctrineEntity
* @DoctrineTable(name="forum_users")
* @DoctrineInheritanceType("joined")
* @DoctrineDiscriminatorColumn(name="dtype", type="varchar", length=20)
* @DoctrineDiscriminatorMap({
"user" = "Doctrine\Tests\Models\Forum\ForumUser",
"admin" = "Doctrine\Tests\Models\Forum\ForumAdministrator"})
* @DoctrineSubclasses({"Doctrine\Tests\Models\Forum\ForumAdministrator"})
*/
class ForumUser
{
......
......@@ -70,8 +70,5 @@ class EntityPersisterTest extends \Doctrine\Tests\OrmTestCase
//avatar_id join column
$this->assertTrue(isset($inserts['forum_users'][0]['avatar_id']));
$this->assertEquals(0, $inserts['forum_users'][0]['avatar_id']);
//dtype discriminator column
$this->assertTrue(isset($inserts['forum_users'][0]['dtype']));
$this->assertEquals('user', $inserts['forum_users'][0]['dtype']);
}
}
\ No newline at end of file
......@@ -20,6 +20,8 @@ class AllTests
$suite = new \Doctrine\Tests\OrmFunctionalTestSuite('Doctrine Orm Functional');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\BasicFunctionalTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\NativeQueryTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\SingleTableInheritanceTest');
return $suite;
}
......
<?php
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\Tests\Models\CMS\CmsUser;
require_once __DIR__ . '/../../TestInit.php';
/**
* NativeQueryTest
*
* @author robo
*/
class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp() {
$this->useModelSet('cms');
parent::setUp();
}
public function testBasicNativeQuery()
{
$user = new CmsUser;
$user->name = 'Roman';
$user->username = 'romanb';
$user->status = 'dev';
$this->_em->save($user);
$this->_em->flush();
$rsm = new ResultSetMapping;
$rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u');
$rsm->addFieldResult('u', 'id', 'id');
$rsm->addFieldResult('u', 'name', 'name');
$query = $this->_em->createNativeQuery('SELECT id, name FROM cms_users WHERE username = ?', $rsm);
$query->setParameter(1, 'romanb');
$users = $query->getResultList();
$this->assertEquals(1, count($users));
$this->assertEquals('Roman', $users[0]->name);
}
}
<?php
namespace Doctrine\Tests\ORM\Functional;
require_once __DIR__ . '/../../TestInit.php';
/**
* Functional tests for the Single Table Inheritance mapping strategy.
*
* @author robo
*/
class SingleTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp() {
parent::setUp();
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\ParentEntity'),
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\ChildEntity')
));
}
public function testInsert()
{
$parent = new ParentEntity;
$parent->setData('foobar');
$this->_em->save($parent);
$child = new ChildEntity;
$child->setData('thedata');
$child->setNumber(1234);
$this->_em->save($child);
$this->_em->flush();
$this->_em->clear();
$query = $this->_em->createQuery("select e from Doctrine\Tests\ORM\Functional\ParentEntity e");
$entities = $query->getResultList();
$this->assertEquals(2, count($entities));
$this->assertTrue($entities[0] instanceof ParentEntity);
$this->assertTrue($entities[1] instanceof ChildEntity);
$this->assertEquals('foobar', $entities[0]->getData());
$this->assertEquals('thedata', $entities[1]->getData());
$this->assertEquals(1234, $entities[1]->getNumber());
}
}
/**
* @DoctrineEntity
* @DoctrineInheritanceType("singleTable")
* @DoctrineDiscriminatorColumn(name="discr", type="varchar")
* @DoctrineSubClasses({"Doctrine\Tests\ORM\Functional\ChildEntity"})
* @DoctrineDiscriminatorValue("parent")
*/
class ParentEntity {
/**
* @DoctrineId
* @DoctrineColumn(type="integer")
* @DoctrineGeneratedValue(strategy="auto")
*/
private $id;
/**
* @DoctrineColumn(type="varchar")
*/
private $data;
public function getId() {
return $this->id;
}
public function getData() {
return $this->data;
}
public function setData($data) {
$this->data = $data;
}
}
/**
* @DoctrineEntity
* @DoctrineDiscriminatorValue("child")
*/
class ChildEntity extends ParentEntity {
/**
* @DoctrineColumn(type="integer", nullable=true)
*/
private $number;
public function getNumber() {
return $this->number;
}
public function setNumber($number) {
$this->number = $number;
}
}
......@@ -35,7 +35,7 @@ class ArrayHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
......@@ -78,7 +78,7 @@ class ArrayHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(4, count($result));
......@@ -140,7 +140,7 @@ class ArrayHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
......@@ -192,7 +192,7 @@ class ArrayHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
......@@ -255,7 +255,7 @@ class ArrayHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
......@@ -365,7 +365,7 @@ class ArrayHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
......@@ -505,7 +505,7 @@ class ArrayHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
......@@ -618,7 +618,7 @@ class ArrayHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
......@@ -653,7 +653,7 @@ class ArrayHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$iterableResult = $hydrator->iterate($stmt, $this->_createParserResult($rsm));
$iterableResult = $hydrator->iterate($stmt, $rsm);
$rowNum = 0;
while (($row = $iterableResult->next()) !== false) {
......
......@@ -35,7 +35,7 @@ class ObjectHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result));
$this->assertTrue($result[0] instanceof \Doctrine\Tests\Models\CMS\CmsUser);
......@@ -79,7 +79,7 @@ class ObjectHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(4, count($result));
......@@ -146,7 +146,7 @@ class ObjectHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
......@@ -205,7 +205,7 @@ class ObjectHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
......@@ -270,7 +270,7 @@ class ObjectHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
......@@ -384,7 +384,7 @@ class ObjectHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
......@@ -519,7 +519,7 @@ class ObjectHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
......@@ -626,7 +626,7 @@ class ObjectHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result));
$this->assertTrue($result[0] instanceof \Doctrine\Tests\Models\Forum\ForumCategory);
......@@ -663,7 +663,7 @@ class ObjectHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$iterableResult = $hydrator->iterate($stmt, $this->_createParserResult($rsm));
$iterableResult = $hydrator->iterate($stmt, $rsm);
$rowNum = 0;
while (($row = $iterableResult->next()) !== false) {
......@@ -739,6 +739,6 @@ class ObjectHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm, true));
$result = $hydrator->hydrateAll($stmt, $rsm);
}
}
\ No newline at end of file
......@@ -35,7 +35,7 @@ class ScalarHydratorTest extends HydrationTest
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ScalarHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertTrue(is_array($result));
$this->assertEquals(2, count($result));
......
......@@ -63,14 +63,14 @@ class SingleScalarHydratorTest extends HydrationTest
$hydrator = new \Doctrine\ORM\Internal\Hydration\SingleScalarHydrator($this->_em);
if ($name == 'result1') {
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals('romanb', $result);
} else if ($name == 'result2') {
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult($rsm));
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(1, $result);
} else if ($name == 'result3' || $name == 'result4') {
try {
$result = $hydrator->hydrateall($stmt, $this->_createParserResult($rsm));
$result = $hydrator->hydrateall($stmt, $rsm);
$this->fail();
} catch (\Doctrine\ORM\Internal\Hydration\HydrationException $ex) {}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment