1
0
mirror of synced 2025-03-22 16:03:49 +03:00

Merge branch 'master' into DDC-1452

This commit is contained in:
Benjamin Eberlei 2011-11-14 21:53:36 +01:00
commit 98033cc878
93 changed files with 4784 additions and 2754 deletions

3
.gitignore vendored
View File

@ -7,3 +7,6 @@ download/
lib/api/ lib/api/
lib/Doctrine/Common lib/Doctrine/Common
lib/Doctrine/DBAL lib/Doctrine/DBAL
/.settings/
.buildpath
.project

19
.travis.yml Normal file
View File

@ -0,0 +1,19 @@
language: php
php:
- 5.3
- 5.4
env:
- DB=mysql
- DB=pgsql
- DB=sqlite
before_script:
- sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'DROP DATABASE IF EXISTS doctrine_tests;' -U postgres; fi"
- sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'DROP DATABASE IF EXISTS doctrine_tests_tmp;' -U postgres; fi"
- sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'create database doctrine_tests;' -U postgres; fi"
- sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'create database doctrine_tests_tmp;' -U postgres; fi"
- sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'create database IF NOT EXISTS doctrine_tests_tmp;create database IF NOT EXISTS doctrine_tests;'; fi"
- git submodule update --init
script: phpunit --configuration tests/travis/$DB.travis.xml

View File

@ -1,14 +1,18 @@
# Doctrine 2 ORM # Doctrine 2 ORM
Master: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=master)](http://travis-ci.org/doctrine/doctrine2)
2.1.x: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=2.1.x)](http://travis-ci.org/doctrine/doctrine2)
Doctrine 2 is an object-relational mapper (ORM) for PHP 5.3.2+ that provides transparent persistence Doctrine 2 is an object-relational mapper (ORM) for PHP 5.3.2+ that provides transparent persistence
for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features
is the option to write database queries in a proprietary object oriented SQL dialect called Doctrine Query Language (DQL), is the option to write database queries in a proprietary object oriented SQL dialect called Doctrine Query Language (DQL),
inspired by Hibernates HQL. This provides developers with a powerful alternative to SQL that maintains flexibility inspired by Hibernates HQL. This provides developers with a powerful alternative to SQL that maintains flexibility
without requiring unnecessary code duplication. without requiring unnecessary code duplication.
More resources: ## More resources:
* [Website](http://www.doctrine-project.org) * [Website](http://www.doctrine-project.org)
* [Documentation](http://www.doctrine-project.org/projects/orm/2.0/docs/reference/introduction/en) * [Documentation](http://www.doctrine-project.org/projects/orm/2.0/docs/reference/introduction/en)
* [Issue Tracker](http://www.doctrine-project.org/jira/browse/DDC) * [Issue Tracker](http://www.doctrine-project.org/jira/browse/DDC)
* [Downloads](http://github.com/doctrine/doctrine2/downloads) * [Downloads](http://github.com/doctrine/doctrine2/downloads)

View File

@ -16,5 +16,8 @@
"ext-pdo": "*", "ext-pdo": "*",
"doctrine/common": "master-dev", "doctrine/common": "master-dev",
"doctrine/dbal": "master-dev" "doctrine/dbal": "master-dev"
},
"autoload": {
"psr-0": { "Doctrine\\ORM": "lib/" }
} }
} }

View File

@ -545,7 +545,7 @@ abstract class AbstractQuery
* *
* @param array $params The query parameters. * @param array $params The query parameters.
* @param integer $hydrationMode The hydration mode to use. * @param integer $hydrationMode The hydration mode to use.
* @return IterableResult * @return \Doctrine\ORM\Internal\Hydration\IterableResult
*/ */
public function iterate(array $params = array(), $hydrationMode = null) public function iterate(array $params = array(), $hydrationMode = null)
{ {

View File

@ -225,6 +225,14 @@ class EntityRepository implements ObjectRepository
return $this->_entityName; return $this->_entityName;
} }
/**
* @return string
*/
public function getClassName()
{
return $this->getEntityName();
}
/** /**
* @return EntityManager * @return EntityManager
*/ */
@ -240,4 +248,4 @@ class EntityRepository implements ObjectRepository
{ {
return $this->_class; return $this->_class;
} }
} }

View File

@ -0,0 +1,53 @@
<?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\Event;
/**
* Provides event arguments for the preFlush event.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
* @since 2.0
* @version $Revision$
* @author Roman Borschel <roman@code-factory.de>
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class PreFlushEventArgs extends \Doctrine\Common\EventArgs
{
/**
* @var EntityManager
*/
private $_em;
public function __construct($em)
{
$this->_em = $em;
}
/**
* @return EntityManager
*/
public function getEntityManager()
{
return $this->_em;
}
}

View File

@ -109,6 +109,13 @@ final class Events
*/ */
const loadClassMetadata = 'loadClassMetadata'; const loadClassMetadata = 'loadClassMetadata';
/**
* The preFlush event occurs when the EntityManager#flush() operation is invoked,
* but before any changes to managed entites have been calculated. This event is
* always raised right after EntityManager#flush() call.
*/
const preFlush = 'preFlush';
/** /**
* The onFlush event occurs when the EntityManager#flush() operation is invoked, * The onFlush event occurs when the EntityManager#flush() operation is invoked,
* after any changes to managed entities have been determined but before any * after any changes to managed entities have been determined but before any

View File

@ -20,6 +20,7 @@
namespace Doctrine\ORM\Id; namespace Doctrine\ORM\Id;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\ORMException; use Doctrine\ORM\ORMException;
/** /**
@ -42,46 +43,29 @@ class AssignedGenerator extends AbstractIdGenerator
*/ */
public function generate(EntityManager $em, $entity) public function generate(EntityManager $em, $entity)
{ {
$class = $em->getClassMetadata(get_class($entity)); $class = $em->getClassMetadata(get_class($entity));
$idFields = $class->getIdentifierFieldNames();
$identifier = array(); $identifier = array();
if ($class->isIdentifierComposite) {
$idFields = $class->getIdentifierFieldNames(); foreach ($idFields as $idField) {
foreach ($idFields as $idField) {
$value = $class->reflFields[$idField]->getValue($entity);
if (isset($value)) {
if (isset($class->associationMappings[$idField])) {
if (!$em->getUnitOfWork()->isInIdentityMap($value)) {
throw ORMException::entityMissingForeignAssignedId($entity, $value);
}
// NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced.
$identifier[$idField] = current($em->getUnitOfWork()->getEntityIdentifier($value));
} else {
$identifier[$idField] = $value;
}
} else {
throw ORMException::entityMissingAssignedIdForField($entity, $idField);
}
}
} else {
$idField = $class->identifier[0];
$value = $class->reflFields[$idField]->getValue($entity); $value = $class->reflFields[$idField]->getValue($entity);
if (isset($value)) {
if (isset($class->associationMappings[$idField])) { if ( ! isset($value)) {
if (!$em->getUnitOfWork()->isInIdentityMap($value)) {
throw ORMException::entityMissingForeignAssignedId($entity, $value);
}
// NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced.
$identifier[$idField] = current($em->getUnitOfWork()->getEntityIdentifier($value));
} else {
$identifier[$idField] = $value;
}
} else {
throw ORMException::entityMissingAssignedIdForField($entity, $idField); throw ORMException::entityMissingAssignedIdForField($entity, $idField);
} }
}
if (isset($class->associationMappings[$idField])) {
if ( ! $em->getUnitOfWork()->isInIdentityMap($value)) {
throw ORMException::entityMissingForeignAssignedId($entity, $value);
}
// NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced.
$value = current($em->getUnitOfWork()->getEntityIdentifier($value));
}
$identifier[$idField] = $value;
}
return $identifier; return $identifier;
} }
} }

View File

@ -46,7 +46,7 @@ class IdentityGenerator extends AbstractIdGenerator
*/ */
public function generate(EntityManager $em, $entity) public function generate(EntityManager $em, $entity)
{ {
return $em->getConnection()->lastInsertId($this->_seqName); return (int)$em->getConnection()->lastInsertId($this->_seqName);
} }
/** /**

View File

@ -46,7 +46,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
$this->_sequenceName = $sequenceName; $this->_sequenceName = $sequenceName;
$this->_allocationSize = $allocationSize; $this->_allocationSize = $allocationSize;
} }
/** /**
* Generates an ID for the given entity. * Generates an ID for the given entity.
* *
@ -59,10 +59,12 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
if ($this->_maxValue === null || $this->_nextValue == $this->_maxValue) { if ($this->_maxValue === null || $this->_nextValue == $this->_maxValue) {
// Allocate new values // Allocate new values
$conn = $em->getConnection(); $conn = $em->getConnection();
$sql = $conn->getDatabasePlatform()->getSequenceNextValSQL($this->_sequenceName); $sql = $conn->getDatabasePlatform()->getSequenceNextValSQL($this->_sequenceName);
$this->_nextValue = $conn->fetchColumn($sql);
$this->_maxValue = $this->_nextValue + $this->_allocationSize; $this->_nextValue = (int)$conn->fetchColumn($sql);
$this->_maxValue = $this->_nextValue + $this->_allocationSize;
} }
return $this->_nextValue++; return $this->_nextValue++;
} }
@ -90,13 +92,14 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
{ {
return serialize(array( return serialize(array(
'allocationSize' => $this->_allocationSize, 'allocationSize' => $this->_allocationSize,
'sequenceName' => $this->_sequenceName 'sequenceName' => $this->_sequenceName
)); ));
} }
public function unserialize($serialized) public function unserialize($serialized)
{ {
$array = unserialize($serialized); $array = unserialize($serialized);
$this->_sequenceName = $array['sequenceName']; $this->_sequenceName = $array['sequenceName'];
$this->_allocationSize = $array['allocationSize']; $this->_allocationSize = $array['allocationSize'];
} }

View File

@ -50,11 +50,12 @@ class TableGenerator extends AbstractIdGenerator
if ($this->_maxValue === null || $this->_nextValue == $this->_maxValue) { if ($this->_maxValue === null || $this->_nextValue == $this->_maxValue) {
// Allocate new values // Allocate new values
$conn = $em->getConnection(); $conn = $em->getConnection();
if ($conn->getTransactionNestingLevel() == 0) {
if ($conn->getTransactionNestingLevel() === 0) {
// use select for update // use select for update
$sql = $conn->getDatabasePlatform()->getTableHiLoCurrentValSql($this->_tableName, $this->_sequenceName); $sql = $conn->getDatabasePlatform()->getTableHiLoCurrentValSql($this->_tableName, $this->_sequenceName);
$currentLevel = $conn->fetchColumn($sql); $currentLevel = $conn->fetchColumn($sql);
if ($currentLevel != null) { if ($currentLevel != null) {
$this->_nextValue = $currentLevel; $this->_nextValue = $currentLevel;
$this->_maxValue = $this->_nextValue + $this->_allocationSize; $this->_maxValue = $this->_nextValue + $this->_allocationSize;
@ -74,6 +75,7 @@ class TableGenerator extends AbstractIdGenerator
// or do we want to work with table locks exclusively? // or do we want to work with table locks exclusively?
} }
} }
return $this->_nextValue++; return $this->_nextValue++;
} }
} }

View File

@ -22,15 +22,17 @@ namespace Doctrine\ORM\Internal\Hydration;
use PDO, use PDO,
Doctrine\DBAL\Connection, Doctrine\DBAL\Connection,
Doctrine\DBAL\Types\Type, Doctrine\DBAL\Types\Type,
Doctrine\ORM\EntityManager; Doctrine\ORM\EntityManager,
Doctrine\ORM\Mapping\ClassMetadata;
/** /**
* Base class for all hydrators. A hydrator is a class that provides some form * Base class for all hydrators. A hydrator is a class that provides some form
* of transformation of an SQL result set into another structure. * of transformation of an SQL result set into another structure.
* *
* @since 2.0 * @since 2.0
* @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>
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
*/ */
abstract class AbstractHydrator abstract class AbstractHydrator
{ {
@ -62,9 +64,9 @@ abstract class AbstractHydrator
*/ */
public function __construct(EntityManager $em) public function __construct(EntityManager $em)
{ {
$this->_em = $em; $this->_em = $em;
$this->_platform = $em->getConnection()->getDatabasePlatform(); $this->_platform = $em->getConnection()->getDatabasePlatform();
$this->_uow = $em->getUnitOfWork(); $this->_uow = $em->getUnitOfWork();
} }
/** /**
@ -72,14 +74,17 @@ abstract class AbstractHydrator
* *
* @param object $stmt * @param object $stmt
* @param object $resultSetMapping * @param object $resultSetMapping
*
* @return IterableResult * @return IterableResult
*/ */
public function iterate($stmt, $resultSetMapping, array $hints = array()) public function iterate($stmt, $resultSetMapping, array $hints = array())
{ {
$this->_stmt = $stmt; $this->_stmt = $stmt;
$this->_rsm = $resultSetMapping; $this->_rsm = $resultSetMapping;
$this->_hints = $hints; $this->_hints = $hints;
$this->_prepare();
$this->prepare();
return new IterableResult($this); return new IterableResult($this);
} }
@ -92,12 +97,16 @@ abstract class AbstractHydrator
*/ */
public function hydrateAll($stmt, $resultSetMapping, array $hints = array()) public function hydrateAll($stmt, $resultSetMapping, array $hints = array())
{ {
$this->_stmt = $stmt; $this->_stmt = $stmt;
$this->_rsm = $resultSetMapping; $this->_rsm = $resultSetMapping;
$this->_hints = $hints; $this->_hints = $hints;
$this->_prepare();
$result = $this->_hydrateAll(); $this->prepare();
$this->_cleanup();
$result = $this->hydrateAllData();
$this->cleanup();
return $result; return $result;
} }
@ -110,12 +119,17 @@ abstract class AbstractHydrator
public function hydrateRow() public function hydrateRow()
{ {
$row = $this->_stmt->fetch(PDO::FETCH_ASSOC); $row = $this->_stmt->fetch(PDO::FETCH_ASSOC);
if ( ! $row) { if ( ! $row) {
$this->_cleanup(); $this->cleanup();
return false; return false;
} }
$result = array(); $result = array();
$this->_hydrateRow($row, $this->_cache, $result);
$this->hydrateRowData($row, $this->_cache, $result);
return $result; return $result;
} }
@ -123,16 +137,17 @@ abstract class AbstractHydrator
* Excutes one-time preparation tasks, once each time hydration is started * Excutes one-time preparation tasks, once each time hydration is started
* through {@link hydrateAll} or {@link iterate()}. * through {@link hydrateAll} or {@link iterate()}.
*/ */
protected function _prepare() protected function prepare()
{} {}
/** /**
* Excutes one-time cleanup tasks at the end of a hydration that was initiated * Excutes one-time cleanup tasks at the end of a hydration that was initiated
* through {@link hydrateAll} or {@link iterate()}. * through {@link hydrateAll} or {@link iterate()}.
*/ */
protected function _cleanup() protected function cleanup()
{ {
$this->_rsm = null; $this->_rsm = null;
$this->_stmt->closeCursor(); $this->_stmt->closeCursor();
$this->_stmt = null; $this->_stmt = null;
} }
@ -146,23 +161,24 @@ abstract class AbstractHydrator
* @param array $cache The cache to use. * @param array $cache The cache to use.
* @param mixed $result The result to fill. * @param mixed $result The result to fill.
*/ */
protected function _hydrateRow(array $data, array &$cache, array &$result) protected function hydrateRowData(array $data, array &$cache, array &$result)
{ {
throw new HydrationException("_hydrateRow() not implemented by this hydrator."); throw new HydrationException("hydrateRowData() not implemented by this hydrator.");
} }
/** /**
* Hydrates all rows from the current statement instance at once. * Hydrates all rows from the current statement instance at once.
*/ */
abstract protected function _hydrateAll(); abstract protected function hydrateAllData();
/** /**
* Processes a row of the result set. * Processes a row of the result set.
*
* Used for identity-based hydration (HYDRATE_OBJECT and HYDRATE_ARRAY). * Used for identity-based hydration (HYDRATE_OBJECT and HYDRATE_ARRAY).
* Puts the elements of a result row into a new array, grouped by the class * Puts the elements of a result row into a new array, grouped by the dql alias
* they belong to. The column names in the result set are mapped to their * they belong to. The column names in the result set are mapped to their
* field names during this procedure as well as any necessary conversions on * field names during this procedure as well as any necessary conversions on
* the values applied. * the values applied. Scalar values are kept in a specfic key 'scalars'.
* *
* @param array $data SQL Result Row * @param array $data SQL Result Row
* @param array &$cache Cache for column to field result information * @param array &$cache Cache for column to field result information
@ -172,40 +188,51 @@ abstract class AbstractHydrator
* @return array An array with all the fields (name => value) of the data row, * @return array An array with all the fields (name => value) of the data row,
* grouped by their component alias. * grouped by their component alias.
*/ */
protected function _gatherRowData(array $data, array &$cache, array &$id, array &$nonemptyComponents) protected function gatherRowData(array $data, array &$cache, array &$id, array &$nonemptyComponents)
{ {
$rowData = array(); $rowData = array();
foreach ($data as $key => $value) { foreach ($data as $key => $value) {
// Parse each column name only once. Cache the results. // Parse each column name only once. Cache the results.
if ( ! isset($cache[$key])) { if ( ! isset($cache[$key])) {
if (isset($this->_rsm->scalarMappings[$key])) { switch (true) {
$cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key]; // NOTE: Most of the times it's a field mapping, so keep it first!!!
$cache[$key]['isScalar'] = true; case (isset($this->_rsm->fieldMappings[$key])):
} else if (isset($this->_rsm->fieldMappings[$key])) { $fieldName = $this->_rsm->fieldMappings[$key];
$fieldName = $this->_rsm->fieldMappings[$key]; $classMetadata = $this->_em->getClassMetadata($this->_rsm->declaringClasses[$key]);
$classMetadata = $this->_em->getClassMetadata($this->_rsm->declaringClasses[$key]);
$cache[$key]['fieldName'] = $fieldName; $cache[$key]['fieldName'] = $fieldName;
$cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']); $cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']);
$cache[$key]['isIdentifier'] = $classMetadata->isIdentifier($fieldName); $cache[$key]['isIdentifier'] = $classMetadata->isIdentifier($fieldName);
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key]; $cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
} else if (!isset($this->_rsm->metaMappings[$key])) { break;
// this column is a left over, maybe from a LIMIT query hack for example in Oracle or DB2
// maybe from an additional column that has not been defined in a NativeQuery ResultSetMapping. case (isset($this->_rsm->scalarMappings[$key])):
continue; $cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key];
} else { $cache[$key]['isScalar'] = true;
// Meta column (has meaning in relational schema only, i.e. foreign keys or discriminator columns). break;
$fieldName = $this->_rsm->metaMappings[$key];
$cache[$key]['isMetaColumn'] = true; case (isset($this->_rsm->metaMappings[$key])):
$cache[$key]['fieldName'] = $fieldName; // Meta column (has meaning in relational schema only, i.e. foreign keys or discriminator columns).
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key]; $fieldName = $this->_rsm->metaMappings[$key];
$classMetadata = $this->_em->getClassMetadata($this->_rsm->aliasMap[$cache[$key]['dqlAlias']]); $classMetadata = $this->_em->getClassMetadata($this->_rsm->aliasMap[$this->_rsm->columnOwnerMap[$key]]);
$cache[$key]['isIdentifier'] = isset($this->_rsm->isIdentifierColumn[$cache[$key]['dqlAlias']][$key]);
$cache[$key]['isMetaColumn'] = true;
$cache[$key]['fieldName'] = $fieldName;
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
$cache[$key]['isIdentifier'] = isset($this->_rsm->isIdentifierColumn[$cache[$key]['dqlAlias']][$key]);
break;
default:
// this column is a left over, maybe from a LIMIT query hack for example in Oracle or DB2
// maybe from an additional column that has not been defined in a NativeQuery ResultSetMapping.
continue 2;
} }
} }
if (isset($cache[$key]['isScalar'])) { if (isset($cache[$key]['isScalar'])) {
$rowData['scalars'][$cache[$key]['fieldName']] = $value; $rowData['scalars'][$cache[$key]['fieldName']] = $value;
continue; continue;
} }
@ -216,13 +243,14 @@ abstract class AbstractHydrator
} }
if (isset($cache[$key]['isMetaColumn'])) { if (isset($cache[$key]['isMetaColumn'])) {
if (!isset($rowData[$dqlAlias][$cache[$key]['fieldName']]) || $value !== null) { if ( ! isset($rowData[$dqlAlias][$cache[$key]['fieldName']]) || $value !== null) {
$rowData[$dqlAlias][$cache[$key]['fieldName']] = $value; $rowData[$dqlAlias][$cache[$key]['fieldName']] = $value;
} }
continue; continue;
} }
// in an inheritance hierachy the same field could be defined several times. // in an inheritance hierarchy the same field could be defined several times.
// We overwrite this value so long we dont have a non-null value, that value we keep. // We overwrite this value so long we dont have a non-null value, that value we keep.
// Per definition it cannot be that a field is defined several times and has several values. // Per definition it cannot be that a field is defined several times and has several values.
if (isset($rowData[$dqlAlias][$cache[$key]['fieldName']]) && $value === null) { if (isset($rowData[$dqlAlias][$cache[$key]['fieldName']]) && $value === null) {
@ -241,6 +269,7 @@ abstract class AbstractHydrator
/** /**
* Processes a row of the result set. * Processes a row of the result set.
*
* Used for HYDRATE_SCALAR. This is a variant of _gatherRowData() that * Used for HYDRATE_SCALAR. This is a variant of _gatherRowData() that
* simply converts column names to field names and properly converts the * simply converts column names to field names and properly converts the
* values according to their types. The resulting row has the same number * values according to their types. The resulting row has the same number
@ -248,52 +277,77 @@ abstract class AbstractHydrator
* *
* @param array $data * @param array $data
* @param array $cache * @param array $cache
*
* @return array The processed row. * @return array The processed row.
*/ */
protected function _gatherScalarRowData(&$data, &$cache) protected function gatherScalarRowData(&$data, &$cache)
{ {
$rowData = array(); $rowData = array();
foreach ($data as $key => $value) { foreach ($data as $key => $value) {
// Parse each column name only once. Cache the results. // Parse each column name only once. Cache the results.
if ( ! isset($cache[$key])) { if ( ! isset($cache[$key])) {
if (isset($this->_rsm->scalarMappings[$key])) { switch (true) {
$cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key]; // NOTE: During scalar hydration, most of the times it's a scalar mapping, keep it first!!!
$cache[$key]['isScalar'] = true; case (isset($this->_rsm->scalarMappings[$key])):
} else if (isset($this->_rsm->fieldMappings[$key])) { $cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key];
$fieldName = $this->_rsm->fieldMappings[$key]; $cache[$key]['isScalar'] = true;
$classMetadata = $this->_em->getClassMetadata($this->_rsm->declaringClasses[$key]); break;
$cache[$key]['fieldName'] = $fieldName;
$cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']); case (isset($this->_rsm->fieldMappings[$key])):
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key]; $fieldName = $this->_rsm->fieldMappings[$key];
} else if (!isset($this->_rsm->metaMappings[$key])) { $classMetadata = $this->_em->getClassMetadata($this->_rsm->declaringClasses[$key]);
// this column is a left over, maybe from a LIMIT query hack for example in Oracle or DB2
// maybe from an additional column that has not been defined in a NativeQuery ResultSetMapping. $cache[$key]['fieldName'] = $fieldName;
continue; $cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']);
} else { $cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
// Meta column (has meaning in relational schema only, i.e. foreign keys or discriminator columns). break;
$cache[$key]['isMetaColumn'] = true;
$cache[$key]['fieldName'] = $this->_rsm->metaMappings[$key]; case (isset($this->_rsm->metaMappings[$key])):
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key]; // Meta column (has meaning in relational schema only, i.e. foreign keys or discriminator columns).
$cache[$key]['isMetaColumn'] = true;
$cache[$key]['fieldName'] = $this->_rsm->metaMappings[$key];
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
break;
default:
// this column is a left over, maybe from a LIMIT query hack for example in Oracle or DB2
// maybe from an additional column that has not been defined in a NativeQuery ResultSetMapping.
continue 2;
} }
} }
$fieldName = $cache[$key]['fieldName']; $fieldName = $cache[$key]['fieldName'];
if (isset($cache[$key]['isScalar'])) { switch (true) {
$rowData[$fieldName] = $value; case (isset($cache[$key]['isScalar'])):
} else if (isset($cache[$key]['isMetaColumn'])) { $rowData[$fieldName] = $value;
$rowData[$cache[$key]['dqlAlias'] . '_' . $fieldName] = $value; break;
} else {
$rowData[$cache[$key]['dqlAlias'] . '_' . $fieldName] = $cache[$key]['type'] case (isset($cache[$key]['isMetaColumn'])):
->convertToPHPValue($value, $this->_platform); $rowData[$cache[$key]['dqlAlias'] . '_' . $fieldName] = $value;
break;
default:
$value = $cache[$key]['type']->convertToPHPValue($value, $this->_platform);
$rowData[$cache[$key]['dqlAlias'] . '_' . $fieldName] = $value;
} }
} }
return $rowData; return $rowData;
} }
protected function registerManaged($class, $entity, $data) /**
* Register entity as managed in UnitOfWork.
*
* @param Doctrine\ORM\Mapping\ClassMetadata $class
* @param object $entity
* @param array $data
*
* @todo The "$id" generation is the same of UnitOfWork#createEntity. Remove this duplication somehow
*/
protected function registerManaged(ClassMetadata $class, $entity, array $data)
{ {
if ($class->isIdentifierComposite) { if ($class->isIdentifierComposite) {
$id = array(); $id = array();
@ -311,6 +365,7 @@ abstract class AbstractHydrator
$id = array($class->identifier[0] => $data[$class->identifier[0]]); $id = array($class->identifier[0] => $data[$class->identifier[0]]);
} }
} }
$this->_em->getUnitOfWork()->registerManaged($entity, $id, $data); $this->_em->getUnitOfWork()->registerManaged($entity, $id, $data);
} }
} }

View File

@ -25,8 +25,14 @@ use PDO, Doctrine\DBAL\Connection, Doctrine\ORM\Mapping\ClassMetadata;
* The ArrayHydrator produces a nested array "graph" that is often (not always) * The ArrayHydrator produces a nested array "graph" that is often (not always)
* interchangeable with the corresponding object graph for read-only access. * interchangeable with the corresponding object graph for read-only access.
* *
* @since 2.0
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
* @since 1.0 * @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
*
* @todo General behavior is "wrong" if you define an alias to selected IdentificationVariable.
* Example: SELECT u AS user FROM User u
* The result should contains an array where each array index is an array: array('user' => [User object])
* Problem must be solved somehow by removing the isMixed in ResultSetMapping
*/ */
class ArrayHydrator extends AbstractHydrator class ArrayHydrator extends AbstractHydrator
{ {
@ -38,45 +44,55 @@ class ArrayHydrator extends AbstractHydrator
private $_idTemplate = array(); private $_idTemplate = array();
private $_resultCounter = 0; private $_resultCounter = 0;
/** @override */ /**
protected function _prepare() * {@inheritdoc}
*/
protected function prepare()
{ {
$this->_isSimpleQuery = count($this->_rsm->aliasMap) <= 1; $this->_isSimpleQuery = count($this->_rsm->aliasMap) <= 1;
$this->_identifierMap = array(); $this->_identifierMap = array();
$this->_resultPointers = array(); $this->_resultPointers = array();
$this->_idTemplate = array(); $this->_idTemplate = array();
$this->_resultCounter = 0; $this->_resultCounter = 0;
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] = '';
} }
} }
/** @override */ /**
protected function _hydrateAll() * {@inheritdoc}
*/
protected function hydrateAllData()
{ {
$result = array(); $result = array();
$cache = array(); $cache = array();
while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) { while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
$this->_hydrateRow($data, $cache, $result); $this->hydrateRowData($data, $cache, $result);
} }
return $result; return $result;
} }
/** @override */ /**
protected function _hydrateRow(array $data, array &$cache, array &$result) * {@inheritdoc}
*/
protected function hydrateRowData(array $row, array &$cache, array &$result)
{ {
// 1) Initialize // 1) Initialize
$id = $this->_idTemplate; // initialize the id-memory $id = $this->_idTemplate; // initialize the id-memory
$nonemptyComponents = array(); $nonemptyComponents = array();
$rowData = $this->_gatherRowData($data, $cache, $id, $nonemptyComponents); $rowData = $this->gatherRowData($row, $cache, $id, $nonemptyComponents);
// Extract scalar values. They're appended at the end. // Extract scalar values. They're appended at the end.
if (isset($rowData['scalars'])) { if (isset($rowData['scalars'])) {
$scalars = $rowData['scalars']; $scalars = $rowData['scalars'];
unset($rowData['scalars']); unset($rowData['scalars']);
if (empty($rowData)) { if (empty($rowData)) {
++$this->_resultCounter; ++$this->_resultCounter;
} }
@ -90,7 +106,7 @@ class ArrayHydrator extends AbstractHydrator
// It's a joined result // It's a joined result
$parent = $this->_rsm->parentAliasMap[$dqlAlias]; $parent = $this->_rsm->parentAliasMap[$dqlAlias];
$path = $parent . '.' . $dqlAlias; $path = $parent . '.' . $dqlAlias;
// missing parent data, skipping as RIGHT JOIN hydration is not supported. // missing parent data, skipping as RIGHT JOIN hydration is not supported.
if ( ! isset($nonemptyComponents[$parent]) ) { if ( ! isset($nonemptyComponents[$parent]) ) {
@ -109,39 +125,41 @@ class ArrayHydrator extends AbstractHydrator
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228 unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
continue; continue;
} }
$relationAlias = $this->_rsm->relationMap[$dqlAlias]; $relationAlias = $this->_rsm->relationMap[$dqlAlias];
$relation = $this->_getClassMetadata($this->_rsm->aliasMap[$parent])->associationMappings[$relationAlias]; $relation = $this->getClassMetadata($this->_rsm->aliasMap[$parent])->associationMappings[$relationAlias];
// Check the type of the relation (many or single-valued) // Check the type of the relation (many or single-valued)
if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) { if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) {
$oneToOne = false; $oneToOne = false;
if (isset($nonemptyComponents[$dqlAlias])) { if (isset($nonemptyComponents[$dqlAlias])) {
if ( ! isset($baseElement[$relationAlias])) { if ( ! isset($baseElement[$relationAlias])) {
$baseElement[$relationAlias] = array(); $baseElement[$relationAlias] = array();
} }
$indexExists = isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]); $indexExists = isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]);
$index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false; $index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false;
$indexIsValid = $index !== false ? isset($baseElement[$relationAlias][$index]) : false; $indexIsValid = $index !== false ? isset($baseElement[$relationAlias][$index]) : false;
if ( ! $indexExists || ! $indexIsValid) { if ( ! $indexExists || ! $indexIsValid) {
$element = $data; $element = $data;
if (isset($this->_rsm->indexByMap[$dqlAlias])) { if (isset($this->_rsm->indexByMap[$dqlAlias])) {
$field = $this->_rsm->indexByMap[$dqlAlias]; $baseElement[$relationAlias][$row[$this->_rsm->indexByMap[$dqlAlias]]] = $element;
$baseElement[$relationAlias][$element[$field]] = $element;
} else { } else {
$baseElement[$relationAlias][] = $element; $baseElement[$relationAlias][] = $element;
} }
end($baseElement[$relationAlias]); end($baseElement[$relationAlias]);
$this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] =
key($baseElement[$relationAlias]); $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] = key($baseElement[$relationAlias]);
} }
} else if ( ! isset($baseElement[$relationAlias])) { } else if ( ! isset($baseElement[$relationAlias])) {
$baseElement[$relationAlias] = array(); $baseElement[$relationAlias] = array();
} }
} else { } else {
$oneToOne = true; $oneToOne = true;
if ( ! isset($nonemptyComponents[$dqlAlias]) && ! isset($baseElement[$relationAlias])) { if ( ! isset($nonemptyComponents[$dqlAlias]) && ! isset($baseElement[$relationAlias])) {
$baseElement[$relationAlias] = null; $baseElement[$relationAlias] = null;
} else if ( ! isset($baseElement[$relationAlias])) { } else if ( ! isset($baseElement[$relationAlias])) {
@ -157,43 +175,42 @@ class ArrayHydrator extends AbstractHydrator
} else { } else {
// It's a root result element // It's a root result element
$this->_rootAliases[$dqlAlias] = true; // Mark as root $this->_rootAliases[$dqlAlias] = true; // Mark as root
$entityKey = $this->_rsm->entityMappings[$dqlAlias] ?: 0;
// if this row has a NULL value for the root result id then make it a null result. // if this row has a NULL value for the root result id then make it a null result.
if ( ! isset($nonemptyComponents[$dqlAlias]) ) { if ( ! isset($nonemptyComponents[$dqlAlias]) ) {
if ($this->_rsm->isMixed) { if ($this->_rsm->isMixed) {
$result[] = array(0 => null); $result[] = array($entityKey => null);
} else { } else {
$result[] = null; $result[] = null;
} }
$resultKey = $this->_resultCounter;
++$this->_resultCounter; ++$this->_resultCounter;
continue; continue;
} }
// Check for an existing element // Check for an existing element
if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) { if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
$element = $rowData[$dqlAlias]; $element = $rowData[$dqlAlias];
if (isset($this->_rsm->indexByMap[$dqlAlias])) { if ($this->_rsm->isMixed) {
$field = $this->_rsm->indexByMap[$dqlAlias]; $element = array($entityKey => $element);
if ($this->_rsm->isMixed) {
$result[] = array($element[$field] => $element);
++$this->_resultCounter;
} else {
$result[$element[$field]] = $element;
}
} else {
if ($this->_rsm->isMixed) {
$result[] = array($element);
++$this->_resultCounter;
} else {
$result[] = $element;
}
} }
end($result);
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = key($result); if (isset($this->_rsm->indexByMap[$dqlAlias])) {
$resultKey = $row[$this->_rsm->indexByMap[$dqlAlias]];
$result[$resultKey] = $element;
} else {
$resultKey = $this->_resultCounter;
$result[] = $element;
++$this->_resultCounter;
}
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
} else { } else {
$index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]]; $index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
$resultKey = $index;
/*if ($this->_rsm->isMixed) { /*if ($this->_rsm->isMixed) {
$result[] =& $result[$index]; $result[] =& $result[$index];
++$this->_resultCounter; ++$this->_resultCounter;
@ -205,8 +222,17 @@ class ArrayHydrator extends AbstractHydrator
// Append scalar values to mixed result sets // Append scalar values to mixed result sets
if (isset($scalars)) { if (isset($scalars)) {
if ( ! isset($resultKey) ) {
// this only ever happens when no object is fetched (scalar result only)
if (isset($this->_rsm->indexByMap['scalars'])) {
$resultKey = $row[$this->_rsm->indexByMap['scalars']];
} else {
$resultKey = $this->_resultCounter - 1;
}
}
foreach ($scalars as $name => $value) { foreach ($scalars as $name => $value) {
$result[$this->_resultCounter - 1][$name] = $value; $result[$resultKey][$name] = $value;
} }
} }
} }
@ -224,28 +250,45 @@ class ArrayHydrator extends AbstractHydrator
{ {
if ($coll === null) { if ($coll === null) {
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228 unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
return; return;
} }
if ($index !== false) { if ($index !== false) {
$this->_resultPointers[$dqlAlias] =& $coll[$index]; $this->_resultPointers[$dqlAlias] =& $coll[$index];
return; return;
} else {
if ($coll) {
if ($oneToOne) {
$this->_resultPointers[$dqlAlias] =& $coll;
} else {
end($coll);
$this->_resultPointers[$dqlAlias] =& $coll[key($coll)];
}
}
} }
if ( ! $coll) {
return;
}
if ($oneToOne) {
$this->_resultPointers[$dqlAlias] =& $coll;
return;
}
end($coll);
$this->_resultPointers[$dqlAlias] =& $coll[key($coll)];
return;
} }
private function _getClassMetadata($className) /**
* Retrieve ClassMetadata associated to entity class name.
*
* @param string $className
*
* @return Doctrine\ORM\Mapping\ClassMetadata
*/
private function getClassMetadata($className)
{ {
if ( ! isset($this->_ce[$className])) { if ( ! isset($this->_ce[$className])) {
$this->_ce[$className] = $this->_em->getClassMetadata($className); $this->_ce[$className] = $this->_em->getClassMetadata($className);
} }
return $this->_ce[$className]; return $this->_ce[$className];
} }
} }

View File

@ -8,10 +8,19 @@ class HydrationException extends \Doctrine\ORM\ORMException
{ {
return new self("The result returned by the query was not unique."); return new self("The result returned by the query was not unique.");
} }
public static function parentObjectOfRelationNotFound($alias, $parentAlias) public static function parentObjectOfRelationNotFound($alias, $parentAlias)
{ {
return new self("The parent object of entity result with alias '$alias' was not found." return new self("The parent object of entity result with alias '$alias' was not found."
. " The parent alias is '$parentAlias'."); . " The parent alias is '$parentAlias'.");
} }
public static function emptyDiscriminatorValue($dqlAlias)
{
return new self("The DQL alias '" . $dqlAlias . "' contains an entity ".
"of an inheritance hierachy with an empty discriminator value. This means " .
"that the database contains inconsistent data with an empty " .
"discriminator value in a table row."
);
}
} }

View File

