Commit 909e98c6 authored by romanb's avatar romanb

[2.0][DDC-202][DDC-132][DDC-185] Fixed.

parent a26464da
...@@ -292,7 +292,8 @@ class Connection ...@@ -292,7 +292,8 @@ class Connection
/** /**
* Establishes the connection with the database. * Establishes the connection with the database.
* *
* @return boolean * @return boolean TRUE if the connection was successfully established, FALSE if
* the connection is already open.
*/ */
public function connect() public function connect()
{ {
...@@ -311,11 +312,13 @@ class Connection ...@@ -311,11 +312,13 @@ class Connection
} }
/** /**
* Convenience method for PDO::query("...") followed by $stmt->fetch(PDO::FETCH_ASSOC). * Prepares and executes an SQL query and returns the first row of the result
* as an associative array.
* *
* @param string $statement The SQL query. * @param string $statement The SQL query.
* @param array $params The query parameters. * @param array $params The query parameters.
* @return array * @return array
* @todo Rename: fetchAssoc
*/ */
public function fetchRow($statement, array $params = array()) public function fetchRow($statement, array $params = array())
{ {
...@@ -323,7 +326,8 @@ class Connection ...@@ -323,7 +326,8 @@ class Connection
} }
/** /**
* Convenience method for PDO::query("...") followed by $stmt->fetch(PDO::FETCH_NUM). * Prepares and executes an SQL query and returns the first row of the result
* as a numerically indexed array.
* *
* @param string $statement sql query to be executed * @param string $statement sql query to be executed
* @param array $params prepared statement params * @param array $params prepared statement params
...@@ -335,12 +339,13 @@ class Connection ...@@ -335,12 +339,13 @@ class Connection
} }
/** /**
* Convenience method for PDO::query("...") followed by $stmt->fetchColumn(...). * Prepares and executes an SQL query and returns the value of a single column
* of the first row of the result.
* *
* @param string $statement sql query to be executed * @param string $statement sql query to be executed
* @param array $params prepared statement params * @param array $params prepared statement params
* @param int $colnum 0-indexed column number to retrieve * @param int $colnum 0-indexed column number to retrieve
* @return array * @return mixed
*/ */
public function fetchColumn($statement, array $params = array(), $colnum = 0) public function fetchColumn($statement, array $params = array(), $colnum = 0)
{ {
...@@ -357,22 +362,10 @@ class Connection ...@@ -357,22 +362,10 @@ class Connection
return $this->_isConnected; return $this->_isConnected;
} }
/**
* Convenience method for PDO::query("...") followed by $stmt->fetchAll(PDO::FETCH_BOTH).
*
* @param string $statement sql query to be executed
* @param array $params prepared statement params
* @return array
*/
public function fetchBoth($statement, array $params = array())
{
return $this->execute($statement, $params)->fetchAll(Connection::FETCH_BOTH);
}
/** /**
* Deletes table row(s) matching the specified identifier. * Deletes table row(s) matching the specified identifier.
* *
* @param string $table The table to delete data from * @param string $table The table to delete data from.
* @param array $identifier An associateve array containing identifier fieldname-value pairs. * @param array $identifier An associateve array containing identifier fieldname-value pairs.
* @return integer The number of affected rows * @return integer The number of affected rows
*/ */
...@@ -532,7 +525,7 @@ class Connection ...@@ -532,7 +525,7 @@ class Connection
} }
/** /**
* Convenience method for PDO::query("...") followed by $stmt->fetchAll(PDO::FETCH_ASSOC). * Prepares and executes an SQL query and returns the result as an associative array.
* *
* @param string $sql The SQL query. * @param string $sql The SQL query.
* @param array $params The query parameters. * @param array $params The query parameters.
...@@ -546,8 +539,8 @@ class Connection ...@@ -546,8 +539,8 @@ class Connection
/** /**
* Prepares an SQL statement. * Prepares an SQL statement.
* *
* @param string $statement * @param string $statement The SQL statement to prepare.
* @return Statement * @return Statement The prepared statement.
*/ */
public function prepare($statement) public function prepare($statement)
{ {
...@@ -557,29 +550,11 @@ class Connection ...@@ -557,29 +550,11 @@ class Connection
} }
/** /**
* Queries the database with limit and offset added to the query and returns * Prepares and executes an SQL query.
* a Statement object.
* *
* @param string $query * @param string $query The SQL query to prepare and execute.
* @param integer $limit * @param array $params The parameters, if any.
* @param integer $offset * @return Statement The prepared and executed statement.
* @return Statement
*/
public function select($query, $limit = 0, $offset = 0)
{
if ($limit > 0 || $offset > 0) {
$query = $this->_platform->modifyLimitQuery($query, $limit, $offset);
}
return $this->execute($query);
}
/**
* Executes an SQL SELECT query with the given parameters.
*
* @param string $query sql query
* @param array $params query parameters
* @return PDOStatement
*/ */
public function execute($query, array $params = array()) public function execute($query, array $params = array())
{ {
...@@ -599,6 +574,35 @@ class Connection ...@@ -599,6 +574,35 @@ class Connection
return $stmt; return $stmt;
} }
/**
* Prepares and executes an SQL query and returns the result, optionally applying a
* transformation on the rows of the result.
*
* @param string $query The SQL query to execute.
* @param array $params The parameters, if any.
* @param Closure $mapper The transformation function that is applied on each row.
* The function receives a single paramater, an array, that
* represents a row of the result set.
* @return mixed The (possibly transformed) result of the query.
*/
public function query($query, array $params = array(), \Closure $mapper = null)
{
$result = array();
$stmt = $this->execute($query, $params);
while ($row = $stmt->fetch()) {
if ($mapper === null) {
$result[] = $row;
} else {
$result[] = $mapper($row);
}
}
$stmt->closeCursor();
return $result;
}
/** /**
* Executes an SQL INSERT/UPDATE/DELETE query with the given parameters. * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters.
* *
...@@ -726,7 +730,7 @@ class Connection ...@@ -726,7 +730,7 @@ class Connection
* this method can be listened with onPreTransactionRollback and onTransactionRollback * this method can be listened with onPreTransactionRollback and onTransactionRollback
* eventlistener methods * eventlistener methods
* *
* @throws ConnectionException If the rollback operation fails at database level. * @throws ConnectionException If the rollback operation failed.
*/ */
public function rollback() public function rollback()
{ {
......
...@@ -143,7 +143,7 @@ class OCI8Statement implements \Doctrine\DBAL\Driver\Statement ...@@ -143,7 +143,7 @@ class OCI8Statement implements \Doctrine\DBAL\Driver\Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetch($fetchStyle = Connection::FETCH_BOTH, $cursorOrientation = \PDO::FETCH_ORI_NEXT, $cursorOffset = 0) public function fetch($fetchStyle = Connection::FETCH_BOTH)
{ {
if ( ! isset(self::$fetchStyleMap[$fetchStyle])) { if ( ! isset(self::$fetchStyleMap[$fetchStyle])) {
throw new \InvalidArgumentException("Invalid fetch style: " . $fetchStyle); throw new \InvalidArgumentException("Invalid fetch style: " . $fetchStyle);
...@@ -176,38 +176,6 @@ class OCI8Statement implements \Doctrine\DBAL\Driver\Statement ...@@ -176,38 +176,6 @@ class OCI8Statement implements \Doctrine\DBAL\Driver\Statement
return $row[$columnIndex]; return $row[$columnIndex];
} }
/**
* {@inheritdoc}
*/
public function fetchObject($className = 'stdClass', $args = array())
{
throw new \Exception(__METHOD__ . " not supported.");
}
/**
* {@inheritdoc}
*/
public function getAttribute($attribute)
{
throw new \Exception(__METHOD__ . " not supported.");
}
/**
* {@inheritdoc}
*/
public function getColumnMeta($column)
{
throw new \Exception(__METHOD__ . " not supported.");
}
/**
* {@inheritdoc}
*/
public function nextRowset()
{
throw new \Exception(__METHOD__ . " not supported.");
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
...@@ -215,21 +183,4 @@ class OCI8Statement implements \Doctrine\DBAL\Driver\Statement ...@@ -215,21 +183,4 @@ class OCI8Statement implements \Doctrine\DBAL\Driver\Statement
{ {
return oci_num_rows($this->_sth); return oci_num_rows($this->_sth);
} }
/**
* {@inheritdoc}
*/
public function setAttribute($attribute, $value)
{
throw new \Exception(__METHOD__ . " not supported.");
}
/**
* {@inheritdoc}
*/
public function setFetchMode($mode, $arg1)
{
throw new \Exception(__METHOD__ . " not supported.");
}
} }
\ No newline at end of file
...@@ -36,6 +36,5 @@ class PDOConnection extends PDO implements Connection ...@@ -36,6 +36,5 @@ class PDOConnection extends PDO implements Connection
parent::__construct($dsn, $user, $password, $options); parent::__construct($dsn, $user, $password, $options);
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('Doctrine\DBAL\Driver\PDOStatement', array())); $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('Doctrine\DBAL\Driver\PDOStatement', array()));
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//$this->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
} }
} }
\ No newline at end of file
...@@ -21,11 +21,13 @@ ...@@ -21,11 +21,13 @@
namespace Doctrine\DBAL\Driver; namespace Doctrine\DBAL\Driver;
use Doctrine\DBAL\Connection as DBALConnection;
/** /**
* Statement interface. * Statement interface.
* Drivers must implement this interface. * Drivers must implement this interface.
* *
* This resembles the PDOStatement interface. * This resembles (a subset of) the PDOStatement interface.
* *
* @author Konsta Vesterinen <kvesteri@cc.hut.fi> * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
...@@ -92,7 +94,6 @@ interface Statement ...@@ -92,7 +94,6 @@ interface Statement
function bindParam($column, &$variable, $type = null, $length = null, $driverOptions = array()); function bindParam($column, &$variable, $type = null, $length = null, $driverOptions = array());
/** /**
* closeCursor
* Closes the cursor, enabling the statement to be executed again. * Closes the cursor, enabling the statement to be executed again.
* *
* @return boolean Returns TRUE on success or FALSE on failure. * @return boolean Returns TRUE on success or FALSE on failure.
...@@ -170,12 +171,9 @@ interface Statement ...@@ -170,12 +171,9 @@ interface Statement
* *
* @return mixed * @return mixed
*/ */
function fetch($fetchStyle = Query::HYDRATE_BOTH, function fetch($fetchStyle = DBALConnection::FETCH_BOTH);
$cursorOrientation = Query::HYDRATE_ORI_NEXT,
$cursorOffset = null);
/** /**
* fetchAll
* Returns an array containing all of the result set rows * Returns an array containing all of the result set rows
* *
* @param integer $fetchStyle Controls how the next row will be returned to the caller. * @param integer $fetchStyle Controls how the next row will be returned to the caller.
...@@ -187,7 +185,7 @@ interface Statement ...@@ -187,7 +185,7 @@ interface Statement
* *
* @return array * @return array
*/ */
function fetchAll($fetchStyle = Query::HYDRATE_BOTH); function fetchAll($fetchStyle = DBALConnection::FETCH_BOTH);
/** /**
* fetchColumn * fetchColumn
...@@ -202,62 +200,6 @@ interface Statement ...@@ -202,62 +200,6 @@ interface Statement
*/ */
function fetchColumn($columnIndex = 0); function fetchColumn($columnIndex = 0);
/**
* fetchObject
* Fetches the next row and returns it as an object.
*
* Fetches the next row and returns it as an object. This function is an alternative to
* PDOStatement->fetch() with Query::HYDRATE_CLASS or Query::HYDRATE_OBJ style.
*
* @param string $className Name of the created class, defaults to stdClass.
* @param array $args Elements of this array are passed to the constructor.
*
* @return mixed an instance of the required class with property names that correspond
* to the column names or FALSE in case of an error.
*/
function fetchObject($className = 'stdClass', $args = array());
/**
* getAttribute
* Retrieve a statement attribute
*
* @param integer $attribute
* @see Doctrine::ATTR_* constants
* @return mixed the attribute value
*/
function getAttribute($attribute);
/**
* getColumnMeta
* Returns metadata for a column in a result set
*
* @param integer $column The 0-indexed column in the result set.
*
* @return array Associative meta data array with the following structure:
*
* native_type The PHP native type used to represent the column value.
* driver:decl_ type The SQL type used to represent the column value in the database. If the column in the result set is the result of a function, this value is not returned by PDOStatement->getColumnMeta().
* flags Any flags set for this column.
* name The name of this column as returned by the database.
* len The length of this column. Normally -1 for types other than floating point decimals.
* precision The numeric precision of this column. Normally 0 for types other than floating point decimals.
* pdo_type The type of this column as represented by the PDO::PARAM_* constants.
*/
function getColumnMeta($column);
/**
* nextRowset
* Advances to the next rowset in a multi-rowset statement handle
*
* Some database servers support stored procedures that return more than one rowset
* (also known as a result set). The nextRowset() method enables you to access the second
* and subsequent rowsets associated with a PDOStatement object. Each rowset can have a
* different set of columns from the preceding rowset.
*
* @return boolean Returns TRUE on success or FALSE on failure.
*/
function nextRowset();
/** /**
* rowCount * rowCount
* rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement * rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement
...@@ -271,23 +213,4 @@ interface Statement ...@@ -271,23 +213,4 @@ interface Statement
* @return integer Returns the number of rows. * @return integer Returns the number of rows.
*/ */
function rowCount(); function rowCount();
/**
* setAttribute
* Set a statement attribute
*
* @param integer $attribute
* @param mixed $value the value of given attribute
* @return boolean Returns TRUE on success or FALSE on failure.
*/
function setAttribute($attribute, $value);
/**
* setFetchMode
* Set the default fetch mode for this statement
*
* @param integer $mode The fetch mode must be one of the Query::HYDRATE_* constants.
* @return boolean Returns 1 on success or FALSE on failure.
*/
function setFetchMode($mode, $arg1);
} }
\ No newline at end of file
...@@ -62,7 +62,7 @@ class ObjectHydrator extends AbstractHydrator ...@@ -62,7 +62,7 @@ class ObjectHydrator extends AbstractHydrator
foreach ($this->_rsm->aliasMap as $dqlAlias => $className) { foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
$this->_identifierMap[$dqlAlias] = array(); $this->_identifierMap[$dqlAlias] = array();
$this->_resultPointers[$dqlAlias] = array(); //$this->_resultPointers[$dqlAlias] = array();
$this->_idTemplate[$dqlAlias] = ''; $this->_idTemplate[$dqlAlias] = '';
$class = $this->_em->getClassMetadata($className); $class = $this->_em->getClassMetadata($className);
......
...@@ -334,7 +334,7 @@ final class ClassMetadata extends ClassMetadataInfo ...@@ -334,7 +334,7 @@ final class ClassMetadata extends ClassMetadataInfo
'inheritanceType', 'inheritanceType',
'inheritedAssociationFields', 'inheritedAssociationFields',
'insertSql', 'insertSql',
'inverseMappings', 'inverseMappings', //TODO: Remove!
'isIdentifierComposite', 'isIdentifierComposite',
'isMappedSuperclass', 'isMappedSuperclass',
'isVersioned', 'isVersioned',
...@@ -343,7 +343,6 @@ final class ClassMetadata extends ClassMetadataInfo ...@@ -343,7 +343,6 @@ final class ClassMetadata extends ClassMetadataInfo
'namespace', 'namespace',
'parentClasses', 'parentClasses',
'primaryTable', 'primaryTable',
'resultColumnNames',
'rootEntityName', 'rootEntityName',
'sequenceGeneratorDefinition', 'sequenceGeneratorDefinition',
'subClasses', 'subClasses',
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
namespace Doctrine\ORM\Mapping; namespace Doctrine\ORM\Mapping;
use Doctrine\Common\DoctrineException, use Doctrine\ORM\ORMException,
Doctrine\DBAL\Platforms\AbstractPlatform, Doctrine\DBAL\Platforms\AbstractPlatform,
Doctrine\ORM\Events; Doctrine\ORM\Events;
...@@ -189,7 +189,6 @@ class ClassMetadataFactory ...@@ -189,7 +189,6 @@ class ClassMetadataFactory
$class->setVersioned($parent->isVersioned); $class->setVersioned($parent->isVersioned);
$class->setVersionField($parent->versionField); $class->setVersionField($parent->versionField);
$class->setDiscriminatorMap($parent->discriminatorMap); $class->setDiscriminatorMap($parent->discriminatorMap);
$class->setResultColumnNames($parent->resultColumnNames);
} }
// Invoke driver // Invoke driver
...@@ -230,13 +229,6 @@ class ClassMetadataFactory ...@@ -230,13 +229,6 @@ class ClassMetadataFactory
$this->_generateStaticSql($class); $this->_generateStaticSql($class);
} }
if ($parent) {
foreach ($visited as $parentClassName) {
$parentClass = $this->_loadedMetadata[$parentClassName];
$parentClass->setResultColumnNames(array_merge($parentClass->resultColumnNames, $class->resultColumnNames));
}
}
$this->_loadedMetadata[$className] = $class; $this->_loadedMetadata[$className] = $class;
$parent = $class; $parent = $class;
...@@ -321,11 +313,6 @@ class ClassMetadataFactory ...@@ -321,11 +313,6 @@ class ClassMetadataFactory
if (isset($class->fieldMappings[$name]['inherited']) && ! isset($class->fieldMappings[$name]['id']) if (isset($class->fieldMappings[$name]['inherited']) && ! isset($class->fieldMappings[$name]['id'])
|| isset($class->inheritedAssociationFields[$name]) || isset($class->inheritedAssociationFields[$name])
|| ($versioned && $versionField == $name)) { || ($versioned && $versionField == $name)) {
if (isset($class->columnNames[$name])) {
// Add column mapping for SQL result sets
$columnName = $class->columnNames[$name];
$class->resultColumnNames[$this->_targetPlatform->getSqlResultCasing($columnName)] = $columnName;
}
continue; continue;
} }
...@@ -334,19 +321,10 @@ class ClassMetadataFactory ...@@ -334,19 +321,10 @@ class ClassMetadataFactory
if ($assoc->isOneToOne() && $assoc->isOwningSide) { if ($assoc->isOneToOne() && $assoc->isOwningSide) {
foreach ($assoc->targetToSourceKeyColumns as $sourceCol) { foreach ($assoc->targetToSourceKeyColumns as $sourceCol) {
$columns[] = $assoc->getQuotedJoinColumnName($sourceCol, $this->_targetPlatform); $columns[] = $assoc->getQuotedJoinColumnName($sourceCol, $this->_targetPlatform);
// Add column mapping for SQL result sets
$class->resultColumnNames[$this->_targetPlatform->getSqlResultCasing($sourceCol)] = $sourceCol;
} }
} }
} else if ($class->name != $class->rootEntityName || ! $class->isIdGeneratorIdentity() || $class->identifier[0] != $name) { } else if ($class->name != $class->rootEntityName || ! $class->isIdGeneratorIdentity() || $class->identifier[0] != $name) {
$columns[] = $class->getQuotedColumnName($name, $this->_targetPlatform); $columns[] = $class->getQuotedColumnName($name, $this->_targetPlatform);
// Add column mapping for SQL result sets
$columnName = $class->columnNames[$name];
$class->resultColumnNames[$this->_targetPlatform->getSqlResultCasing($columnName)] = $columnName;
} else {
// Add column mapping for SQL result sets
$columnName = $class->columnNames[$name];
$class->resultColumnNames[$this->_targetPlatform->getSqlResultCasing($columnName)] = $columnName;
} }
} }
} else { } else {
...@@ -360,19 +338,10 @@ class ClassMetadataFactory ...@@ -360,19 +338,10 @@ class ClassMetadataFactory
if ($assoc->isOwningSide && $assoc->isOneToOne()) { if ($assoc->isOwningSide && $assoc->isOneToOne()) {
foreach ($assoc->targetToSourceKeyColumns as $sourceCol) { foreach ($assoc->targetToSourceKeyColumns as $sourceCol) {
$columns[] = $assoc->getQuotedJoinColumnName($sourceCol, $this->_targetPlatform); $columns[] = $assoc->getQuotedJoinColumnName($sourceCol, $this->_targetPlatform);
// Add column mapping for SQL result sets
$class->resultColumnNames[$this->_targetPlatform->getSqlResultCasing($sourceCol)] = $sourceCol;
} }
} }
} else if ($class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY || $class->identifier[0] != $name) { } else if ($class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY || $class->identifier[0] != $name) {
$columns[] = $class->getQuotedColumnName($name, $this->_targetPlatform); $columns[] = $class->getQuotedColumnName($name, $this->_targetPlatform);
// Add column mapping for SQL result sets
$columnName = $class->columnNames[$name];
$class->resultColumnNames[$this->_targetPlatform->getSqlResultCasing($columnName)] = $columnName;
} else {
// Add column mapping for SQL result sets
$columnName = $class->columnNames[$name];
$class->resultColumnNames[$this->_targetPlatform->getSqlResultCasing($columnName)] = $columnName;
} }
} }
} }
...@@ -383,9 +352,6 @@ class ClassMetadataFactory ...@@ -383,9 +352,6 @@ class ClassMetadataFactory
&& $class->name == $class->rootEntityName) { && $class->name == $class->rootEntityName) {
$columns[] = $class->getQuotedDiscriminatorColumnName($this->_targetPlatform); $columns[] = $class->getQuotedDiscriminatorColumnName($this->_targetPlatform);
} }
// Add column mapping for SQL result sets
$columnName = $class->discriminatorColumn['name'];
$class->resultColumnNames[$this->_targetPlatform->getSqlResultCasing($columnName)] = $columnName;
} }
if (empty($columns)) { if (empty($columns)) {
...@@ -448,10 +414,10 @@ class ClassMetadataFactory ...@@ -448,10 +414,10 @@ class ClassMetadataFactory
$class->setIdGenerator(new \Doctrine\ORM\Id\Assigned()); $class->setIdGenerator(new \Doctrine\ORM\Id\Assigned());
break; break;
case ClassMetadata::GENERATOR_TYPE_TABLE: case ClassMetadata::GENERATOR_TYPE_TABLE:
throw new DoctrineException("DoctrineTableGenerator not yet implemented."); throw new ORMException("TableGenerator not yet implemented.");
break; break;
default: default:
throw new DoctrineException("Unexhaustive match."); throw new ORMException("Unknown generator type: " . $class->generatorType);
} }
} }
} }
...@@ -258,18 +258,6 @@ class ClassMetadataInfo ...@@ -258,18 +258,6 @@ class ClassMetadataInfo
*/ */
public $columnNames = array(); public $columnNames = array();
/**
* A map of column names as they appear in an SQL result set to column names as they
* are defined in the mapping. This includes the columns of all mapped fields as well
* as any join columns and discriminator columns.
*
* @var array
* @todo Remove. Or at least remove from serialization/unserialization and instead
* populate them during runtime.
* See http://www.doctrine-project.org/jira/browse/DDC-132.
*/
public $resultColumnNames = array();
/** /**
* Whether to automatically OUTER JOIN subtypes when a basetype is queried. * Whether to automatically OUTER JOIN subtypes when a basetype is queried.
* *
...@@ -340,6 +328,7 @@ class ClassMetadataInfo ...@@ -340,6 +328,7 @@ class ClassMetadataInfo
* List of inverse association mappings, indexed by mappedBy field name. * List of inverse association mappings, indexed by mappedBy field name.
* *
* @var array * @var array
* @todo Remove! See http://www.doctrine-project.org/jira/browse/DDC-193
*/ */
public $inverseMappings = array(); public $inverseMappings = array();
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
namespace Doctrine\ORM\Persisters; namespace Doctrine\ORM\Persisters;
use Doctrine\Common\DoctrineException; use Doctrine\ORM\ORMException;
/** /**
* The joined subclass persister maps a single entity instance to several tables in the * The joined subclass persister maps a single entity instance to several tables in the
...@@ -52,8 +52,7 @@ class JoinedSubclassPersister extends StandardEntityPersister ...@@ -52,8 +52,7 @@ class JoinedSubclassPersister extends StandardEntityPersister
if ($isInsert) { if ($isInsert) {
$discColumn = $this->_class->discriminatorColumn; $discColumn = $this->_class->discriminatorColumn;
$rootClass = $this->_em->getClassMetadata($this->_class->rootEntityName); $rootClass = $this->_em->getClassMetadata($this->_class->rootEntityName);
$result[$rootClass->primaryTable['name']][$discColumn['name']] = $result[$rootClass->primaryTable['name']][$discColumn['name']] = $this->_class->discriminatorValue;
$this->_class->discriminatorValue;
} }
} }
...@@ -280,6 +279,7 @@ class JoinedSubclassPersister extends StandardEntityPersister ...@@ -280,6 +279,7 @@ class JoinedSubclassPersister extends StandardEntityPersister
$aliasIndex = 1; $aliasIndex = 1;
$idColumns = $this->_class->getIdentifierColumnNames(); $idColumns = $this->_class->getIdentifierColumnNames();
$baseTableAlias = 't0'; $baseTableAlias = 't0';
$setResultColumnNames = empty($this->_resultColumnNames);
foreach (array_merge($this->_class->subClasses, $this->_class->parentClasses) as $className) { foreach (array_merge($this->_class->subClasses, $this->_class->parentClasses) as $className) {
$tableAliases[$className] = 't' . $aliasIndex++; $tableAliases[$className] = 't' . $aliasIndex++;
...@@ -292,6 +292,11 @@ class JoinedSubclassPersister extends StandardEntityPersister ...@@ -292,6 +292,11 @@ class JoinedSubclassPersister extends StandardEntityPersister
$tableAliases[$mapping['inherited']] : $baseTableAlias; $tableAliases[$mapping['inherited']] : $baseTableAlias;
if ($columnList != '') $columnList .= ', '; if ($columnList != '') $columnList .= ', ';
$columnList .= $tableAlias . '.' . $this->_class->getQuotedColumnName($fieldName, $this->_platform); $columnList .= $tableAlias . '.' . $this->_class->getQuotedColumnName($fieldName, $this->_platform);
if ($setResultColumnNames) {
$resultColumnName = $this->_platform->getSqlResultCasing($mapping['columnName']);
$this->_resultColumnNames[$resultColumnName] = $mapping['columnName'];
}
} }
// Add foreign key columns // Add foreign key columns
...@@ -299,6 +304,11 @@ class JoinedSubclassPersister extends StandardEntityPersister ...@@ -299,6 +304,11 @@ class JoinedSubclassPersister extends StandardEntityPersister
if ($assoc2->isOwningSide && $assoc2->isOneToOne()) { if ($assoc2->isOwningSide && $assoc2->isOneToOne()) {
foreach ($assoc2->targetToSourceKeyColumns as $srcColumn) { foreach ($assoc2->targetToSourceKeyColumns as $srcColumn) {
$columnList .= ', ' . $assoc2->getQuotedJoinColumnName($srcColumn, $this->_platform); $columnList .= ', ' . $assoc2->getQuotedJoinColumnName($srcColumn, $this->_platform);
if ($setResultColumnNames) {
$resultColumnName = $this->_platform->getSqlResultCasing($srcColumn);
$this->_resultColumnNames[$resultColumnName] = $srcColumn;
}
} }
} }
} }
...@@ -312,6 +322,11 @@ class JoinedSubclassPersister extends StandardEntityPersister ...@@ -312,6 +322,11 @@ class JoinedSubclassPersister extends StandardEntityPersister
$this->_class->getQuotedDiscriminatorColumnName($this->_platform); $this->_class->getQuotedDiscriminatorColumnName($this->_platform);
} }
if ($setResultColumnNames) {
$resultColumnName = $this->_platform->getSqlResultCasing($this->_class->discriminatorColumn['name']);
$this->_resultColumnNames[$resultColumnName] = $this->_class->discriminatorColumn['name'];
}
// INNER JOIN parent tables // INNER JOIN parent tables
$joinSql = ''; $joinSql = '';
foreach ($this->_class->parentClasses as $parentClassName) { foreach ($this->_class->parentClasses as $parentClassName) {
...@@ -336,6 +351,11 @@ class JoinedSubclassPersister extends StandardEntityPersister ...@@ -336,6 +351,11 @@ class JoinedSubclassPersister extends StandardEntityPersister
continue; continue;
} }
$columnList .= ', ' . $tableAlias . '.' . $subClass->getQuotedColumnName($fieldName, $this->_platform); $columnList .= ', ' . $tableAlias . '.' . $subClass->getQuotedColumnName($fieldName, $this->_platform);
if ($setResultColumnNames) {
$resultColumnName = $this->_platform->getSqlResultCasing($mapping['columnName']);
$this->_resultColumnNames[$resultColumnName] = $mapping['columnName'];
}
} }
// Add join columns (foreign keys) // Add join columns (foreign keys)
...@@ -343,6 +363,11 @@ class JoinedSubclassPersister extends StandardEntityPersister ...@@ -343,6 +363,11 @@ class JoinedSubclassPersister extends StandardEntityPersister
if ($assoc2->isOwningSide && $assoc2->isOneToOne() && ! isset($subClass->inheritedAssociationFields[$assoc2->sourceFieldName])) { if ($assoc2->isOwningSide && $assoc2->isOneToOne() && ! isset($subClass->inheritedAssociationFields[$assoc2->sourceFieldName])) {
foreach ($assoc2->targetToSourceKeyColumns as $srcColumn) { foreach ($assoc2->targetToSourceKeyColumns as $srcColumn) {
$columnList .= ', ' . $tableAlias . '.' . $assoc2->getQuotedJoinColumnName($srcColumn, $this->_platform); $columnList .= ', ' . $tableAlias . '.' . $assoc2->getQuotedJoinColumnName($srcColumn, $this->_platform);
if ($setResultColumnNames) {
$resultColumnName = $this->_platform->getSqlResultCasing($srcColumn);
$this->_resultColumnNames[$resultColumnName] = $srcColumn;
}
} }
} }
} }
...@@ -365,7 +390,7 @@ class JoinedSubclassPersister extends StandardEntityPersister ...@@ -365,7 +390,7 @@ class JoinedSubclassPersister extends StandardEntityPersister
} else if ($assoc !== null) { } else if ($assoc !== null) {
$conditionSql .= $assoc->getQuotedJoinColumnName($field, $this->_platform); $conditionSql .= $assoc->getQuotedJoinColumnName($field, $this->_platform);
} else { } else {
throw DoctrineException::unrecognizedField($field); throw ORMException::unrecognizedField($field);
} }
$conditionSql .= ' = ?'; $conditionSql .= ' = ?';
} }
......
...@@ -50,9 +50,16 @@ class SingleTablePersister extends StandardEntityPersister ...@@ -50,9 +50,16 @@ class SingleTablePersister extends StandardEntityPersister
/** @override */ /** @override */
protected function _getSelectColumnList() protected function _getSelectColumnList()
{ {
$setResultColumnNames = empty($this->_resultColumnNames);
$columnList = parent::_getSelectColumnList(); $columnList = parent::_getSelectColumnList();
// Append discriminator column // Append discriminator column
$columnList .= ', ' . $this->_class->getQuotedDiscriminatorColumnName($this->_platform); $columnList .= ', ' . $this->_class->getQuotedDiscriminatorColumnName($this->_platform);
if ($setResultColumnNames) {
$resultColumnName = $this->_platform->getSqlResultCasing($this->_class->discriminatorColumn['name']);
$this->_resultColumnNames[$resultColumnName] = $this->_class->discriminatorColumn['name'];
}
///$tableAlias = $this->_class->getQuotedTableName($this->_platform); ///$tableAlias = $this->_class->getQuotedTableName($this->_platform);
foreach ($this->_class->subClasses as $subClassName) { foreach ($this->_class->subClasses as $subClassName) {
$subClass = $this->_em->getClassMetadata($subClassName); $subClass = $this->_em->getClassMetadata($subClassName);
...@@ -60,6 +67,10 @@ class SingleTablePersister extends StandardEntityPersister ...@@ -60,6 +67,10 @@ class SingleTablePersister extends StandardEntityPersister
foreach ($subClass->fieldMappings as $fieldName => $mapping) { foreach ($subClass->fieldMappings as $fieldName => $mapping) {
if ( ! isset($mapping['inherited'])) { if ( ! isset($mapping['inherited'])) {
$columnList .= ', ' . $subClass->getQuotedColumnName($fieldName, $this->_platform); $columnList .= ', ' . $subClass->getQuotedColumnName($fieldName, $this->_platform);
if ($setResultColumnNames) {
$resultColumnName = $this->_platform->getSqlResultCasing($mapping['columnName']);
$this->_resultColumnNames[$resultColumnName] = $mapping['columnName'];
}
} }
} }
...@@ -68,6 +79,10 @@ class SingleTablePersister extends StandardEntityPersister ...@@ -68,6 +79,10 @@ class SingleTablePersister extends StandardEntityPersister
if ($assoc->isOwningSide && $assoc->isOneToOne() && ! isset($subClass->inheritedAssociationFields[$assoc->sourceFieldName])) { if ($assoc->isOwningSide && $assoc->isOneToOne() && ! isset($subClass->inheritedAssociationFields[$assoc->sourceFieldName])) {
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) { foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
$columnList .= ', ' /*. $tableAlias . '.'*/ . $assoc->getQuotedJoinColumnName($srcColumn, $this->_platform); $columnList .= ', ' /*. $tableAlias . '.'*/ . $assoc->getQuotedJoinColumnName($srcColumn, $this->_platform);
if ($setResultColumnNames) {
$resultColumnName = $this->_platform->getSqlResultCasing($srcColumn);
$this->_resultColumnNames[$resultColumnName] = $srcColumn;
}
} }
} }
} }
......
...@@ -87,6 +87,8 @@ class StandardEntityPersister ...@@ -87,6 +87,8 @@ class StandardEntityPersister
*/ */
protected $_queuedInserts = array(); protected $_queuedInserts = array();
protected $_resultColumnNames = array();
/** /**
* Initializes a new instance of a class derived from AbstractEntityPersister * Initializes a new instance of a class derived from AbstractEntityPersister
* that uses the given EntityManager and persists instances of the class described * that uses the given EntityManager and persists instances of the class described
...@@ -189,8 +191,8 @@ class StandardEntityPersister ...@@ -189,8 +191,8 @@ class StandardEntityPersister
$identifier = $this->_class->getIdentifierColumnNames(); $identifier = $this->_class->getIdentifierColumnNames();
$versionFieldColumnName = $this->_class->getColumnName($versionField); $versionFieldColumnName = $this->_class->getColumnName($versionField);
//FIXME: Order with composite keys might not be correct //FIXME: Order with composite keys might not be correct
$sql = "SELECT " . $versionFieldColumnName . " FROM " . $class->getQuotedTableName($this->_platform) . $sql = "SELECT " . $versionFieldColumnName . " FROM " . $class->getQuotedTableName($this->_platform)
" WHERE " . implode(' = ? AND ', $identifier) . " = ?"; . " WHERE " . implode(' = ? AND ', $identifier) . " = ?";
$value = $this->_conn->fetchColumn($sql, array_values((array)$id)); $value = $this->_conn->fetchColumn($sql, array_values((array)$id));
$this->_class->setFieldValue($entity, $versionField, $value); $this->_class->setFieldValue($entity, $versionField, $value);
} }
...@@ -453,7 +455,7 @@ class StandardEntityPersister ...@@ -453,7 +455,7 @@ class StandardEntityPersister
// Refresh simple state // Refresh simple state
foreach ($result as $column => $value) { foreach ($result as $column => $value) {
$column = $this->_class->resultColumnNames[$column]; $column = isset($this->_resultColumnNames[$column]) ? $this->_resultColumnNames[$column] : $column;
if (isset($this->_class->fieldNames[$column])) { if (isset($this->_class->fieldNames[$column])) {
$fieldName = $this->_class->fieldNames[$column]; $fieldName = $this->_class->fieldNames[$column];
$type = Type::getType($this->_class->fieldMappings[$fieldName]['type']); $type = Type::getType($this->_class->fieldMappings[$fieldName]['type']);
...@@ -636,7 +638,7 @@ class StandardEntityPersister ...@@ -636,7 +638,7 @@ class StandardEntityPersister
{ {
$data = array(); $data = array();
foreach ($sqlResult as $column => $value) { foreach ($sqlResult as $column => $value) {
$column = $this->_class->resultColumnNames[$column]; $column = isset($this->_resultColumnNames[$column]) ? $this->_resultColumnNames[$column] : $column;
if (isset($this->_class->fieldNames[$column])) { if (isset($this->_class->fieldNames[$column])) {
$field = $this->_class->fieldNames[$column]; $field = $this->_class->fieldNames[$column];
$data[$field] = Type::getType($this->_class->fieldMappings[$field]['type']) $data[$field] = Type::getType($this->_class->fieldMappings[$field]['type'])
...@@ -690,11 +692,18 @@ class StandardEntityPersister ...@@ -690,11 +692,18 @@ class StandardEntityPersister
protected function _getSelectColumnList() protected function _getSelectColumnList()
{ {
$columnList = ''; $columnList = '';
$tableName = $this->_class->getQuotedTableName($this->_platform);
$setResultColumnNames = empty($this->_resultColumnNames);
// Add regular columns to select list // Add regular columns to select list
foreach ($this->_class->fieldNames as $field) { foreach ($this->_class->fieldNames as $field) {
if ($columnList != '') $columnList .= ', '; if ($columnList != '') $columnList .= ', ';
$columnList .= $this->_class->getQuotedColumnName($field, $this->_platform); $columnList .= $tableName . '.' . $this->_class->getQuotedColumnName($field, $this->_platform);
if ($setResultColumnNames) {
$resultColumnName = $this->_platform->getSqlResultCasing($this->_class->columnNames[$field]);
$this->_resultColumnNames[$resultColumnName] = $this->_class->columnNames[$field];
}
} }
// Add join columns (foreign keys) to select list // Add join columns (foreign keys) to select list
...@@ -702,6 +711,11 @@ class StandardEntityPersister ...@@ -702,6 +711,11 @@ class StandardEntityPersister
if ($assoc->isOwningSide && $assoc->isOneToOne()) { if ($assoc->isOwningSide && $assoc->isOneToOne()) {
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) { foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
$columnList .= ', ' . $assoc->getQuotedJoinColumnName($srcColumn, $this->_platform); $columnList .= ', ' . $assoc->getQuotedJoinColumnName($srcColumn, $this->_platform);
if ($setResultColumnNames) {
$resultColumnName = $this->_platform->getSqlResultCasing($srcColumn);
$this->_resultColumnNames[$resultColumnName] = $srcColumn;
}
} }
} }
} }
...@@ -717,22 +731,6 @@ class StandardEntityPersister ...@@ -717,22 +731,6 @@ class StandardEntityPersister
*/ */
protected function _getSelectManyToManyEntityCollectionSql($manyToMany, array &$criteria) protected function _getSelectManyToManyEntityCollectionSql($manyToMany, array &$criteria)
{ {
$columnList = '';
$tableName = $this->_class->getQuotedTableName($this->_platform);
foreach ($this->_class->fieldNames as $field) {
if ($columnList != '') $columnList .= ', ';
$columnList .= $tableName . '.' . $this->_class->getQuotedColumnName($field, $this->_platform);
}
foreach ($this->_class->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
$columnList .= ', ' . $assoc->getQuotedJoinColumnName($srcColumn, $this->_platform);
}
}
}
if ($manyToMany->isOwningSide) { if ($manyToMany->isOwningSide) {
$owningAssoc = $manyToMany; $owningAssoc = $manyToMany;
$joinClauses = $manyToMany->relationToTargetKeyColumns; $joinClauses = $manyToMany->relationToTargetKeyColumns;
...@@ -762,7 +760,7 @@ class StandardEntityPersister ...@@ -762,7 +760,7 @@ class StandardEntityPersister
$conditionSql .= $columnName . ' = ?'; $conditionSql .= $columnName . ' = ?';
} }
return 'SELECT ' . $columnList return 'SELECT ' . $this->_getSelectColumnList()
. ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' FROM ' . $this->_class->getQuotedTableName($this->_platform)
. $joinSql . $joinSql
. ' WHERE ' . $conditionSql; . ' WHERE ' . $conditionSql;
...@@ -774,7 +772,7 @@ class StandardEntityPersister ...@@ -774,7 +772,7 @@ class StandardEntityPersister
$data = array(); $data = array();
$entityName = $this->_class->name; $entityName = $this->_class->name;
foreach ($sqlResult as $column => $value) { foreach ($sqlResult as $column => $value) {
$column = $this->_class->resultColumnNames[$column]; $column = isset($this->_resultColumnNames[$column]) ? $this->_resultColumnNames[$column] : $column;
if (($class = $this->_findDeclaringClass($column)) !== false) { if (($class = $this->_findDeclaringClass($column)) !== false) {
$field = $class->fieldNames[$column]; $field = $class->fieldNames[$column];
$data[$field] = Type::getType($class->fieldMappings[$field]['type']) $data[$field] = Type::getType($class->fieldMappings[$field]['type'])
......
...@@ -45,7 +45,7 @@ class LifecycleCallbackTest extends \Doctrine\Tests\OrmFunctionalTestCase ...@@ -45,7 +45,7 @@ class LifecycleCallbackTest extends \Doctrine\Tests\OrmFunctionalTestCase
{ {
$user = new LifecycleCallbackTestUser; $user = new LifecycleCallbackTestUser;
$user->setName('Bob'); $user->setName('Bob');
$user->setValue(''); $user->setValue('value');
$this->_em->persist($user); $this->_em->persist($user);
$this->_em->flush(); $this->_em->flush();
......
...@@ -11,6 +11,9 @@ class DDC168Test extends \Doctrine\Tests\OrmFunctionalTestCase ...@@ -11,6 +11,9 @@ class DDC168Test extends \Doctrine\Tests\OrmFunctionalTestCase
parent::setUp(); parent::setUp();
} }
/**
* @group DDC-168
*/
public function testJoinedSubclassPersisterRequiresSpecificOrderOfMetadataReflFieldsArray() public function testJoinedSubclassPersisterRequiresSpecificOrderOfMetadataReflFieldsArray()
{ {
$metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyEmployee'); $metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyEmployee');
......
...@@ -84,7 +84,7 @@ class DDC199ChildClass extends DDC199ParentClass ...@@ -84,7 +84,7 @@ class DDC199ChildClass extends DDC199ParentClass
public $childData; public $childData;
} }
/** @Entity @Table(name="ddcxxx_relatedclass") */ /** @Entity @Table(name="ddc199_relatedclass") */
class DDC199RelatedClass class DDC199RelatedClass
{ {
/** @Id @Column(type="integer") @GeneratedValue(strategy="AUTO") */ /** @Id @Column(type="integer") @GeneratedValue(strategy="AUTO") */
......
...@@ -8,6 +8,8 @@ use Doctrine\ORM\Proxy\ProxyFactory; ...@@ -8,6 +8,8 @@ use Doctrine\ORM\Proxy\ProxyFactory;
use Doctrine\ORM\Mapping\AssociationMapping; use Doctrine\ORM\Mapping\AssociationMapping;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
use Doctrine\Tests\Models\CMS\CmsUser;
require_once __DIR__ . '/../../TestInit.php'; require_once __DIR__ . '/../../TestInit.php';
class ObjectHydratorTest extends HydrationTestCase class ObjectHydratorTest extends HydrationTestCase
...@@ -686,6 +688,62 @@ class ObjectHydratorTest extends HydrationTestCase ...@@ -686,6 +688,62 @@ class ObjectHydratorTest extends HydrationTestCase
} }
public function testChainedJoinWithEmptyCollections()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsArticle',
'a',
'u',
'articles'
);
$rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsComment',
'c',
'a',
'comments'
);
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addFieldResult('a', 'a__id', 'id');
$rsm->addFieldResult('a', 'a__topic', 'topic');
$rsm->addFieldResult('c', 'c__id', 'id');
$rsm->addFieldResult('c', 'c__topic', 'topic');
// Faked result set
$resultSet = array(
//row1
array(
'u__id' => '1',
'u__status' => 'developer',
'a__id' => null,
'a__topic' => null,
'c__id' => null,
'c__topic' => null
),
array(
'u__id' => '2',
'u__status' => 'developer',
'a__id' => null,
'a__topic' => null,
'c__id' => null,
'c__topic' => null
),
);
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
$this->assertEquals(2, count($result));
$this->assertTrue($result[0] instanceof CmsUser);
$this->assertTrue($result[1] instanceof CmsUser);
$this->assertEquals(0, $result[0]->articles->count());
$this->assertEquals(0, $result[1]->articles->count());
}
public function testResultIteration() public function testResultIteration()
{ {
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
......
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