@ -29,9 +29,16 @@ use PDO,
/** /**
* The ObjectHydrator constructs an object graph out of an SQL result set. * The ObjectHydrator constructs an object graph out of an SQL result set.
* *
* @since 2.0
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
* @since 2.0 * @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
*
* @internal Highly performance-sensitive code. * @internal Highly performance-sensitive code.
*
* @todo General behavior is "wrong" if you define an alias to selected IdentificationVariable.
* Example: SELECT u AS user FROM User u
* The result should contains an array where each array index is an array: array('user' => [User object])
* Problem must be solved somehow by removing the isMixed in ResultSetMapping
*/ */
class ObjectHydrator extends AbstractHydrator class ObjectHydrator extends AbstractHydrator
{ {
@ -53,57 +60,72 @@ class ObjectHydrator extends AbstractHydrator
/** @override */ /** @override */
protected function _prepare() protected function prepare()
{ {
$this->_identifierMap = $this->_identifierMap =
$this->_resultPointers = $this->_resultPointers =
$this->_idTemplate = array(); $this->_idTemplate = array();
$this->_resultCounter = 0; $this->_resultCounter = 0;
if (!isset($this->_hints['deferEagerLoad'])) {
if ( ! isset($this->_hints['deferEagerLoad'])) {
$this->_hints['deferEagerLoad'] = true; $this->_hints['deferEagerLoad'] = true;
} }
foreach ($this->_rsm->aliasMap as $dqlAlias => $className) { foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
$this->_identifierMap[$dqlAlias] = array(); $this->_identifierMap[$dqlAlias] = array();
$this->_idTemplate[$dqlAlias] = ''; $this->_idTemplate[$dqlAlias] = '';
$class = $this->_em->getClassMetadata($className);
if ( ! isset($this->_ce[$className])) { if ( ! isset($this->_ce[$className])) {
$this->_ce[$className] = $class; $this->_ce[$className] = $this->_em->getClassMetadata($className);
} }
// Remember which associations are "fetch joined", so that we know where to inject // Remember which associations are "fetch joined", so that we know where to inject
// collection stubs or proxies and where not. // collection stubs or proxies and where not.
if (isset($this->_rsm->relationMap[$dqlAlias])) { if ( ! isset($this->_rsm->relationMap[$dqlAlias])) {
if ( ! isset($this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]])) { continue;
throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $this->_rsm->parentAliasMap[$dqlAlias]); }
if ( ! isset($this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]])) {
throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $this->_rsm->parentAliasMap[$dqlAlias]);
}
$sourceClassName = $this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]];
$sourceClass = $this->_getClassMetadata($sourceClassName);
$assoc = $sourceClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]];
$this->_hints['fetched'][$sourceClassName][$assoc['fieldName']] = true;
if ($sourceClass->subClasses) {
foreach ($sourceClass->subClasses as $sourceSubclassName) {
$this->_hints['fetched'][$sourceSubclassName][$assoc['fieldName']] = true;
}
}
if ($assoc['type'] === ClassMetadata::MANY_TO_MANY) {
continue;
}
// Mark any non-collection opposite sides as fetched, too.
if ($assoc['mappedBy']) {
$this->_hints['fetched'][$className][$assoc['mappedBy']] = true;
continue;
}
if ($assoc['inversedBy']) {
$class = $this->_ce[$className];
$inverseAssoc = $class->associationMappings[$assoc['inversedBy']];
if ( ! ($inverseAssoc['type'] & ClassMetadata::TO_ONE)) {
continue;
} }
$sourceClassName = $this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]]; $this->_hints['fetched'][$className][$inverseAssoc['fieldName']] = true;
$sourceClass = $this->_getClassMetadata($sourceClassName);
$assoc = $sourceClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]]; if ($class->subClasses) {
$this->_hints['fetched'][$sourceClassName][$assoc['fieldName']] = true; foreach ($class->subClasses as $targetSubclassName) {
if ($sourceClass->subClasses) { $this->_hints['fetched'][$targetSubclassName][$inverseAssoc['fieldName']] = true;
foreach ($sourceClass->subClasses as $sourceSubclassName) {
$this->_hints['fetched'][$sourceSubclassName][$assoc['fieldName']] = true;
}
}
if ($assoc['type'] != ClassMetadata::MANY_TO_MANY) {
// Mark any non-collection opposite sides as fetched, too.
if ($assoc['mappedBy']) {
$this->_hints['fetched'][$className][$assoc['mappedBy']] = true;
} else {
if ($assoc['inversedBy']) {
$inverseAssoc = $class->associationMappings[$assoc['inversedBy']];
if ($inverseAssoc['type'] & ClassMetadata::TO_ONE) {
$this->_hints['fetched'][$className][$inverseAssoc['fieldName']] = true;
if ($class->subClasses) {
foreach ($class->subClasses as $targetSubclassName) {
$this->_hints['fetched'][$targetSubclassName][$inverseAssoc['fieldName']] = true;
}
}
}
}
} }
} }
} }
@ -113,11 +135,12 @@ class ObjectHydrator extends AbstractHydrator
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
protected function _cleanup() protected function cleanup()
{ {
$eagerLoad = (isset($this->_hints['deferEagerLoad'])) && $this->_hints['deferEagerLoad'] == true; $eagerLoad = (isset($this->_hints['deferEagerLoad'])) && $this->_hints['deferEagerLoad'] == true;
parent::_cleanup(); parent::cleanup();
$this->_identifierMap = $this->_identifierMap =
$this->_initializedCollections = $this->_initializedCollections =
$this->_existingCollections = $this->_existingCollections =
@ -131,13 +154,13 @@ class ObjectHydrator extends AbstractHydrator
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
protected function _hydrateAll() protected function hydrateAllData()
{ {
$result = array(); $result = array();
$cache = array(); $cache = array();
while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) { while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
$this->_hydrateRow($row, $cache, $result); $this->hydrateRowData($row, $cache, $result);
} }
// Take snapshots from all newly initialized collections // Take snapshots from all newly initialized collections
@ -156,31 +179,34 @@ class ObjectHydrator extends AbstractHydrator
*/ */
private function _initRelatedCollection($entity, $class, $fieldName) private function _initRelatedCollection($entity, $class, $fieldName)
{ {
$oid = spl_object_hash($entity); $oid = spl_object_hash($entity);
$relation = $class->associationMappings[$fieldName]; $relation = $class->associationMappings[$fieldName];
$value = $class->reflFields[$fieldName]->getValue($entity);
$value = $class->reflFields[$fieldName]->getValue($entity);
if ($value === null) { if ($value === null) {
$value = new ArrayCollection; $value = new ArrayCollection;
} }
if ( ! $value instanceof PersistentCollection) { if ( ! $value instanceof PersistentCollection) {
$value = new PersistentCollection( $value = new PersistentCollection(
$this->_em, $this->_em, $this->_ce[$relation['targetEntity']], $value
$this->_ce[$relation['targetEntity']],
$value
); );
$value->setOwner($entity, $relation); $value->setOwner($entity, $relation);
$class->reflFields[$fieldName]->setValue($entity, $value); $class->reflFields[$fieldName]->setValue($entity, $value);
$this->_uow->setOriginalEntityProperty($oid, $fieldName, $value); $this->_uow->setOriginalEntityProperty($oid, $fieldName, $value);
$this->_initializedCollections[$oid . $fieldName] = $value; $this->_initializedCollections[$oid . $fieldName] = $value;
} else if (isset($this->_hints[Query::HINT_REFRESH]) || } else if (
isset($this->_hints['fetched'][$class->name][$fieldName]) && isset($this->_hints[Query::HINT_REFRESH]) ||
! $value->isInitialized()) { isset($this->_hints['fetched'][$class->name][$fieldName]) &&
! $value->isInitialized()
) {
// Is already PersistentCollection, but either REFRESH or FETCH-JOIN and UNINITIALIZED! // Is already PersistentCollection, but either REFRESH or FETCH-JOIN and UNINITIALIZED!
$value->setDirty(false); $value->setDirty(false);
$value->setInitialized(true); $value->setInitialized(true);
$value->unwrap()->clear(); $value->unwrap()->clear();
$this->_initializedCollections[$oid . $fieldName] = $value; $this->_initializedCollections[$oid . $fieldName] = $value;
} else { } else {
// Is already PersistentCollection, and DON'T REFRESH or FETCH-JOIN! // Is already PersistentCollection, and DON'T REFRESH or FETCH-JOIN!
@ -200,15 +226,21 @@ class ObjectHydrator extends AbstractHydrator
private function _getEntity(array $data, $dqlAlias) private function _getEntity(array $data, $dqlAlias)
{ {
$className = $this->_rsm->aliasMap[$dqlAlias]; $className = $this->_rsm->aliasMap[$dqlAlias];
if (isset($this->_rsm->discriminatorColumns[$dqlAlias])) { if (isset($this->_rsm->discriminatorColumns[$dqlAlias])) {
$discrColumn = $this->_rsm->metaMappings[$this->_rsm->discriminatorColumns[$dqlAlias]]; $discrColumn = $this->_rsm->metaMappings[$this->_rsm->discriminatorColumns[$dqlAlias]];
if ($data[$discrColumn] === "") {
throw HydrationException::emptyDiscriminatorValue($dqlAlias);
}
$className = $this->_ce[$className]->discriminatorMap[$data[$discrColumn]]; $className = $this->_ce[$className]->discriminatorMap[$data[$discrColumn]];
unset($data[$discrColumn]); unset($data[$discrColumn]);
} }
if (isset($this->_hints[Query::HINT_REFRESH_ENTITY]) && isset($this->_rootAliases[$dqlAlias])) { if (isset($this->_hints[Query::HINT_REFRESH_ENTITY]) && isset($this->_rootAliases[$dqlAlias])) {
$class = $this->_ce[$className]; $this->registerManaged($this->_ce[$className], $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
$this->registerManaged($class, $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
} }
return $this->_uow->createEntity($className, $data, $this->_hints); return $this->_uow->createEntity($className, $data, $this->_hints);
@ -218,6 +250,7 @@ class ObjectHydrator extends AbstractHydrator
{ {
// TODO: Abstract this code and UnitOfWork::createEntity() equivalent? // TODO: Abstract this code and UnitOfWork::createEntity() equivalent?
$class = $this->_ce[$className]; $class = $this->_ce[$className];
/* @var $class ClassMetadata */ /* @var $class ClassMetadata */
if ($class->isIdentifierComposite) { if ($class->isIdentifierComposite) {
$idHash = ''; $idHash = '';
@ -249,6 +282,7 @@ class ObjectHydrator extends AbstractHydrator
if ( ! isset($this->_ce[$className])) { if ( ! isset($this->_ce[$className])) {
$this->_ce[$className] = $this->_em->getClassMetadata($className); $this->_ce[$className] = $this->_em->getClassMetadata($className);
} }
return $this->_ce[$className]; return $this->_ce[$className];
} }
@ -273,13 +307,13 @@ class ObjectHydrator extends AbstractHydrator
* @param array $cache The cache to use. * @param array $cache The cache to use.
* @param array $result The result array to fill. * @param array $result The result array to fill.
*/ */
protected function _hydrateRow(array $data, array &$cache, array &$result) protected function hydrateRowData(array $row, array &$cache, array &$result)
{ {
// Initialize // Initialize
$id = $this->_idTemplate; // initialize the id-memory $id = $this->_idTemplate; // initialize the id-memory
$nonemptyComponents = array(); $nonemptyComponents = array();
// Split the row data into chunks of class data. // Split the row data into chunks of class data.
$rowData = $this->_gatherRowData($data, $cache, $id, $nonemptyComponents); $rowData = $this->gatherRowData($row, $cache, $id, $nonemptyComponents);
// Extract scalar values. They're appended at the end. // Extract scalar values. They're appended at the end.
if (isset($rowData['scalars'])) { if (isset($rowData['scalars'])) {
@ -352,8 +386,7 @@ class ObjectHydrator extends AbstractHydrator
$element = $this->_getEntity($data, $dqlAlias); $element = $this->_getEntity($data, $dqlAlias);
if (isset($this->_rsm->indexByMap[$dqlAlias])) { if (isset($this->_rsm->indexByMap[$dqlAlias])) {
$field = $this->_rsm->indexByMap[$dqlAlias]; $indexValue = $row[$this->_rsm->indexByMap[$dqlAlias]];
$indexValue = $this->_ce[$entityName]->reflFields[$field]->getValue($element);
$reflFieldValue->hydrateSet($indexValue, $element); $reflFieldValue->hydrateSet($indexValue, $element);
$this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $indexValue; $this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $indexValue;
} else { } else {
@ -380,6 +413,7 @@ class ObjectHydrator extends AbstractHydrator
$reflField->setValue($parentObject, $element); $reflField->setValue($parentObject, $element);
$this->_uow->setOriginalEntityProperty($oid, $relationField, $element); $this->_uow->setOriginalEntityProperty($oid, $relationField, $element);
$targetClass = $this->_ce[$relation['targetEntity']]; $targetClass = $this->_ce[$relation['targetEntity']];
if ($relation['isOwningSide']) { if ($relation['isOwningSide']) {
//TODO: Just check hints['fetched'] here? //TODO: Just check hints['fetched'] here?
// If there is an inverse mapping on the target class its bidirectional // If there is an inverse mapping on the target class its bidirectional
@ -410,14 +444,16 @@ class ObjectHydrator extends AbstractHydrator
} else { } else {
// PATH C: Its a root result element // PATH C: Its a root result element
$this->_rootAliases[$dqlAlias] = true; // Mark as root alias $this->_rootAliases[$dqlAlias] = true; // Mark as root alias
$entityKey = $this->_rsm->entityMappings[$dqlAlias] ?: 0;
// if this row has a NULL value for the root result id then make it a null result. // if this row has a NULL value for the root result id then make it a null result.
if ( ! isset($nonemptyComponents[$dqlAlias]) ) { if ( ! isset($nonemptyComponents[$dqlAlias]) ) {
if ($this->_rsm->isMixed) { if ($this->_rsm->isMixed) {
$result[] = array(0 => null); $result[] = array($entityKey => null);
} else { } else {
$result[] = null; $result[] = null;
} }
$resultKey = $this->_resultCounter;
++$this->_resultCounter; ++$this->_resultCounter;
continue; continue;
} }
@ -425,35 +461,31 @@ class ObjectHydrator extends AbstractHydrator
// check for existing result from the iterations before // check for existing result from the iterations before
if ( ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) { if ( ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
$element = $this->_getEntity($rowData[$dqlAlias], $dqlAlias); $element = $this->_getEntity($rowData[$dqlAlias], $dqlAlias);
if ($this->_rsm->isMixed) {
$element = array($entityKey => $element);
}
if (isset($this->_rsm->indexByMap[$dqlAlias])) { if (isset($this->_rsm->indexByMap[$dqlAlias])) {
$field = $this->_rsm->indexByMap[$dqlAlias]; $resultKey = $row[$this->_rsm->indexByMap[$dqlAlias]];
$key = $this->_ce[$entityName]->reflFields[$field]->getValue($element);
if ($this->_rsm->isMixed) {
$element = array($key => $element);
$result[] = $element;
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $this->_resultCounter;
++$this->_resultCounter;
} else {
$result[$key] = $element;
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $key;
}
if (isset($this->_hints['collection'])) { if (isset($this->_hints['collection'])) {
$this->_hints['collection']->hydrateSet($key, $element); $this->_hints['collection']->hydrateSet($resultKey, $element);
} }
$result[$resultKey] = $element;
} else { } else {
if ($this->_rsm->isMixed) { $resultKey = $this->_resultCounter;
$element = array(0 => $element);
}
$result[] = $element;
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $this->_resultCounter;
++$this->_resultCounter; ++$this->_resultCounter;
if (isset($this->_hints['collection'])) { if (isset($this->_hints['collection'])) {
$this->_hints['collection']->hydrateAdd($element); $this->_hints['collection']->hydrateAdd($element);
} }
$result[] = $element;
} }
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
// Update result pointer // Update result pointer
$this->_resultPointers[$dqlAlias] = $element; $this->_resultPointers[$dqlAlias] = $element;
@ -461,6 +493,7 @@ class ObjectHydrator extends AbstractHydrator
// Update result pointer // Update result pointer
$index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]]; $index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
$this->_resultPointers[$dqlAlias] = $result[$index]; $this->_resultPointers[$dqlAlias] = $result[$index];
$resultKey = $index;
/*if ($this->_rsm->isMixed) { /*if ($this->_rsm->isMixed) {
$result[] = $result[$index]; $result[] = $result[$index];
++$this->_resultCounter; ++$this->_resultCounter;
@ -471,8 +504,16 @@ class ObjectHydrator extends AbstractHydrator
// Append scalar values to mixed result sets // Append scalar values to mixed result sets
if (isset($scalars)) { if (isset($scalars)) {
if ( ! isset($resultKey) ) {
if (isset($this->_rsm->indexByMap['scalars'])) {
$resultKey = $row[$this->_rsm->indexByMap['scalars']];
} else {
$resultKey = $this->_resultCounter - 1;
}
}
foreach ($scalars as $name => $value) { foreach ($scalars as $name => $value) {
$result[$this->_resultCounter - 1][$name] = $value; $result[$resultKey][$name] = $value;
} }
} }
} }

View File

@ -26,25 +26,32 @@ use Doctrine\DBAL\Connection;
* The created result is almost the same as a regular SQL result set, except * 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 take place. * that column names are mapped to field names and data type conversions take place.
* *
* @since 2.0
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
* @since 2.0 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
*/ */
class ScalarHydrator extends AbstractHydrator class ScalarHydrator extends AbstractHydrator
{ {
/** @override */ /**
protected function _hydrateAll() * {@inheritdoc}
*/
protected function hydrateAllData()
{ {
$result = array(); $result = array();
$cache = array(); $cache = array();
while ($data = $this->_stmt->fetch(\PDO::FETCH_ASSOC)) { while ($data = $this->_stmt->fetch(\PDO::FETCH_ASSOC)) {
$result[] = $this->_gatherScalarRowData($data, $cache); $this->hydrateRowData($data, $cache, $result);
} }
return $result; return $result;
} }
/** @override */ /**
protected function _hydrateRow(array $data, array &$cache, array &$result) * {@inheritdoc}
*/
protected function hydrateRowData(array $data, array &$cache, array &$result)
{ {
$result[] = $this->_gatherScalarRowData($data, $cache); $result[] = $this->gatherScalarRowData($data, $cache);
} }
} }

View File

@ -17,7 +17,6 @@
* <http://www.doctrine-project.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Internal\Hydration; namespace Doctrine\ORM\Internal\Hydration;
use \PDO; use \PDO;
@ -32,15 +31,21 @@ class SimpleObjectHydrator extends AbstractHydrator
*/ */
private $class; private $class;
/**
* @var array
*/
private $declaringClasses = array(); private $declaringClasses = array();
protected function _hydrateAll() /**
* {@inheritdoc}
*/
protected function hydrateAllData()
{ {
$result = array(); $result = array();
$cache = array(); $cache = array();
while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) { while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
$this->_hydrateRow($row, $cache, $result); $this->hydrateRowData($row, $cache, $result);
} }
$this->_em->getUnitOfWork()->triggerEagerLoads(); $this->_em->getUnitOfWork()->triggerEagerLoads();
@ -48,77 +53,71 @@ class SimpleObjectHydrator extends AbstractHydrator
return $result; return $result;
} }
protected function _prepare() /**
* {@inheritdoc}
*/
protected function prepare()
{ {
if (count($this->_rsm->aliasMap) == 1) { if (count($this->_rsm->aliasMap) !== 1) {
$this->class = $this->_em->getClassMetadata(reset($this->_rsm->aliasMap)); throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping that contains more than one object result.");
if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
foreach ($this->_rsm->declaringClasses AS $column => $class) {
$this->declaringClasses[$column] = $this->_em->getClassMetadata($class);
}
}
} else {
throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping not containing exactly one object result.");
} }
if ($this->_rsm->scalarMappings) { if ($this->_rsm->scalarMappings) {
throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping that contains scalar mappings."); throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping that contains scalar mappings.");
} }
$this->class = $this->_em->getClassMetadata(reset($this->_rsm->aliasMap));
// We only need to add declaring classes if we have inheritance.
if ($this->class->inheritanceType === ClassMetadata::INHERITANCE_TYPE_NONE) {
return;
}
foreach ($this->_rsm->declaringClasses AS $column => $class) {
$this->declaringClasses[$column] = $this->_em->getClassMetadata($class);
}
} }
protected function _hydrateRow(array $sqlResult, array &$cache, array &$result) /**
* {@inheritdoc}
*/
protected function hydrateRowData(array $sqlResult, array &$cache, array &$result)
{ {
$data = array(); $entityName = $this->class->name;
if ($this->class->inheritanceType == ClassMetadata::INHERITANCE_TYPE_NONE) { $data = array();
foreach ($sqlResult as $column => $value) {
// We need to find the correct entity class name if we have inheritance in resultset
if (!isset($cache[$column])) { if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
if (isset($this->_rsm->fieldMappings[$column])) {
$cache[$column]['name'] = $this->_rsm->fieldMappings[$column];
$cache[$column]['field'] = true;
} else {
$cache[$column]['name'] = $this->_rsm->metaMappings[$column];
}
}
if (isset($cache[$column]['field'])) {
$value = Type::getType($this->class->fieldMappings[$cache[$column]['name']]['type'])
->convertToPHPValue($value, $this->_platform);
}
$data[$cache[$column]['name']] = $value;
}
$entityName = $this->class->name;
} else {
$discrColumnName = $this->_platform->getSQLResultCasing($this->class->discriminatorColumn['name']); $discrColumnName = $this->_platform->getSQLResultCasing($this->class->discriminatorColumn['name']);
if ($sqlResult[$discrColumnName] === '') {
throw HydrationException::emptyDiscriminatorValue(key($this->_rsm->aliasMap));
}
$entityName = $this->class->discriminatorMap[$sqlResult[$discrColumnName]]; $entityName = $this->class->discriminatorMap[$sqlResult[$discrColumnName]];
unset($sqlResult[$discrColumnName]); unset($sqlResult[$discrColumnName]);
foreach ($sqlResult as $column => $value) { }
if (!isset($cache[$column])) {
if (isset($this->_rsm->fieldMappings[$column])) { foreach ($sqlResult as $column => $value) {
$field = $this->_rsm->fieldMappings[$column]; // Hydrate column information if not yet present
$class = $this->declaringClasses[$column]; if ( ! isset($cache[$column])) {
if ($class->name == $entityName || is_subclass_of($entityName, $class->name)) { if (($info = $this->hydrateColumnInfo($entityName, $column)) === null) {
$cache[$column]['name'] = $field; continue;
$cache[$column]['class'] = $class;
}
} else if (isset($this->_rsm->relationMap[$column])) {
if ($this->_rsm->relationMap[$column] == $entityName || is_subclass_of($entityName, $this->_rsm->relationMap[$column])) {
$cache[$column]['name'] = $field;
}
} else {
$cache[$column]['name'] = $this->_rsm->metaMappings[$column];
}
} }
$cache[$column] = $info;
}
if (isset($cache[$column]['class'])) { // Convert field to a valid PHP value
$value = Type::getType($cache[$column]['class']->fieldMappings[$cache[$column]['name']]['type']) if (isset($cache[$column]['field'])) {
->convertToPHPValue($value, $this->_platform); $type = Type::getType($cache[$column]['class']->fieldMappings[$cache[$column]['name']]['type']);
} $value = $type->convertToPHPValue($value, $this->_platform);
}
// the second and part is to prevent overwrites in case of multiple
// inheritance classes using the same property name (See AbstractHydrator) // Prevent overwrite in case of inherit classes using same property name (See AbstractHydrator)
if (isset($cache[$column]) && (!isset($data[$cache[$column]['name']]) || $value !== null)) { if (isset($cache[$column]) && ( ! isset($data[$cache[$column]['name']]) || $value !== null)) {
$data[$cache[$column]['name']] = $value; $data[$cache[$column]['name']] = $value;
}
} }
} }
@ -128,4 +127,52 @@ class SimpleObjectHydrator extends AbstractHydrator
$result[] = $this->_em->getUnitOfWork()->createEntity($entityName, $data, $this->_hints); $result[] = $this->_em->getUnitOfWork()->createEntity($entityName, $data, $this->_hints);
} }
/**
* Retrieve column information form ResultSetMapping.
*
* @param string $entityName
* @param string $column
*
* @return array
*/
protected function hydrateColumnInfo($entityName, $column)
{
switch (true) {
case (isset($this->_rsm->fieldMappings[$column])):
$class = isset($this->declaringClasses[$column])
? $this->declaringClasses[$column]
: $this->class;
// If class is not part of the inheritance, ignore
if ( ! ($class->name === $entityName || is_subclass_of($entityName, $class->name))) {
return null;
}
return array(
'class' => $class,
'name' => $this->_rsm->fieldMappings[$column],
'field' => true,
);
case (isset($this->_rsm->relationMap[$column])):
$class = isset($this->_rsm->relationMap[$column])
? $this->_rsm->relationMap[$column]
: $this->class;
// If class is not self referencing, ignore
if ( ! ($class === $entityName || is_subclass_of($entityName, $class))) {
return null;
}
// TODO: Decide what to do with associations. It seems original code is incomplete.
// One solution is to load the association, but it might require extra efforts.
return array('name' => $column);
default:
return array(
'name' => $this->_rsm->metaMappings[$column]
);
}
}
} }

View File

@ -19,30 +19,37 @@
namespace Doctrine\ORM\Internal\Hydration; namespace Doctrine\ORM\Internal\Hydration;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection,
Doctrine\ORM\NoResultException,
Doctrine\ORM\NonUniqueResultException;
/** /**
* Hydrator that hydrates a single scalar value from the result set. * Hydrator that hydrates a single scalar value from the result set.
* *
* @since 2.0
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
* @since 2.0 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
*/ */
class SingleScalarHydrator extends AbstractHydrator class SingleScalarHydrator extends AbstractHydrator
{ {
/** @override */ /**
protected function _hydrateAll() * {@inheritdoc}
*/
protected function hydrateAllData()
{ {
$cache = array(); $data = $this->_stmt->fetchAll(\PDO::FETCH_ASSOC);
$result = $this->_stmt->fetchAll(\PDO::FETCH_ASSOC); $numRows = count($data);
$num = count($result);
if ($numRows === 0) {
if ($num == 0) { throw new NoResultException();
throw new \Doctrine\ORM\NoResultException;
} else if ($num > 1 || count($result[key($result)]) > 1) {
throw new \Doctrine\ORM\NonUniqueResultException;
} }
$result = $this->_gatherScalarRowData($result[key($result)], $cache); if ($numRows > 1 || count($data[key($data)]) > 1) {
throw new NonUniqueResultException();
}
$cache = array();
$result = $this->gatherScalarRowData($data[key($data)], $cache);
return array_shift($result); return array_shift($result);
} }

View File

@ -312,6 +312,10 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
if ($parent && $parent->containsForeignIdentifier) { if ($parent && $parent->containsForeignIdentifier) {
$class->containsForeignIdentifier = true; $class->containsForeignIdentifier = true;
} }
if ($parent && !empty ($parent->namedQueries)) {
$this->addInheritedNamedQueries($class, $parent);
}
$class->setParentClasses($visited); $class->setParentClasses($visited);
@ -428,6 +432,25 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
$subClass->addInheritedAssociationMapping($mapping); $subClass->addInheritedAssociationMapping($mapping);
} }
} }
/**
* Adds inherited named queries to the subclass mapping.
*
* @since 2.2
* @param Doctrine\ORM\Mapping\ClassMetadata $subClass
* @param Doctrine\ORM\Mapping\ClassMetadata $parentClass
*/
private function addInheritedNamedQueries(ClassMetadata $subClass, ClassMetadata $parentClass)
{
foreach ($parentClass->namedQueries as $name => $query) {
if (!isset ($subClass->namedQueries[$name])) {
$subClass->addNamedQuery(array(
'name' => $query['name'],
'query' => $query['query']
));
}
}
}
/** /**
* Completes the ID generator mapping. If "auto" is specified we choose the generator * Completes the ID generator mapping. If "auto" is specified we choose the generator

View File

@ -136,10 +136,6 @@ class ClassMetadataInfo implements ClassMetadata
* Identifies a many-to-one association. * Identifies a many-to-one association.
*/ */
const MANY_TO_ONE = 2; const MANY_TO_ONE = 2;
/**
* Combined bitmask for to-one (single-valued) associations.
*/
const TO_ONE = 3;
/** /**
* Identifies a one-to-many association. * Identifies a one-to-many association.
*/ */
@ -148,6 +144,10 @@ class ClassMetadataInfo implements ClassMetadata
* Identifies a many-to-many association. * Identifies a many-to-many association.
*/ */
const MANY_TO_MANY = 8; const MANY_TO_MANY = 8;
/**
* Combined bitmask for to-one (single-valued) associations.
*/
const TO_ONE = 3;
/** /**
* Combined bitmask for to-many (collection-valued) associations. * Combined bitmask for to-many (collection-valued) associations.
*/ */
@ -685,7 +685,7 @@ class ClassMetadataInfo implements ClassMetadata
if ( ! isset($this->namedQueries[$queryName])) { if ( ! isset($this->namedQueries[$queryName])) {
throw MappingException::queryNotFound($this->name, $queryName); throw MappingException::queryNotFound($this->name, $queryName);
} }
return $this->namedQueries[$queryName]; return $this->namedQueries[$queryName]['dql'];
} }
/** /**
@ -1111,25 +1111,25 @@ class ClassMetadataInfo implements ClassMetadata
*/ */
public function getIdentifierColumnNames() public function getIdentifierColumnNames()
{ {
if ($this->isIdentifierComposite) { $columnNames = array();
$columnNames = array();
foreach ($this->identifier as $idField) { foreach ($this->identifier as $idProperty) {
if (isset($this->associationMappings[$idField])) { if (isset($this->fieldMappings[$idProperty])) {
// no composite pk as fk entity assumption: $columnNames[] = $this->fieldMappings[$idProperty]['columnName'];
$columnNames[] = $this->associationMappings[$idField]['joinColumns'][0]['name'];
} else { continue;
$columnNames[] = $this->fieldMappings[$idField]['columnName'];
}
} }
return $columnNames;
} else if(isset($this->fieldMappings[$this->identifier[0]])) { // Association defined as Id field
return array($this->fieldMappings[$this->identifier[0]]['columnName']); $joinColumns = $this->associationMappings[$idProperty]['joinColumns'];
} else { $assocColumnNames = array_map(function ($joinColumn) { return $joinColumn['name']; }, $joinColumns);
// no composite pk as fk entity assumption:
return array($this->associationMappings[$this->identifier[0]]['joinColumns'][0]['name']); $columnNames = array_merge($columnNames, $assocColumnNames);
} }
return $columnNames;
} }
/** /**
* Sets the type of Id generator to use for the mapped class. * Sets the type of Id generator to use for the mapped class.
*/ */
@ -1448,8 +1448,15 @@ class ClassMetadataInfo implements ClassMetadata
if (isset($this->namedQueries[$queryMapping['name']])) { if (isset($this->namedQueries[$queryMapping['name']])) {
throw MappingException::duplicateQueryMapping($this->name, $queryMapping['name']); throw MappingException::duplicateQueryMapping($this->name, $queryMapping['name']);
} }
$query = str_replace('__CLASS__', $this->name, $queryMapping['query']);
$this->namedQueries[$queryMapping['name']] = $query; $name = $queryMapping['name'];
$query = $queryMapping['query'];
$dql = str_replace('__CLASS__', $this->name, $query);
$this->namedQueries[$name] = array(
'name' => $name,
'query' => $query,
'dql' => $dql
);
} }
/** /**
@ -1504,14 +1511,16 @@ class ClassMetadataInfo implements ClassMetadata
/** /**
* Stores the association mapping. * Stores the association mapping.
* *
* @param AssociationMapping $assocMapping * @param array $assocMapping
*/ */
protected function _storeAssociationMapping(array $assocMapping) protected function _storeAssociationMapping(array $assocMapping)
{ {
$sourceFieldName = $assocMapping['fieldName']; $sourceFieldName = $assocMapping['fieldName'];
if (isset($this->fieldMappings[$sourceFieldName]) || isset($this->associationMappings[$sourceFieldName])) { if (isset($this->fieldMappings[$sourceFieldName]) || isset($this->associationMappings[$sourceFieldName])) {
throw MappingException::duplicateFieldMapping($this->name, $sourceFieldName); throw MappingException::duplicateFieldMapping($this->name, $sourceFieldName);
} }
$this->associationMappings[$sourceFieldName] = $assocMapping; $this->associationMappings[$sourceFieldName] = $assocMapping;
} }
@ -1904,6 +1913,42 @@ class ClassMetadataInfo implements ClassMetadata
return $this->name; return $this->name;
} }
/**
* Gets the (possibly quoted) identifier column names for safe use in an SQL statement.
*
* @param AbstractPlatform $platform
* @return array
*/
public function getQuotedIdentifierColumnNames($platform)
{
$quotedColumnNames = array();
foreach ($this->identifier as $idProperty) {
if (isset($this->fieldMappings[$idProperty])) {
$quotedColumnNames[] = isset($this->fieldMappings[$idProperty]['quoted'])
? $platform->quoteIdentifier($this->fieldMappings[$idProperty]['columnName'])
: $this->fieldMappings[$idProperty]['columnName'];
continue;
}
// Association defined as Id field
$joinColumns = $this->associationMappings[$idProperty]['joinColumns'];
$assocQuotedColumnNames = array_map(
function ($joinColumn) {
return isset($joinColumn['quoted'])
? $platform->quoteIdentifier($joinColumn['name'])
: $joinColumn['name'];
},
$joinColumns
);
$quotedColumnNames = array_merge($quotedColumnNames, $assocQuotedColumnNames);
}
return $quotedColumnNames;
}
/** /**
* Gets the (possibly quoted) column name of a mapped field for safe use * Gets the (possibly quoted) column name of a mapped field for safe use
* in an SQL statement. * in an SQL statement.
@ -1914,7 +1959,9 @@ class ClassMetadataInfo implements ClassMetadata
*/ */
public function getQuotedColumnName($field, $platform) public function getQuotedColumnName($field, $platform)
{ {
return isset($this->fieldMappings[$field]['quoted']) ? $platform->quoteIdentifier($this->fieldMappings[$field]['columnName']) : $this->fieldMappings[$field]['columnName']; return isset($this->fieldMappings[$field]['quoted'])
? $platform->quoteIdentifier($this->fieldMappings[$field]['columnName'])
: $this->fieldMappings[$field]['columnName'];
} }
/** /**

View File

@ -331,7 +331,7 @@ class AnnotationDriver implements Driver
$mapping['inversedBy'] = $oneToOneAnnot->inversedBy; $mapping['inversedBy'] = $oneToOneAnnot->inversedBy;
$mapping['cascade'] = $oneToOneAnnot->cascade; $mapping['cascade'] = $oneToOneAnnot->cascade;
$mapping['orphanRemoval'] = $oneToOneAnnot->orphanRemoval; $mapping['orphanRemoval'] = $oneToOneAnnot->orphanRemoval;
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToOneAnnot->fetch); $mapping['fetch'] = $this->getFetchMode($className, $oneToOneAnnot->fetch);
$metadata->mapOneToOne($mapping); $metadata->mapOneToOne($mapping);
} else if ($oneToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToMany')) { } else if ($oneToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToMany')) {
$mapping['mappedBy'] = $oneToManyAnnot->mappedBy; $mapping['mappedBy'] = $oneToManyAnnot->mappedBy;
@ -339,7 +339,7 @@ class AnnotationDriver implements Driver
$mapping['cascade'] = $oneToManyAnnot->cascade; $mapping['cascade'] = $oneToManyAnnot->cascade;
$mapping['indexBy'] = $oneToManyAnnot->indexBy; $mapping['indexBy'] = $oneToManyAnnot->indexBy;
$mapping['orphanRemoval'] = $oneToManyAnnot->orphanRemoval; $mapping['orphanRemoval'] = $oneToManyAnnot->orphanRemoval;
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToManyAnnot->fetch); $mapping['fetch'] = $this->getFetchMode($className, $oneToManyAnnot->fetch);
if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) { if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
$mapping['orderBy'] = $orderByAnnot->value; $mapping['orderBy'] = $orderByAnnot->value;
@ -355,7 +355,7 @@ class AnnotationDriver implements Driver
$mapping['cascade'] = $manyToOneAnnot->cascade; $mapping['cascade'] = $manyToOneAnnot->cascade;
$mapping['inversedBy'] = $manyToOneAnnot->inversedBy; $mapping['inversedBy'] = $manyToOneAnnot->inversedBy;
$mapping['targetEntity'] = $manyToOneAnnot->targetEntity; $mapping['targetEntity'] = $manyToOneAnnot->targetEntity;
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToOneAnnot->fetch); $mapping['fetch'] = $this->getFetchMode($className, $manyToOneAnnot->fetch);
$metadata->mapManyToOne($mapping); $metadata->mapManyToOne($mapping);
} else if ($manyToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToMany')) { } else if ($manyToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToMany')) {
$joinTable = array(); $joinTable = array();
@ -395,7 +395,7 @@ class AnnotationDriver implements Driver
$mapping['inversedBy'] = $manyToManyAnnot->inversedBy; $mapping['inversedBy'] = $manyToManyAnnot->inversedBy;
$mapping['cascade'] = $manyToManyAnnot->cascade; $mapping['cascade'] = $manyToManyAnnot->cascade;
$mapping['indexBy'] = $manyToManyAnnot->indexBy; $mapping['indexBy'] = $manyToManyAnnot->indexBy;
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToManyAnnot->fetch); $mapping['fetch'] = $this->getFetchMode($className, $manyToManyAnnot->fetch);
if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) { if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
$mapping['orderBy'] = $orderByAnnot->value; $mapping['orderBy'] = $orderByAnnot->value;
@ -446,6 +446,10 @@ class AnnotationDriver implements Driver
if (isset($annotations['Doctrine\ORM\Mapping\PostLoad'])) { if (isset($annotations['Doctrine\ORM\Mapping\PostLoad'])) {
$metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::postLoad); $metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::postLoad);
} }
if (isset($annotations['Doctrine\ORM\Mapping\PreFlush'])) {
$metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::preFlush);
}
} }
} }
} }
@ -536,6 +540,22 @@ class AnnotationDriver implements Driver
return $classes; return $classes;
} }
/**
* Attempts to resolve the fetch mode.
*
* @param string $className The class name
* @param string $fetchMode The fetch mode
* @return integer The fetch mode as defined in ClassMetadata
* @throws MappingException If the fetch mode is not valid
*/
private function getFetchMode($className, $fetchMode)
{
if(!defined('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode)) {
throw MappingException::invalidFetchMode($className, $fetchMode);
}
return constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode);
}
/** /**
* Factory method for the Annotation Driver * Factory method for the Annotation Driver
* *

View File

@ -387,3 +387,9 @@ final class PostRemove implements Annotation {}
* @Target("METHOD") * @Target("METHOD")
*/ */
final class PostLoad implements Annotation {} final class PostLoad implements Annotation {}
/**
* @Annotation
* @Target("METHOD")
*/
final class PreFlush implements Annotation {}

View File

@ -89,7 +89,7 @@ class XmlDriver extends AbstractFileDriver
if (isset($xmlRoot['schema'])) { if (isset($xmlRoot['schema'])) {
$metadata->table['schema'] = (string)$xmlRoot['schema']; $metadata->table['schema'] = (string)$xmlRoot['schema'];
}*/ }*/
if (isset($xmlRoot['inheritance-type'])) { if (isset($xmlRoot['inheritance-type'])) {
$inheritanceType = (string)$xmlRoot['inheritance-type']; $inheritanceType = (string)$xmlRoot['inheritance-type'];
$metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceType)); $metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceType));
@ -166,9 +166,12 @@ class XmlDriver extends AbstractFileDriver
foreach ($xmlRoot->field as $fieldMapping) { foreach ($xmlRoot->field as $fieldMapping) {
$mapping = array( $mapping = array(
'fieldName' => (string)$fieldMapping['name'], 'fieldName' => (string)$fieldMapping['name'],
'type' => (string)$fieldMapping['type']
); );
if (isset($fieldMapping['type'])) {
$mapping['type'] = (string)$fieldMapping['type'];
}
if (isset($fieldMapping['column'])) { if (isset($fieldMapping['column'])) {
$mapping['columnName'] = (string)$fieldMapping['column']; $mapping['columnName'] = (string)$fieldMapping['column'];
} }
@ -219,9 +222,12 @@ class XmlDriver extends AbstractFileDriver
$mapping = array( $mapping = array(
'id' => true, 'id' => true,
'fieldName' => (string)$idElement['name'], 'fieldName' => (string)$idElement['name']
'type' => (string)$idElement['type']
); );
if (isset($fieldMapping['type'])) {
$mapping['type'] = (string)$idElement['type'];
}
if (isset($idElement['column'])) { if (isset($idElement['column'])) {
$mapping['columnName'] = (string)$idElement['column']; $mapping['columnName'] = (string)$idElement['column'];
@ -327,6 +333,8 @@ class XmlDriver extends AbstractFileDriver
if (isset($oneToManyElement['index-by'])) { if (isset($oneToManyElement['index-by'])) {
$mapping['indexBy'] = (string)$oneToManyElement['index-by']; $mapping['indexBy'] = (string)$oneToManyElement['index-by'];
} else if (isset($oneToManyElement->{'index-by'})) {
throw new \InvalidArgumentException("<index-by /> is not a valid tag");
} }
$metadata->mapOneToMany($mapping); $metadata->mapOneToMany($mapping);
@ -432,8 +440,10 @@ class XmlDriver extends AbstractFileDriver
$mapping['orderBy'] = $orderBy; $mapping['orderBy'] = $orderBy;
} }
if (isset($manyToManyElement->{'index-by'})) { if (isset($manyToManyElement['index-by'])) {
$mapping['indexBy'] = (string)$manyToManyElement->{'index-by'}; $mapping['indexBy'] = (string)$manyToManyElement['index-by'];
} else if (isset($manyToManyElement->{'index-by'})) {
throw new \InvalidArgumentException("<index-by /> is not a valid tag");
} }
$metadata->mapManyToMany($mapping); $metadata->mapManyToMany($mapping);

View File

@ -165,15 +165,14 @@ class YamlDriver extends AbstractFileDriver
continue; continue;
} }
if (!isset($idElement['type'])) {
throw MappingException::propertyTypeIsRequired($className, $name);
}
$mapping = array( $mapping = array(
'id' => true, 'id' => true,
'fieldName' => $name, 'fieldName' => $name
'type' => $idElement['type']
); );
if (isset($idElement['type'])) {
$mapping['type'] = $idElement['type'];
}
if (isset($idElement['column'])) { if (isset($idElement['column'])) {
$mapping['columnName'] = $idElement['column']; $mapping['columnName'] = $idElement['column'];
@ -201,19 +200,21 @@ class YamlDriver extends AbstractFileDriver
// Evaluate fields // Evaluate fields
if (isset($element['fields'])) { if (isset($element['fields'])) {
foreach ($element['fields'] as $name => $fieldMapping) { foreach ($element['fields'] as $name => $fieldMapping) {
if (!isset($fieldMapping['type'])) {
throw MappingException::propertyTypeIsRequired($className, $name);
}
$e = explode('(', $fieldMapping['type']);
$fieldMapping['type'] = $e[0];
if (isset($e[1])) {
$fieldMapping['length'] = substr($e[1], 0, strlen($e[1]) - 1);
}
$mapping = array( $mapping = array(
'fieldName' => $name, 'fieldName' => $name
'type' => $fieldMapping['type']
); );
if (isset($fieldMapping['type'])) {
$e = explode('(', $fieldMapping['type']);
$fieldMapping['type'] = $e[0];
$mapping['type'] = $fieldMapping['type'];
if (isset($e[1])) {
$fieldMapping['length'] = substr($e[1], 0, strlen($e[1]) - 1);
}
}
if (isset($fieldMapping['id'])) { if (isset($fieldMapping['id'])) {
$mapping['id'] = true; $mapping['id'] = true;
if (isset($fieldMapping['generator']['strategy'])) { if (isset($fieldMapping['generator']['strategy'])) {

View File

@ -298,4 +298,9 @@ class MappingException extends \Doctrine\ORM\ORMException
{ {
return new self("Entity '" . $className . "' has no method '" . $methodName . "' to be registered as lifecycle callback."); return new self("Entity '" . $className . "' has no method '" . $methodName . "' to be registered as lifecycle callback.");
} }
}
public static function invalidFetchMode($className, $annotation)
{
return new self("Entity '" . $className . "' has a mapping with invalid fetch mode '" . $annotation . "'");
}
}

View File

@ -93,21 +93,21 @@ final class PersistentCollection implements Collection
/** /**
* Whether the collection has already been initialized. * Whether the collection has already been initialized.
* *
* @var boolean * @var boolean
*/ */
private $initialized = true; private $initialized = true;
/** /**
* The wrapped Collection instance. * The wrapped Collection instance.
* *
* @var Collection * @var Collection
*/ */
private $coll; private $coll;
/** /**
* Creates a new persistent collection. * Creates a new persistent collection.
* *
* @param EntityManager $em The EntityManager the collection will be associated with. * @param EntityManager $em The EntityManager the collection will be associated with.
* @param ClassMetadata $class The class descriptor of the entity type of this collection. * @param ClassMetadata $class The class descriptor of the entity type of this collection.
* @param array The collection elements. * @param array The collection elements.
@ -144,7 +144,7 @@ final class PersistentCollection implements Collection
{ {
return $this->owner; return $this->owner;
} }
public function getTypeClass() public function getTypeClass()
{ {
return $this->typeClass; return $this->typeClass;
@ -154,7 +154,7 @@ final class PersistentCollection implements Collection
* INTERNAL: * INTERNAL:
* Adds an element to a collection during hydration. This will automatically * Adds an element to a collection during hydration. This will automatically
* complete bidirectional associations in the case of a one-to-many association. * complete bidirectional associations in the case of a one-to-many association.
* *
* @param mixed $element The element to add. * @param mixed $element The element to add.
*/ */
public function hydrateAdd($element) public function hydrateAdd($element)
@ -172,7 +172,7 @@ final class PersistentCollection implements Collection
$this->owner); $this->owner);
} }
} }
/** /**
* INTERNAL: * INTERNAL:
* Sets a keyed element in the collection during hydration. * Sets a keyed element in the collection during hydration.
@ -271,7 +271,7 @@ final class PersistentCollection implements Collection
{ {
return $this->association; return $this->association;
} }
/** /**
* Marks this collection as changed/dirty. * Marks this collection as changed/dirty.
*/ */
@ -306,17 +306,17 @@ final class PersistentCollection implements Collection
{ {
$this->isDirty = $dirty; $this->isDirty = $dirty;
} }
/** /**
* Sets the initialized flag of the collection, forcing it into that state. * Sets the initialized flag of the collection, forcing it into that state.
* *
* @param boolean $bool * @param boolean $bool
*/ */
public function setInitialized($bool) public function setInitialized($bool)
{ {
$this->initialized = $bool; $this->initialized = $bool;
} }
/** /**
* Checks whether this collection has been initialized. * Checks whether this collection has been initialized.
* *
@ -377,7 +377,7 @@ final class PersistentCollection implements Collection
$this->em->getUnitOfWork()->getCollectionPersister($this->association) $this->em->getUnitOfWork()->getCollectionPersister($this->association)
->deleteRows($this, $element); ->deleteRows($this, $element);
}*/ }*/
$this->initialize(); $this->initialize();
$removed = $this->coll->removeElement($element); $removed = $this->coll->removeElement($element);
if ($removed) { if ($removed) {
@ -410,7 +410,7 @@ final class PersistentCollection implements Collection
->getCollectionPersister($this->association) ->getCollectionPersister($this->association)
->contains($this, $element); ->contains($this, $element);
} }
$this->initialize(); $this->initialize();
return $this->coll->contains($element); return $this->coll->contains($element);
} }
@ -468,7 +468,7 @@ final class PersistentCollection implements Collection
if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) { if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
return $this->em->getUnitOfWork() return $this->em->getUnitOfWork()
->getCollectionPersister($this->association) ->getCollectionPersister($this->association)
->count($this) + $this->coll->count(); ->count($this) + ($this->isDirty ? $this->coll->count() : 0);
} }
$this->initialize(); $this->initialize();
@ -503,7 +503,7 @@ final class PersistentCollection implements Collection
$this->initialize(); $this->initialize();
return $this->coll->isEmpty(); return $this->coll->isEmpty();
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -530,7 +530,7 @@ final class PersistentCollection implements Collection
$this->initialize(); $this->initialize();
return $this->coll->filter($p); return $this->coll->filter($p);
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -548,7 +548,7 @@ final class PersistentCollection implements Collection
$this->initialize(); $this->initialize();
return $this->coll->partition($p); return $this->coll->partition($p);
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -579,7 +579,7 @@ final class PersistentCollection implements Collection
$this->takeSnapshot(); $this->takeSnapshot();
} }
} }
/** /**
* Called by PHP when this collection is serialized. Ensures that only the * Called by PHP when this collection is serialized. Ensures that only the
* elements are properly serialized. * elements are properly serialized.
@ -591,7 +591,7 @@ final class PersistentCollection implements Collection
{ {
return array('coll', 'initialized'); return array('coll', 'initialized');
} }
/* ArrayAccess implementation */ /* ArrayAccess implementation */
/** /**
@ -629,12 +629,12 @@ final class PersistentCollection implements Collection
{ {
return $this->remove($offset); return $this->remove($offset);
} }
public function key() public function key()
{ {
return $this->coll->key(); return $this->coll->key();
} }
/** /**
* Gets the element of the collection at the current iterator position. * Gets the element of the collection at the current iterator position.
*/ */
@ -642,7 +642,7 @@ final class PersistentCollection implements Collection
{ {
return $this->coll->current(); return $this->coll->current();
} }
/** /**
* Moves the internal iterator position to the next element. * Moves the internal iterator position to the next element.
*/ */
@ -650,7 +650,7 @@ final class PersistentCollection implements Collection
{ {
return $this->coll->next(); return $this->coll->next();
} }
/** /**
* Retrieves the wrapped Collection instance. * Retrieves the wrapped Collection instance.
*/ */
@ -672,7 +672,10 @@ final class PersistentCollection implements Collection
*/ */
public function slice($offset, $length = null) public function slice($offset, $length = null)
{ {
if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) { if ( ! $this->initialized &&
! $this->isDirty &&
$this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
return $this->em->getUnitOfWork() return $this->em->getUnitOfWork()
->getCollectionPersister($this->association) ->getCollectionPersister($this->association)
->slice($this, $offset, $length); ->slice($this, $offset, $length);

View File

@ -62,7 +62,7 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
{ {
$columnName = $class->columnNames[$field]; $columnName = $class->columnNames[$field];
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) . '.' . $class->getQuotedColumnName($field, $this->_platform); $sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) . '.' . $class->getQuotedColumnName($field, $this->_platform);
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++); $columnAlias = $this->getSQLColumnAlias($columnName);
$this->_rsm->addFieldResult($alias, $columnAlias, $field, $class->name); $this->_rsm->addFieldResult($alias, $columnAlias, $field, $class->name);
return $sql . ' AS ' . $columnAlias; return $sql . ' AS ' . $columnAlias;
@ -70,10 +70,9 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
protected function getSelectJoinColumnSQL($tableAlias, $joinColumnName, $className) protected function getSelectJoinColumnSQL($tableAlias, $joinColumnName, $className)
{ {
$columnAlias = $joinColumnName . $this->_sqlAliasCounter++; $columnAlias = $this->getSQLColumnAlias($joinColumnName);
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias); $this->_rsm->addMetaResult('r', $columnAlias, $joinColumnName);
$this->_rsm->addMetaResult('r', $resultColumnName, $joinColumnName);
return $tableAlias . '.' . $joinColumnName . ' AS ' . $columnAlias; return $tableAlias . '.' . $joinColumnName . ' AS ' . $columnAlias;
} }
} }

View File

@ -1001,27 +1001,26 @@ class BasicEntityPersister
$columnList .= $assoc2ColumnSQL; $columnList .= $assoc2ColumnSQL;
} }
} }
$this->_selectJoinSql .= ' LEFT JOIN'; // TODO: Inner join when all join columns are NOT nullable.
$first = true; $first = true;
if ($assoc['isOwningSide']) { if ($assoc['isOwningSide']) {
$this->_selectJoinSql .= ' ' . $this->getJoinSQLForJoinColumns($assoc['joinColumns']);
$this->_selectJoinSql .= ' ' . $eagerEntity->getQuotedTableName($this->_platform) . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) .' ON '; $this->_selectJoinSql .= ' ' . $eagerEntity->getQuotedTableName($this->_platform) . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) .' ON ';
foreach ($assoc['sourceToTargetKeyColumns'] AS $sourceCol => $targetCol) { foreach ($assoc['sourceToTargetKeyColumns'] AS $sourceCol => $targetCol) {
if ( ! $first) { if ( ! $first) {
$this->_selectJoinSql .= ' AND '; $this->_selectJoinSql .= ' AND ';
} }
$this->_selectJoinSql .= $this->_getSQLTableAlias($assoc['sourceEntity']) . '.' . $sourceCol . ' = '
$this->_selectJoinSql .= $this->_getSQLTableAlias($assoc['sourceEntity']) . '.' . $sourceCol . ' = ' . $this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias) . '.' . $targetCol;
. $this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias) . '.' . $targetCol . ' ';
$first = false; $first = false;
} }
} else { } else {
$eagerEntity = $this->_em->getClassMetadata($assoc['targetEntity']); $eagerEntity = $this->_em->getClassMetadata($assoc['targetEntity']);
$owningAssoc = $eagerEntity->getAssociationMapping($assoc['mappedBy']); $owningAssoc = $eagerEntity->getAssociationMapping($assoc['mappedBy']);
$this->_selectJoinSql .= ' ' . $eagerEntity->getQuotedTableName($this->_platform) . ' ' $this->_selectJoinSql .= ' LEFT JOIN';
$this->_selectJoinSql .= ' ' . $eagerEntity->getQuotedTableName($this->_platform) . ' '
. $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) . ' ON '; . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) . ' ON ';
foreach ($owningAssoc['sourceToTargetKeyColumns'] AS $sourceCol => $targetCol) { foreach ($owningAssoc['sourceToTargetKeyColumns'] AS $sourceCol => $targetCol) {
@ -1030,7 +1029,7 @@ class BasicEntityPersister
} }
$this->_selectJoinSql .= $this->_getSQLTableAlias($owningAssoc['sourceEntity'], $assocAlias) . '.' . $sourceCol . ' = ' $this->_selectJoinSql .= $this->_getSQLTableAlias($owningAssoc['sourceEntity'], $assocAlias) . '.' . $sourceCol . ' = '
. $this->_getSQLTableAlias($owningAssoc['targetEntity']) . '.' . $targetCol . ' '; . $this->_getSQLTableAlias($owningAssoc['targetEntity']) . '.' . $targetCol;
$first = false; $first = false;
} }
} }
@ -1060,9 +1059,8 @@ class BasicEntityPersister
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) { foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
if ($columnList) $columnList .= ', '; if ($columnList) $columnList .= ', ';
$columnAlias = $srcColumn . $this->_sqlAliasCounter++; $resultColumnName = $this->getSQLColumnAlias($srcColumn);
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias); $columnList .= $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) )
$columnList .= $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) )
. '.' . $srcColumn . ' AS ' . $resultColumnName; . '.' . $srcColumn . ' AS ' . $resultColumnName;
$this->_rsm->addMetaResult($alias, $resultColumnName, $srcColumn, isset($assoc['id']) && $assoc['id'] === true); $this->_rsm->addMetaResult($alias, $resultColumnName, $srcColumn, isset($assoc['id']) && $assoc['id'] === true);
} }
@ -1180,10 +1178,9 @@ class BasicEntityPersister
*/ */
protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r') protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r')
{ {
$columnName = $class->columnNames[$field]; $sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias)
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias)
. '.' . $class->getQuotedColumnName($field, $this->_platform); . '.' . $class->getQuotedColumnName($field, $this->_platform);
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++); $columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]);
$this->_rsm->addFieldResult($alias, $columnAlias, $field); $this->_rsm->addFieldResult($alias, $columnAlias, $field);
@ -1500,4 +1497,37 @@ class BasicEntityPersister
return (bool) $this->_conn->fetchColumn($sql, $params); return (bool) $this->_conn->fetchColumn($sql, $params);
} }
/**
* Generates the appropriate join SQL for the given join column.
*
* @param array $joinColumns The join columns definition of an association.
* @return string LEFT JOIN if one of the columns is nullable, INNER JOIN otherwise.
*/
protected function getJoinSQLForJoinColumns($joinColumns)
{
// if one of the join columns is nullable, return left join
foreach($joinColumns as $joinColumn) {
if(isset($joinColumn['nullable']) && $joinColumn['nullable']){
return 'LEFT JOIN';
}
}
return 'INNER JOIN';
}
/**
* Gets an SQL column alias for a column name.
*
* @param string $columnName
* @return string
*/
public function getSQLColumnAlias($columnName)
{
// Trim the column alias to the maximum identifier length of the platform.
// If the alias is to long, characters are cut off from the beginning.
return $this->_platform->getSQLResultCasing(
substr($columnName . $this->_sqlAliasCounter++, -$this->_platform->getMaxIdentifierLength())
);
}
} }

View File

@ -165,11 +165,13 @@ class ProxyFactory
{ {
$methods = ''; $methods = '';
$methodNames = array();
foreach ($class->reflClass->getMethods() as $method) { foreach ($class->reflClass->getMethods() as $method) {
/* @var $method ReflectionMethod */ /* @var $method ReflectionMethod */
if ($method->isConstructor() || in_array(strtolower($method->getName()), array("__sleep", "__clone"))) { if ($method->isConstructor() || in_array(strtolower($method->getName()), array("__sleep", "__clone")) || isset($methodNames[$method->getName()])) {
continue; continue;
} }
$methodNames[$method->getName()] = true;
if ($method->isPublic() && ! $method->isFinal() && ! $method->isStatic()) { if ($method->isPublic() && ! $method->isFinal() && ! $method->isStatic()) {
$methods .= "\n" . ' public function '; $methods .= "\n" . ' public function ';
@ -210,8 +212,12 @@ class ProxyFactory
$methods .= $parameterString . ')'; $methods .= $parameterString . ')';
$methods .= "\n" . ' {' . "\n"; $methods .= "\n" . ' {' . "\n";
if ($this->isShortIdentifierGetter($method, $class)) { if ($this->isShortIdentifierGetter($method, $class)) {
$identifier = lcfirst(substr($method->getName(), 3));
$cast = in_array($class->fieldMappings[$identifier]['type'], array('integer', 'smallint')) ? '(int) ' : '';
$methods .= ' if ($this->__isInitialized__ === false) {' . "\n"; $methods .= ' if ($this->__isInitialized__ === false) {' . "\n";
$methods .= ' return $this->_identifier["' . lcfirst(substr($method->getName(), 3)) . '"];' . "\n"; $methods .= ' return ' . $cast . '$this->_identifier["' . $identifier . '"];' . "\n";
$methods .= ' }' . "\n"; $methods .= ' }' . "\n";
} }
$methods .= ' $this->__load();' . "\n"; $methods .= ' $this->__load();' . "\n";
@ -230,13 +236,14 @@ class ProxyFactory
*/ */
private function isShortIdentifierGetter($method, $class) private function isShortIdentifierGetter($method, $class)
{ {
$identifier = lcfirst(substr($method->getName(), 3)); $identifier = lcfirst(substr($method->getName(), 3));
return ( return (
$method->getNumberOfParameters() == 0 && $method->getNumberOfParameters() == 0 &&
substr($method->getName(), 0, 3) == "get" && substr($method->getName(), 0, 3) == "get" &&
in_array($identifier, $class->identifier, true) && in_array($identifier, $class->identifier, true) &&
$class->hasField($identifier) && $class->hasField($identifier) &&
(($method->getEndLine() - $method->getStartLine()) <= 4) (($method->getEndLine() - $method->getStartLine()) <= 4)
&& in_array($class->fieldMappings[$identifier]['type'], array('integer', 'bigint', 'smallint', 'string'))
); );
} }

View File

@ -526,7 +526,7 @@ final class Query extends AbstractQuery
* *
* @param array $params The query parameters. * @param array $params The query parameters.
* @param integer $hydrationMode The hydration mode to use. * @param integer $hydrationMode The hydration mode to use.
* @return IterableResult * @return \Doctrine\ORM\Internal\Hydration\IterableResult
*/ */
public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_OBJECT) public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_OBJECT)
{ {

View File

@ -39,30 +39,30 @@ class Composite extends Base
if ($this->count() === 1) { if ($this->count() === 1) {
return (string) $this->_parts[0]; return (string) $this->_parts[0];
} }
$components = array(); $components = array();
foreach ($this->_parts as $part) { foreach ($this->_parts as $part) {
$components[] = $this->processQueryPart($part); $components[] = $this->processQueryPart($part);
} }
return implode($this->_separator, $components); return implode($this->_separator, $components);
} }
private function processQueryPart($part) private function processQueryPart($part)
{ {
$queryPart = (string) $part; $queryPart = (string) $part;
if (is_object($part) && $part instanceof self && $part->count() > 1) { if (is_object($part) && $part instanceof self && $part->count() > 1) {
return $this->_preSeparator . $queryPart . $this->_postSeparator; return $this->_preSeparator . $queryPart . $this->_postSeparator;
} }
// Fixes DDC-1237: User may have added a where item containing nested expression (with "OR" or "AND") // Fixes DDC-1237: User may have added a where item containing nested expression (with "OR" or "AND")
if (mb_stripos($queryPart, ' OR ') !== false || mb_stripos($queryPart, ' AND ') !== false) { if (stripos($queryPart, ' OR ') !== false || stripos($queryPart, ' AND ') !== false) {
return $this->_preSeparator . $queryPart . $this->_postSeparator; return $this->_preSeparator . $queryPart . $this->_postSeparator;
} }
return $queryPart; return $queryPart;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -47,6 +47,11 @@ class QueryException extends \Doctrine\ORM\ORMException
return new self('[Semantical Error] ' . $message); return new self('[Semantical Error] ' . $message);
} }
public static function invalidLockMode()
{
return new self('Invalid lock mode hint provided.');
}
public static function invalidParameterType($expected, $received) public static function invalidParameterType($expected, $received)
{ {
return new self('Invalid parameter type, ' . $received . ' given, but ' . $expected . ' expected.'); return new self('Invalid parameter type, ' . $received . ' given, but ' . $expected . ' expected.');

View File

@ -26,7 +26,7 @@ namespace Doctrine\ORM\Query;
* The properties of this class are only public for fast internal READ access and to (drastically) * The properties of this class are only public for fast internal READ access and to (drastically)
* reduce the size of serialized instances for more effective caching due to better (un-)serialization * reduce the size of serialized instances for more effective caching due to better (un-)serialization
* performance. * performance.
* *
* <b>Users should use the public methods.</b> * <b>Users should use the public methods.</b>
* *
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
@ -36,87 +36,79 @@ namespace Doctrine\ORM\Query;
class ResultSetMapping class ResultSetMapping
{ {
/** /**
* Whether the result is mixed (contains scalar values together with field values).
*
* @ignore * @ignore
* @var boolean * @var boolean Whether the result is mixed (contains scalar values together with field values).
*/ */
public $isMixed = false; public $isMixed = false;
/** /**
* Maps alias names to class names.
*
* @ignore * @ignore
* @var array * @var array Maps alias names to class names.
*/ */
public $aliasMap = array(); public $aliasMap = array();
/** /**
* Maps alias names to related association field names.
*
* @ignore * @ignore
* @var array * @var array Maps alias names to related association field names.
*/ */
public $relationMap = array(); public $relationMap = array();
/** /**
* Maps alias names to parent alias names.
*
* @ignore * @ignore
* @var array * @var array Maps alias names to parent alias names.
*/ */
public $parentAliasMap = array(); public $parentAliasMap = array();
/** /**
* Maps column names in the result set to field names for each class.
*
* @ignore * @ignore
* @var array * @var array Maps column names in the result set to field names for each class.
*/ */
public $fieldMappings = array(); public $fieldMappings = array();
/** /**
* Maps column names in the result set to the alias/field name to use in the mapped result.
*
* @ignore * @ignore
* @var array * @var array Maps column names in the result set to the alias/field name to use in the mapped result.
*/ */
public $scalarMappings = array(); public $scalarMappings = array();
/** /**
* Maps column names of meta columns (foreign keys, discriminator columns, ...) to field names.
*
* @ignore * @ignore
* @var array * @var array Maps entities in the result set to the alias name to use in the mapped result.
*/
public $entityMappings = array();
/**
* @ignore
* @var array Maps column names of meta columns (foreign keys, discriminator columns, ...) to field names.
*/ */
public $metaMappings = array(); public $metaMappings = array();
/** /**
* Maps column names in the result set to the alias they belong to.
*
* @ignore * @ignore
* @var array * @var array Maps column names in the result set to the alias they belong to.
*/ */
public $columnOwnerMap = array(); public $columnOwnerMap = array();
/** /**
* List of columns in the result set that are used as discriminator columns.
*
* @ignore * @ignore
* @var array * @var array List of columns in the result set that are used as discriminator columns.
*/ */
public $discriminatorColumns = array(); public $discriminatorColumns = array();
/** /**
* Maps alias names to field names that should be used for indexing.
*
* @ignore * @ignore
* @var array * @var array Maps alias names to field names that should be used for indexing.
*/ */
public $indexByMap = array(); public $indexByMap = array();
/** /**
* Map from column names to class names that declare the field the column is mapped to.
*
* @ignore * @ignore
* @var array * @var array Map from column names to class names that declare the field the column is mapped to.
*/ */
public $declaringClasses = array(); public $declaringClasses = array();
/** /**
* This is necessary to hydrate derivate foreign keys correctly. * @var array This is necessary to hydrate derivate foreign keys correctly.
*
* @var array
*/ */
public $isIdentifierColumn = array(); public $isIdentifierColumn = array();
@ -126,11 +118,15 @@ class ResultSetMapping
* @param string $class The class name of the entity. * @param string $class The class name of the entity.
* @param string $alias The alias for the class. The alias must be unique among all entity * @param string $alias The alias for the class. The alias must be unique among all entity
* results or joined entity results within this ResultSetMapping. * results or joined entity results within this ResultSetMapping.
* @param string $resultAlias The result alias with which the entity result should be
* placed in the result structure.
*
* @todo Rename: addRootEntity * @todo Rename: addRootEntity
*/ */
public function addEntityResult($class, $alias) public function addEntityResult($class, $alias, $resultAlias = null)
{ {
$this->aliasMap[$alias] = $class; $this->aliasMap[$alias] = $class;
$this->entityMappings[$alias] = $resultAlias;
} }
/** /**
@ -141,6 +137,7 @@ class ResultSetMapping
* @param string $alias The alias of the entity result or joined entity result the discriminator * @param string $alias The alias of the entity result or joined entity result the discriminator
* column should be used for. * column should be used for.
* @param string $discrColumn The name of the discriminator column in the SQL result set. * @param string $discrColumn The name of the discriminator column in the SQL result set.
*
* @todo Rename: addDiscriminatorColumn * @todo Rename: addDiscriminatorColumn
*/ */
public function setDiscriminatorColumn($alias, $discrColumn) public function setDiscriminatorColumn($alias, $discrColumn)
@ -157,7 +154,51 @@ class ResultSetMapping
*/ */
public function addIndexBy($alias, $fieldName) public function addIndexBy($alias, $fieldName)
{ {
$this->indexByMap[$alias] = $fieldName; $found = false;
foreach ($this->fieldMappings AS $columnName => $columnFieldName) {
if ( ! ($columnFieldName === $fieldName && $this->columnOwnerMap[$columnName] === $alias)) continue;
$this->addIndexByColumn($alias, $columnName);
$found = true;
break;
}
/* TODO: check if this exception can be put back, for now it's gone because of assumptions made by some ORM internals
if ( ! $found) {
$message = sprintf(
'Cannot add index by for DQL alias %s and field %s without calling addFieldResult() for them before.',
$alias,
$fieldName
);
throw new \LogicException($message);
}
*/
}
/**
* Set to index by a scalar result column name
*
* @param $resultColumnName
* @return void
*/
public function addIndexByScalar($resultColumnName)
{
$this->indexByMap['scalars'] = $resultColumnName;
}
/**
* Sets a column to use for indexing an entity or joined entity result by the given alias name.
*
* @param $alias
* @param $resultColumnName
* @return void
*/
public function addIndexByColumn($alias, $resultColumnName)
{
$this->indexByMap[$alias] = $resultColumnName;
} }
/** /**
@ -207,6 +248,7 @@ class ResultSetMapping
$this->columnOwnerMap[$columnName] = $alias; $this->columnOwnerMap[$columnName] = $alias;
// field name => class name of declaring class // field name => class name of declaring class
$this->declaringClasses[$columnName] = $declaringClass ?: $this->aliasMap[$alias]; $this->declaringClasses[$columnName] = $declaringClass ?: $this->aliasMap[$alias];
if ( ! $this->isMixed && $this->scalarMappings) { if ( ! $this->isMixed && $this->scalarMappings) {
$this->isMixed = true; $this->isMixed = true;
} }
@ -223,11 +265,11 @@ class ResultSetMapping
*/ */
public function addJoinedEntityResult($class, $alias, $parentAlias, $relation) public function addJoinedEntityResult($class, $alias, $parentAlias, $relation)
{ {
$this->aliasMap[$alias] = $class; $this->aliasMap[$alias] = $class;
$this->parentAliasMap[$alias] = $parentAlias; $this->parentAliasMap[$alias] = $parentAlias;
$this->relationMap[$alias] = $relation; $this->relationMap[$alias] = $relation;
} }
/** /**
* Adds a scalar result mapping. * Adds a scalar result mapping.
* *
@ -238,6 +280,7 @@ class ResultSetMapping
public function addScalarResult($columnName, $alias) public function addScalarResult($columnName, $alias)
{ {
$this->scalarMappings[$columnName] = $alias; $this->scalarMappings[$columnName] = $alias;
if ( ! $this->isMixed && $this->fieldMappings) { if ( ! $this->isMixed && $this->fieldMappings) {
$this->isMixed = true; $this->isMixed = true;
} }
@ -245,7 +288,7 @@ class ResultSetMapping
/** /**
* Checks whether a column with a given name is mapped as a scalar result. * Checks whether a column with a given name is mapped as a scalar result.
* *
* @param string $columName The name of the column in the SQL result set. * @param string $columName The name of the column in the SQL result set.
* @return boolean * @return boolean
* @todo Rename: isScalar * @todo Rename: isScalar
@ -384,10 +427,10 @@ class ResultSetMapping
{ {
return $this->isMixed; return $this->isMixed;
} }
/** /**
* Adds a meta column (foreign key or discriminator column) to the result set. * Adds a meta column (foreign key or discriminator column) to the result set.
* *
* @param string $alias * @param string $alias
* @param string $columnName * @param string $columnName
* @param string $fieldName * @param string $fieldName
@ -397,8 +440,9 @@ class ResultSetMapping
{ {
$this->metaMappings[$columnName] = $fieldName; $this->metaMappings[$columnName] = $fieldName;
$this->columnOwnerMap[$columnName] = $alias; $this->columnOwnerMap[$columnName] = $alias;
if ($isIdentifierColumn) { if ($isIdentifierColumn) {
$this->isIdentifierColumn[$alias][$columnName] = true; $this->isIdentifierColumn[$alias][$columnName] = true;
} }
} }
} }

View File

@ -86,20 +86,22 @@ class ResultSetMappingBuilder extends ResultSetMapping
if (isset($renamedColumns[$columnName])) { if (isset($renamedColumns[$columnName])) {
$columnName = $renamedColumns[$columnName]; $columnName = $renamedColumns[$columnName];
} }
$columnName = $platform->getSQLResultCasing($columnName);
if (isset($this->fieldMappings[$columnName])) { if (isset($this->fieldMappings[$columnName])) {
throw new \InvalidArgumentException("The column '$columnName' conflicts with another column in the mapper."); throw new \InvalidArgumentException("The column '$columnName' conflicts with another column in the mapper.");
} }
$this->addFieldResult($alias, $platform->getSQLResultCasing($columnName), $propertyName); $this->addFieldResult($alias, $columnName, $propertyName);
} }
foreach ($classMetadata->associationMappings AS $associationMapping) { foreach ($classMetadata->associationMappings AS $associationMapping) {
if ($associationMapping['isOwningSide'] && $associationMapping['type'] & ClassMetadataInfo::TO_ONE) { if ($associationMapping['isOwningSide'] && $associationMapping['type'] & ClassMetadataInfo::TO_ONE) {
foreach ($associationMapping['joinColumns'] AS $joinColumn) { foreach ($associationMapping['joinColumns'] AS $joinColumn) {
$columnName = $joinColumn['name']; $columnName = $joinColumn['name'];
$renamedColumnName = isset($renamedColumns[$columnName]) ? $renamedColumns[$columnName] : $columnName; $renamedColumnName = isset($renamedColumns[$columnName]) ? $renamedColumns[$columnName] : $columnName;
$renamedColumnName = $platform->getSQLResultCasing($renamedColumnName);
if (isset($this->metaMappings[$renamedColumnName])) { if (isset($this->metaMappings[$renamedColumnName])) {
throw new \InvalidArgumentException("The column '$renamedColumnName' conflicts with another column in the mapper."); throw new \InvalidArgumentException("The column '$renamedColumnName' conflicts with another column in the mapper.");
} }
$this->addMetaResult($alias, $platform->getSQLResultCasing($renamedColumnName), $platform->getSQLResultCasing($columnName)); $this->addMetaResult($alias, $renamedColumnName, $columnName);
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -117,7 +117,7 @@ public function <methodName>()
* @param <variableType>$<variableName> * @param <variableType>$<variableName>
* @return <entity> * @return <entity>
*/ */
public function <methodName>(<methodTypeHint>$<variableName>) public function <methodName>(<methodTypeHint>$<variableName><variableDefault>)
{ {
<spaces>$this-><fieldName> = $<variableName>; <spaces>$this-><fieldName> = $<variableName>;
<spaces>return $this; <spaces>return $this;
@ -406,7 +406,7 @@ public function <methodName>()
} }
if ($collections) { if ($collections) {
return $this->_prefixCodeWithSpaces(str_replace("<collections>", implode("\n", $collections), self::$_constructorMethodTemplate)); return $this->_prefixCodeWithSpaces(str_replace("<collections>", implode("\n".$this->_spaces, $collections), self::$_constructorMethodTemplate));
} }
return ''; return '';
@ -634,7 +634,8 @@ public function <methodName>()
foreach ($metadata->associationMappings as $associationMapping) { foreach ($metadata->associationMappings as $associationMapping) {
if ($associationMapping['type'] & ClassMetadataInfo::TO_ONE) { if ($associationMapping['type'] & ClassMetadataInfo::TO_ONE) {
if ($code = $this->_generateEntityStubMethod($metadata, 'set', $associationMapping['fieldName'], $associationMapping['targetEntity'])) { $nullable = $this->_isAssociationIsNullable($associationMapping) ? 'null' : null;
if ($code = $this->_generateEntityStubMethod($metadata, 'set', $associationMapping['fieldName'], $associationMapping['targetEntity'], $nullable)) {
$methods[] = $code; $methods[] = $code;
} }
if ($code = $this->_generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], $associationMapping['targetEntity'])) { if ($code = $this->_generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
@ -653,6 +654,22 @@ public function <methodName>()
return implode("\n\n", $methods); return implode("\n\n", $methods);
} }
private function _isAssociationIsNullable($associationMapping)
{
if (isset($associationMapping['joinColumns'])) {
$joinColumns = $associationMapping['joinColumns'];
} else {
//@todo thereis no way to retreive targetEntity metadata
$joinColumns = array();
}
foreach ($joinColumns as $joinColumn) {
if(isset($joinColumn['nullable']) && !$joinColumn['nullable']) {
return false;
}
}
return true;
}
private function _generateEntityLifecycleCallbackMethods(ClassMetadataInfo $metadata) private function _generateEntityLifecycleCallbackMethods(ClassMetadataInfo $metadata)
{ {
if (isset($metadata->lifecycleCallbacks) && $metadata->lifecycleCallbacks) { if (isset($metadata->lifecycleCallbacks) && $metadata->lifecycleCallbacks) {
@ -707,7 +724,7 @@ public function <methodName>()
return implode("\n", $lines); return implode("\n", $lines);
} }
private function _generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null) private function _generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null, $defaultValue = null)
{ {
if ($type == "add") { if ($type == "add") {
$addMethod = explode("\\", $typeHint); $addMethod = explode("\\", $typeHint);
@ -737,6 +754,7 @@ public function <methodName>()
'<variableName>' => Inflector::camelize($fieldName), '<variableName>' => Inflector::camelize($fieldName),
'<methodName>' => $methodName, '<methodName>' => $methodName,
'<fieldName>' => $fieldName, '<fieldName>' => $fieldName,
'<variableDefault>' => ($defaultValue !== null ) ? ('='.$defaultValue) : '',
'<entity>' => $this->_getClassName($metadata) '<entity>' => $this->_getClassName($metadata)
); );
@ -805,7 +823,12 @@ public function <methodName>()
{ {
$lines = array(); $lines = array();
$lines[] = $this->_spaces . '/**'; $lines[] = $this->_spaces . '/**';
$lines[] = $this->_spaces . ' * @var ' . $associationMapping['targetEntity'];
if ($associationMapping['type'] & ClassMetadataInfo::TO_MANY) {
$lines[] = $this->_spaces . ' * @var \Doctrine\Common\Collections\ArrayCollection';
} else {
$lines[] = $this->_spaces . ' * @var ' . $associationMapping['targetEntity'];
}
if ($this->_generateAnnotations) { if ($this->_generateAnnotations) {
$lines[] = $this->_spaces . ' *'; $lines[] = $this->_spaces . ' *';

View File

@ -67,7 +67,9 @@ class SchemaTool
/** /**
* Creates the database schema for the given array of ClassMetadata instances. * Creates the database schema for the given array of ClassMetadata instances.
* *
* @throws ToolsException
* @param array $classes * @param array $classes
* @return void
*/ */
public function createSchema(array $classes) public function createSchema(array $classes)
{ {
@ -75,7 +77,11 @@ class SchemaTool
$conn = $this->_em->getConnection(); $conn = $this->_em->getConnection();
foreach ($createSchemaSql as $sql) { foreach ($createSchemaSql as $sql) {
$conn->executeQuery($sql); try {
$conn->executeQuery($sql);
} catch(\Exception $e) {
throw ToolsException::schemaToolFailure($sql, $e);
}
} }
} }
@ -94,7 +100,7 @@ class SchemaTool
/** /**
* Some instances of ClassMetadata don't need to be processed in the SchemaTool context. This method detects them. * Some instances of ClassMetadata don't need to be processed in the SchemaTool context. This method detects them.
* *
* @param ClassMetadata $class * @param ClassMetadata $class
* @param array $processedClasses * @param array $processedClasses
* @return bool * @return bool
@ -139,7 +145,7 @@ class SchemaTool
$this->_gatherRelationsSql($class, $table, $schema); $this->_gatherRelationsSql($class, $table, $schema);
// Add the discriminator column // Add the discriminator column
$discrColumnDef = $this->_getDiscriminatorColumnDefinition($class, $table); $this->addDiscriminatorColumnDefinition($class, $table);
// Aggregate all the information from all classes in the hierarchy // Aggregate all the information from all classes in the hierarchy
foreach ($class->parentClasses as $parentClassName) { foreach ($class->parentClasses as $parentClassName) {
@ -171,7 +177,7 @@ class SchemaTool
// Add the discriminator column only to the root table // Add the discriminator column only to the root table
if ($class->name == $class->rootEntityName) { if ($class->name == $class->rootEntityName) {
$discrColumnDef = $this->_getDiscriminatorColumnDefinition($class, $table); $this->addDiscriminatorColumnDefinition($class, $table);
} else { } else {
// Add an ID FK column to child tables // Add an ID FK column to child tables
/* @var Doctrine\ORM\Mapping\ClassMetadata $class */ /* @var Doctrine\ORM\Mapping\ClassMetadata $class */
@ -261,7 +267,7 @@ class SchemaTool
* @return array The portable column definition of the discriminator column as required by * @return array The portable column definition of the discriminator column as required by
* the DBAL. * the DBAL.
*/ */
private function _getDiscriminatorColumnDefinition($class, $table) private function addDiscriminatorColumnDefinition($class, $table)
{ {
$discrColumn = $class->discriminatorColumn; $discrColumn = $class->discriminatorColumn;
@ -551,7 +557,7 @@ class SchemaTool
try { try {
$conn->executeQuery($sql); $conn->executeQuery($sql);
} catch(\Exception $e) { } catch(\Exception $e) {
} }
} }
} }
@ -589,7 +595,7 @@ class SchemaTool
/** /**
* Get SQL to drop the tables defined by the passed classes. * Get SQL to drop the tables defined by the passed classes.
* *
* @param array $classes * @param array $classes
* @return array * @return array
*/ */
@ -615,7 +621,7 @@ class SchemaTool
} }
} }
} }
if ($this->_platform->supportsSequences()) { if ($this->_platform->supportsSequences()) {
foreach ($schema->getSequences() AS $sequence) { foreach ($schema->getSequences() AS $sequence) {
$visitor->acceptSequence($sequence); $visitor->acceptSequence($sequence);
@ -659,7 +665,7 @@ class SchemaTool
/** /**
* Gets the sequence of SQL statements that need to be performed in order * Gets the sequence of SQL statements that need to be performed in order
* to bring the given class mappings in-synch with the relational schema. * to bring the given class mappings in-synch with the relational schema.
* If $saveMode is set to true the command is executed in the Database, * If $saveMode is set to true the command is executed in the Database,
* else SQL is returned. * else SQL is returned.
* *
* @param array $classes The classes to consider. * @param array $classes The classes to consider.

View File

@ -50,7 +50,7 @@ class SchemaValidator
} }
/** /**
* Checks the internal consistency of mapping files. * Checks the internal consistency of all mapping files.
* *
* There are several checks that can't be done at runtime or are too expensive, which can be verified * There are several checks that can't be done at runtime or are too expensive, which can be verified
* with this command. For example: * with this command. For example:
@ -69,150 +69,7 @@ class SchemaValidator
$classes = $cmf->getAllMetadata(); $classes = $cmf->getAllMetadata();
foreach ($classes AS $class) { foreach ($classes AS $class) {
$ce = array(); if ($ce = $this->validateClass($class)) {
/* @var $class ClassMetadata */
foreach ($class->associationMappings AS $fieldName => $assoc) {
if (!$cmf->hasMetadataFor($assoc['targetEntity'])) {
$ce[] = "The target entity '" . $assoc['targetEntity'] . "' specified on " . $class->name . '#' . $fieldName . ' is unknown.';
}
if ($assoc['mappedBy'] && $assoc['inversedBy']) {
$ce[] = "The association " . $class . "#" . $fieldName . " cannot be defined as both inverse and owning.";
}
$targetMetadata = $cmf->getMetadataFor($assoc['targetEntity']);
/* @var $assoc AssociationMapping */
if ($assoc['mappedBy']) {
if ($targetMetadata->hasField($assoc['mappedBy'])) {
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the owning side ".
"field " . $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " which is not defined as association.";
}
if (!$targetMetadata->hasAssociation($assoc['mappedBy'])) {
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the owning side ".
"field " . $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " which does not exist.";
} else if ($targetMetadata->associationMappings[$assoc['mappedBy']]['inversedBy'] == null) {
$ce[] = "The field " . $class->name . "#" . $fieldName . " is on the inverse side of a ".
"bi-directional relationship, but the specified mappedBy association on the target-entity ".
$assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " does not contain the required ".
"'inversedBy' attribute.";
} else if ($targetMetadata->associationMappings[$assoc['mappedBy']]['inversedBy'] != $fieldName) {
$ce[] = "The mappings " . $class->name . "#" . $fieldName . " and " .
$assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " are ".
"incosistent with each other.";
}
}
if ($assoc['inversedBy']) {
if ($targetMetadata->hasField($assoc['inversedBy'])) {
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the inverse side ".
"field " . $assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " which is not defined as association.";
}
if (!$targetMetadata->hasAssociation($assoc['inversedBy'])) {
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the inverse side ".
"field " . $assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " which does not exist.";
} else if ($targetMetadata->associationMappings[$assoc['inversedBy']]['mappedBy'] == null) {
$ce[] = "The field " . $class->name . "#" . $fieldName . " is on the owning side of a ".
"bi-directional relationship, but the specified mappedBy association on the target-entity ".
$assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " does not contain the required ".
"'inversedBy' attribute.";
} else if ($targetMetadata->associationMappings[$assoc['inversedBy']]['mappedBy'] != $fieldName) {
$ce[] = "The mappings " . $class->name . "#" . $fieldName . " and " .
$assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " are ".
"incosistent with each other.";
}
}
if ($assoc['isOwningSide']) {
if ($assoc['type'] == ClassMetadataInfo::MANY_TO_MANY) {
foreach ($assoc['joinTable']['joinColumns'] AS $joinColumn) {
if (!isset($class->fieldNames[$joinColumn['referencedColumnName']])) {
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' does not " .
"have a corresponding field with this column name on the class '" . $class->name . "'.";
break;
}
$fieldName = $class->fieldNames[$joinColumn['referencedColumnName']];
if (!in_array($fieldName, $class->identifier)) {
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " .
"has to be a primary key column.";
}
}
foreach ($assoc['joinTable']['inverseJoinColumns'] AS $inverseJoinColumn) {
$targetClass = $cmf->getMetadataFor($assoc['targetEntity']);
if (!isset($targetClass->fieldNames[$inverseJoinColumn['referencedColumnName']])) {
$ce[] = "The inverse referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' does not " .
"have a corresponding field with this column name on the class '" . $targetClass->name . "'.";
break;
}
$fieldName = $targetClass->fieldNames[$inverseJoinColumn['referencedColumnName']];
if (!in_array($fieldName, $targetClass->identifier)) {
$ce[] = "The referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' " .
"has to be a primary key column.";
}
}
if (count($targetClass->identifier) != count($assoc['joinTable']['inverseJoinColumns'])) {
$ce[] = "The inverse join columns of the many-to-many table '" . $assoc['joinTable']['name'] . "' " .
"have to match to ALL identifier columns of the target entity '". $targetClass->name . "'";
}
if (count($class->identifier) != count($assoc['joinTable']['joinColumns'])) {
$ce[] = "The join columns of the many-to-many table '" . $assoc['joinTable']['name'] . "' " .
"have to match to ALL identifier columns of the source entity '". $class->name . "'";
}
} else if ($assoc['type'] & ClassMetadataInfo::TO_ONE) {
foreach ($assoc['joinColumns'] AS $joinColumn) {
$targetClass = $cmf->getMetadataFor($assoc['targetEntity']);
if (!isset($targetClass->fieldNames[$joinColumn['referencedColumnName']])) {
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' does not " .
"have a corresponding field with this column name on the class '" . $targetClass->name . "'.";
break;
}
$fieldName = $targetClass->fieldNames[$joinColumn['referencedColumnName']];
if (!in_array($fieldName, $targetClass->identifier)) {
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " .
"has to be a primary key column.";
}
}
if (count($class->identifier) != count($assoc['joinColumns'])) {
$ce[] = "The join columns of the association '" . $assoc['fieldName'] . "' " .
"have to match to ALL identifier columns of the source entity '". $class->name . "'";
}
}
}
if (isset($assoc['orderBy']) && $assoc['orderBy'] !== null) {
$targetClass = $cmf->getMetadataFor($assoc['targetEntity']);
foreach ($assoc['orderBy'] AS $orderField => $orientation) {
if (!$targetClass->hasField($orderField)) {
$ce[] = "The association " . $class->name."#".$fieldName." is ordered by a foreign field " .
$orderField . " that is not a field on the target entity " . $targetClass->name;
}
}
}
}
foreach ($class->reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $publicAttr) {
if ($publicAttr->isStatic()) {
continue;
}
$ce[] = "Field '".$publicAttr->getName()."' in class '".$class->name."' must be private ".
"or protected. Public fields may break lazy-loading.";
}
foreach ($class->subClasses AS $subClass) {
if (!in_array($class->name, class_parents($subClass))) {
$ce[] = "According to the discriminator map class '" . $subClass . "' has to be a child ".
"of '" . $class->name . "' but these entities are not related through inheritance.";
}
}
if ($ce) {
$errors[$class->name] = $ce; $errors[$class->name] = $ce;
} }
} }
@ -220,6 +77,170 @@ class SchemaValidator
return $errors; return $errors;
} }
/**
* Validate a single class of the current
*
* @param ClassMetadataInfo $class
* @return array
*/
public function validateClass(ClassMetadataInfo $class)
{
$ce = array();
$cmf = $this->em->getMetadataFactory();
foreach ($class->associationMappings AS $fieldName => $assoc) {
if (!$cmf->hasMetadataFor($assoc['targetEntity'])) {
$ce[] = "The target entity '" . $assoc['targetEntity'] . "' specified on " . $class->name . '#' . $fieldName . ' is unknown.';
return $ce;
}
if ($assoc['mappedBy'] && $assoc['inversedBy']) {
$ce[] = "The association " . $class . "#" . $fieldName . " cannot be defined as both inverse and owning.";
}
$targetMetadata = $cmf->getMetadataFor($assoc['targetEntity']);
/* @var $assoc AssociationMapping */
if ($assoc['mappedBy']) {
if ($targetMetadata->hasField($assoc['mappedBy'])) {
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the owning side ".
"field " . $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " which is not defined as association.";
}
if (!$targetMetadata->hasAssociation($assoc['mappedBy'])) {
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the owning side ".
"field " . $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " which does not exist.";
} else if ($targetMetadata->associationMappings[$assoc['mappedBy']]['inversedBy'] == null) {
$ce[] = "The field " . $class->name . "#" . $fieldName . " is on the inverse side of a ".
"bi-directional relationship, but the specified mappedBy association on the target-entity ".
$assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " does not contain the required ".
"'inversedBy' attribute.";
} else if ($targetMetadata->associationMappings[$assoc['mappedBy']]['inversedBy'] != $fieldName) {
$ce[] = "The mappings " . $class->name . "#" . $fieldName . " and " .
$assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " are ".
"incosistent with each other.";
}
}
if ($assoc['inversedBy']) {
if ($targetMetadata->hasField($assoc['inversedBy'])) {
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the inverse side ".
"field " . $assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " which is not defined as association.";
}
if (!$targetMetadata->hasAssociation($assoc['inversedBy'])) {
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the inverse side ".
"field " . $assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " which does not exist.";
} else if ($targetMetadata->associationMappings[$assoc['inversedBy']]['mappedBy'] == null) {
$ce[] = "The field " . $class->name . "#" . $fieldName . " is on the owning side of a ".
"bi-directional relationship, but the specified mappedBy association on the target-entity ".
$assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " does not contain the required ".
"'inversedBy' attribute.";
} else if ($targetMetadata->associationMappings[$assoc['inversedBy']]['mappedBy'] != $fieldName) {
$ce[] = "The mappings " . $class->name . "#" . $fieldName . " and " .
$assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " are ".
"incosistent with each other.";
}
}
if ($assoc['isOwningSide']) {
if ($assoc['type'] == ClassMetadataInfo::MANY_TO_MANY) {
foreach ($assoc['joinTable']['joinColumns'] AS $joinColumn) {
if (!isset($class->fieldNames[$joinColumn['referencedColumnName']])) {
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' does not " .
"have a corresponding field with this column name on the class '" . $class->name . "'.";
break;
}
$fieldName = $class->fieldNames[$joinColumn['referencedColumnName']];
if (!in_array($fieldName, $class->identifier)) {
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " .
"has to be a primary key column.";
}
}
foreach ($assoc['joinTable']['inverseJoinColumns'] AS $inverseJoinColumn) {
if (!isset($targetMetadata->fieldNames[$inverseJoinColumn['referencedColumnName']])) {
$ce[] = "The inverse referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' does not " .
"have a corresponding field with this column name on the class '" . $targetMetadata->name . "'.";
break;
}
$fieldName = $targetMetadata->fieldNames[$inverseJoinColumn['referencedColumnName']];
if (!in_array($fieldName, $targetMetadata->identifier)) {
$ce[] = "The referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' " .
"has to be a primary key column.";
}
}
if (count($targetMetadata->getIdentifierColumnNames()) != count($assoc['joinTable']['inverseJoinColumns'])) {
$ce[] = "The inverse join columns of the many-to-many table '" . $assoc['joinTable']['name'] . "' " .
"have to contain to ALL identifier columns of the target entity '". $targetMetadata->name . "', " .
"however '" . implode(", ", array_diff($targetMetadata->getIdentifierColumnNames(), array_values($assoc['relationToTargetKeyColumns']))) .
"' are missing.";
}
if (count($class->getIdentifierColumnNames()) != count($assoc['joinTable']['joinColumns'])) {
$ce[] = "The join columns of the many-to-many table '" . $assoc['joinTable']['name'] . "' " .
"have to contain to ALL identifier columns of the source entity '". $class->name . "', " .
"however '" . implode(", ", array_diff($class->getIdentifierColumnNames(), array_values($assoc['relationToSourceKeyColumns']))) .
"' are missing.";
}
} else if ($assoc['type'] & ClassMetadataInfo::TO_ONE) {
foreach ($assoc['joinColumns'] AS $joinColumn) {
if (!isset($targetMetadata->fieldNames[$joinColumn['referencedColumnName']])) {
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' does not " .
"have a corresponding field with this column name on the class '" . $targetMetadata->name . "'.";
break;
}
$fieldName = $targetMetadata->fieldNames[$joinColumn['referencedColumnName']];
if (!in_array($fieldName, $targetMetadata->identifier)) {
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " .
"has to be a primary key column.";
}
}
if (count($class->getIdentifierColumnNames()) != count($assoc['joinColumns'])) {
$ids = array();
foreach ($assoc['joinColumns'] AS $joinColumn) {
$ids[] = $joinColumn['name'];
}
$ce[] = "The join columns of the association '" . $assoc['fieldName'] . "' " .
"have to match to ALL identifier columns of the source entity '". $class->name . "', " .
"however '" . implode(", ", array_diff($class->getIdentifierColumnNames(), $ids)) .
"' are missing.";
}
}
}
if (isset($assoc['orderBy']) && $assoc['orderBy'] !== null) {
foreach ($assoc['orderBy'] AS $orderField => $orientation) {
if (!$targetMetadata->hasField($orderField)) {
$ce[] = "The association " . $class->name."#".$fieldName." is ordered by a foreign field " .
$orderField . " that is not a field on the target entity " . $targetMetadata->name;
}
}
}
}
foreach ($class->reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $publicAttr) {
if ($publicAttr->isStatic()) {
continue;
}
$ce[] = "Field '".$publicAttr->getName()."' in class '".$class->name."' must be private ".
"or protected. Public fields may break lazy-loading.";
}
foreach ($class->subClasses AS $subClass) {
if (!in_array($class->name, class_parents($subClass))) {
$ce[] = "According to the discriminator map class '" . $subClass . "' has to be a child ".
"of '" . $class->name . "' but these entities are not related through inheritance.";
}
}
return $ce;
}
/** /**
* Check if the Database Schema is in sync with the current metadata state. * Check if the Database Schema is in sync with the current metadata state.
* *
@ -230,6 +251,6 @@ class SchemaValidator
$schemaTool = new SchemaTool($this->em); $schemaTool = new SchemaTool($this->em);
$allMetadata = $this->em->getMetadataFactory()->getAllMetadata(); $allMetadata = $this->em->getMetadataFactory()->getAllMetadata();
return (count($schemaTool->getUpdateSchemaSql($allMetadata, false)) == 0); return (count($schemaTool->getUpdateSchemaSql($allMetadata, true)) == 0);
} }
} }

View File

@ -1,11 +1,38 @@
<?php <?php
/*
* 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\Tools; namespace Doctrine\ORM\Tools;
use Doctrine\ORM\ORMException; use Doctrine\ORM\ORMException;
/**
* Tools related Exceptions
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class ToolsException extends ORMException class ToolsException extends ORMException
{ {
public static function schemaToolFailure($sql, \Exception $e)
{
return new self("Schema-Tool failed with Error '" . $e->getMessage() . "' while executing DDL: " . $sql, "0", $e);
}
public static function couldNotMapDoctrine1Type($type) public static function couldNotMapDoctrine1Type($type)
{ {
return new self("Could not map doctrine 1 type '$type'!"); return new self("Could not map doctrine 1 type '$type'!");

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@ class ConnectionMock extends \Doctrine\DBAL\Connection
private $_platformMock; private $_platformMock;
private $_lastInsertId = 0; private $_lastInsertId = 0;
private $_inserts = array(); private $_inserts = array();
public function __construct(array $params, $driver, $config = null, $eventManager = null) public function __construct(array $params, $driver, $config = null, $eventManager = null)
{ {
$this->_platformMock = new DatabasePlatformMock(); $this->_platformMock = new DatabasePlatformMock();
@ -18,7 +18,7 @@ class ConnectionMock extends \Doctrine\DBAL\Connection
// Override possible assignment of platform to database platform mock // Override possible assignment of platform to database platform mock
$this->_platform = $this->_platformMock; $this->_platform = $this->_platformMock;
} }
/** /**
* @override * @override
*/ */
@ -26,15 +26,15 @@ class ConnectionMock extends \Doctrine\DBAL\Connection
{ {
return $this->_platformMock; return $this->_platformMock;
} }
/** /**
* @override * @override
*/ */
public function insert($tableName, array $data) public function insert($tableName, array $data, array $types = array())
{ {
$this->_inserts[$tableName][] = $data; $this->_inserts[$tableName][] = $data;
} }
/** /**
* @override * @override
*/ */
@ -50,7 +50,7 @@ class ConnectionMock extends \Doctrine\DBAL\Connection
{ {
return $this->_fetchOneResult; return $this->_fetchOneResult;
} }
/** /**
* @override * @override
*/ */
@ -61,29 +61,29 @@ class ConnectionMock extends \Doctrine\DBAL\Connection
} }
return $input; return $input;
} }
/* Mock API */ /* Mock API */
public function setFetchOneResult($fetchOneResult) public function setFetchOneResult($fetchOneResult)
{ {
$this->_fetchOneResult = $fetchOneResult; $this->_fetchOneResult = $fetchOneResult;
} }
public function setDatabasePlatform($platform) public function setDatabasePlatform($platform)
{ {
$this->_platformMock = $platform; $this->_platformMock = $platform;
} }
public function setLastInsertId($id) public function setLastInsertId($id)
{ {
$this->_lastInsertId = $id; $this->_lastInsertId = $id;
} }
public function getInserts() public function getInserts()
{ {
return $this->_inserts; return $this->_inserts;
} }
public function reset() public function reset()
{ {
$this->_inserts = array(); $this->_inserts = array();

View File

@ -57,7 +57,7 @@ class DatabasePlatformMock extends \Doctrine\DBAL\Platforms\AbstractPlatform
/** @override */ /** @override */
public function getVarcharTypeDeclarationSQL(array $field) {} public function getVarcharTypeDeclarationSQL(array $field) {}
/** @override */ /** @override */
public function getClobTypeDeclarationSQL(array $field) {} public function getClobTypeDeclarationSQL(array $field) {}
@ -85,6 +85,13 @@ class DatabasePlatformMock extends \Doctrine\DBAL\Platforms\AbstractPlatform
protected function initializeDoctrineTypeMappings() protected function initializeDoctrineTypeMappings()
{ {
}
/**
* Gets the SQL Snippet used to declare a BLOB column type.
*/
public function getBlobTypeDeclarationSQL(array $field)
{
throw DBALException::notSupported(__METHOD__);
} }
} }

View File

@ -8,10 +8,10 @@ namespace Doctrine\Tests\Mocks;
* *
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
*/ */
class HydratorMockStatement implements \Doctrine\DBAL\Driver\Statement class HydratorMockStatement implements \IteratorAggregate, \Doctrine\DBAL\Driver\Statement
{ {
private $_resultSet; private $_resultSet;
/** /**
* Creates a new mock statement that will serve the provided fake result set to clients. * Creates a new mock statement that will serve the provided fake result set to clients.
* *
@ -21,7 +21,7 @@ class HydratorMockStatement implements \Doctrine\DBAL\Driver\Statement
{ {
$this->_resultSet = $resultSet; $this->_resultSet = $resultSet;
} }
/** /**
* Fetches all rows from the result set. * Fetches all rows from the result set.
* *
@ -31,7 +31,7 @@ class HydratorMockStatement implements \Doctrine\DBAL\Driver\Statement
{ {
return $this->_resultSet; return $this->_resultSet;
} }
public function fetchColumn($columnNumber = 0) public function fetchColumn($columnNumber = 0)
{ {
$row = current($this->_resultSet); $row = current($this->_resultSet);
@ -39,10 +39,10 @@ class HydratorMockStatement implements \Doctrine\DBAL\Driver\Statement
$val = array_shift($row); $val = array_shift($row);
return $val !== null ? $val : false; return $val !== null ? $val : false;
} }
/** /**
* Fetches the next row in the result set. * Fetches the next row in the result set.
* *
*/ */
public function fetch($fetchStyle = null) public function fetch($fetchStyle = null)
{ {
@ -50,7 +50,7 @@ class HydratorMockStatement implements \Doctrine\DBAL\Driver\Statement
next($this->_resultSet); next($this->_resultSet);
return $current; return $current;
} }
/** /**
* Closes the cursor, enabling the statement to be executed again. * Closes the cursor, enabling the statement to be executed again.
* *
@ -60,13 +60,13 @@ class HydratorMockStatement implements \Doctrine\DBAL\Driver\Statement
{ {
return true; return true;
} }
public function setResultSet(array $resultSet) public function setResultSet(array $resultSet)
{ {
reset($resultSet); reset($resultSet);
$this->_resultSet = $resultSet; $this->_resultSet = $resultSet;
} }
public function bindColumn($column, &$param, $type = null) public function bindColumn($column, &$param, $type = null)
{ {
} }
@ -78,7 +78,7 @@ class HydratorMockStatement implements \Doctrine\DBAL\Driver\Statement
public function bindParam($column, &$variable, $type = null, $length = null, $driverOptions = array()) public function bindParam($column, &$variable, $type = null, $length = null, $driverOptions = array())
{ {
} }
public function columnCount() public function columnCount()
{ {
} }
@ -86,16 +86,26 @@ class HydratorMockStatement implements \Doctrine\DBAL\Driver\Statement
public function errorCode() public function errorCode()
{ {
} }
public function errorInfo() public function errorInfo()
{ {
} }
public function execute($params = array()) public function execute($params = array())
{ {
} }
public function rowCount() public function rowCount()
{ {
} }
public function getIterator()
{
return $this->_resultSet;
}
public function setFetchMode($fetchMode)
{
}
} }

View File

@ -46,7 +46,7 @@ class CmsAddress
public function getId() { public function getId() {
return $this->id; return $this->id;
} }
public function getUser() { public function getUser() {
return $this->user; return $this->user;
} }
@ -62,7 +62,7 @@ class CmsAddress
public function getCity() { public function getCity() {
return $this->city; return $this->city;
} }
public function setUser(CmsUser $user) { public function setUser(CmsUser $user) {
if ($this->user !== $user) { if ($this->user !== $user) {
$this->user = $user; $this->user = $user;

View File

@ -9,6 +9,7 @@ class DDC117Article
{ {
/** @Id @Column(type="integer", name="article_id") @GeneratedValue */ /** @Id @Column(type="integer", name="article_id") @GeneratedValue */
private $id; private $id;
/** @Column */ /** @Column */
private $title; private $title;

View File

@ -0,0 +1,76 @@
<?php
/*
* 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\Tests\Models\DDC1476;
/**
* @Entity()
*/
class DDC1476EntityWithDefaultFieldType
{
/**
* @Id
* @Column()
* @GeneratedValue("NONE")
*/
protected $id;
/** @column() */
protected $name;
/**
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata)
{
$metadata->mapField(array(
'id' => true,
'fieldName' => 'id',
));
$metadata->mapField(array(
'fieldName' => 'name',
));
$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadataInfo::GENERATOR_TYPE_NONE);
}
}

View File

@ -21,7 +21,7 @@ class LegacyUser
*/ */
public $_username; public $_username;
/** /**
* @Column(type="string", length=255) * @Column(type="string", length=255, name="name")
*/ */
public $_name; public $_name;
/** /**

View File

@ -23,12 +23,12 @@ class LegacyUserReference
private $_target; private $_target;
/** /**
* @column(type="string") * @column(type="string", name="description")
*/ */
private $_description; private $_description;
/** /**
* @column(type="datetime") * @column(type="datetime", name="created")
*/ */
private $_created; private $_created;

View File

@ -1,7 +1,5 @@
<?php <?php
/* /*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@ -33,11 +31,13 @@ require_once __DIR__ . '/../../TestInit.php';
* @link http://www.doctrine-project.org * @link http://www.doctrine-project.org
* @since 2.0 * @since 2.0
*/ */
class CustomTreeWalkersTest extends \Doctrine\Tests\OrmFunctionalTestCase class CustomTreeWalkersTest extends \Doctrine\Tests\OrmTestCase
{ {
protected function setUp() { private $_em;
$this->useModelSet('cms');
parent::setUp(); protected function setUp()
{
$this->_em = $this->_getTestEntityManager();
} }
public function assertSqlGeneration($dqlToBeTested, $sqlToBeConfirmed) public function assertSqlGeneration($dqlToBeTested, $sqlToBeConfirmed)
@ -70,7 +70,7 @@ class CustomTreeWalkersTest extends \Doctrine\Tests\OrmFunctionalTestCase
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c0_.email_id AS email_id4 FROM cms_users c0_ WHERE (c0_.name = ? OR c0_.name = ?) AND c0_.id = 1" "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c0_.email_id AS email_id4 FROM cms_users c0_ WHERE (c0_.name = ? OR c0_.name = ?) AND c0_.id = 1"
); );
} }
public function testSupportsQueriesWithSimpleConditionalExpression() public function testSupportsQueriesWithSimpleConditionalExpression()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
@ -94,7 +94,7 @@ class CustomTreeWalker extends Query\TreeWalkerAdapter
$dqlAliases[] = $dqlAlias; $dqlAliases[] = $dqlAlias;
} }
} }
// Create our conditions for all involved classes // Create our conditions for all involved classes
$factors = array(); $factors = array();
foreach ($dqlAliases as $alias) { foreach ($dqlAliases as $alias) {
@ -108,7 +108,7 @@ class CustomTreeWalker extends Query\TreeWalkerAdapter
$factor = new Query\AST\ConditionalFactor($condPrimary); $factor = new Query\AST\ConditionalFactor($condPrimary);
$factors[] = $factor; $factors[] = $factor;
} }
if (($whereClause = $selectStatement->whereClause) !== null) { if (($whereClause = $selectStatement->whereClause) !== null) {
// There is already a WHERE clause, so append the conditions // There is already a WHERE clause, so append the conditions
$condExpr = $whereClause->conditionalExpression; $condExpr = $whereClause->conditionalExpression;
@ -119,18 +119,18 @@ class CustomTreeWalker extends Query\TreeWalkerAdapter
$whereClause->conditionalExpression = $condExpr; $whereClause->conditionalExpression = $condExpr;
} }
$existingTerms = $whereClause->conditionalExpression->conditionalTerms; $existingTerms = $whereClause->conditionalExpression->conditionalTerms;
if (count($existingTerms) > 1) { if (count($existingTerms) > 1) {
// More than one term, so we need to wrap all these terms in a single root term // More than one term, so we need to wrap all these terms in a single root term
// i.e: "WHERE u.name = :foo or u.other = :bar" => "WHERE (u.name = :foo or u.other = :bar) AND <our condition>" // i.e: "WHERE u.name = :foo or u.other = :bar" => "WHERE (u.name = :foo or u.other = :bar) AND <our condition>"
$primary = new Query\AST\ConditionalPrimary; $primary = new Query\AST\ConditionalPrimary;
$primary->conditionalExpression = new Query\AST\ConditionalExpression($existingTerms); $primary->conditionalExpression = new Query\AST\ConditionalExpression($existingTerms);
$existingFactor = new Query\AST\ConditionalFactor($primary); $existingFactor = new Query\AST\ConditionalFactor($primary);
$term = new Query\AST\ConditionalTerm(array_merge(array($existingFactor), $factors)); $term = new Query\AST\ConditionalTerm(array_merge(array($existingFactor), $factors));
$selectStatement->whereClause->conditionalExpression->conditionalTerms = array($term); $selectStatement->whereClause->conditionalExpression->conditionalTerms = array($term);
} else { } else {
// Just one term so we can simply append our factors to that term // Just one term so we can simply append our factors to that term

View File

@ -20,7 +20,9 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
public function tearDown() public function tearDown()
{ {
$this->_em->getConfiguration()->setEntityNamespaces(array()); if ($this->_em) {
$this->_em->getConfiguration()->setEntityNamespaces(array());
}
parent::tearDown(); parent::tearDown();
} }
@ -78,7 +80,7 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
return array($user->id, $address->id); return array($user->id, $address->id);
} }
public function buildUser($name, $username, $status, $address) public function buildUser($name, $username, $status, $address)
{ {
$user = new CmsUser(); $user = new CmsUser();
@ -89,10 +91,10 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->persist($user); $this->_em->persist($user);
$this->_em->flush(); $this->_em->flush();
return $user; return $user;
} }
public function buildAddress($country, $city, $street, $zip) public function buildAddress($country, $city, $street, $zip)
{ {
$address = new CmsAddress(); $address = new CmsAddress();
@ -103,7 +105,7 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->persist($address); $this->_em->persist($address);
$this->_em->flush(); $this->_em->flush();
return $address; return $address;
} }
@ -134,22 +136,22 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
{ {
$address1 = $this->buildAddress('Germany', 'Berlim', 'Foo st.', '123456'); $address1 = $this->buildAddress('Germany', 'Berlim', 'Foo st.', '123456');
$user1 = $this->buildUser('Benjamin', 'beberlei', 'dev', $address1); $user1 = $this->buildUser('Benjamin', 'beberlei', 'dev', $address1);
$address2 = $this->buildAddress('Brazil', 'São Paulo', 'Bar st.', '654321'); $address2 = $this->buildAddress('Brazil', 'São Paulo', 'Bar st.', '654321');
$user2 = $this->buildUser('Guilherme', 'guilhermeblanco', 'freak', $address2); $user2 = $this->buildUser('Guilherme', 'guilhermeblanco', 'freak', $address2);
$address3 = $this->buildAddress('USA', 'Nashville', 'Woo st.', '321654'); $address3 = $this->buildAddress('USA', 'Nashville', 'Woo st.', '321654');
$user3 = $this->buildUser('Jonathan', 'jwage', 'dev', $address3); $user3 = $this->buildUser('Jonathan', 'jwage', 'dev', $address3);
unset($address1); unset($address1);
unset($address2); unset($address2);
unset($address3); unset($address3);
$this->_em->clear(); $this->_em->clear();
$repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress'); $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress');
$addresses = $repository->findBy(array('user' => array($user1->getId(), $user2->getId()))); $addresses = $repository->findBy(array('user' => array($user1->getId(), $user2->getId())));
$this->assertEquals(2, count($addresses)); $this->assertEquals(2, count($addresses));
$this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress',$addresses[0]); $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress',$addresses[0]);
} }
@ -158,22 +160,22 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
{ {
$address1 = $this->buildAddress('Germany', 'Berlim', 'Foo st.', '123456'); $address1 = $this->buildAddress('Germany', 'Berlim', 'Foo st.', '123456');
$user1 = $this->buildUser('Benjamin', 'beberlei', 'dev', $address1); $user1 = $this->buildUser('Benjamin', 'beberlei', 'dev', $address1);
$address2 = $this->buildAddress('Brazil', 'São Paulo', 'Bar st.', '654321'); $address2 = $this->buildAddress('Brazil', 'São Paulo', 'Bar st.', '654321');
$user2 = $this->buildUser('Guilherme', 'guilhermeblanco', 'freak', $address2); $user2 = $this->buildUser('Guilherme', 'guilhermeblanco', 'freak', $address2);
$address3 = $this->buildAddress('USA', 'Nashville', 'Woo st.', '321654'); $address3 = $this->buildAddress('USA', 'Nashville', 'Woo st.', '321654');
$user3 = $this->buildUser('Jonathan', 'jwage', 'dev', $address3); $user3 = $this->buildUser('Jonathan', 'jwage', 'dev', $address3);
unset($address1); unset($address1);
unset($address2); unset($address2);
unset($address3); unset($address3);
$this->_em->clear(); $this->_em->clear();
$repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress'); $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress');
$addresses = $repository->findBy(array('user' => array($user1, $user2))); $addresses = $repository->findBy(array('user' => array($user1, $user2)));
$this->assertEquals(2, count($addresses)); $this->assertEquals(2, count($addresses));
$this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress',$addresses[0]); $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress',$addresses[0]);
} }
@ -189,7 +191,7 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals('Guilherme', $users[0]->name); $this->assertEquals('Guilherme', $users[0]->name);
$this->assertEquals('dev', $users[0]->status); $this->assertEquals('dev', $users[0]->status);
} }
public function testFindAll() public function testFindAll()
{ {
$user1Id = $this->loadFixture(); $user1Id = $this->loadFixture();
@ -280,7 +282,7 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$userId = $user->id; $userId = $user->id;
$this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $userId); $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $userId);
$this->setExpectedException('Doctrine\ORM\OptimisticLockException'); $this->setExpectedException('Doctrine\ORM\OptimisticLockException');
$this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $userId, \Doctrine\DBAL\LockMode::OPTIMISTIC); $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $userId, \Doctrine\DBAL\LockMode::OPTIMISTIC);
} }
@ -423,7 +425,7 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
public function testFindByLimitOffset() public function testFindByLimitOffset()
{ {
$this->loadFixture(); $this->loadFixture();
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
$users1 = $repos->findBy(array(), null, 1, 0); $users1 = $repos->findBy(array(), null, 1, 0);
@ -451,8 +453,8 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertSame($usersAsc[0], $usersDesc[2]); $this->assertSame($usersAsc[0], $usersDesc[2]);
$this->assertSame($usersAsc[2], $usersDesc[0]); $this->assertSame($usersAsc[2], $usersDesc[0]);
} }
/** /**
* @group DDC-753 * @group DDC-753
*/ */
@ -465,19 +467,19 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$repos = $this->_em->getRepository('Doctrine\Tests\Models\DDC753\DDC753EntityWithDefaultCustomRepository'); $repos = $this->_em->getRepository('Doctrine\Tests\Models\DDC753\DDC753EntityWithDefaultCustomRepository');
$this->assertInstanceOf("Doctrine\Tests\Models\DDC753\DDC753DefaultRepository", $repos); $this->assertInstanceOf("Doctrine\Tests\Models\DDC753\DDC753DefaultRepository", $repos);
$this->assertTrue($repos->isDefaultRepository()); $this->assertTrue($repos->isDefaultRepository());
$repos = $this->_em->getRepository('Doctrine\Tests\Models\DDC753\DDC753EntityWithCustomRepository'); $repos = $this->_em->getRepository('Doctrine\Tests\Models\DDC753\DDC753EntityWithCustomRepository');
$this->assertInstanceOf("Doctrine\Tests\Models\DDC753\DDC753CustomRepository", $repos); $this->assertInstanceOf("Doctrine\Tests\Models\DDC753\DDC753CustomRepository", $repos);
$this->assertTrue($repos->isCustomRepository()); $this->assertTrue($repos->isCustomRepository());
$this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\Tests\Models\DDC753\DDC753DefaultRepository"); $this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\Tests\Models\DDC753\DDC753DefaultRepository");
$this->_em->getConfiguration()->setDefaultRepositoryClassName("Doctrine\ORM\EntityRepository"); $this->_em->getConfiguration()->setDefaultRepositoryClassName("Doctrine\ORM\EntityRepository");
$this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\ORM\EntityRepository"); $this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\ORM\EntityRepository");
} }
/** /**
* @group DDC-753 * @group DDC-753
* @expectedException Doctrine\ORM\ORMException * @expectedException Doctrine\ORM\ORMException
@ -488,6 +490,6 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\ORM\EntityRepository"); $this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\ORM\EntityRepository");
$this->_em->getConfiguration()->setDefaultRepositoryClassName("Doctrine\Tests\Models\DDC753\DDC753InvalidRepository"); $this->_em->getConfiguration()->setDefaultRepositoryClassName("Doctrine\Tests\Models\DDC753\DDC753InvalidRepository");
} }
} }

View File

@ -29,7 +29,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup'); $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup');
$class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; $class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY;
$this->loadFixture(); $this->loadFixture();
} }
@ -137,9 +137,9 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
{ {
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
$this->assertFalse($user->groups->isInitialized(), "Pre-Condition: Collection is not initialized."); $this->assertFalse($user->groups->isInitialized(), "Pre-Condition: Collection is not initialized.");
$queryCount = $this->getCurrentQueryCount(); $queryCount = $this->getCurrentQueryCount();
$someGroups = $user->groups->slice(0, 2); $someGroups = $user->groups->slice(0, 2);
$this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsGroup', $someGroups); $this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsGroup', $someGroups);
@ -225,7 +225,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertFalse($user->articles->isInitialized(), "Pre-Condition: Collection is not initialized."); $this->assertFalse($user->articles->isInitialized(), "Pre-Condition: Collection is not initialized.");
$article = $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId); $article = $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId);
$queryCount = $this->getCurrentQueryCount(); $queryCount = $this->getCurrentQueryCount();
$this->assertTrue($user->articles->contains($article)); $this->assertTrue($user->articles->contains($article));
$this->assertFalse($user->articles->isInitialized(), "Post-Condition: Collection is not initialized."); $this->assertFalse($user->articles->isInitialized(), "Post-Condition: Collection is not initialized.");
@ -304,6 +304,49 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized."); $this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
} }
/**
* @group DDC-1399
*/
public function testCountAfterAddThenFlush()
{
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
$newGroup = new \Doctrine\Tests\Models\CMS\CmsGroup();
$newGroup->name = "Test4";
$user->addGroup($newGroup);
$this->_em->persist($newGroup);
$this->assertFalse($user->groups->isInitialized());
$this->assertEquals(4, count($user->groups));
$this->assertFalse($user->groups->isInitialized());
$this->_em->flush();
$this->assertEquals(4, count($user->groups));
}
/**
* @group DDC-1462
*/
public function testSliceOnDirtyCollection()
{
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
/* @var $user CmsUser */
$newGroup = new \Doctrine\Tests\Models\CMS\CmsGroup();
$newGroup->name = "Test4";
$user->addGroup($newGroup);
$this->_em->persist($newGroup);
$qc = $this->getCurrentQueryCount();
$groups = $user->groups->slice(0, 10);
$this->assertEquals(4, count($groups));
$this->assertEquals($qc + 1, $this->getCurrentQueryCount());
}
private function loadFixture() private function loadFixture()
{ {
$user1 = new \Doctrine\Tests\Models\CMS\CmsUser(); $user1 = new \Doctrine\Tests\Models\CMS\CmsUser();
@ -364,7 +407,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->persist($article1); $this->_em->persist($article1);
$this->_em->persist($article2); $this->_em->persist($article2);
$this->_em->flush(); $this->_em->flush();
$this->_em->clear(); $this->_em->clear();

View File

@ -43,6 +43,29 @@ class LifecycleCallbackTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals('changed from preUpdate callback!', $result[0]->value); $this->assertEquals('changed from preUpdate callback!', $result[0]->value);
} }
public function testPreFlushCallbacksAreInvoked()
{
$entity = new LifecycleCallbackTestEntity;
$entity->value = 'hello';
$this->_em->persist($entity);
$this->_em->flush();
$this->assertTrue($entity->prePersistCallbackInvoked);
$this->assertTrue($entity->preFlushCallbackInvoked);
$entity->preFlushCallbackInvoked = false;
$this->_em->flush();
$this->assertTrue($entity->preFlushCallbackInvoked);
$entity->value = 'bye';
$entity->preFlushCallbackInvoked = false;
$this->_em->flush();
$this->assertTrue($entity->preFlushCallbackInvoked);
}
public function testChangesDontGetLost() public function testChangesDontGetLost()
{ {
$user = new LifecycleCallbackTestUser; $user = new LifecycleCallbackTestUser;
@ -190,6 +213,8 @@ class LifecycleCallbackTestEntity
public $postPersistCallbackInvoked = false; public $postPersistCallbackInvoked = false;
public $postLoadCallbackInvoked = false; public $postLoadCallbackInvoked = false;
public $preFlushCallbackInvoked = false;
/** /**
* @Id @Column(type="integer") * @Id @Column(type="integer")
* @GeneratedValue(strategy="AUTO") * @GeneratedValue(strategy="AUTO")
@ -233,6 +258,11 @@ class LifecycleCallbackTestEntity
public function doStuffOnPreUpdate() { public function doStuffOnPreUpdate() {
$this->value = 'changed from preUpdate callback!'; $this->value = 'changed from preUpdate callback!';
} }
/** @PreFlush */
public function doStuffOnPreFlush() {
$this->preFlushCallbackInvoked = true;
}
} }
/** /**

View File

@ -39,6 +39,7 @@ class MappedSuperclassTest extends \Doctrine\Tests\OrmFunctionalTestCase
$cleanFile = $this->_em->find(get_class($file), $file->getId()); $cleanFile = $this->_em->find(get_class($file), $file->getId());
$this->assertInstanceOf('Doctrine\Tests\Models\DirectoryTree\Directory', $cleanFile->getParent()); $this->assertInstanceOf('Doctrine\Tests\Models\DirectoryTree\Directory', $cleanFile->getParent());
$this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $cleanFile->getParent());
$this->assertEquals($directory->getId(), $cleanFile->getParent()->getId()); $this->assertEquals($directory->getId(), $cleanFile->getParent()->getId());
$this->assertInstanceOf('Doctrine\Tests\Models\DirectoryTree\Directory', $cleanFile->getParent()->getParent()); $this->assertInstanceOf('Doctrine\Tests\Models\DirectoryTree\Directory', $cleanFile->getParent()->getParent());
$this->assertEquals($root->getId(), $cleanFile->getParent()->getParent()->getId()); $this->assertEquals($root->getId(), $cleanFile->getParent()->getParent()->getId());

View File

@ -35,7 +35,7 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$user->status = 'dev'; $user->status = 'dev';
$this->_em->persist($user); $this->_em->persist($user);
$this->_em->flush(); $this->_em->flush();
$this->_em->clear(); $this->_em->clear();
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
@ -94,24 +94,24 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals($addr->street, $addresses[0]->street); $this->assertEquals($addr->street, $addresses[0]->street);
$this->assertTrue($addresses[0]->user instanceof CmsUser); $this->assertTrue($addresses[0]->user instanceof CmsUser);
} }
public function testJoinedOneToManyNativeQuery() public function testJoinedOneToManyNativeQuery()
{ {
$user = new CmsUser; $user = new CmsUser;
$user->name = 'Roman'; $user->name = 'Roman';
$user->username = 'romanb'; $user->username = 'romanb';
$user->status = 'dev'; $user->status = 'dev';
$phone = new CmsPhonenumber; $phone = new CmsPhonenumber;
$phone->phonenumber = 424242; $phone->phonenumber = 424242;
$user->addPhonenumber($phone); $user->addPhonenumber($phone);
$this->_em->persist($user); $this->_em->persist($user);
$this->_em->flush(); $this->_em->flush();
$this->_em->clear(); $this->_em->clear();
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$rsm->addFieldResult('u', $this->platform->getSQLResultCasing('id'), 'id'); $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('id'), 'id');
@ -119,7 +119,7 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$rsm->addFieldResult('u', $this->platform->getSQLResultCasing('status'), 'status'); $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('status'), 'status');
$rsm->addJoinedEntityResult('Doctrine\Tests\Models\CMS\CmsPhonenumber', 'p', 'u', 'phonenumbers'); $rsm->addJoinedEntityResult('Doctrine\Tests\Models\CMS\CmsPhonenumber', 'p', 'u', 'phonenumbers');
$rsm->addFieldResult('p', $this->platform->getSQLResultCasing('phonenumber'), 'phonenumber'); $rsm->addFieldResult('p', $this->platform->getSQLResultCasing('phonenumber'), 'phonenumber');
$query = $this->_em->createNativeQuery('SELECT id, name, status, phonenumber FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username = ?', $rsm); $query = $this->_em->createNativeQuery('SELECT id, name, status, phonenumber FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username = ?', $rsm);
$query->setParameter(1, 'romanb'); $query->setParameter(1, 'romanb');
@ -133,30 +133,30 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$phones = $users[0]->getPhonenumbers(); $phones = $users[0]->getPhonenumbers();
$this->assertEquals(424242, $phones[0]->phonenumber); $this->assertEquals(424242, $phones[0]->phonenumber);
$this->assertTrue($phones[0]->getUser() === $users[0]); $this->assertTrue($phones[0]->getUser() === $users[0]);
} }
public function testJoinedOneToOneNativeQuery() public function testJoinedOneToOneNativeQuery()
{ {
$user = new CmsUser; $user = new CmsUser;
$user->name = 'Roman'; $user->name = 'Roman';
$user->username = 'romanb'; $user->username = 'romanb';
$user->status = 'dev'; $user->status = 'dev';
$addr = new CmsAddress; $addr = new CmsAddress;
$addr->country = 'germany'; $addr->country = 'germany';
$addr->zip = 10827; $addr->zip = 10827;
$addr->city = 'Berlin'; $addr->city = 'Berlin';
$user->setAddress($addr); $user->setAddress($addr);
$this->_em->persist($user); $this->_em->persist($user);
$this->_em->flush(); $this->_em->flush();
$this->_em->clear(); $this->_em->clear();
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$rsm->addFieldResult('u', $this->platform->getSQLResultCasing('id'), 'id'); $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('id'), 'id');
@ -167,12 +167,12 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$rsm->addFieldResult('a', $this->platform->getSQLResultCasing('country'), 'country'); $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('country'), 'country');
$rsm->addFieldResult('a', $this->platform->getSQLResultCasing('zip'), 'zip'); $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('zip'), 'zip');
$rsm->addFieldResult('a', $this->platform->getSQLResultCasing('city'), 'city'); $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('city'), 'city');
$query = $this->_em->createNativeQuery('SELECT u.id, u.name, u.status, a.id AS a_id, a.country, a.zip, a.city FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?', $rsm); $query = $this->_em->createNativeQuery('SELECT u.id, u.name, u.status, a.id AS a_id, a.country, a.zip, a.city FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?', $rsm);
$query->setParameter(1, 'romanb'); $query->setParameter(1, 'romanb');
$users = $query->getResult(); $users = $query->getResult();
$this->assertEquals(1, count($users)); $this->assertEquals(1, count($users));
$this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[0]); $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[0]);
$this->assertEquals('Roman', $users[0]->name); $this->assertEquals('Roman', $users[0]->name);

View File

@ -73,7 +73,14 @@ class OneToManyUnidirectionalAssociationTest extends \Doctrine\Tests\OrmFunction
$this->_em->persist($routeA); $this->_em->persist($routeA);
$this->_em->persist($routeB); $this->_em->persist($routeB);
$this->setExpectedException('Exception'); // depends on the underyling Database Driver $exceptionThrown = false;
$this->_em->flush(); // Exception try {
// exception depending on the underyling Database Driver
$this->_em->flush();
} catch(\Exception $e) {
$exceptionThrown = true;
}
$this->assertTrue($exceptionThrown, "The underlying database driver throws an exception.");
} }
} }

View File

@ -19,6 +19,7 @@ class OneToOneEagerLoadingTest extends \Doctrine\Tests\OrmFunctionalTestCase
$schemaTool->createSchema(array( $schemaTool->createSchema(array(
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Train'), $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Train'),
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\TrainDriver'), $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\TrainDriver'),
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\TrainOwner'),
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Waggon'), $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Waggon'),
)); ));
} catch(\Exception $e) {} } catch(\Exception $e) {}
@ -26,7 +27,7 @@ class OneToOneEagerLoadingTest extends \Doctrine\Tests\OrmFunctionalTestCase
public function testEagerLoadOneToOneOwningSide() public function testEagerLoadOneToOneOwningSide()
{ {
$train = new Train(); $train = new Train(new TrainOwner("Alexander"));
$driver = new TrainDriver("Benjamin"); $driver = new TrainDriver("Benjamin");
$waggon = new Waggon(); $waggon = new Waggon();
@ -48,7 +49,7 @@ class OneToOneEagerLoadingTest extends \Doctrine\Tests\OrmFunctionalTestCase
public function testEagerLoadOneToOneNullOwningSide() public function testEagerLoadOneToOneNullOwningSide()
{ {
$train = new Train(); $train = new Train(new TrainOwner("Alexander"));
$this->_em->persist($train); // cascades $this->_em->persist($train); // cascades
$this->_em->flush(); $this->_em->flush();
@ -65,9 +66,8 @@ class OneToOneEagerLoadingTest extends \Doctrine\Tests\OrmFunctionalTestCase
public function testEagerLoadOneToOneInverseSide() public function testEagerLoadOneToOneInverseSide()
{ {
$train = new Train(); $owner = new TrainOwner("Alexander");
$driver = new TrainDriver("Benjamin"); $train = new Train($owner);
$train->setDriver($driver);
$this->_em->persist($train); // cascades $this->_em->persist($train); // cascades
$this->_em->flush(); $this->_em->flush();
@ -75,9 +75,9 @@ class OneToOneEagerLoadingTest extends \Doctrine\Tests\OrmFunctionalTestCase
$sqlCount = count($this->_sqlLoggerStack->queries); $sqlCount = count($this->_sqlLoggerStack->queries);
$driver = $this->_em->find(get_class($driver), $driver->id); $driver = $this->_em->find(get_class($owner), $owner->id);
$this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $driver->train); $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $owner->train);
$this->assertNotNull($driver->train); $this->assertNotNull($owner->train);
$this->assertEquals($sqlCount + 1, count($this->_sqlLoggerStack->queries)); $this->assertEquals($sqlCount + 1, count($this->_sqlLoggerStack->queries));
} }
@ -103,7 +103,7 @@ class OneToOneEagerLoadingTest extends \Doctrine\Tests\OrmFunctionalTestCase
public function testEagerLoadManyToOne() public function testEagerLoadManyToOne()
{ {
$train = new Train(); $train = new Train(new TrainOwner("Alexander"));
$waggon = new Waggon(); $waggon = new Waggon();
$train->addWaggon($waggon); $train->addWaggon($waggon);
@ -115,6 +115,59 @@ class OneToOneEagerLoadingTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $waggon->train); $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $waggon->train);
$this->assertNotNull($waggon->train); $this->assertNotNull($waggon->train);
} }
public function testEagerLoadWithNullableColumnsGeneratesLeftJoinOnBothSides()
{
$train = new Train(new TrainOwner("Alexander"));
$driver = new TrainDriver("Benjamin");
$train->setDriver($driver);
$this->_em->persist($train);
$this->_em->flush();
$this->_em->clear();
$train = $this->_em->find(get_class($train), $train->id);
$this->assertEquals(
"SELECT t0.id AS id1, t0.driver_id AS driver_id2, t3.id AS id4, t3.name AS name5, t0.owner_id AS owner_id6, t7.id AS id8, t7.name AS name9 FROM Train t0 LEFT JOIN TrainDriver t3 ON t0.driver_id = t3.id INNER JOIN TrainOwner t7 ON t0.owner_id = t7.id WHERE t0.id = ?",
$this->_sqlLoggerStack->queries[$this->_sqlLoggerStack->currentQuery]['sql']
);
$this->_em->clear();
$driver = $this->_em->find(get_class($driver), $driver->id);
$this->assertEquals(
"SELECT t0.id AS id1, t0.name AS name2, t3.id AS id4, t3.driver_id AS driver_id5, t3.owner_id AS owner_id6 FROM TrainOwner t0 LEFT JOIN Train t3 ON t3.owner_id = t0.id WHERE t0.id IN (?)",
$this->_sqlLoggerStack->queries[$this->_sqlLoggerStack->currentQuery]['sql']
);
}
public function testEagerLoadWithNonNullableColumnsGeneratesInnerJoinOnOwningSide()
{
$waggon = new Waggon();
$this->_em->persist($waggon);
$this->_em->flush();
$this->_em->clear();
$waggon = $this->_em->find(get_class($waggon), $waggon->id);
$this->assertEquals(
"SELECT t0.id AS id1, t0.train_id AS train_id2, t3.id AS id4, t3.driver_id AS driver_id5, t3.owner_id AS owner_id6 FROM Waggon t0 INNER JOIN Train t3 ON t0.train_id = t3.id WHERE t0.id = ?",
$this->_sqlLoggerStack->queries[$this->_sqlLoggerStack->currentQuery]['sql']
);
}
public function testEagerLoadWithNonNullableColumnsGeneratesLeftJoinOnNonOwningSide()
{
$owner = new TrainOwner('Alexander');
$train = new Train($owner);
$this->_em->persist($train);
$this->_em->flush();
$this->_em->clear();
$waggon = $this->_em->find(get_class($owner), $owner->id);
$this->assertEquals(
"SELECT t0.id AS id1, t0.name AS name2, t3.id AS id4, t3.driver_id AS driver_id5, t3.owner_id AS owner_id6 FROM TrainOwner t0 LEFT JOIN Train t3 ON t3.owner_id = t0.id WHERE t0.id = ?",
$this->_sqlLoggerStack->queries[$this->_sqlLoggerStack->currentQuery]['sql']
);
}
} }
/** /**
@ -130,16 +183,23 @@ class Train
/** /**
* Owning side * Owning side
* @OneToOne(targetEntity="TrainDriver", inversedBy="train", fetch="EAGER", cascade={"persist"}) * @OneToOne(targetEntity="TrainDriver", inversedBy="train", fetch="EAGER", cascade={"persist"})
* @JoinColumn(nullable=true)
*/ */
public $driver; public $driver;
/**
* Owning side
* @OneToOne(targetEntity="TrainOwner", inversedBy="train", fetch="EAGER", cascade={"persist"})
*/
public $owner;
/** /**
* @oneToMany(targetEntity="Waggon", mappedBy="train", cascade={"persist"}) * @oneToMany(targetEntity="Waggon", mappedBy="train", cascade={"persist"})
*/ */
public $waggons; public $waggons;
public function __construct() public function __construct(TrainOwner $owner)
{ {
$this->waggons = new \Doctrine\Common\Collections\ArrayCollection(); $this->waggons = new \Doctrine\Common\Collections\ArrayCollection();
$this->setOwner($owner);
} }
public function setDriver(TrainDriver $driver) public function setDriver(TrainDriver $driver)
@ -148,6 +208,12 @@ class Train
$driver->setTrain($this); $driver->setTrain($this);
} }
public function setOwner(TrainOwner $owner)
{
$this->owner = $owner;
$owner->setTrain($this);
}
public function addWaggon(Waggon $w) public function addWaggon(Waggon $w)
{ {
$w->setTrain($this); $w->setTrain($this);
@ -181,6 +247,32 @@ class TrainDriver
} }
} }
/**
* @Entity
*/
class TrainOwner
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
/** @column(type="string") */
public $name;
/**
* Inverse side
* @OneToOne(targetEntity="Train", mappedBy="owner", fetch="EAGER")
*/
public $train;
public function __construct($name)
{
$this->name = $name;
}
public function setTrain(Train $t)
{
$this->train = $t;
}
}
/** /**
* @Entity * @Entity
*/ */
@ -195,4 +287,4 @@ class Waggon
{ {
$this->train = $train; $this->train = $train;
} }
} }

View File

@ -27,14 +27,14 @@ class ReadOnlyTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->flush(); $this->_em->flush();
$readOnly->name = "Test2"; $readOnly->name = "Test2";
$readOnly->number = 4321; $readOnly->numericValue = 4321;
$this->_em->flush(); $this->_em->flush();
$this->_em->clear(); $this->_em->clear();
$dbReadOnly = $this->_em->find('Doctrine\Tests\ORM\Functional\ReadOnlyEntity', $readOnly->id); $dbReadOnly = $this->_em->find('Doctrine\Tests\ORM\Functional\ReadOnlyEntity', $readOnly->id);
$this->assertEquals("Test1", $dbReadOnly->name); $this->assertEquals("Test1", $dbReadOnly->name);
$this->assertEquals(1234, $dbReadOnly->number); $this->assertEquals(1234, $dbReadOnly->numericValue);
} }
} }
@ -51,11 +51,11 @@ class ReadOnlyEntity
/** @column(type="string") */ /** @column(type="string") */
public $name; public $name;
/** @Column(type="integer") */ /** @Column(type="integer") */
public $number; public $numericValue;
public function __construct($name, $number) public function __construct($name, $number)
{ {
$this->name = $name; $this->name = $name;
$this->number = $number; $this->numericValue = $number;
} }
} }

View File

@ -5,6 +5,7 @@ namespace Doctrine\Tests\ORM\Functional;
use Doctrine\ORM\Proxy\ProxyFactory; use Doctrine\ORM\Proxy\ProxyFactory;
use Doctrine\ORM\Proxy\ProxyClassGenerator; use Doctrine\ORM\Proxy\ProxyClassGenerator;
use Doctrine\Tests\Models\ECommerce\ECommerceProduct; use Doctrine\Tests\Models\ECommerce\ECommerceProduct;
use Doctrine\Tests\Models\ECommerce\ECommerceShipping;
require_once __DIR__ . '/../../TestInit.php'; require_once __DIR__ . '/../../TestInit.php';
@ -97,7 +98,7 @@ class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertTrue($clone->isCloned); $this->assertTrue($clone->isCloned);
$this->assertFalse($entity->isCloned); $this->assertFalse($entity->isCloned);
} }
/** /**
* @group DDC-733 * @group DDC-733
*/ */
@ -107,12 +108,12 @@ class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase
/* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */ /* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */
$entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id); $entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id);
$this->assertFalse($entity->__isInitialized__, "Pre-Condition: Object is unitialized proxy."); $this->assertFalse($entity->__isInitialized__, "Pre-Condition: Object is unitialized proxy.");
$this->_em->getUnitOfWork()->initializeObject($entity); $this->_em->getUnitOfWork()->initializeObject($entity);
$this->assertTrue($entity->__isInitialized__, "Should be initialized after called UnitOfWork::initializeObject()"); $this->assertTrue($entity->__isInitialized__, "Should be initialized after called UnitOfWork::initializeObject()");
} }
/** /**
* @group DDC-1163 * @group DDC-1163
*/ */
@ -123,10 +124,10 @@ class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase
/* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */ /* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */
$entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id); $entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id);
$entity->setName('Doctrine 2 Cookbook'); $entity->setName('Doctrine 2 Cookbook');
$this->_em->flush(); $this->_em->flush();
$this->_em->clear(); $this->_em->clear();
$entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id); $entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id);
$this->assertEquals('Doctrine 2 Cookbook', $entity->getName()); $this->assertEquals('Doctrine 2 Cookbook', $entity->getName());
} }
@ -160,6 +161,29 @@ class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertFalse($entity->__isInitialized__, "Getting the identifier doesn't initialize the proxy."); $this->assertFalse($entity->__isInitialized__, "Getting the identifier doesn't initialize the proxy.");
} }
public function testDoNotInitializeProxyOnGettingTheIdentifierAndReturnTheRightType()
{
$product = new ECommerceProduct();
$product->setName('Doctrine Cookbook');
$shipping = new ECommerceShipping();
$shipping->setDays(1);
$product->setShipping($shipping);
$this->_em->persist($product);
$this->_em->flush();
$this->_em->clear();
$id = $shipping->getId();
$product = $this->_em->getRepository('Doctrine\Tests\Models\ECommerce\ECommerceProduct')->find($product->getId());
$entity = $product->getShipping();
$this->assertFalse($entity->__isInitialized__, "Pre-Condition: Object is unitialized proxy.");
$this->assertEquals($id, $entity->getId());
$this->assertSame($id, $entity->getId(), "Check that the id's are the same value, and type.");
$this->assertFalse($entity->__isInitialized__, "Getting the identifier doesn't initialize the proxy.");
}
public function testInitializeProxyOnGettingSomethingOtherThanTheIdentifier() public function testInitializeProxyOnGettingSomethingOtherThanTheIdentifier()
{ {
$id = $this->createProduct(); $id = $this->createProduct();

View File

@ -21,7 +21,7 @@ class PostgreSqlSchemaToolTest extends \Doctrine\Tests\OrmFunctionalTestCase
$address = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); $address = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress');
$this->assertEquals(1, $address->sequenceGeneratorDefinition['allocationSize']); $this->assertEquals(1, $address->sequenceGeneratorDefinition['allocationSize']);
} }
public function testGetCreateSchemaSql() public function testGetCreateSchemaSql()
{ {
$classes = array( $classes = array(
@ -32,26 +32,30 @@ class PostgreSqlSchemaToolTest extends \Doctrine\Tests\OrmFunctionalTestCase
$tool = new SchemaTool($this->_em); $tool = new SchemaTool($this->_em);
$sql = $tool->getCreateSchemaSql($classes); $sql = $tool->getCreateSchemaSql($classes);
$sqlCount = count($sql);
$this->assertEquals("CREATE TABLE cms_addresses (id INT NOT NULL, user_id INT DEFAULT NULL, country VARCHAR(50) NOT NULL, zip VARCHAR(50) NOT NULL, city VARCHAR(50) NOT NULL, PRIMARY KEY(id))", $sql[0]);
$this->assertEquals("CREATE UNIQUE INDEX UNIQ_ACAC157BA76ED395 ON cms_addresses (user_id)", $sql[1]); $this->assertEquals("CREATE TABLE cms_addresses (id INT NOT NULL, user_id INT DEFAULT NULL, country VARCHAR(50) NOT NULL, zip VARCHAR(50) NOT NULL, city VARCHAR(50) NOT NULL, PRIMARY KEY(id))", array_shift($sql));
$this->assertEquals("CREATE TABLE cms_users (id INT NOT NULL, status VARCHAR(50) NOT NULL, username VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id))", $sql[2]); $this->assertEquals("CREATE UNIQUE INDEX UNIQ_ACAC157BA76ED395 ON cms_addresses (user_id)", array_shift($sql));
$this->assertEquals("CREATE UNIQUE INDEX UNIQ_3AF03EC5F85E0677 ON cms_users (username)", $sql[3]); $this->assertEquals("CREATE TABLE cms_users (id INT NOT NULL, email_id INT DEFAULT NULL, status VARCHAR(50) DEFAULT NULL, username VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id))", array_shift($sql));
$this->assertEquals("CREATE TABLE cms_users_groups (user_id INT NOT NULL, group_id INT NOT NULL, PRIMARY KEY(user_id, group_id))", $sql[4]); $this->assertEquals("CREATE UNIQUE INDEX UNIQ_3AF03EC5F85E0677 ON cms_users (username)", array_shift($sql));
$this->assertEquals("CREATE INDEX IDX_7EA9409AA76ED395 ON cms_users_groups (user_id)", $sql[5]); $this->assertEquals("CREATE UNIQUE INDEX UNIQ_3AF03EC5A832C1C9 ON cms_users (email_id)", array_shift($sql));
$this->assertEquals("CREATE INDEX IDX_7EA9409AFE54D947 ON cms_users_groups (group_id)", $sql[6]); $this->assertEquals("CREATE TABLE cms_users_groups (user_id INT NOT NULL, group_id INT NOT NULL, PRIMARY KEY(user_id, group_id))", array_shift($sql));
$this->assertEquals("CREATE TABLE cms_phonenumbers (phonenumber VARCHAR(50) NOT NULL, user_id INT DEFAULT NULL, PRIMARY KEY(phonenumber))", $sql[7]); $this->assertEquals("CREATE INDEX IDX_7EA9409AA76ED395 ON cms_users_groups (user_id)", array_shift($sql));
$this->assertEquals("CREATE INDEX IDX_F21F790FA76ED395 ON cms_phonenumbers (user_id)", $sql[8]); $this->assertEquals("CREATE INDEX IDX_7EA9409AFE54D947 ON cms_users_groups (group_id)", array_shift($sql));
$this->assertEquals("CREATE SEQUENCE cms_addresses_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[9]); $this->assertEquals("CREATE TABLE cms_phonenumbers (phonenumber VARCHAR(50) NOT NULL, user_id INT DEFAULT NULL, PRIMARY KEY(phonenumber))", array_shift($sql));
$this->assertEquals("CREATE SEQUENCE cms_users_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[10]); $this->assertEquals("CREATE INDEX IDX_F21F790FA76ED395 ON cms_phonenumbers (user_id)", array_shift($sql));
$this->assertEquals("ALTER TABLE cms_addresses ADD FOREIGN KEY (user_id) REFERENCES cms_users(id) NOT DEFERRABLE INITIALLY IMMEDIATE", $sql[11]); $this->assertEquals("CREATE SEQUENCE cms_addresses_id_seq INCREMENT BY 1 MINVALUE 1 START 1", array_shift($sql));
$this->assertEquals("ALTER TABLE cms_users_groups ADD FOREIGN KEY (user_id) REFERENCES cms_users(id) NOT DEFERRABLE INITIALLY IMMEDIATE", $sql[12]); $this->assertEquals("CREATE SEQUENCE cms_users_id_seq INCREMENT BY 1 MINVALUE 1 START 1", array_shift($sql));
$this->assertEquals("ALTER TABLE cms_users_groups ADD FOREIGN KEY (group_id) REFERENCES cms_groups(id) NOT DEFERRABLE INITIALLY IMMEDIATE", $sql[13]); $this->assertEquals("ALTER TABLE cms_addresses ADD CONSTRAINT FK_ACAC157BA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id) NOT DEFERRABLE INITIALLY IMMEDIATE", array_shift($sql));
$this->assertEquals("ALTER TABLE cms_phonenumbers ADD FOREIGN KEY (user_id) REFERENCES cms_users(id) NOT DEFERRABLE INITIALLY IMMEDIATE", $sql[14]); $this->assertEquals("ALTER TABLE cms_users ADD CONSTRAINT FK_3AF03EC5A832C1C9 FOREIGN KEY (email_id) REFERENCES cms_emails (id) NOT DEFERRABLE INITIALLY IMMEDIATE", array_shift($sql));
$this->assertEquals("ALTER TABLE cms_users_groups ADD CONSTRAINT FK_7EA9409AA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id) NOT DEFERRABLE INITIALLY IMMEDIATE", array_shift($sql));
$this->assertEquals(count($sql), 15); $this->assertEquals("ALTER TABLE cms_users_groups ADD CONSTRAINT FK_7EA9409AFE54D947 FOREIGN KEY (group_id) REFERENCES cms_groups (id) NOT DEFERRABLE INITIALLY IMMEDIATE", array_shift($sql));
$this->assertEquals("ALTER TABLE cms_phonenumbers ADD CONSTRAINT FK_F21F790FA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id) NOT DEFERRABLE INITIALLY IMMEDIATE", array_shift($sql));
$this->assertEquals(array(), $sql, "SQL Array should be empty now.");
$this->assertEquals(17, $sqlCount, "Total of 17 queries should be executed");
} }
public function testGetCreateSchemaSql2() public function testGetCreateSchemaSql2()
{ {
$classes = array( $classes = array(
@ -62,11 +66,11 @@ class PostgreSqlSchemaToolTest extends \Doctrine\Tests\OrmFunctionalTestCase
$sql = $tool->getCreateSchemaSql($classes); $sql = $tool->getCreateSchemaSql($classes);
$this->assertEquals(2, count($sql)); $this->assertEquals(2, count($sql));
$this->assertEquals('CREATE TABLE decimal_model (id INT NOT NULL, "decimal" NUMERIC(5, 2) NOT NULL, "high_scale" NUMERIC(14, 4) NOT NULL, PRIMARY KEY(id))', $sql[0]); $this->assertEquals('CREATE TABLE decimal_model (id INT NOT NULL, "decimal" NUMERIC(5, 2) NOT NULL, "high_scale" NUMERIC(14, 4) NOT NULL, PRIMARY KEY(id))', $sql[0]);
$this->assertEquals("CREATE SEQUENCE decimal_model_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[1]); $this->assertEquals("CREATE SEQUENCE decimal_model_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[1]);
} }
public function testGetCreateSchemaSql3() public function testGetCreateSchemaSql3()
{ {
$classes = array( $classes = array(
@ -75,12 +79,12 @@ class PostgreSqlSchemaToolTest extends \Doctrine\Tests\OrmFunctionalTestCase
$tool = new SchemaTool($this->_em); $tool = new SchemaTool($this->_em);
$sql = $tool->getCreateSchemaSql($classes); $sql = $tool->getCreateSchemaSql($classes);
$this->assertEquals(2, count($sql)); $this->assertEquals(2, count($sql));
$this->assertEquals("CREATE TABLE boolean_model (id INT NOT NULL, booleanField BOOLEAN NOT NULL, PRIMARY KEY(id))", $sql[0]); $this->assertEquals("CREATE TABLE boolean_model (id INT NOT NULL, booleanField BOOLEAN NOT NULL, PRIMARY KEY(id))", $sql[0]);
$this->assertEquals("CREATE SEQUENCE boolean_model_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[1]); $this->assertEquals("CREATE SEQUENCE boolean_model_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[1]);
} }
public function testGetDropSchemaSql() public function testGetDropSchemaSql()
{ {
$classes = array( $classes = array(
@ -91,8 +95,8 @@ class PostgreSqlSchemaToolTest extends \Doctrine\Tests\OrmFunctionalTestCase
$tool = new SchemaTool($this->_em); $tool = new SchemaTool($this->_em);
$sql = $tool->getDropSchemaSQL($classes); $sql = $tool->getDropSchemaSQL($classes);
$this->assertEquals(13, count($sql)); $this->assertEquals(14, count($sql));
$dropSequenceSQLs = 0; $dropSequenceSQLs = 0;
foreach ($sql AS $stmt) { foreach ($sql AS $stmt) {
if (strpos($stmt, "DROP SEQUENCE") === 0) { if (strpos($stmt, "DROP SEQUENCE") === 0) {

View File

@ -24,7 +24,7 @@ class DDC1040Test extends \Doctrine\Tests\OrmFunctionalTestCase
$user->name = "John Galt"; $user->name = "John Galt";
$user->username = "jgalt"; $user->username = "jgalt";
$user->status = "inactive"; $user->status = "inactive";
$article = new CmsArticle(); $article = new CmsArticle();
$article->topic = "This is John Galt speaking!"; $article->topic = "This is John Galt speaking!";
$article->text = "Yadda Yadda!"; $article->text = "Yadda Yadda!";
@ -44,11 +44,10 @@ class DDC1040Test extends \Doctrine\Tests\OrmFunctionalTestCase
->setParameter('author', $user) ->setParameter('author', $user)
->getResult(); ->getResult();
$dql = "SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.topic = :topic AND a.user = :author AND a.user = :author AND a.text = :text"; $dql = "SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.topic = :topic AND a.user = :author AND a.user = :author";
$farticle = $this->_em->createQuery($dql) $farticle = $this->_em->createQuery($dql)
->setParameter('author', $user) ->setParameter('author', $user)
->setParameter('topic', 'This is John Galt speaking!') ->setParameter('topic', 'This is John Galt speaking!')
->setParameter('text', 'Yadda Yadda!')
->getSingleResult(); ->getSingleResult();
$this->assertSame($article, $farticle); $this->assertSame($article, $farticle);
@ -70,12 +69,11 @@ class DDC1040Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->persist($article); $this->_em->persist($article);
$this->_em->flush(); $this->_em->flush();
$dql = "SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.topic = ?1 AND a.user = ?2 AND a.user = ?3 AND a.text = ?4"; $dql = "SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.topic = ?1 AND a.user = ?2 AND a.user = ?3";
$farticle = $this->_em->createQuery($dql) $farticle = $this->_em->createQuery($dql)
->setParameter(1, 'This is John Galt speaking!') ->setParameter(1, 'This is John Galt speaking!')
->setParameter(2, $user) ->setParameter(2, $user)
->setParameter(3, $user) ->setParameter(3, $user)
->setParameter(4, 'Yadda Yadda!')
->getSingleResult(); ->getSingleResult();
$this->assertSame($article, $farticle); $this->assertSame($article, $farticle);

View File

@ -8,18 +8,18 @@ require_once __DIR__ . '/../../../TestInit.php';
* @group DDC-1151 * @group DDC-1151
*/ */
class DDC1151Test extends \Doctrine\Tests\OrmFunctionalTestCase class DDC1151Test extends \Doctrine\Tests\OrmFunctionalTestCase
{ {
public function testQuoteForeignKey() public function testQuoteForeignKey()
{ {
if ($this->_em->getConnection()->getDatabasePlatform()->getName() != 'postgresql') { if ($this->_em->getConnection()->getDatabasePlatform()->getName() != 'postgresql') {
$this->markTestSkipped("This test is useful for all databases, but designed only for postgresql."); $this->markTestSkipped("This test is useful for all databases, but designed only for postgresql.");
} }
$sql = $this->_schemaTool->getCreateSchemaSql(array( $sql = $this->_schemaTool->getCreateSchemaSql(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1151User'), $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1151User'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1151Group'), $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1151Group'),
)); ));
$this->assertEquals("CREATE TABLE \"User\" (id INT NOT NULL, PRIMARY KEY(id))", $sql[0]); $this->assertEquals("CREATE TABLE \"User\" (id INT NOT NULL, PRIMARY KEY(id))", $sql[0]);
$this->assertEquals("CREATE TABLE ddc1151user_ddc1151group (ddc1151user_id INT NOT NULL, ddc1151group_id INT NOT NULL, PRIMARY KEY(ddc1151user_id, ddc1151group_id))", $sql[1]); $this->assertEquals("CREATE TABLE ddc1151user_ddc1151group (ddc1151user_id INT NOT NULL, ddc1151group_id INT NOT NULL, PRIMARY KEY(ddc1151user_id, ddc1151group_id))", $sql[1]);
$this->assertEquals("CREATE INDEX IDX_88A3259AC5AD08A ON ddc1151user_ddc1151group (ddc1151user_id)", $sql[2]); $this->assertEquals("CREATE INDEX IDX_88A3259AC5AD08A ON ddc1151user_ddc1151group (ddc1151user_id)", $sql[2]);
@ -27,8 +27,8 @@ class DDC1151Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals("CREATE TABLE \"Group\" (id INT NOT NULL, PRIMARY KEY(id))", $sql[4]); $this->assertEquals("CREATE TABLE \"Group\" (id INT NOT NULL, PRIMARY KEY(id))", $sql[4]);
$this->assertEquals("CREATE SEQUENCE User_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[5]); $this->assertEquals("CREATE SEQUENCE User_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[5]);
$this->assertEquals("CREATE SEQUENCE Group_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[6]); $this->assertEquals("CREATE SEQUENCE Group_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[6]);
$this->assertEquals("ALTER TABLE ddc1151user_ddc1151group ADD FOREIGN KEY (ddc1151user_id) REFERENCES \"User\"(id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE", $sql[7]); $this->assertEquals("ALTER TABLE ddc1151user_ddc1151group ADD CONSTRAINT FK_88A3259AC5AD08A FOREIGN KEY (ddc1151user_id) REFERENCES \"User\" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE", $sql[7]);
$this->assertEquals("ALTER TABLE ddc1151user_ddc1151group ADD FOREIGN KEY (ddc1151group_id) REFERENCES \"Group\"(id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE", $sql[8]); $this->assertEquals("ALTER TABLE ddc1151user_ddc1151group ADD CONSTRAINT FK_88A32597357E0B1 FOREIGN KEY (ddc1151group_id) REFERENCES \"Group\" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE", $sql[8]);
} }
} }
@ -40,7 +40,7 @@ class DDC1151User
{ {
/** @Id @Column(type="integer") @GeneratedValue */ /** @Id @Column(type="integer") @GeneratedValue */
public $id; public $id;
/** @ManyToMany(targetEntity="DDC1151Group") */ /** @ManyToMany(targetEntity="DDC1151Group") */
public $groups; public $groups;
} }

View File

@ -209,8 +209,15 @@ class DDC117Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->article1->addTranslation('en', 'Bar'); $this->article1->addTranslation('en', 'Bar');
$this->article1->addTranslation('en', 'Baz'); $this->article1->addTranslation('en', 'Baz');
$this->setExpectedException('Exception'); $exceptionThrown = false;
$this->_em->flush(); try {
// exception depending on the underyling Database Driver
$this->_em->flush();
} catch(\Exception $e) {
$exceptionThrown = true;
}
$this->assertTrue($exceptionThrown, "The underlying database driver throws an exception.");
} }
/** /**

View File

@ -106,7 +106,7 @@ class DDC1209_3
{ {
/** /**
* @Id * @Id
* @Column(type="datetime") * @Column(type="datetime", name="somedate")
*/ */
private $date; private $date;

View File

@ -21,10 +21,10 @@ class DDC1225Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1225_TestEntity2'), $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1225_TestEntity2'),
)); ));
} catch(\PDOException $e) { } catch(\PDOException $e) {
} }
} }
public function testIssue() public function testIssue()
{ {
$qb = $this->_em->createQueryBuilder(); $qb = $this->_em->createQueryBuilder();
@ -32,10 +32,10 @@ class DDC1225Test extends \Doctrine\Tests\OrmFunctionalTestCase
->select('te1') ->select('te1')
->where('te1.testEntity2 = ?1') ->where('te1.testEntity2 = ?1')
->setParameter(1, 0); ->setParameter(1, 0);
$this->assertEquals( $this->assertEquals(
'SELECT t0_.test_entity2_id AS test_entity2_id0 FROM te1 t0_ WHERE t0_.test_entity2_id = ?', strtolower('SELECT t0_.test_entity2_id AS test_entity2_id0 FROM te1 t0_ WHERE t0_.test_entity2_id = ?'),
$qb->getQuery()->getSQL() strtolower($qb->getQuery()->getSQL())
); );
} }
} }

View File

@ -21,58 +21,58 @@ class DDC1228Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1228User'), $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1228User'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1228Profile'), $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1228Profile'),
)); ));
} catch(\PDOException $e) { } catch(\Exception $e) {
} }
} }
public function testOneToOnePersist() public function testOneToOnePersist()
{ {
$user = new DDC1228User; $user = new DDC1228User;
$profile = new DDC1228Profile(); $profile = new DDC1228Profile();
$profile->name = "Foo"; $profile->name = "Foo";
$user->profile = $profile; $user->profile = $profile;
$this->_em->persist($user); $this->_em->persist($user);
$this->_em->persist($profile); $this->_em->persist($profile);
$this->_em->flush(); $this->_em->flush();
$this->_em->clear(); $this->_em->clear();
$user = $this->_em->find(__NAMESPACE__ . '\\DDC1228User', $user->id); $user = $this->_em->find(__NAMESPACE__ . '\\DDC1228User', $user->id);
$this->assertFalse($user->getProfile()->__isInitialized__, "Proxy is not initialized"); $this->assertFalse($user->getProfile()->__isInitialized__, "Proxy is not initialized");
$user->getProfile()->setName("Bar"); $user->getProfile()->setName("Bar");
$this->assertTrue($user->getProfile()->__isInitialized__, "Proxy is not initialized"); $this->assertTrue($user->getProfile()->__isInitialized__, "Proxy is not initialized");
$this->assertEquals("Bar", $user->getProfile()->getName()); $this->assertEquals("Bar", $user->getProfile()->getName());
$this->assertEquals(array("id" => 1, "name" => "Foo"), $this->_em->getUnitOfWork()->getOriginalEntityData($user->getProfile())); $this->assertEquals(array("id" => 1, "name" => "Foo"), $this->_em->getUnitOfWork()->getOriginalEntityData($user->getProfile()));
$this->_em->flush(); $this->_em->flush();
$this->_em->clear(); $this->_em->clear();
$user = $this->_em->find(__NAMESPACE__ . '\\DDC1228User', $user->id); $user = $this->_em->find(__NAMESPACE__ . '\\DDC1228User', $user->id);
$this->assertEquals("Bar", $user->getProfile()->getName()); $this->assertEquals("Bar", $user->getProfile()->getName());
} }
public function testRefresh() public function testRefresh()
{ {
$user = new DDC1228User; $user = new DDC1228User;
$profile = new DDC1228Profile(); $profile = new DDC1228Profile();
$profile->name = "Foo"; $profile->name = "Foo";
$user->profile = $profile; $user->profile = $profile;
$this->_em->persist($user); $this->_em->persist($user);
$this->_em->persist($profile); $this->_em->persist($profile);
$this->_em->flush(); $this->_em->flush();
$this->_em->clear(); $this->_em->clear();
$user = $this->_em->getReference(__NAMESPACE__ . '\\DDC1228User', $user->id); $user = $this->_em->getReference(__NAMESPACE__ . '\\DDC1228User', $user->id);
$this->_em->refresh($user); $this->_em->refresh($user);
$user->name = "Baz"; $user->name = "Baz";
$this->_em->flush(); $this->_em->flush();
$this->_em->clear(); $this->_em->clear();
$user = $this->_em->find(__NAMESPACE__ . '\\DDC1228User', $user->id); $user = $this->_em->find(__NAMESPACE__ . '\\DDC1228User', $user->id);
$this->assertEquals("Baz", $user->name); $this->assertEquals("Baz", $user->name);
} }
@ -88,20 +88,20 @@ class DDC1228User
* @var int * @var int
*/ */
public $id; public $id;
/** /**
* @column(type="string") * @Column(type="string")
* @var string * @var string
*/ */
public $name = ''; public $name = 'Bar';
/** /**
* @OneToOne(targetEntity="DDC1228Profile") * @OneToOne(targetEntity="DDC1228Profile")
* @var Profile * @var Profile
*/ */
public $profile; public $profile;
public function getProfile() public function getProfile()
{ {
return $this->profile; return $this->profile;
} }
@ -117,13 +117,13 @@ class DDC1228Profile
* @var int * @var int
*/ */
public $id; public $id;
/** /**
* @column(type="string") * @column(type="string")
* @var string * @var string
*/ */
public $name; public $name;
public function getName() public function getName()
{ {
return $this->name; return $this->name;

View File

@ -19,49 +19,49 @@ class DDC1238Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_schemaTool->createSchema(array( $this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1238User'), $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1238User'),
)); ));
} catch(\PDOException $e) { } catch(\Exception $e) {
} }
} }
public function testIssue() public function testIssue()
{ {
$user = new DDC1238User; $user = new DDC1238User;
$user->setName("test"); $user->setName("test");
$this->_em->persist($user); $this->_em->persist($user);
$this->_em->flush(); $this->_em->flush();
$this->_em->clear(); $this->_em->clear();
$userId = $user->getId(); $userId = $user->getId();
$this->_em->clear(); $this->_em->clear();
$user = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId); $user = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId);
$this->_em->clear(); $this->_em->clear();
$userId2 = $user->getId(); $userId2 = $user->getId();
$this->assertEquals($userId, $userId2, "This proxy can still be initialized."); $this->assertEquals($userId, $userId2, "This proxy can still be initialized.");
} }
public function testIssueProxyClear() public function testIssueProxyClear()
{ {
$user = new DDC1238User; $user = new DDC1238User;
$user->setName("test"); $user->setName("test");
$this->_em->persist($user); $this->_em->persist($user);
$this->_em->flush(); $this->_em->flush();
$this->_em->clear(); $this->_em->clear();
// force proxy load, getId() doesn't work anymore // force proxy load, getId() doesn't work anymore
$user->getName(); $user->getName();
$userId = $user->getId(); $userId = $user->getId();
$this->_em->clear(); $this->_em->clear();
$user = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId); $user = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId);
$this->_em->clear(); $this->_em->clear();
$user2 = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId); $user2 = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId);
// force proxy load, getId() doesn't work anymore // force proxy load, getId() doesn't work anymore
$user->getName(); $user->getName();
$this->assertNull($user->getId(), "Now this is null, we already have a user instance of that type"); $this->assertNull($user->getId(), "Now this is null, we already have a user instance of that type");
@ -75,18 +75,18 @@ class DDC1238User
{ {
/** @Id @GeneratedValue @Column(type="integer") */ /** @Id @GeneratedValue @Column(type="integer") */
private $id; private $id;
/** /**
* @Column * @Column
* @var string * @var string
*/ */
private $name; private $name;
public function getId() public function getId()
{ {
return $this->id; return $this->id;
} }
public function getName() public function getName()
{ {
return $this->name; return $this->name;

View File

@ -7,56 +7,56 @@ use DateTime;
require_once __DIR__ . '/../../../TestInit.php'; require_once __DIR__ . '/../../../TestInit.php';
/** /**
* @group DDC-1135 * @group DDC-1335
*/ */
class DDC1135Test extends \Doctrine\Tests\OrmFunctionalTestCase class DDC1335Test extends \Doctrine\Tests\OrmFunctionalTestCase
{ {
protected function setUp() protected function setUp()
{ {
parent::setUp(); parent::setUp();
try { try {
$this->_schemaTool->createSchema(array( $this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1135User'), $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1335User'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1135Phone'), $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1335Phone'),
)); ));
$this->loadFixture(); $this->loadFixture();
} catch(\Exception $e) { } catch(\Exception $e) {
} }
} }
public function testDql() public function testDql()
{ {
$dql = 'SELECT u FROM ' . __NAMESPACE__ . '\DDC1135User u INDEX BY u.id'; $dql = 'SELECT u FROM ' . __NAMESPACE__ . '\DDC1335User u INDEX BY u.id';
$query = $this->_em->createQuery($dql); $query = $this->_em->createQuery($dql);
$result = $query->getResult(); $result = $query->getResult();
$this->assertEquals(sizeof($result), 3); $this->assertEquals(sizeof($result), 3);
$this->assertArrayHasKey(1, $result); $this->assertArrayHasKey(1, $result);
$this->assertArrayHasKey(2, $result); $this->assertArrayHasKey(2, $result);
$this->assertArrayHasKey(3, $result); $this->assertArrayHasKey(3, $result);
$dql = 'SELECT u, p FROM '.__NAMESPACE__ . '\DDC1135User u INDEX BY u.email INNER JOIN u.phones p INDEX BY p.id'; $dql = 'SELECT u, p FROM '.__NAMESPACE__ . '\DDC1335User u INDEX BY u.email INNER JOIN u.phones p INDEX BY p.id';
$query = $this->_em->createQuery($dql); $query = $this->_em->createQuery($dql);
$result = $query->getResult(); $result = $query->getResult();
$this->assertEquals(sizeof($result), 3); $this->assertEquals(sizeof($result), 3);
$this->assertArrayHasKey('foo@foo.com', $result); $this->assertArrayHasKey('foo@foo.com', $result);
$this->assertArrayHasKey('bar@bar.com', $result); $this->assertArrayHasKey('bar@bar.com', $result);
$this->assertArrayHasKey('foobar@foobar.com', $result); $this->assertArrayHasKey('foobar@foobar.com', $result);
$this->assertEquals(sizeof($result['foo@foo.com']->phones), 3); $this->assertEquals(sizeof($result['foo@foo.com']->phones), 3);
$this->assertEquals(sizeof($result['bar@bar.com']->phones), 3); $this->assertEquals(sizeof($result['bar@bar.com']->phones), 3);
$this->assertEquals(sizeof($result['foobar@foobar.com']->phones), 3); $this->assertEquals(sizeof($result['foobar@foobar.com']->phones), 3);
$this->assertArrayHasKey(1, $result['foo@foo.com']->phones->toArray()); $this->assertArrayHasKey(1, $result['foo@foo.com']->phones->toArray());
$this->assertArrayHasKey(2, $result['foo@foo.com']->phones->toArray()); $this->assertArrayHasKey(2, $result['foo@foo.com']->phones->toArray());
$this->assertArrayHasKey(3, $result['foo@foo.com']->phones->toArray()); $this->assertArrayHasKey(3, $result['foo@foo.com']->phones->toArray());
$this->assertArrayHasKey(4, $result['bar@bar.com']->phones->toArray()); $this->assertArrayHasKey(4, $result['bar@bar.com']->phones->toArray());
$this->assertArrayHasKey(5, $result['bar@bar.com']->phones->toArray()); $this->assertArrayHasKey(5, $result['bar@bar.com']->phones->toArray());
$this->assertArrayHasKey(6, $result['bar@bar.com']->phones->toArray()); $this->assertArrayHasKey(6, $result['bar@bar.com']->phones->toArray());
$this->assertArrayHasKey(7, $result['foobar@foobar.com']->phones->toArray()); $this->assertArrayHasKey(7, $result['foobar@foobar.com']->phones->toArray());
$this->assertArrayHasKey(8, $result['foobar@foobar.com']->phones->toArray()); $this->assertArrayHasKey(8, $result['foobar@foobar.com']->phones->toArray());
$this->assertArrayHasKey(9, $result['foobar@foobar.com']->phones->toArray()); $this->assertArrayHasKey(9, $result['foobar@foobar.com']->phones->toArray());
@ -65,77 +65,77 @@ class DDC1135Test extends \Doctrine\Tests\OrmFunctionalTestCase
public function testTicket() public function testTicket()
{ {
$builder = $this->_em->createQueryBuilder(); $builder = $this->_em->createQueryBuilder();
$builder->select('u')->from(__NAMESPACE__ . '\DDC1135User', 'u', 'u.id'); $builder->select('u')->from(__NAMESPACE__ . '\DDC1335User', 'u', 'u.id');
$dql = $builder->getQuery()->getDQL(); $dql = $builder->getQuery()->getDQL();
$result = $builder->getQuery()->getResult(); $result = $builder->getQuery()->getResult();
$this->assertEquals(sizeof($result), 3); $this->assertEquals(sizeof($result), 3);
$this->assertArrayHasKey(1, $result); $this->assertArrayHasKey(1, $result);
$this->assertArrayHasKey(2, $result); $this->assertArrayHasKey(2, $result);
$this->assertArrayHasKey(3, $result); $this->assertArrayHasKey(3, $result);
$this->assertEquals('SELECT u FROM ' . __NAMESPACE__ . '\DDC1135User u INDEX BY u.id', $dql); $this->assertEquals('SELECT u FROM ' . __NAMESPACE__ . '\DDC1335User u INDEX BY u.id', $dql);
} }
public function testIndexByUnique() public function testIndexByUnique()
{ {
$builder = $this->_em->createQueryBuilder(); $builder = $this->_em->createQueryBuilder();
$builder->select('u')->from(__NAMESPACE__ . '\DDC1135User', 'u', 'u.email'); $builder->select('u')->from(__NAMESPACE__ . '\DDC1335User', 'u', 'u.email');
$dql = $builder->getQuery()->getDQL(); $dql = $builder->getQuery()->getDQL();
$result = $builder->getQuery()->getResult(); $result = $builder->getQuery()->getResult();
$this->assertEquals(sizeof($result), 3); $this->assertEquals(sizeof($result), 3);
$this->assertArrayHasKey('foo@foo.com', $result); $this->assertArrayHasKey('foo@foo.com', $result);
$this->assertArrayHasKey('bar@bar.com', $result); $this->assertArrayHasKey('bar@bar.com', $result);
$this->assertArrayHasKey('foobar@foobar.com', $result); $this->assertArrayHasKey('foobar@foobar.com', $result);
$this->assertEquals('SELECT u FROM ' . __NAMESPACE__ . '\DDC1135User u INDEX BY u.email', $dql); $this->assertEquals('SELECT u FROM ' . __NAMESPACE__ . '\DDC1335User u INDEX BY u.email', $dql);
} }
public function testIndexWithJoin() public function testIndexWithJoin()
{ {
$builder = $this->_em->createQueryBuilder(); $builder = $this->_em->createQueryBuilder();
$builder->select('u','p') $builder->select('u','p')
->from(__NAMESPACE__ . '\DDC1135User', 'u', 'u.email') ->from(__NAMESPACE__ . '\DDC1335User', 'u', 'u.email')
->join('u.phones', 'p', null, null, 'p.id'); ->join('u.phones', 'p', null, null, 'p.id');
$dql = $builder->getQuery()->getDQL(); $dql = $builder->getQuery()->getDQL();
$result = $builder->getQuery()->getResult(); $result = $builder->getQuery()->getResult();
$this->assertEquals(sizeof($result), 3); $this->assertEquals(sizeof($result), 3);
$this->assertArrayHasKey('foo@foo.com', $result); $this->assertArrayHasKey('foo@foo.com', $result);
$this->assertArrayHasKey('bar@bar.com', $result); $this->assertArrayHasKey('bar@bar.com', $result);
$this->assertArrayHasKey('foobar@foobar.com', $result); $this->assertArrayHasKey('foobar@foobar.com', $result);
$this->assertEquals(sizeof($result['foo@foo.com']->phones), 3); $this->assertEquals(sizeof($result['foo@foo.com']->phones), 3);
$this->assertEquals(sizeof($result['bar@bar.com']->phones), 3); $this->assertEquals(sizeof($result['bar@bar.com']->phones), 3);
$this->assertEquals(sizeof($result['foobar@foobar.com']->phones), 3); $this->assertEquals(sizeof($result['foobar@foobar.com']->phones), 3);
$this->assertArrayHasKey(1, $result['foo@foo.com']->phones->toArray()); $this->assertArrayHasKey(1, $result['foo@foo.com']->phones->toArray());
$this->assertArrayHasKey(2, $result['foo@foo.com']->phones->toArray()); $this->assertArrayHasKey(2, $result['foo@foo.com']->phones->toArray());
$this->assertArrayHasKey(3, $result['foo@foo.com']->phones->toArray()); $this->assertArrayHasKey(3, $result['foo@foo.com']->phones->toArray());
$this->assertArrayHasKey(4, $result['bar@bar.com']->phones->toArray()); $this->assertArrayHasKey(4, $result['bar@bar.com']->phones->toArray());
$this->assertArrayHasKey(5, $result['bar@bar.com']->phones->toArray()); $this->assertArrayHasKey(5, $result['bar@bar.com']->phones->toArray());
$this->assertArrayHasKey(6, $result['bar@bar.com']->phones->toArray()); $this->assertArrayHasKey(6, $result['bar@bar.com']->phones->toArray());
$this->assertArrayHasKey(7, $result['foobar@foobar.com']->phones->toArray()); $this->assertArrayHasKey(7, $result['foobar@foobar.com']->phones->toArray());
$this->assertArrayHasKey(8, $result['foobar@foobar.com']->phones->toArray()); $this->assertArrayHasKey(8, $result['foobar@foobar.com']->phones->toArray());
$this->assertArrayHasKey(9, $result['foobar@foobar.com']->phones->toArray()); $this->assertArrayHasKey(9, $result['foobar@foobar.com']->phones->toArray());
$this->assertEquals('SELECT u, p FROM '.__NAMESPACE__ . '\DDC1135User u INDEX BY u.email INNER JOIN u.phones p INDEX BY p.id', $dql); $this->assertEquals('SELECT u, p FROM '.__NAMESPACE__ . '\DDC1335User u INDEX BY u.email INNER JOIN u.phones p INDEX BY p.id', $dql);
} }
private function loadFixture() private function loadFixture()
{ {
$p1 = array('11 xxxx-xxxx','11 yyyy-yyyy','11 zzzz-zzzz'); $p1 = array('11 xxxx-xxxx','11 yyyy-yyyy','11 zzzz-zzzz');
$p2 = array('22 xxxx-xxxx','22 yyyy-yyyy','22 zzzz-zzzz'); $p2 = array('22 xxxx-xxxx','22 yyyy-yyyy','22 zzzz-zzzz');
$p3 = array('33 xxxx-xxxx','33 yyyy-yyyy','33 zzzz-zzzz'); $p3 = array('33 xxxx-xxxx','33 yyyy-yyyy','33 zzzz-zzzz');
$u1 = new DDC1135User("foo@foo.com", "Foo",$p1); $u1 = new DDC1335User("foo@foo.com", "Foo",$p1);
$u2 = new DDC1135User("bar@bar.com", "Bar",$p2); $u2 = new DDC1335User("bar@bar.com", "Bar",$p2);
$u3 = new DDC1135User("foobar@foobar.com", "Foo Bar",$p3); $u3 = new DDC1335User("foobar@foobar.com", "Foo Bar",$p3);
$this->_em->persist($u1); $this->_em->persist($u1);
$this->_em->persist($u2); $this->_em->persist($u2);
$this->_em->persist($u3); $this->_em->persist($u3);
@ -148,7 +148,7 @@ class DDC1135Test extends \Doctrine\Tests\OrmFunctionalTestCase
/** /**
* @Entity * @Entity
*/ */
class DDC1135User class DDC1335User
{ {
/** /**
* @Id @Column(type="integer") * @Id @Column(type="integer")
@ -160,25 +160,25 @@ class DDC1135User
* @Column(type="string", unique=true) * @Column(type="string", unique=true)
*/ */
public $email; public $email;
/** /**
* @Column(type="string") * @Column(type="string")
*/ */
public $name; public $name;
/** /**
* @OneToMany(targetEntity="DDC1135Phone", mappedBy="user", cascade={"persist", "remove"}) * @OneToMany(targetEntity="DDC1335Phone", mappedBy="user", cascade={"persist", "remove"})
*/ */
public $phones; public $phones;
public function __construct($email, $name, array $numbers = array()) public function __construct($email, $name, array $numbers = array())
{ {
$this->name = $name; $this->name = $name;
$this->email = $email; $this->email = $email;
$this->phones = new \Doctrine\Common\Collections\ArrayCollection(); $this->phones = new \Doctrine\Common\Collections\ArrayCollection();
foreach ($numbers as $number) { foreach ($numbers as $number) {
$this->phones->add(new DDC1135Phone($this,$number)); $this->phones->add(new DDC1335Phone($this,$number));
} }
} }
} }
@ -186,22 +186,22 @@ class DDC1135User
/** /**
* @Entity * @Entity
*/ */
class DDC1135Phone class DDC1335Phone
{ {
/** /**
* @Id * @Id
* @Column(name="id", type="integer") * @Column(name="id", type="integer")
* @GeneratedValue(strategy="AUTO") * @GeneratedValue
*/ */
public $id; public $id;
/** /**
* @Column(name="number", type="string", nullable = false) * @Column(name="numericalValue", type="string", nullable = false)
*/ */
public $number; public $numericalValue;
/** /**
* @ManyToOne(targetEntity="DDC1135User", inversedBy="phones") * @ManyToOne(targetEntity="DDC1335User", inversedBy="phones")
* @JoinColumn(name="user_id", referencedColumnName="id", nullable = false) * @JoinColumn(name="user_id", referencedColumnName="id", nullable = false)
*/ */
public $user; public $user;
@ -209,6 +209,6 @@ class DDC1135Phone
public function __construct($user, $number) public function __construct($user, $number)
{ {
$this->user = $user; $this->user = $user;
$this->number = $number; $this->numericalValue = $number;
} }
} }

View File

@ -0,0 +1,129 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
require_once __DIR__ . '/../../../TestInit.php';
/**
* @group DDC-1404
*/
class DDC1404Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp()
{
parent::setUp();
try {
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1404ParentEntity'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1404ChildEntity'),
));
$this->loadFixtures();
} catch (Exception $exc) {
}
}
public function testTicket()
{
$repository = $this->_em->getRepository(__NAMESPACE__ . '\DDC1404ChildEntity');
$queryAll = $repository->createNamedQuery('all');
$queryFirst = $repository->createNamedQuery('first');
$querySecond = $repository->createNamedQuery('second');
$this->assertEquals('SELECT p FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1404ChildEntity p', $queryAll->getDQL());
$this->assertEquals('SELECT p FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1404ChildEntity p WHERE p.id = 1', $queryFirst->getDQL());
$this->assertEquals('SELECT p FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1404ChildEntity p WHERE p.id = 2', $querySecond->getDQL());
$this->assertEquals(sizeof($queryAll->getResult()), 2);
$this->assertEquals(sizeof($queryFirst->getResult()), 1);
$this->assertEquals(sizeof($querySecond->getResult()), 1);
}
public function loadFixtures()
{
$c1 = new DDC1404ChildEntity("ChildEntity 1");
$c2 = new DDC1404ChildEntity("ChildEntity 2");
$this->_em->persist($c1);
$this->_em->persist($c2);
$this->_em->flush();
}
}
/**
* @MappedSuperclass
*
* @NamedQueries({
* @NamedQuery(name="all", query="SELECT p FROM __CLASS__ p"),
* @NamedQuery(name="first", query="SELECT p FROM __CLASS__ p WHERE p.id = 1"),
* })
*/
class DDC1404ParentEntity
{
/**
* @Id
* @Column(type="integer")
* @GeneratedValue()
*/
protected $id;
/**
* @return integer
*/
public function getId()
{
return $this->id;
}
}
/**
* @Entity
*
* @NamedQueries({
* @NamedQuery(name="first", query="SELECT p FROM __CLASS__ p WHERE p.id = 1"),
* @NamedQuery(name="second", query="SELECT p FROM __CLASS__ p WHERE p.id = 2")
* })
*/
class DDC1404ChildEntity extends DDC1404ParentEntity
{
/**
* @column(type="string")
*/
private $name;
/**
* @param string $name
*/
public function __construct($name)
{
$this->name = $name;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
}

View File

@ -0,0 +1,131 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\Tests\Models\CMS\CmsGroup;
require_once __DIR__ . '/../../../TestInit.php';
class DDC1258Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
public function setUp()
{
parent::setUp();
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\TestEntity'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\TestAdditionalEntity')
));
}
public function testIssue()
{
$testEntity = new TestEntity();
$testEntity->setValue(3);
$testEntity->setAdditional(new TestAdditionalEntity());
$this->_em->persist($testEntity);
$this->_em->flush();
$this->_em->clear();
// So here the value is 3
$this->assertEquals(3, $testEntity->getValue());
$test = $this->_em->getRepository(__NAMESPACE__ . '\TestEntity')->find(1);
// New value is set
$test->setValue(5);
// So here the value is 5
$this->assertEquals(5, $test->getValue());
// Get the additional entity
$additional = $test->getAdditional();
// Still 5..
$this->assertEquals(5, $test->getValue());
// Force the proxy to load
$additional->getBool();
// The value should still be 5
$this->assertEquals(5, $test->getValue());
}
}
/**
* @Entity
*/
class TestEntity
{
/**
* @Id
* @Column(type="integer")
* @GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @Column(type="integer")
*/
protected $value;
/**
* @OneToOne(targetEntity="TestAdditionalEntity", inversedBy="entity", orphanRemoval=true, cascade={"persist", "remove"})
*/
protected $additional;
public function getValue()
{
return $this->value;
}
public function setValue($value)
{
$this->value = $value;
}
public function getAdditional()
{
return $this->additional;
}
public function setAdditional($additional)
{
$this->additional = $additional;
}
}
/**
* @Entity
*/
class TestAdditionalEntity
{
/**
* @Id
* @Column(type="integer")
* @GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @OneToOne(targetEntity="TestEntity", mappedBy="additional")
*/
protected $entity;
/**
* @Column(type="boolean")
*/
protected $bool;
public function __construct()
{
$this->bool = false;
}
public function getBool()
{
return $this->bool;
}
public function setBool($bool)
{
$this->bool = $bool;
}
}

View File

@ -0,0 +1,86 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Tests\Models\CMS\CmsArticle;
use Doctrine\Tests\Models\CMS\CmsUser;
require_once __DIR__ . '/../../../TestInit.php';
/**
* @group DDC-1461
*/
class DDC1461Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
public function setUp()
{
parent::setUp();
try {
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1461TwitterAccount'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1461User')
));
} catch(\Exception $e) {
}
}
public function testChangeDetectionDeferredExplicit()
{
$user = new DDC1461User;
$this->_em->persist($user);
$this->_em->flush();
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $this->_em->getUnitOfWork()->getEntityState($user, \Doctrine\ORM\UnitOfWork::STATE_NEW), "Entity should be managed.");
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $this->_em->getUnitOfWork()->getEntityState($user), "Entity should be managed.");
$acc = new DDC1461TwitterAccount;
$user->twitterAccount = $acc;
$this->_em->persist($user);
$this->_em->flush();
$user = $this->_em->find(get_class($user), $user->id);
$this->assertNotNull($user->twitterAccount);
}
}
/**
* @Entity
* @ChangeTrackingPolicy("DEFERRED_EXPLICIT")
*/
class DDC1461User
{
/**
* @Id
* @GeneratedValue(strategy="AUTO")
* @Column(type="integer")
*/
public $id;
/**
* @OneToOne(targetEntity="DDC1461TwitterAccount", orphanRemoval=true, fetch="EAGER", cascade = {"persist"}, inversedBy="user")
* @var TwitterAccount
*/
public $twitterAccount;
}
/**
* @Entity
* @ChangeTrackingPolicy("DEFERRED_EXPLICIT")
*/
class DDC1461TwitterAccount
{
/**
* @Id
* @GeneratedValue(strategy="AUTO")
* @Column(type="integer")
*/
public $id;
/**
* @OneToOne(targetEntity="DDC1461User", fetch="EAGER")
*/
public $user;
}

View File

@ -25,18 +25,15 @@ class DDC331Test extends \Doctrine\Tests\OrmFunctionalTestCase
parent::setUp(); parent::setUp();
} }
/**
* @group DDC-331
*/
public function testSelectFieldOnRootEntity() public function testSelectFieldOnRootEntity()
{ {
$employee = new CompanyEmployee;
$employee->setName('Roman S. Borschel');
$employee->setSalary(100000);
$employee->setDepartment('IT');
$this->_em->persist($employee);
$this->_em->flush();
$this->_em->clear();
$q = $this->_em->createQuery('SELECT e.name FROM Doctrine\Tests\Models\Company\CompanyEmployee e'); $q = $this->_em->createQuery('SELECT e.name FROM Doctrine\Tests\Models\Company\CompanyEmployee e');
$this->assertEquals('SELECT c0_.name AS name0 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ ON c1_.id = c2_.id', $q->getSql()); $this->assertEquals(
strtolower('SELECT c0_.name AS name0 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ ON c1_.id = c2_.id'),
strtolower($q->getSql())
);
} }
} }

View File

@ -18,7 +18,10 @@ class DDC448Test extends \Doctrine\Tests\OrmFunctionalTestCase
public function testIssue() public function testIssue()
{ {
$q = $this->_em->createQuery("select b from ".__NAMESPACE__."\\DDC448SubTable b where b.connectedClassId = ?1"); $q = $this->_em->createQuery("select b from ".__NAMESPACE__."\\DDC448SubTable b where b.connectedClassId = ?1");
$this->assertEquals('SELECT d0_.id AS id0, d0_.discr AS discr1, d0_.connectedClassId AS connectedClassId2 FROM SubTable s1_ INNER JOIN DDC448MainTable d0_ ON s1_.id = d0_.id WHERE d0_.connectedClassId = ?', $q->getSQL()); $this->assertEquals(
strtolower('SELECT d0_.id AS id0, d0_.discr AS discr1, d0_.connectedClassId AS connectedClassId2 FROM SubTable s1_ INNER JOIN DDC448MainTable d0_ ON s1_.id = d0_.id WHERE d0_.connectedClassId = ?'),
strtolower($q->getSQL())
);
} }
} }

View File

@ -18,7 +18,10 @@ class DDC493Test extends \Doctrine\Tests\OrmFunctionalTestCase
public function testIssue() public function testIssue()
{ {
$q = $this->_em->createQuery("select u, c.data from ".__NAMESPACE__."\\DDC493Distributor u JOIN u.contact c"); $q = $this->_em->createQuery("select u, c.data from ".__NAMESPACE__."\\DDC493Distributor u JOIN u.contact c");
$this->assertEquals('SELECT d0_.id AS id0, d1_.data AS data1, d0_.discr AS discr2, d0_.contact AS contact3 FROM DDC493Distributor d2_ INNER JOIN DDC493Customer d0_ ON d2_.id = d0_.id INNER JOIN DDC493Contact d1_ ON d0_.contact = d1_.id', $q->getSQL()); $this->assertEquals(
strtolower('SELECT d0_.id AS id0, d1_.data AS data1, d0_.discr AS discr2, d0_.contact AS contact3 FROM DDC493Distributor d2_ INNER JOIN DDC493Customer d0_ ON d2_.id = d0_.id INNER JOIN DDC493Contact d1_ ON d0_.contact = d1_.id'),
strtolower($q->getSQL())
);
} }
} }

View File

@ -18,7 +18,10 @@ class DDC513Test extends \Doctrine\Tests\OrmFunctionalTestCase
public function testIssue() public function testIssue()
{ {
$q = $this->_em->createQuery("select u from ".__NAMESPACE__."\\DDC513OfferItem u left join u.price p"); $q = $this->_em->createQuery("select u from ".__NAMESPACE__."\\DDC513OfferItem u left join u.price p");
$this->assertEquals('SELECT d0_.id AS id0, d0_.discr AS discr1, d0_.price AS price2 FROM DDC513OfferItem d1_ INNER JOIN DDC513Item d0_ ON d1_.id = d0_.id LEFT JOIN DDC513Price d2_ ON d0_.price = d2_.id', $q->getSQL()); $this->assertEquals(
strtolower('SELECT d0_.id AS id0, d0_.discr AS discr1, d0_.price AS price2 FROM DDC513OfferItem d1_ INNER JOIN DDC513Item d0_ ON d1_.id = d0_.id LEFT JOIN DDC513Price d2_ ON d0_.price = d2_.id'),
strtolower($q->getSQL())
);
} }
} }

View File

@ -30,7 +30,10 @@ class DDC698Test extends \Doctrine\Tests\OrmFunctionalTestCase
$sql = $qb->getQuery()->getSQL(); $sql = $qb->getQuery()->getSQL();
$this->assertEquals('SELECT p0_.privilegeID AS privilegeID0, p0_.name AS name1, r1_.roleID AS roleID2, r1_.name AS name3, r1_.shortName AS shortName4 FROM Privileges p0_ LEFT JOIN RolePrivileges r2_ ON p0_.privilegeID = r2_.privilegeID LEFT JOIN Roles r1_ ON r1_.roleID = r2_.roleID', $sql); $this->assertEquals(
strtolower('SELECT p0_.privilegeID AS privilegeID0, p0_.name AS name1, r1_.roleID AS roleID2, r1_.name AS name3, r1_.shortName AS shortName4 FROM Privileges p0_ LEFT JOIN RolePrivileges r2_ ON p0_.privilegeID = r2_.privilegeID LEFT JOIN Roles r1_ ON r1_.roleID = r2_.roleID'),
strtolower($sql)
);
} }
} }

View File

@ -19,7 +19,10 @@ class DDC719Test extends \Doctrine\Tests\OrmFunctionalTestCase
{ {
$q = $this->_em->createQuery('SELECT g, c FROM Doctrine\Tests\ORM\Functional\Ticket\DDC719Group g LEFT JOIN g.children c WHERE g.parents IS EMPTY'); $q = $this->_em->createQuery('SELECT g, c FROM Doctrine\Tests\ORM\Functional\Ticket\DDC719Group g LEFT JOIN g.children c WHERE g.parents IS EMPTY');
$this->assertEquals('SELECT g0_.name AS name0, g0_.description AS description1, g0_.id AS id2, g1_.name AS name3, g1_.description AS description4, g1_.id AS id5 FROM groups g0_ LEFT JOIN groups_groups g2_ ON g0_.id = g2_.parent_id LEFT JOIN groups g1_ ON g1_.id = g2_.child_id WHERE (SELECT COUNT(*) FROM groups_groups g3_ WHERE g3_.child_id = g0_.id) = 0', $q->getSQL()); $this->assertEquals(
strtolower('SELECT g0_.name AS name0, g0_.description AS description1, g0_.id AS id2, g1_.name AS name3, g1_.description AS description4, g1_.id AS id5 FROM groups g0_ LEFT JOIN groups_groups g2_ ON g0_.id = g2_.parent_id LEFT JOIN groups g1_ ON g1_.id = g2_.child_id WHERE (SELECT COUNT(*) FROM groups_groups g3_ WHERE g3_.child_id = g0_.id) = 0'),
strtolower($q->getSQL())
);
} }
} }
@ -28,12 +31,12 @@ class DDC719Test extends \Doctrine\Tests\OrmFunctionalTestCase
*/ */
class Entity class Entity
{ {
/** /**
* @Id @GeneratedValue * @Id @GeneratedValue
* @Column(type="integer") * @Column(type="integer")
*/ */
protected $id; protected $id;
public function getId() { return $this->id; } public function getId() { return $this->id; }
} }

View File

@ -34,10 +34,10 @@ class DDC949Test extends \Doctrine\Tests\OrmFunctionalTestCase
$true = $this->_em->getRepository('Doctrine\Tests\Models\Generic\BooleanModel')->findOneBy(array('booleanField' => true)); $true = $this->_em->getRepository('Doctrine\Tests\Models\Generic\BooleanModel')->findOneBy(array('booleanField' => true));
$false = $this->_em->getRepository('Doctrine\Tests\Models\Generic\BooleanModel')->findOneBy(array('booleanField' => false)); $false = $this->_em->getRepository('Doctrine\Tests\Models\Generic\BooleanModel')->findOneBy(array('booleanField' => false));
$this->assertInstanceOf('Doctrine\Tests\Models\Generic\BooleanModel', $true); $this->assertInstanceOf('Doctrine\Tests\Models\Generic\BooleanModel', $true, "True model not found");
$this->assertTrue($true->booleanField, "True Boolean Model should be true."); $this->assertTrue($true->booleanField, "True Boolean Model should be true.");
$this->assertInstanceOf('Doctrine\Tests\Models\Generic\BooleanModel', $false); $this->assertInstanceOf('Doctrine\Tests\Models\Generic\BooleanModel', $false, "False model not found");
$this->assertFalse($false->booleanField, "False Boolean Model should be false."); $this->assertFalse($false->booleanField, "False Boolean Model should be false.");
} }
} }

View File

@ -9,13 +9,34 @@ require_once __DIR__ . '/../../TestInit.php';
class ArrayHydratorTest extends HydrationTestCase class ArrayHydratorTest extends HydrationTestCase
{ {
public function provideDataForUserEntityResult()
{
return array(
array(0),
array('user'),
);
}
public function provideDataForMultipleRootEntityResult()
{
return array(
array(0, 0),
array('user', 0),
array(0, 'article'),
array('user', 'article'),
);
}
/** /**
* Select u.id, u.name from Doctrine\Tests\Models\CMS\CmsUser u * SELECT PARTIAL u.{id, name}
* FROM Doctrine\Tests\Models\CMS\CmsUser u
*
* @dataProvider provideDataForUserEntityResult
*/ */
public function testSimpleEntityQuery() public function testSimpleEntityQuery($userEntityKey)
{ {
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null);
$rsm->addFieldResult('u', 'u__id', 'id'); $rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__name', 'name'); $rsm->addFieldResult('u', 'u__name', 'name');
@ -24,35 +45,39 @@ class ArrayHydratorTest extends HydrationTestCase
array( array(
'u__id' => '1', 'u__id' => '1',
'u__name' => 'romanb' 'u__name' => 'romanb'
), ),
array( array(
'u__id' => '2', 'u__id' => '2',
'u__name' => 'jwage' 'u__name' => 'jwage'
) )
); );
$stmt = new HydratorMockStatement($resultSet);
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result)); $this->assertEquals(2, count($result));
$this->assertTrue(is_array($result)); $this->assertTrue(is_array($result));
$this->assertEquals(1, $result[0]['id']); $this->assertEquals(1, $result[0]['id']);
$this->assertEquals('romanb', $result[0]['name']); $this->assertEquals('romanb', $result[0]['name']);
$this->assertEquals(2, $result[1]['id']); $this->assertEquals(2, $result[1]['id']);
$this->assertEquals('jwage', $result[1]['name']); $this->assertEquals('jwage', $result[1]['name']);
} }
/** /**
* * SELECT PARTIAL u.{id, name}, PARTIAL a.{id, topic}
* FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a
*
* @dataProvider provideDataForMultipleRootEntityResult
*/ */
public function testSimpleMultipleRootEntityQuery() public function testSimpleMultipleRootEntityQuery($userEntityKey, $articleEntityKey)
{ {
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null);
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsArticle', 'a'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsArticle', 'a', $articleEntityKey ?: null);
$rsm->addFieldResult('u', 'u__id', 'id'); $rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__name', 'name'); $rsm->addFieldResult('u', 'u__name', 'name');
$rsm->addFieldResult('a', 'a__id', 'id'); $rsm->addFieldResult('a', 'a__id', 'id');
@ -65,47 +90,51 @@ class ArrayHydratorTest extends HydrationTestCase
'u__name' => 'romanb', 'u__name' => 'romanb',
'a__id' => '1', 'a__id' => '1',
'a__topic' => 'Cool things.' 'a__topic' => 'Cool things.'
), ),
array( array(
'u__id' => '2', 'u__id' => '2',
'u__name' => 'jwage', 'u__name' => 'jwage',
'a__id' => '2', 'a__id' => '2',
'a__topic' => 'Cool things II.' 'a__topic' => 'Cool things II.'
) )
); );
$stmt = new HydratorMockStatement($resultSet);
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(4, count($result)); $this->assertEquals(4, count($result));
$this->assertEquals(1, $result[0]['id']); $this->assertEquals(1, $result[0]['id']);
$this->assertEquals('romanb', $result[0]['name']); $this->assertEquals('romanb', $result[0]['name']);
$this->assertEquals(1, $result[1]['id']); $this->assertEquals(1, $result[1]['id']);
$this->assertEquals('Cool things.', $result[1]['topic']); $this->assertEquals('Cool things.', $result[1]['topic']);
$this->assertEquals(2, $result[2]['id']); $this->assertEquals(2, $result[2]['id']);
$this->assertEquals('jwage', $result[2]['name']); $this->assertEquals('jwage', $result[2]['name']);
$this->assertEquals(2, $result[3]['id']); $this->assertEquals(2, $result[3]['id']);
$this->assertEquals('Cool things II.', $result[3]['topic']); $this->assertEquals('Cool things II.', $result[3]['topic']);
} }
/** /**
* select u.id, u.status, p.phonenumber, upper(u.name) nameUpper from User u * SELECT PARTIAL u.{id, status}, PARTIAL p.{phonenumber}, UPPER(u.name) AS nameUpper
* join u.phonenumbers p * FROM Doctrine\Tests\Models\CMS\CmsUser u
* = * JOIN u.phonenumbers p
* select u.id, u.status, p.phonenumber, upper(u.name) as u__0 from USERS u *
* INNER JOIN PHONENUMBERS p ON u.id = p.user_id * @dataProvider provideDataForUserEntityResult
*/ */
public function testMixedQueryFetchJoin() public function testMixedQueryFetchJoin($userEntityKey)
{ {
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null);
$rsm->addJoinedEntityResult( $rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsPhonenumber', 'p', 'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'u', 'phonenumbers'); 'p',
'u',
'phonenumbers'
);
$rsm->addFieldResult('u', 'u__id', 'id'); $rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status'); $rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addScalarResult('sclr0', 'nameUpper'); $rsm->addScalarResult('sclr0', 'nameUpper');
@ -119,54 +148,56 @@ class ArrayHydratorTest extends HydrationTestCase
'u__status' => 'developer', 'u__status' => 'developer',
'sclr0' => 'ROMANB', 'sclr0' => 'ROMANB',
'p__phonenumber' => '42', 'p__phonenumber' => '42',
), ),
array( array(
'u__id' => '1', 'u__id' => '1',
'u__status' => 'developer', 'u__status' => 'developer',
'sclr0' => 'ROMANB', 'sclr0' => 'ROMANB',
'p__phonenumber' => '43', 'p__phonenumber' => '43',
), ),
array( array(
'u__id' => '2', 'u__id' => '2',
'u__status' => 'developer', 'u__status' => 'developer',
'sclr0' => 'JWAGE', 'sclr0' => 'JWAGE',
'p__phonenumber' => '91' 'p__phonenumber' => '91'
) )
); );
$stmt = new HydratorMockStatement($resultSet); $stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result)); $this->assertEquals(2, count($result));
$this->assertTrue(is_array($result)); $this->assertTrue(is_array($result));
$this->assertTrue(is_array($result[0])); $this->assertTrue(is_array($result[0]));
$this->assertTrue(is_array($result[1])); $this->assertTrue(is_array($result[1]));
// first user => 2 phonenumbers // first user => 2 phonenumbers
$this->assertEquals(2, count($result[0][0]['phonenumbers'])); $this->assertEquals(2, count($result[0][$userEntityKey]['phonenumbers']));
$this->assertEquals('ROMANB', $result[0]['nameUpper']); $this->assertEquals('ROMANB', $result[0]['nameUpper']);
// second user => 1 phonenumber // second user => 1 phonenumber
$this->assertEquals(1, count($result[1][0]['phonenumbers'])); $this->assertEquals(1, count($result[1][$userEntityKey]['phonenumbers']));
$this->assertEquals('JWAGE', $result[1]['nameUpper']); $this->assertEquals('JWAGE', $result[1]['nameUpper']);
$this->assertEquals(42, $result[0][0]['phonenumbers'][0]['phonenumber']); $this->assertEquals(42, $result[0][$userEntityKey]['phonenumbers'][0]['phonenumber']);
$this->assertEquals(43, $result[0][0]['phonenumbers'][1]['phonenumber']); $this->assertEquals(43, $result[0][$userEntityKey]['phonenumbers'][1]['phonenumber']);
$this->assertEquals(91, $result[1][0]['phonenumbers'][0]['phonenumber']); $this->assertEquals(91, $result[1][$userEntityKey]['phonenumbers'][0]['phonenumber']);
} }
/** /**
* select u.id, u.status, count(p.phonenumber) numPhones from User u * SELECT PARTIAL u.{id, status}, COUNT(p.phonenumber) AS numPhones
* join u.phonenumbers p group by u.status, u.id * FROM Doctrine\Tests\Models\CMS\CmsUser u
* = * JOIN u.phonenumbers p
* select u.id, u.status, count(p.phonenumber) as p__0 from USERS u * GROUP BY u.status, u.id
* INNER JOIN PHONENUMBERS p ON u.id = p.user_id group by u.id, u.status *
* @dataProvider provideDataForUserEntityResult
*/ */
public function testMixedQueryNormalJoin() public function testMixedQueryNormalJoin($userEntityKey)
{ {
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null);
$rsm->addFieldResult('u', 'u__id', 'id'); $rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status'); $rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addScalarResult('sclr0', 'numPhones'); $rsm->addScalarResult('sclr0', 'numPhones');
@ -178,45 +209,50 @@ class ArrayHydratorTest extends HydrationTestCase
'u__id' => '1', 'u__id' => '1',
'u__status' => 'developer', 'u__status' => 'developer',
'sclr0' => '2', 'sclr0' => '2',
), ),
array( array(
'u__id' => '2', 'u__id' => '2',
'u__status' => 'developer', 'u__status' => 'developer',
'sclr0' => '1', 'sclr0' => '1',
) )
); );
$stmt = new HydratorMockStatement($resultSet); $stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result)); $this->assertEquals(2, count($result));
$this->assertTrue(is_array($result)); $this->assertTrue(is_array($result));
$this->assertTrue(is_array($result[0])); $this->assertTrue(is_array($result[0]));
$this->assertTrue(is_array($result[1])); $this->assertTrue(is_array($result[1]));
// first user => 2 phonenumbers // first user => 2 phonenumbers
$this->assertArrayHasKey($userEntityKey, $result[0]);
$this->assertEquals(2, $result[0]['numPhones']); $this->assertEquals(2, $result[0]['numPhones']);
// second user => 1 phonenumber // second user => 1 phonenumber
$this->assertArrayHasKey($userEntityKey, $result[1]);
$this->assertEquals(1, $result[1]['numPhones']); $this->assertEquals(1, $result[1]['numPhones']);
} }
/** /**
* select u.id, u.status, upper(u.name) nameUpper from User u index by u.id * SELECT PARTIAL u.{id, status}, UPPER(u.name) nameUpper
* join u.phonenumbers p indexby p.phonenumber * FROM Doctrine\Tests\Models\CMS\CmsUser u
* = * INDEX BY u.id
* select u.id, u.status, upper(u.name) as p__0 from USERS u * JOIN u.phonenumbers p
* INNER JOIN PHONENUMBERS p ON u.id = p.user_id * INDEX BY p.phonenumber
*
* @dataProvider provideDataForUserEntityResult
*/ */
public function testMixedQueryFetchJoinCustomIndex() public function testMixedQueryFetchJoinCustomIndex($userEntityKey)
{ {
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null);
$rsm->addJoinedEntityResult( $rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsPhonenumber', 'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'p', 'p',
'u', 'u',
'phonenumbers' 'phonenumbers'
); );
$rsm->addFieldResult('u', 'u__id', 'id'); $rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status'); $rsm->addFieldResult('u', 'u__status', 'status');
@ -233,43 +269,46 @@ class ArrayHydratorTest extends HydrationTestCase
'u__status' => 'developer', 'u__status' => 'developer',
'sclr0' => 'ROMANB', 'sclr0' => 'ROMANB',
'p__phonenumber' => '42', 'p__phonenumber' => '42',
), ),
array( array(
'u__id' => '1', 'u__id' => '1',
'u__status' => 'developer', 'u__status' => 'developer',
'sclr0' => 'ROMANB', 'sclr0' => 'ROMANB',
'p__phonenumber' => '43', 'p__phonenumber' => '43',
), ),
array( array(
'u__id' => '2', 'u__id' => '2',
'u__status' => 'developer', 'u__status' => 'developer',
'sclr0' => 'JWAGE', 'sclr0' => 'JWAGE',
'p__phonenumber' => '91' 'p__phonenumber' => '91'
) )
); );
$stmt = new HydratorMockStatement($resultSet); $stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result)); $this->assertEquals(2, count($result));
$this->assertTrue(is_array($result)); $this->assertTrue(is_array($result));
$this->assertTrue(is_array($result[0]));
$this->assertTrue(is_array($result[1])); $this->assertTrue(is_array($result[1]));
$this->assertTrue(is_array($result[2]));
// test the scalar values // test the scalar values
$this->assertEquals('ROMANB', $result[0]['nameUpper']); $this->assertEquals('ROMANB', $result[1]['nameUpper']);
$this->assertEquals('JWAGE', $result[1]['nameUpper']); $this->assertEquals('JWAGE', $result[2]['nameUpper']);
// first user => 2 phonenumbers. notice the custom indexing by user id // first user => 2 phonenumbers. notice the custom indexing by user id
$this->assertEquals(2, count($result[0]['1']['phonenumbers'])); $this->assertEquals(2, count($result[1][$userEntityKey]['phonenumbers']));
// second user => 1 phonenumber. notice the custom indexing by user id // second user => 1 phonenumber. notice the custom indexing by user id
$this->assertEquals(1, count($result[1]['2']['phonenumbers'])); $this->assertEquals(1, count($result[2][$userEntityKey]['phonenumbers']));
// test the custom indexing of the phonenumbers // test the custom indexing of the phonenumbers
$this->assertTrue(isset($result[0]['1']['phonenumbers']['42'])); $this->assertTrue(isset($result[1][$userEntityKey]['phonenumbers']['42']));
$this->assertTrue(isset($result[0]['1']['phonenumbers']['43'])); $this->assertTrue(isset($result[1][$userEntityKey]['phonenumbers']['43']));
$this->assertTrue(isset($result[1]['2']['phonenumbers']['91'])); $this->assertTrue(isset($result[2][$userEntityKey]['phonenumbers']['91']));
} }
/** /**
@ -288,16 +327,16 @@ class ArrayHydratorTest extends HydrationTestCase
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$rsm->addJoinedEntityResult( $rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsPhonenumber', 'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'p', 'p',
'u', 'u',
'phonenumbers' 'phonenumbers'
); );
$rsm->addJoinedEntityResult( $rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsArticle', 'Doctrine\Tests\Models\CMS\CmsArticle',
'a', 'a',
'u', 'u',
'articles' 'articles'
); );
$rsm->addFieldResult('u', 'u__id', 'id'); $rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status'); $rsm->addFieldResult('u', 'u__status', 'status');
@ -316,15 +355,15 @@ class ArrayHydratorTest extends HydrationTestCase
'p__phonenumber' => '42', 'p__phonenumber' => '42',
'a__id' => '1', 'a__id' => '1',
'a__topic' => 'Getting things done!' 'a__topic' => 'Getting things done!'
), ),
array( array(
'u__id' => '1', 'u__id' => '1',
'u__status' => 'developer', 'u__status' => 'developer',
'sclr0' => 'ROMANB', 'sclr0' => 'ROMANB',
'p__phonenumber' => '43', 'p__phonenumber' => '43',
'a__id' => '1', 'a__id' => '1',
'a__topic' => 'Getting things done!' 'a__topic' => 'Getting things done!'
), ),
array( array(
'u__id' => '1', 'u__id' => '1',
'u__status' => 'developer', 'u__status' => 'developer',
@ -332,15 +371,15 @@ class ArrayHydratorTest extends HydrationTestCase
'p__phonenumber' => '42', 'p__phonenumber' => '42',
'a__id' => '2', 'a__id' => '2',
'a__topic' => 'ZendCon' 'a__topic' => 'ZendCon'
), ),
array( array(
'u__id' => '1', 'u__id' => '1',
'u__status' => 'developer', 'u__status' => 'developer',
'sclr0' => 'ROMANB', 'sclr0' => 'ROMANB',
'p__phonenumber' => '43', 'p__phonenumber' => '43',
'a__id' => '2', 'a__id' => '2',
'a__topic' => 'ZendCon' 'a__topic' => 'ZendCon'
), ),
array( array(
'u__id' => '2', 'u__id' => '2',
'u__status' => 'developer', 'u__status' => 'developer',
@ -348,21 +387,20 @@ class ArrayHydratorTest extends HydrationTestCase
'p__phonenumber' => '91', 'p__phonenumber' => '91',
'a__id' => '3', 'a__id' => '3',
'a__topic' => 'LINQ' 'a__topic' => 'LINQ'
), ),
array( array(
'u__id' => '2', 'u__id' => '2',
'u__status' => 'developer', 'u__status' => 'developer',
'sclr0' => 'JWAGE', 'sclr0' => 'JWAGE',
'p__phonenumber' => '91', 'p__phonenumber' => '91',
'a__id' => '4', 'a__id' => '4',
'a__topic' => 'PHP6' 'a__topic' => 'PHP6'
), ),
); );
$stmt = new HydratorMockStatement($resultSet); $stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result)); $this->assertEquals(2, count($result));
$this->assertTrue(is_array($result)); $this->assertTrue(is_array($result));
@ -408,22 +446,22 @@ class ArrayHydratorTest extends HydrationTestCase
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$rsm->addJoinedEntityResult( $rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsPhonenumber', 'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'p', 'p',
'u', 'u',
'phonenumbers' 'phonenumbers'
); );
$rsm->addJoinedEntityResult( $rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsArticle', 'Doctrine\Tests\Models\CMS\CmsArticle',
'a', 'a',
'u', 'u',
'articles' 'articles'
); );
$rsm->addJoinedEntityResult( $rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsComment', 'Doctrine\Tests\Models\CMS\CmsComment',
'c', 'c',
'a', 'a',
'comments' 'comments'
); );
$rsm->addFieldResult('u', 'u__id', 'id'); $rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status'); $rsm->addFieldResult('u', 'u__status', 'status');
@ -446,8 +484,8 @@ class ArrayHydratorTest extends HydrationTestCase
'a__topic' => 'Getting things done!', 'a__topic' => 'Getting things done!',
'c__id' => '1', 'c__id' => '1',
'c__topic' => 'First!' 'c__topic' => 'First!'
), ),
array( array(
'u__id' => '1', 'u__id' => '1',
'u__status' => 'developer', 'u__status' => 'developer',
'sclr0' => 'ROMANB', 'sclr0' => 'ROMANB',
@ -456,7 +494,7 @@ class ArrayHydratorTest extends HydrationTestCase
'a__topic' => 'Getting things done!', 'a__topic' => 'Getting things done!',
'c__id' => '1', 'c__id' => '1',
'c__topic' => 'First!' 'c__topic' => 'First!'
), ),
array( array(
'u__id' => '1', 'u__id' => '1',
'u__status' => 'developer', 'u__status' => 'developer',
@ -466,8 +504,8 @@ class ArrayHydratorTest extends HydrationTestCase
'a__topic' => 'ZendCon', 'a__topic' => 'ZendCon',
'c__id' => null, 'c__id' => null,
'c__topic' => null 'c__topic' => null
), ),
array( array(
'u__id' => '1', 'u__id' => '1',
'u__status' => 'developer', 'u__status' => 'developer',
'sclr0' => 'ROMANB', 'sclr0' => 'ROMANB',
@ -476,7 +514,7 @@ class ArrayHydratorTest extends HydrationTestCase
'a__topic' => 'ZendCon', 'a__topic' => 'ZendCon',
'c__id' => null, 'c__id' => null,
'c__topic' => null 'c__topic' => null
), ),
array( array(
'u__id' => '2', 'u__id' => '2',
'u__status' => 'developer', 'u__status' => 'developer',
@ -486,8 +524,8 @@ class ArrayHydratorTest extends HydrationTestCase
'a__topic' => 'LINQ', 'a__topic' => 'LINQ',
'c__id' => null, 'c__id' => null,
'c__topic' => null 'c__topic' => null
), ),
array( array(
'u__id' => '2', 'u__id' => '2',
'u__status' => 'developer', 'u__status' => 'developer',
'sclr0' => 'JWAGE', 'sclr0' => 'JWAGE',
@ -496,13 +534,12 @@ class ArrayHydratorTest extends HydrationTestCase
'a__topic' => 'PHP6', 'a__topic' => 'PHP6',
'c__id' => null, 'c__id' => null,
'c__topic' => null 'c__topic' => null
), ),
); );
$stmt = new HydratorMockStatement($resultSet); $stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result)); $this->assertEquals(2, count($result));
$this->assertTrue(is_array($result)); $this->assertTrue(is_array($result));
@ -565,11 +602,12 @@ class ArrayHydratorTest extends HydrationTestCase
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\Forum\ForumCategory', 'c'); $rsm->addEntityResult('Doctrine\Tests\Models\Forum\ForumCategory', 'c');
$rsm->addJoinedEntityResult( $rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\Forum\ForumBoard', 'Doctrine\Tests\Models\Forum\ForumBoard',
'b', 'b',
'c', 'c',
'boards' 'boards'
); );
$rsm->addFieldResult('c', 'c__id', 'id'); $rsm->addFieldResult('c', 'c__id', 'id');
$rsm->addFieldResult('c', 'c__position', 'position'); $rsm->addFieldResult('c', 'c__position', 'position');
$rsm->addFieldResult('c', 'c__name', 'name'); $rsm->addFieldResult('c', 'c__name', 'name');
@ -585,15 +623,15 @@ class ArrayHydratorTest extends HydrationTestCase
'b__id' => '1', 'b__id' => '1',
'b__position' => '0', 'b__position' => '0',
//'b__category_id' => '1' //'b__category_id' => '1'
), ),
array( array(
'c__id' => '2', 'c__id' => '2',
'c__position' => '0', 'c__position' => '0',
'c__name' => 'Second', 'c__name' => 'Second',
'b__id' => '2', 'b__id' => '2',
'b__position' => '0', 'b__position' => '0',
//'b__category_id' => '2' //'b__category_id' => '2'
), ),
array( array(
'c__id' => '1', 'c__id' => '1',
'c__position' => '0', 'c__position' => '0',
@ -601,21 +639,20 @@ class ArrayHydratorTest extends HydrationTestCase
'b__id' => '3', 'b__id' => '3',
'b__position' => '1', 'b__position' => '1',
//'b__category_id' => '1' //'b__category_id' => '1'
), ),
array( array(
'c__id' => '1', 'c__id' => '1',
'c__position' => '0', 'c__position' => '0',
'c__name' => 'First', 'c__name' => 'First',
'b__id' => '4', 'b__id' => '4',
'b__position' => '2', 'b__position' => '2',
//'b__category_id' => '1' //'b__category_id' => '1'
) )
); );
$stmt = new HydratorMockStatement($resultSet); $stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result)); $this->assertEquals(2, count($result));
$this->assertTrue(is_array($result)); $this->assertTrue(is_array($result));
@ -626,15 +663,19 @@ class ArrayHydratorTest extends HydrationTestCase
$this->assertTrue(isset($result[1]['boards'])); $this->assertTrue(isset($result[1]['boards']));
$this->assertEquals(1, count($result[1]['boards'])); $this->assertEquals(1, count($result[1]['boards']));
} }
/** /**
* DQL: select partial u.{id,status}, a.id, a.topic, c.id as cid, c.topic as ctopic from CmsUser u left join u.articles a left join a.comments c * SELECT PARTIAL u.{id,status}, a.id, a.topic, c.id as cid, c.topic as ctopic
* * FROM Doctrine\Tests\Models\CMS\CmsUser u
* LEFT JOIN u.articles a
* LEFT JOIN a.comments c
*
* @dataProvider provideDataForUserEntityResult
*/ */
/*public function testChainedJoinWithScalars() public function testChainedJoinWithScalars($entityKey)
{ {
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $entityKey ?: null);
$rsm->addFieldResult('u', 'u__id', 'id'); $rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status'); $rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addScalarResult('a__id', 'id'); $rsm->addScalarResult('a__id', 'id');
@ -652,7 +693,7 @@ class ArrayHydratorTest extends HydrationTestCase
'a__topic' => 'The First', 'a__topic' => 'The First',
'c__id' => '1', 'c__id' => '1',
'c__topic' => 'First Comment' 'c__topic' => 'First Comment'
), ),
array( array(
'u__id' => '1', 'u__id' => '1',
'u__status' => 'developer', 'u__status' => 'developer',
@ -660,47 +701,52 @@ class ArrayHydratorTest extends HydrationTestCase
'a__topic' => 'The First', 'a__topic' => 'The First',
'c__id' => '2', 'c__id' => '2',
'c__topic' => 'Second Comment' 'c__topic' => 'Second Comment'
), ),
array( array(
'u__id' => '1', 'u__id' => '1',
'u__status' => 'developer', 'u__status' => 'developer',
'a__id' => '42', 'a__id' => '42',
'a__topic' => 'The Answer', 'a__topic' => 'The Answer',
'c__id' => null, 'c__id' => null,
'c__topic' => null 'c__topic' => null
), ),
); );
$stmt = new HydratorMockStatement($resultSet); $stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(3, count($result)); $this->assertEquals(3, count($result));
$this->assertEquals(2, count($result[0][0])); // User array $this->assertEquals(2, count($result[0][$entityKey])); // User array
$this->assertEquals(1, $result[0]['id']); $this->assertEquals(1, $result[0]['id']);
$this->assertEquals('The First', $result[0]['topic']); $this->assertEquals('The First', $result[0]['topic']);
$this->assertEquals(1, $result[0]['cid']); $this->assertEquals(1, $result[0]['cid']);
$this->assertEquals('First Comment', $result[0]['ctopic']); $this->assertEquals('First Comment', $result[0]['ctopic']);
$this->assertEquals(2, count($result[1][0])); // User array, duplicated $this->assertEquals(2, count($result[1][$entityKey])); // User array, duplicated
$this->assertEquals(1, $result[1]['id']); // duplicated $this->assertEquals(1, $result[1]['id']); // duplicated
$this->assertEquals('The First', $result[1]['topic']); // duplicated $this->assertEquals('The First', $result[1]['topic']); // duplicated
$this->assertEquals(2, $result[1]['cid']); $this->assertEquals(2, $result[1]['cid']);
$this->assertEquals('Second Comment', $result[1]['ctopic']); $this->assertEquals('Second Comment', $result[1]['ctopic']);
$this->assertEquals(2, count($result[2][0])); // User array, duplicated $this->assertEquals(2, count($result[2][$entityKey])); // User array, duplicated
$this->assertEquals(42, $result[2]['id']); $this->assertEquals(42, $result[2]['id']);
$this->assertEquals('The Answer', $result[2]['topic']); $this->assertEquals('The Answer', $result[2]['topic']);
$this->assertNull($result[2]['cid']); $this->assertNull($result[2]['cid']);
$this->assertNull($result[2]['ctopic']); $this->assertNull($result[2]['ctopic']);
}*/ }
public function testResultIteration() /**
* SELECT PARTIAL u.{id, status}, UPPER(u.name) AS nameUpper
* FROM Doctrine\Tests\Models\CMS\CmsUser u
*
* @dataProvider provideDataForUserEntityResult
*/
public function testResultIteration($userEntityKey)
{ {
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null);
$rsm->addFieldResult('u', 'u__id', 'id'); $rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__name', 'name'); $rsm->addFieldResult('u', 'u__name', 'name');
@ -709,23 +755,22 @@ class ArrayHydratorTest extends HydrationTestCase
array( array(
'u__id' => '1', 'u__id' => '1',
'u__name' => 'romanb' 'u__name' => 'romanb'
), ),
array( array(
'u__id' => '2', 'u__id' => '2',
'u__name' => 'jwage' 'u__name' => 'jwage'
) )
); );
$stmt = new HydratorMockStatement($resultSet);
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$iterator = $hydrator->iterate($stmt, $rsm);
$rowNum = 0;
$iterableResult = $hydrator->iterate($stmt, $rsm); while (($row = $iterator->next()) !== false) {
$rowNum = 0;
while (($row = $iterableResult->next()) !== false) {
$this->assertEquals(1, count($row)); $this->assertEquals(1, count($row));
$this->assertTrue(is_array($row[0])); $this->assertTrue(is_array($row[0]));
if ($rowNum == 0) { if ($rowNum == 0) {
$this->assertEquals(1, $row[0]['id']); $this->assertEquals(1, $row[0]['id']);
$this->assertEquals('romanb', $row[0]['name']); $this->assertEquals('romanb', $row[0]['name']);
@ -733,17 +778,22 @@ class ArrayHydratorTest extends HydrationTestCase
$this->assertEquals(2, $row[0]['id']); $this->assertEquals(2, $row[0]['id']);
$this->assertEquals('jwage', $row[0]['name']); $this->assertEquals('jwage', $row[0]['name']);
} }
++$rowNum; ++$rowNum;
} }
} }
/** /**
* SELECT PARTIAL u.{id, name}
* FROM Doctrine\Tests\Models\CMS\CmsUser u
*
* @group DDC-644 * @group DDC-644
* @dataProvider provideDataForUserEntityResult
*/ */
public function testSkipUnknownColumns() public function testSkipUnknownColumns($userEntityKey)
{ {
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null);
$rsm->addFieldResult('u', 'u__id', 'id'); $rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__name', 'name'); $rsm->addFieldResult('u', 'u__name', 'name');
@ -753,24 +803,30 @@ class ArrayHydratorTest extends HydrationTestCase
'u__id' => '1', 'u__id' => '1',
'u__name' => 'romanb', 'u__name' => 'romanb',
'foo' => 'bar', // unknown! 'foo' => 'bar', // unknown!
), ),
); );
$stmt = new HydratorMockStatement($resultSet); $stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(1, count($result)); $this->assertEquals(1, count($result));
$this->assertArrayHasKey('id', $result[0]);
$this->assertArrayHasKey('name', $result[0]);
$this->assertArrayNotHasKey('foo', $result[0]);
} }
/** /**
* SELECT PARTIAL u.{id, status}, UPPER(u.name) AS nameUpper
* FROM Doctrine\Tests\Models\CMS\CmsUser u
*
* @group DDC-1358 * @group DDC-1358
* @dataProvider provideDataForUserEntityResult
*/ */
public function testMissingIdForRootEntity() public function testMissingIdForRootEntity($userEntityKey)
{ {
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null);
$rsm->addFieldResult('u', 'u__id', 'id'); $rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status'); $rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addScalarResult('sclr0', 'nameUpper'); $rsm->addScalarResult('sclr0', 'nameUpper');
@ -782,28 +838,27 @@ class ArrayHydratorTest extends HydrationTestCase
'u__id' => '1', 'u__id' => '1',
'u__status' => 'developer', 'u__status' => 'developer',
'sclr0' => 'ROMANB', 'sclr0' => 'ROMANB',
), ),
array( array(
'u__id' => null, 'u__id' => null,
'u__status' => null, 'u__status' => null,
'sclr0' => 'ROMANB', 'sclr0' => 'ROMANB',
), ),
array( array(
'u__id' => '2', 'u__id' => '2',
'u__status' => 'developer', 'u__status' => 'developer',
'sclr0' => 'JWAGE', 'sclr0' => 'JWAGE',
), ),
array( array(
'u__id' => null, 'u__id' => null,
'u__status' => null, 'u__status' => null,
'sclr0' => 'JWAGE', 'sclr0' => 'JWAGE',
), ),
); );
$stmt = new HydratorMockStatement($resultSet); $stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(4, count($result), "Should hydrate four results."); $this->assertEquals(4, count($result), "Should hydrate four results.");
@ -812,9 +867,54 @@ class ArrayHydratorTest extends HydrationTestCase
$this->assertEquals('JWAGE', $result[2]['nameUpper']); $this->assertEquals('JWAGE', $result[2]['nameUpper']);
$this->assertEquals('JWAGE', $result[3]['nameUpper']); $this->assertEquals('JWAGE', $result[3]['nameUpper']);
$this->assertEquals(array('id' => 1, 'status' => 'developer'), $result[0][0]); $this->assertEquals(array('id' => 1, 'status' => 'developer'), $result[0][$userEntityKey]);
$this->assertNull($result[1][0]); $this->assertNull($result[1][$userEntityKey]);
$this->assertEquals(array('id' => 2, 'status' => 'developer'), $result[2][0]); $this->assertEquals(array('id' => 2, 'status' => 'developer'), $result[2][$userEntityKey]);
$this->assertNull($result[3][0]); $this->assertNull($result[3][$userEntityKey]);
}
/**
* SELECT PARTIAL u.{id, status}, UPPER(u.name) AS nameUpper
* FROM Doctrine\Tests\Models\CMS\CmsUser u
* INDEX BY u.id
*
* @group DDC-1385
* @dataProvider provideDataForUserEntityResult
*/
public function testIndexByAndMixedResult($userEntityKey)
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null);
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addScalarResult('sclr0', 'nameUpper');
$rsm->addIndexBy('u', 'id');
// Faked result set
$resultSet = array(
//row1
array(
'u__id' => '1',
'u__status' => 'developer',
'sclr0' => 'ROMANB',
),
array(
'u__id' => '2',
'u__status' => 'developer',
'sclr0' => 'JWAGE',
),
);
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(2, count($result));
$this->assertTrue(isset($result[1]));
$this->assertEquals(1, $result[1][$userEntityKey]['id']);
$this->assertTrue(isset($result[2]));
$this->assertEquals(2, $result[2][$userEntityKey]['id']);
} }
} }

View File

@ -22,7 +22,7 @@ class CustomHydratorTest extends HydrationTestCase
class CustomHydrator extends AbstractHydrator class CustomHydrator extends AbstractHydrator
{ {
protected function _hydrateAll() protected function hydrateAllData()
{ {
return $this->_stmt->fetchAll(PDO::FETCH_ASSOC); return $this->_stmt->fetchAll(PDO::FETCH_ASSOC);
} }

File diff suppressed because it is too large Load Diff

View File

@ -327,6 +327,51 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
$em->getRepository("Doctrine\Tests\Models\DDC869\DDC869ChequePayment")); $em->getRepository("Doctrine\Tests\Models\DDC869\DDC869ChequePayment"));
$this->assertTrue($em->getRepository("Doctrine\Tests\Models\DDC869\DDC869ChequePayment")->isTrue()); $this->assertTrue($em->getRepository("Doctrine\Tests\Models\DDC869\DDC869ChequePayment")->isTrue());
} }
/**
* @group DDC-1476
*/
public function testDefaultFieldType()
{
$driver = $this->_loadDriver();
$em = $this->_getTestEntityManager();
$factory = new \Doctrine\ORM\Mapping\ClassMetadataFactory();
$em->getConfiguration()->setMetadataDriverImpl($driver);
$factory->setEntityManager($em);
$class = $factory->getMetadataFor('Doctrine\Tests\Models\DDC1476\DDC1476EntityWithDefaultFieldType');
$this->assertArrayHasKey('id', $class->fieldMappings);
$this->assertArrayHasKey('name', $class->fieldMappings);
$this->assertArrayHasKey('type', $class->fieldMappings['id']);
$this->assertArrayHasKey('type', $class->fieldMappings['name']);
$this->assertEquals('string', $class->fieldMappings['id']['type']);
$this->assertEquals('string', $class->fieldMappings['name']['type']);
$this->assertArrayHasKey('fieldName', $class->fieldMappings['id']);
$this->assertArrayHasKey('fieldName', $class->fieldMappings['name']);
$this->assertEquals('id', $class->fieldMappings['id']['fieldName']);
$this->assertEquals('name', $class->fieldMappings['name']['fieldName']);
$this->assertArrayHasKey('columnName', $class->fieldMappings['id']);
$this->assertArrayHasKey('columnName', $class->fieldMappings['name']);
$this->assertEquals('id', $class->fieldMappings['id']['columnName']);
$this->assertEquals('name', $class->fieldMappings['name']['columnName']);
$this->assertEquals(ClassMetadataInfo::GENERATOR_TYPE_NONE, $class->generatorType);
}
} }
/** /**

View File

@ -199,6 +199,20 @@ class AnnotationDriverTest extends AbstractMappingDriverTest
$cm = $factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\ChildEntity'); $cm = $factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\ChildEntity');
} }
public function testInvalidFetchOptionThrowsException()
{
$annotationDriver = $this->_loadDriver();
$em = $this->_getTestEntityManager();
$em->getConfiguration()->setMetadataDriverImpl($annotationDriver);
$factory = new \Doctrine\ORM\Mapping\ClassMetadataFactory();
$factory->setEntityManager($em);
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException',
"Entity 'Doctrine\Tests\ORM\Mapping\InvalidFetchOption' has a mapping with invalid fetch mode 'eager");
$cm = $factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\InvalidFetchOption');
}
} }
/** /**
@ -310,4 +324,15 @@ class ChildEntity extends MiddleMappedSuperclass
* @Column(type="string") * @Column(type="string")
*/ */
private $text; private $text;
} }
/**
* @Entity
*/
class InvalidFetchOption
{
/**
* @OneToMany(targetEntity="Doctrine\Tests\Models\CMS\CmsUser", fetch="eager")
*/
private $collection;
}

View File

@ -54,7 +54,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals('phonenumbers', $oneOneMapping['fieldName']); $this->assertEquals('phonenumbers', $oneOneMapping['fieldName']);
$this->assertEquals('Doctrine\Tests\Models\CMS\Bar', $oneOneMapping['targetEntity']); $this->assertEquals('Doctrine\Tests\Models\CMS\Bar', $oneOneMapping['targetEntity']);
$this->assertTrue($cm->isReadOnly); $this->assertTrue($cm->isReadOnly);
$this->assertEquals(array('dql' => 'foo'), $cm->namedQueries); $this->assertEquals(array('dql' => array('name'=>'dql','query'=>'foo','dql'=>'foo')), $cm->namedQueries);
} }
public function testFieldIsNullable() public function testFieldIsNullable()

View File

@ -0,0 +1,12 @@
<?php
use Doctrine\ORM\Mapping\ClassMetadataInfo;
$metadata->mapField(array(
'id' => true,
'fieldName' => 'id',
));
$metadata->mapField(array(
'fieldName' => 'name'
));
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_NONE);

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Doctrine\Tests\Models\DDC1476\DDC1476EntityWithDefaultFieldType">
<id name="id">
<generator strategy="NONE"/>
</id>
<field name="name"/>
</entity>
</doctrine-mapping>

View File

@ -0,0 +1,8 @@
Doctrine\Tests\Models\DDC1476\DDC1476EntityWithDefaultFieldType:
type: entity
id:
id:
generator:
strategy: NONE
fields:
name:

View File

@ -17,11 +17,11 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
/** /**
* Assert a valid SQL generation. * Assert a valid SQL generation.
* *
* @param string $dqlToBeTested * @param string $dqlToBeTested
* @param string $sqlToBeConfirmed * @param string $sqlToBeConfirmed
* @param array $queryHints * @param array $queryHints
* @param array $queryParams * @param array $queryParams
*/ */
public function assertSqlGeneration($dqlToBeTested, $sqlToBeConfirmed, array $queryHints = array(), array $queryParams = array()) public function assertSqlGeneration($dqlToBeTested, $sqlToBeConfirmed, array $queryHints = array(), array $queryParams = array())
{ {
@ -34,11 +34,11 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true) $query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true)
->useQueryCache(false); ->useQueryCache(false);
foreach ($queryHints AS $name => $value) { foreach ($queryHints AS $name => $value) {
$query->setHint($name, $value); $query->setHint($name, $value);
} }
parent::assertEquals($sqlToBeConfirmed, $query->getSQL()); parent::assertEquals($sqlToBeConfirmed, $query->getSQL());
$query->free(); $query->free();
} catch (\Exception $e) { } catch (\Exception $e) {
@ -383,7 +383,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
"SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee')" "SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee')"
); );
} }
public function testSupportsInstanceOfExpressionInWherePartWithMultipleValues() public function testSupportsInstanceOfExpressionInWherePartWithMultipleValues()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
@ -391,7 +391,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
"SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee', 'manager')" "SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee', 'manager')"
); );
} }
/** /**
* @group DDC-1194 * @group DDC-1194
*/ */
@ -402,7 +402,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
"SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee')" "SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee')"
); );
} }
/** /**
* @group DDC-1194 * @group DDC-1194
*/ */
@ -563,7 +563,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
$this->_em->getClassMetadata(get_class($person))->setIdentifierValues($person, array('id' => 101)); $this->_em->getClassMetadata(get_class($person))->setIdentifierValues($person, array('id' => 101));
$q3->setParameter('param', $person); $q3->setParameter('param', $person);
$this->assertEquals( $this->assertEquals(
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c1_.car_id AS car_id3, c2_.salary AS salary4, c2_.department AS department5, c2_.startDate AS startDate6, c0_.discr AS discr7, c0_.spouse_id AS spouse_id8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id WHERE EXISTS (SELECT 1 FROM company_persons_friends c3_ INNER JOIN company_persons c4_ ON c3_.friend_id = c4_.id WHERE c3_.person_id = c0_.id AND c4_.id = ?)', 'SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c2_.salary AS salary3, c2_.department AS department4, c2_.startDate AS startDate5, c0_.discr AS discr6, c0_.spouse_id AS spouse_id7, c1_.car_id AS car_id8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id WHERE EXISTS (SELECT 1 FROM company_persons_friends c3_ INNER JOIN company_persons c4_ ON c3_.friend_id = c4_.id WHERE c3_.person_id = c0_.id AND c4_.id = ?)',
$q3->getSql() $q3->getSql()
); );
} }
@ -606,7 +606,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
. ')' . ')'
); );
} }
public function testExistsExpressionWithSimpleSelectReturningScalar() public function testExistsExpressionWithSimpleSelectReturningScalar()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
@ -703,7 +703,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, (SELECT COUNT(*) FROM cms_articles c1_ WHERE c1_.user_id = c0_.id) AS sclr4 FROM cms_users c0_ ORDER BY sclr4 ASC" "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, (SELECT COUNT(*) FROM cms_articles c1_ WHERE c1_.user_id = c0_.id) AS sclr4 FROM cms_users c0_ ORDER BY sclr4 ASC"
); );
} }
public function testOrderBySupportsSingleValuedPathExpressionOwningSide() public function testOrderBySupportsSingleValuedPathExpressionOwningSide()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
@ -711,7 +711,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
"SELECT c0_.id AS id0, c0_.topic AS topic1, c0_.text AS text2, c0_.version AS version3 FROM cms_articles c0_ ORDER BY c0_.user_id ASC" "SELECT c0_.id AS id0, c0_.topic AS topic1, c0_.text AS text2, c0_.version AS version3 FROM cms_articles c0_ ORDER BY c0_.user_id ASC"
); );
} }
/** /**
* @expectedException Doctrine\ORM\Query\QueryException * @expectedException Doctrine\ORM\Query\QueryException
*/ */
@ -746,12 +746,12 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
$this->assertSqlGeneration( $this->assertSqlGeneration(
"SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b WHERE b.booleanField = true", "SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b WHERE b.booleanField = true",
"SELECT b0_.id AS id0, b0_.booleanField AS booleanField1 FROM boolean_model b0_ WHERE b0_.booleanField = true" "SELECT b0_.id AS id0, b0_.booleanField AS booleanfield1 FROM boolean_model b0_ WHERE b0_.booleanField = true"
); );
$this->assertSqlGeneration( $this->assertSqlGeneration(
"SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b WHERE b.booleanField = false", "SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b WHERE b.booleanField = false",
"SELECT b0_.id AS id0, b0_.booleanField AS booleanField1 FROM boolean_model b0_ WHERE b0_.booleanField = false" "SELECT b0_.id AS id0, b0_.booleanField AS booleanfield1 FROM boolean_model b0_ WHERE b0_.booleanField = false"
); );
$this->_em->getConnection()->setDatabasePlatform($oldPlat); $this->_em->getConnection()->setDatabasePlatform($oldPlat);
@ -894,7 +894,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
$this->assertSqlGeneration( $this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 'gblanco'", "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 'gblanco'",
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 ". "SELECT c0_.id AS ID0, c0_.status AS STATUS1, c0_.username AS USERNAME2, c0_.name AS NAME3 ".
"FROM cms_users c0_ WHERE c0_.username = 'gblanco' FOR UPDATE", "FROM cms_users c0_ WHERE c0_.username = 'gblanco' FOR UPDATE",
array(Query::HINT_LOCK_MODE => \Doctrine\DBAL\LockMode::PESSIMISTIC_READ) array(Query::HINT_LOCK_MODE => \Doctrine\DBAL\LockMode::PESSIMISTIC_READ)
); );
@ -948,7 +948,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
'SELECT c0_.id AS id0, c0_.name AS name1, count(c1_.id) AS sclr2 FROM cms_groups c0_ INNER JOIN cms_users_groups c2_ ON c0_.id = c2_.group_id INNER JOIN cms_users c1_ ON c1_.id = c2_.user_id GROUP BY c0_.id' 'SELECT c0_.id AS id0, c0_.name AS name1, count(c1_.id) AS sclr2 FROM cms_groups c0_ INNER JOIN cms_users_groups c2_ ON c0_.id = c2_.group_id INNER JOIN cms_users c1_ ON c1_.id = c2_.user_id GROUP BY c0_.id'
); );
} }
public function testCaseContainingNullIf() public function testCaseContainingNullIf()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
@ -956,7 +956,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
'SELECT NULLIF(c0_.id, c0_.name) AS sclr0 FROM cms_groups c0_' 'SELECT NULLIF(c0_.id, c0_.name) AS sclr0 FROM cms_groups c0_'
); );
} }
public function testCaseContainingCoalesce() public function testCaseContainingCoalesce()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
@ -1026,248 +1026,281 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
"SELECT d0_.article_id AS article_id0, d0_.title AS title1, d1_.article_id AS article_id2, d1_.title AS title3 FROM DDC117Link d2_ INNER JOIN DDC117Article d0_ ON d2_.target_id = d0_.article_id INNER JOIN DDC117Article d1_ ON d2_.source_id = d1_.article_id" "SELECT d0_.article_id AS article_id0, d0_.title AS title1, d1_.article_id AS article_id2, d1_.title AS title3 FROM DDC117Link d2_ INNER JOIN DDC117Article d0_ ON d2_.target_id = d0_.article_id INNER JOIN DDC117Article d1_ ON d2_.source_id = d1_.article_id"
); );
} }
public function testGeneralCaseWithSingleWhenClause() public function testGeneralCaseWithSingleWhenClause()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
"SELECT g.id, CASE WHEN ((g.id / 2) > 18) THEN 1 ELSE 0 END AS test FROM Doctrine\Tests\Models\CMS\CmsGroup g", "SELECT g.id, CASE WHEN ((g.id / 2) > 18) THEN 1 ELSE 0 END AS test FROM Doctrine\Tests\Models\CMS\CmsGroup g",
"SELECT c0_.id AS id0, CASE WHEN (c0_.id / 2 > 18) THEN 1 ELSE 0 END AS sclr1 FROM cms_groups c0_" "SELECT c0_.id AS id0, CASE WHEN (c0_.id / 2 > 18) THEN 1 ELSE 0 END AS sclr1 FROM cms_groups c0_"
); );
} }
public function testGeneralCaseWithMultipleWhenClause() public function testGeneralCaseWithMultipleWhenClause()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
"SELECT g.id, CASE WHEN (g.id / 2 < 10) THEN 2 WHEN ((g.id / 2) > 20) THEN 1 ELSE 0 END AS test FROM Doctrine\Tests\Models\CMS\CmsGroup g", "SELECT g.id, CASE WHEN (g.id / 2 < 10) THEN 2 WHEN ((g.id / 2) > 20) THEN 1 ELSE 0 END AS test FROM Doctrine\Tests\Models\CMS\CmsGroup g",
"SELECT c0_.id AS id0, CASE WHEN (c0_.id / 2 < 10) THEN 2 WHEN (c0_.id / 2 > 20) THEN 1 ELSE 0 END AS sclr1 FROM cms_groups c0_" "SELECT c0_.id AS id0, CASE WHEN (c0_.id / 2 < 10) THEN 2 WHEN (c0_.id / 2 > 20) THEN 1 ELSE 0 END AS sclr1 FROM cms_groups c0_"
); );
} }
public function testSimpleCaseWithSingleWhenClause() public function testSimpleCaseWithSingleWhenClause()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id = CASE g.name WHEN 'admin' THEN 1 ELSE 2 END", "SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id = CASE g.name WHEN 'admin' THEN 1 ELSE 2 END",
"SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id = CASE c0_.name WHEN admin THEN 1 ELSE 2 END" "SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id = CASE c0_.name WHEN admin THEN 1 ELSE 2 END"
); );
} }
public function testSimpleCaseWithMultipleWhenClause() public function testSimpleCaseWithMultipleWhenClause()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id = (CASE g.name WHEN 'admin' THEN 1 WHEN 'moderator' THEN 2 ELSE 3 END)", "SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id = (CASE g.name WHEN 'admin' THEN 1 WHEN 'moderator' THEN 2 ELSE 3 END)",
"SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id = CASE c0_.name WHEN admin THEN 1 WHEN moderator THEN 2 ELSE 3 END" "SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id = CASE c0_.name WHEN admin THEN 1 WHEN moderator THEN 2 ELSE 3 END"
); );
} }
public function testGeneralCaseWithSingleWhenClauseInSubselect() public function testGeneralCaseWithSingleWhenClauseInSubselect()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE WHEN ((g2.id / 2) > 18) THEN 2 ELSE 1 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)", "SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE WHEN ((g2.id / 2) > 18) THEN 2 ELSE 1 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)",
"SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id IN (SELECT CASE WHEN (c1_.id / 2 > 18) THEN 2 ELSE 1 END AS sclr2 FROM cms_groups c1_)" "SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id IN (SELECT CASE WHEN (c1_.id / 2 > 18) THEN 2 ELSE 1 END AS sclr2 FROM cms_groups c1_)"
); );
} }
public function testGeneralCaseWithMultipleWhenClauseInSubselect() public function testGeneralCaseWithMultipleWhenClauseInSubselect()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE WHEN (g.id / 2 < 10) THEN 3 WHEN ((g.id / 2) > 20) THEN 2 ELSE 1 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)", "SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE WHEN (g.id / 2 < 10) THEN 3 WHEN ((g.id / 2) > 20) THEN 2 ELSE 1 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)",
"SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id IN (SELECT CASE WHEN (c0_.id / 2 < 10) THEN 3 WHEN (c0_.id / 2 > 20) THEN 2 ELSE 1 END AS sclr2 FROM cms_groups c1_)" "SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id IN (SELECT CASE WHEN (c0_.id / 2 < 10) THEN 3 WHEN (c0_.id / 2 > 20) THEN 2 ELSE 1 END AS sclr2 FROM cms_groups c1_)"
); );
} }
public function testSimpleCaseWithSingleWhenClauseInSubselect() public function testSimpleCaseWithSingleWhenClauseInSubselect()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE g2.name WHEN 'admin' THEN 1 ELSE 2 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)", "SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE g2.name WHEN 'admin' THEN 1 ELSE 2 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)",
"SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id IN (SELECT CASE c1_.name WHEN admin THEN 1 ELSE 2 END AS sclr2 FROM cms_groups c1_)" "SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id IN (SELECT CASE c1_.name WHEN admin THEN 1 ELSE 2 END AS sclr2 FROM cms_groups c1_)"
); );
} }
public function testSimpleCaseWithMultipleWhenClauseInSubselect() public function testSimpleCaseWithMultipleWhenClauseInSubselect()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE g2.name WHEN 'admin' THEN 1 WHEN 'moderator' THEN 2 ELSE 3 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)", "SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE g2.name WHEN 'admin' THEN 1 WHEN 'moderator' THEN 2 ELSE 3 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)",
"SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id IN (SELECT CASE c1_.name WHEN admin THEN 1 WHEN moderator THEN 2 ELSE 3 END AS sclr2 FROM cms_groups c1_)" "SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id IN (SELECT CASE c1_.name WHEN admin THEN 1 WHEN moderator THEN 2 ELSE 3 END AS sclr2 FROM cms_groups c1_)"
); );
} }
/** /**
* @group DDC-1339 * @group DDC-1339
*/ */
public function testIdentityFunctionInSelectClause() public function testIdentityFunctionInSelectClause()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
"SELECT IDENTITY(u.email) as email_id FROM Doctrine\Tests\Models\CMS\CmsUser u", "SELECT IDENTITY(u.email) as email_id FROM Doctrine\Tests\Models\CMS\CmsUser u",
"SELECT c0_.email_id AS sclr0 FROM cms_users c0_" "SELECT c0_.email_id AS sclr0 FROM cms_users c0_"
); );
} }
/** /**
* @group DDC-1339 * @group DDC-1339
*/ */
public function testIdentityFunctionDoesNotAcceptStateField() public function testIdentityFunctionDoesNotAcceptStateField()
{ {
$this->assertInvalidSqlGeneration( $this->assertInvalidSqlGeneration(
"SELECT IDENTITY(u.name) as name FROM Doctrine\Tests\Models\CMS\CmsUser u", "SELECT IDENTITY(u.name) as name FROM Doctrine\Tests\Models\CMS\CmsUser u",
"Doctrine\ORM\Query\QueryException" "Doctrine\ORM\Query\QueryException"
); );
} }
/** /**
* @group DDC-1389 * @group DDC-1389
*/ */
public function testInheritanceTypeJoinInRootClassWithDisabledForcePartialLoad() public function testInheritanceTypeJoinInRootClassWithDisabledForcePartialLoad()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
'SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p', 'SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p',
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c1_.car_id AS car_id3, c2_.salary AS salary4, c2_.department AS department5, c2_.startDate AS startDate6, c0_.discr AS discr7, c0_.spouse_id AS spouse_id8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id', 'SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c2_.salary AS salary3, c2_.department AS department4, c2_.startDate AS startDate5, c0_.discr AS discr6, c0_.spouse_id AS spouse_id7, c1_.car_id AS car_id8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id',
array(Query::HINT_FORCE_PARTIAL_LOAD => false) array(Query::HINT_FORCE_PARTIAL_LOAD => false)
); );
} }
/** /**
* @group DDC-1389 * @group DDC-1389
*/ */
public function testInheritanceTypeJoinInRootClassWithEnabledForcePartialLoad() public function testInheritanceTypeJoinInRootClassWithEnabledForcePartialLoad()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
'SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p', 'SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p',
'SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_', 'SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_',
array(Query::HINT_FORCE_PARTIAL_LOAD => true) array(Query::HINT_FORCE_PARTIAL_LOAD => true)
); );
} }
/** /**
* @group DDC-1389 * @group DDC-1389
*/ */
public function testInheritanceTypeJoinInChildClassWithDisabledForcePartialLoad() public function testInheritanceTypeJoinInChildClassWithDisabledForcePartialLoad()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e', 'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e',
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c2_.title AS title5, c2_.car_id AS car_id6, c0_.discr AS discr7, c0_.spouse_id AS spouse_id8 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ ON c1_.id = c2_.id', 'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c2_.title AS title5, c0_.discr AS discr6, c0_.spouse_id AS spouse_id7, c2_.car_id AS car_id8 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ ON c1_.id = c2_.id',
array(Query::HINT_FORCE_PARTIAL_LOAD => false) array(Query::HINT_FORCE_PARTIAL_LOAD => false)
); );
} }
/** /**
* @group DDC-1389 * @group DDC-1389
*/ */
public function testInheritanceTypeJoinInChildClassWithEnabledForcePartialLoad() public function testInheritanceTypeJoinInChildClassWithEnabledForcePartialLoad()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e', 'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e',
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c0_.discr AS discr5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id', 'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c0_.discr AS discr5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id',
array(Query::HINT_FORCE_PARTIAL_LOAD => true) array(Query::HINT_FORCE_PARTIAL_LOAD => true)
); );
} }
/** /**
* @group DDC-1389 * @group DDC-1389
*/ */
public function testInheritanceTypeJoinInLeafClassWithDisabledForcePartialLoad() public function testInheritanceTypeJoinInLeafClassWithDisabledForcePartialLoad()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
'SELECT m FROM Doctrine\Tests\Models\Company\CompanyManager m', 'SELECT m FROM Doctrine\Tests\Models\Company\CompanyManager m',
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c2_.title AS title5, c0_.discr AS discr6, c0_.spouse_id AS spouse_id7, c2_.car_id AS car_id8 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id', 'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c2_.title AS title5, c0_.discr AS discr6, c0_.spouse_id AS spouse_id7, c2_.car_id AS car_id8 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id',
array(Query::HINT_FORCE_PARTIAL_LOAD => false) array(Query::HINT_FORCE_PARTIAL_LOAD => false)
); );
} }
/** /**
* @group DDC-1389 * @group DDC-1389
*/ */
public function testInheritanceTypeJoinInLeafClassWithEnabledForcePartialLoad() public function testInheritanceTypeJoinInLeafClassWithEnabledForcePartialLoad()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
'SELECT m FROM Doctrine\Tests\Models\Company\CompanyManager m', 'SELECT m FROM Doctrine\Tests\Models\Company\CompanyManager m',
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c2_.title AS title5, c0_.discr AS discr6 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id', 'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c2_.title AS title5, c0_.discr AS discr6 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id',
array(Query::HINT_FORCE_PARTIAL_LOAD => true) array(Query::HINT_FORCE_PARTIAL_LOAD => true)
); );
} }
/** /**
* @group DDC-1389 * @group DDC-1389
*/ */
public function testInheritanceTypeSingleTableInRootClassWithDisabledForcePartialLoad() public function testInheritanceTypeSingleTableInRootClassWithDisabledForcePartialLoad()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c', 'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c',
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6, c0_.salesPerson_id AS salesPerson_id7 FROM company_contracts c0_ WHERE c0_.discr IN ('fix', 'flexible', 'flexultra')", "SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6, c0_.salesPerson_id AS salesPerson_id7 FROM company_contracts c0_ WHERE c0_.discr IN ('fix', 'flexible', 'flexultra')",
array(Query::HINT_FORCE_PARTIAL_LOAD => false) array(Query::HINT_FORCE_PARTIAL_LOAD => false)
); );
} }
/** /**
* @group DDC-1389 * @group DDC-1389
*/ */
public function testInheritanceTypeSingleTableInRootClassWithEnabledForcePartialLoad() public function testInheritanceTypeSingleTableInRootClassWithEnabledForcePartialLoad()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c', 'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c',
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6 FROM company_contracts c0_ WHERE c0_.discr IN ('fix', 'flexible', 'flexultra')", "SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6 FROM company_contracts c0_ WHERE c0_.discr IN ('fix', 'flexible', 'flexultra')",
array(Query::HINT_FORCE_PARTIAL_LOAD => true) array(Query::HINT_FORCE_PARTIAL_LOAD => true)
); );
} }
/** /**
* @group DDC-1389 * @group DDC-1389
*/ */
public function testInheritanceTypeSingleTableInChildClassWithDisabledForcePartialLoad() public function testInheritanceTypeSingleTableInChildClassWithDisabledForcePartialLoad()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
'SELECT fc FROM Doctrine\Tests\Models\Company\CompanyFlexContract fc', 'SELECT fc FROM Doctrine\Tests\Models\Company\CompanyFlexContract fc',
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.hoursWorked AS hoursWorked2, c0_.pricePerHour AS pricePerHour3, c0_.maxPrice AS maxPrice4, c0_.discr AS discr5, c0_.salesPerson_id AS salesPerson_id6 FROM company_contracts c0_ WHERE c0_.discr IN ('flexible', 'flexultra')", "SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.hoursWorked AS hoursWorked2, c0_.pricePerHour AS pricePerHour3, c0_.maxPrice AS maxPrice4, c0_.discr AS discr5, c0_.salesPerson_id AS salesPerson_id6 FROM company_contracts c0_ WHERE c0_.discr IN ('flexible', 'flexultra')",
array(Query::HINT_FORCE_PARTIAL_LOAD => false) array(Query::HINT_FORCE_PARTIAL_LOAD => false)
); );
} }
/** /**
* @group DDC-1389 * @group DDC-1389
*/ */
public function testInheritanceTypeSingleTableInChildClassWithEnabledForcePartialLoad() public function testInheritanceTypeSingleTableInChildClassWithEnabledForcePartialLoad()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
'SELECT fc FROM Doctrine\Tests\Models\Company\CompanyFlexContract fc', 'SELECT fc FROM Doctrine\Tests\Models\Company\CompanyFlexContract fc',
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.hoursWorked AS hoursWorked2, c0_.pricePerHour AS pricePerHour3, c0_.maxPrice AS maxPrice4, c0_.discr AS discr5 FROM company_contracts c0_ WHERE c0_.discr IN ('flexible', 'flexultra')", "SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.hoursWorked AS hoursWorked2, c0_.pricePerHour AS pricePerHour3, c0_.maxPrice AS maxPrice4, c0_.discr AS discr5 FROM company_contracts c0_ WHERE c0_.discr IN ('flexible', 'flexultra')",
array(Query::HINT_FORCE_PARTIAL_LOAD => true) array(Query::HINT_FORCE_PARTIAL_LOAD => true)
); );
} }
/** /**
* @group DDC-1389 * @group DDC-1389
*/ */
public function testInheritanceTypeSingleTableInLeafClassWithDisabledForcePartialLoad() public function testInheritanceTypeSingleTableInLeafClassWithDisabledForcePartialLoad()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
'SELECT fuc FROM Doctrine\Tests\Models\Company\CompanyFlexUltraContract fuc', 'SELECT fuc FROM Doctrine\Tests\Models\Company\CompanyFlexUltraContract fuc',
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.hoursWorked AS hoursWorked2, c0_.pricePerHour AS pricePerHour3, c0_.maxPrice AS maxPrice4, c0_.discr AS discr5, c0_.salesPerson_id AS salesPerson_id6 FROM company_contracts c0_ WHERE c0_.discr IN ('flexultra')", "SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.hoursWorked AS hoursWorked2, c0_.pricePerHour AS pricePerHour3, c0_.maxPrice AS maxPrice4, c0_.discr AS discr5, c0_.salesPerson_id AS salesPerson_id6 FROM company_contracts c0_ WHERE c0_.discr IN ('flexultra')",
array(Query::HINT_FORCE_PARTIAL_LOAD => false) array(Query::HINT_FORCE_PARTIAL_LOAD => false)
); );
} }
/** /**
* @group DDC-1389 * @group DDC-1389
*/ */
public function testInheritanceTypeSingleTableInLeafClassWithEnabledForcePartialLoad() public function testInheritanceTypeSingleTableInLeafClassWithEnabledForcePartialLoad()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
'SELECT fuc FROM Doctrine\Tests\Models\Company\CompanyFlexUltraContract fuc', 'SELECT fuc FROM Doctrine\Tests\Models\Company\CompanyFlexUltraContract fuc',
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.hoursWorked AS hoursWorked2, c0_.pricePerHour AS pricePerHour3, c0_.maxPrice AS maxPrice4, c0_.discr AS discr5 FROM company_contracts c0_ WHERE c0_.discr IN ('flexultra')", "SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.hoursWorked AS hoursWorked2, c0_.pricePerHour AS pricePerHour3, c0_.maxPrice AS maxPrice4, c0_.discr AS discr5 FROM company_contracts c0_ WHERE c0_.discr IN ('flexultra')",
array(Query::HINT_FORCE_PARTIAL_LOAD => true) array(Query::HINT_FORCE_PARTIAL_LOAD => true)
); );
} }
/** /**
* @group DDC-1161 * @group DDC-1161
*/ */
public function testSelfReferenceWithOneToOneDoesNotDuplicateAlias() public function testSelfReferenceWithOneToOneDoesNotDuplicateAlias()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
'SELECT p, pp FROM Doctrine\Tests\Models\Company\CompanyPerson p JOIN p.spouse pp', 'SELECT p, pp FROM Doctrine\Tests\Models\Company\CompanyPerson p JOIN p.spouse pp',
"SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c1_.car_id AS car_id3, c2_.salary AS salary4, c2_.department AS department5, c2_.startDate AS startDate6, c3_.id AS id7, c3_.name AS name8, c4_.title AS title9, c4_.car_id AS car_id10, c5_.salary AS salary11, c5_.department AS department12, c5_.startDate AS startDate13, c0_.discr AS discr14, c0_.spouse_id AS spouse_id15, c3_.discr AS discr16, c3_.spouse_id AS spouse_id17 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id INNER JOIN company_persons c3_ ON c0_.spouse_id = c3_.id LEFT JOIN company_managers c4_ ON c3_.id = c4_.id LEFT JOIN company_employees c5_ ON c3_.id = c5_.id", "SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c2_.salary AS salary3, c2_.department AS department4, c2_.startDate AS startDate5, c3_.id AS id6, c3_.name AS name7, c4_.title AS title8, c5_.salary AS salary9, c5_.department AS department10, c5_.startDate AS startDate11, c0_.discr AS discr12, c0_.spouse_id AS spouse_id13, c1_.car_id AS car_id14, c3_.discr AS discr15, c3_.spouse_id AS spouse_id16, c4_.car_id AS car_id17 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id INNER JOIN company_persons c3_ ON c0_.spouse_id = c3_.id LEFT JOIN company_managers c4_ ON c3_.id = c4_.id LEFT JOIN company_employees c5_ ON c3_.id = c5_.id",
array(Query::HINT_FORCE_PARTIAL_LOAD => false) array(Query::HINT_FORCE_PARTIAL_LOAD => false)
); );
} }
/**
* @group DDC-1384
*/
public function testAliasDoesNotExceedPlatformDefinedLength()
{
$this->assertSqlGeneration(
'SELECT m FROM ' . __NAMESPACE__ . '\\DDC1384Model m',
"SELECT d0_.aVeryLongIdentifierThatShouldBeShortenedByTheSQLWalker_fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo AS fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0 FROM DDC1384Model d0_"
);
}
/**
* @group DDC-331
* @group DDC-1384
*/
public function testIssue331()
{
$this->assertSqlGeneration(
'SELECT e.name FROM Doctrine\Tests\Models\Company\CompanyEmployee e',
'SELECT c0_.name AS name0 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id'
);
}
/**
* @group DDC-1435
*/
public function testForeignKeyAsPrimaryKeySubselect()
{
$this->assertSqlGeneration(
"SELECT s FROM Doctrine\Tests\Models\DDC117\DDC117Article s WHERE EXISTS (SELECT r FROM Doctrine\Tests\Models\DDC117\DDC117Reference r WHERE r.source = s)",
"SELECT d0_.article_id AS article_id0, d0_.title AS title1 FROM DDC117Article d0_ WHERE EXISTS (SELECT d1_.source_id, d1_.target_id FROM DDC117Reference d1_ WHERE d1_.source_id = d0_.article_id)"
);
}
} }
@ -1294,7 +1327,19 @@ class MyAbsFunction extends \Doctrine\ORM\Query\AST\Functions\FunctionNode
$parser->match(\Doctrine\ORM\Query\Lexer::T_OPEN_PARENTHESIS); $parser->match(\Doctrine\ORM\Query\Lexer::T_OPEN_PARENTHESIS);
$this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression(); $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(\Doctrine\ORM\Query\Lexer::T_CLOSE_PARENTHESIS); $parser->match(\Doctrine\ORM\Query\Lexer::T_CLOSE_PARENTHESIS);
} }
} }
/**
* @Entity
*/
class DDC1384Model
{
/**
* @Id
* @Column(type="integer")
* @GeneratedValue
*/
protected $aVeryLongIdentifierThatShouldBeShortenedByTheSQLWalker_fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo;
}

View File

@ -71,4 +71,88 @@ class SchemaValidatorTest extends \Doctrine\Tests\OrmTestCase
)); ));
$this->validator->validateMapping(); $this->validator->validateMapping();
} }
/**
* @group DDC-1439
*/
public function testInvalidManyToManyJoinColumnSchema()
{
$class1 = $this->em->getClassMetadata(__NAMESPACE__ . '\InvalidEntity1');
$class2 = $this->em->getClassMetadata(__NAMESPACE__ . '\InvalidEntity2');
$ce = $this->validator->validateClass($class1);
$this->assertEquals(
array(
"The inverse join columns of the many-to-many table 'Entity1Entity2' have to contain to ALL identifier columns of the target entity 'Doctrine\Tests\ORM\Tools\InvalidEntity2', however 'key4' are missing.",
"The join columns of the many-to-many table 'Entity1Entity2' have to contain to ALL identifier columns of the source entity 'Doctrine\Tests\ORM\Tools\InvalidEntity1', however 'key2' are missing."
),
$ce
);
}
/**
* @group DDC-1439
*/
public function testInvalidToOneJoinColumnSchema()
{
$class1 = $this->em->getClassMetadata(__NAMESPACE__ . '\InvalidEntity1');
$class2 = $this->em->getClassMetadata(__NAMESPACE__ . '\InvalidEntity2');
$ce = $this->validator->validateClass($class2);
$this->assertEquals(
array(
"The referenced column name 'id' does not have a corresponding field with this column name on the class 'Doctrine\Tests\ORM\Tools\InvalidEntity1'.",
"The join columns of the association 'assoc' have to match to ALL identifier columns of the source entity 'Doctrine\Tests\ORM\Tools\InvalidEntity2', however 'key3, key4' are missing."
),
$ce
);
}
}
/**
* @Entity
*/
class InvalidEntity1
{
/**
* @Id @Column
*/
protected $key1;
/**
* @Id @Column
*/
protected $key2;
/**
* @ManyToMany (targetEntity="InvalidEntity2")
* @JoinTable (name="Entity1Entity2",
* joinColumns={@JoinColumn(name="key1", referencedColumnName="key1")},
* inverseJoinColumns={@JoinColumn(name="key3", referencedColumnName="key3")}
* )
*/
protected $entity2;
}
/**
* @Entity
*/
class InvalidEntity2
{
/**
* @Id @Column
* @GeneratedValue(strategy="AUTO")
*/
protected $key3;
/**
* @Id @Column
* @GeneratedValue(strategy="AUTO")
*/
protected $key4;
/**
* @ManyToOne(targetEntity="InvalidEntity1")
*/
protected $assoc;
} }

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit>
<php>
<var name="db_type" value="pdo_mysql"/>
<var name="db_host" value="localhost" />
<var name="db_username" value="travis" />
<var name="db_password" value="" />
<var name="db_name" value="doctrine_tests" />
<var name="db_port" value="3306"/>
<var name="tmpdb_type" value="pdo_mysql"/>
<var name="tmpdb_host" value="localhost" />
<var name="tmpdb_username" value="travis" />
<var name="tmpdb_password" value="" />
<var name="tmpdb_name" value="doctrine_tests_tmp" />
<var name="tmpdb_port" value="3306"/>
</php>
<testsuites>
<testsuite name="Doctrine ORM Test Suite">
<directory>./../Doctrine/Tests/ORM</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit>
<php>
<!-- "Real" test database -->
<var name="db_type" value="pdo_pgsql"/>
<var name="db_host" value="localhost" />
<var name="db_username" value="postgres" />
<var name="db_password" value="" />
<var name="db_name" value="doctrine_tests" />
<var name="db_port" value="5432"/>
<!--<var name="db_event_subscribers" value="Doctrine\DBAL\Event\Listeners\OracleSessionInit">-->
<!-- Database for temporary connections (i.e. to drop/create the main database) -->
<var name="tmpdb_type" value="pdo_pgsql"/>
<var name="tmpdb_host" value="localhost" />
<var name="tmpdb_username" value="postgres" />
<var name="tmpdb_password" value="" />
<var name="tmpdb_name" value="doctrine_tests_tmp" />
<var name="tmpdb_port" value="5432"/>
</php>
<testsuites>
<testsuite name="Doctrine ORM Test Suite">
<directory>./../Doctrine/Tests/ORM</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit>
<testsuites>
<testsuite name="Doctrine ORM Test Suite">
<directory>./../Doctrine/Tests/ORM</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>