1
0
mirror of synced 2025-03-21 23:43:53 +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/Doctrine/Common
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
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
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),
inspired by Hibernates HQL. This provides developers with a powerful alternative to SQL that maintains flexibility
without requiring unnecessary code duplication.
More resources:
## More resources:
* [Website](http://www.doctrine-project.org)
* [Documentation](http://www.doctrine-project.org/projects/orm/2.0/docs/reference/introduction/en)
* [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": "*",
"doctrine/common": "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 integer $hydrationMode The hydration mode to use.
* @return IterableResult
* @return \Doctrine\ORM\Internal\Hydration\IterableResult
*/
public function iterate(array $params = array(), $hydrationMode = null)
{

View File

@ -225,6 +225,14 @@ class EntityRepository implements ObjectRepository
return $this->_entityName;
}
/**
* @return string
*/
public function getClassName()
{
return $this->getEntityName();
}
/**
* @return EntityManager
*/
@ -240,4 +248,4 @@ class EntityRepository implements ObjectRepository
{
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';
/**
* 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,
* after any changes to managed entities have been determined but before any

View File

@ -20,6 +20,7 @@
namespace Doctrine\ORM\Id;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\ORMException;
/**
@ -42,46 +43,29 @@ class AssignedGenerator extends AbstractIdGenerator
*/
public function generate(EntityManager $em, $entity)
{
$class = $em->getClassMetadata(get_class($entity));
$class = $em->getClassMetadata(get_class($entity));
$idFields = $class->getIdentifierFieldNames();
$identifier = array();
if ($class->isIdentifierComposite) {
$idFields = $class->getIdentifierFieldNames();
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];
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 {
if ( ! isset($value)) {
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;
}
}

View File

@ -46,7 +46,7 @@ class IdentityGenerator extends AbstractIdGenerator
*/
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->_allocationSize = $allocationSize;
}
/**
* 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) {
// Allocate new values
$conn = $em->getConnection();
$sql = $conn->getDatabasePlatform()->getSequenceNextValSQL($this->_sequenceName);
$this->_nextValue = $conn->fetchColumn($sql);
$this->_maxValue = $this->_nextValue + $this->_allocationSize;
$sql = $conn->getDatabasePlatform()->getSequenceNextValSQL($this->_sequenceName);
$this->_nextValue = (int)$conn->fetchColumn($sql);
$this->_maxValue = $this->_nextValue + $this->_allocationSize;
}
return $this->_nextValue++;
}
@ -90,13 +92,14 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
{
return serialize(array(
'allocationSize' => $this->_allocationSize,
'sequenceName' => $this->_sequenceName
'sequenceName' => $this->_sequenceName
));
}
public function unserialize($serialized)
{
$array = unserialize($serialized);
$this->_sequenceName = $array['sequenceName'];
$this->_allocationSize = $array['allocationSize'];
}

View File

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

View File

@ -22,15 +22,17 @@ namespace Doctrine\ORM\Internal\Hydration;
use PDO,
Doctrine\DBAL\Connection,
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
* of transformation of an SQL result set into another structure.
*
* @since 2.0
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org>
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
*/
abstract class AbstractHydrator
{
@ -62,9 +64,9 @@ abstract class AbstractHydrator
*/
public function __construct(EntityManager $em)
{
$this->_em = $em;
$this->_em = $em;
$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 $resultSetMapping
*
* @return IterableResult
*/
public function iterate($stmt, $resultSetMapping, array $hints = array())
{
$this->_stmt = $stmt;
$this->_rsm = $resultSetMapping;
$this->_stmt = $stmt;
$this->_rsm = $resultSetMapping;
$this->_hints = $hints;
$this->_prepare();
$this->prepare();
return new IterableResult($this);
}
@ -92,12 +97,16 @@ abstract class AbstractHydrator
*/
public function hydrateAll($stmt, $resultSetMapping, array $hints = array())
{
$this->_stmt = $stmt;
$this->_rsm = $resultSetMapping;
$this->_stmt = $stmt;
$this->_rsm = $resultSetMapping;
$this->_hints = $hints;
$this->_prepare();
$result = $this->_hydrateAll();
$this->_cleanup();
$this->prepare();
$result = $this->hydrateAllData();
$this->cleanup();
return $result;
}
@ -110,12 +119,17 @@ abstract class AbstractHydrator
public function hydrateRow()
{
$row = $this->_stmt->fetch(PDO::FETCH_ASSOC);
if ( ! $row) {
$this->_cleanup();
$this->cleanup();
return false;
}
$result = array();
$this->_hydrateRow($row, $this->_cache, $result);
$this->hydrateRowData($row, $this->_cache, $result);
return $result;
}
@ -123,16 +137,17 @@ abstract class AbstractHydrator
* Excutes one-time preparation tasks, once each time hydration is started
* 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
* through {@link hydrateAll} or {@link iterate()}.
*/
protected function _cleanup()
protected function cleanup()
{
$this->_rsm = null;
$this->_stmt->closeCursor();
$this->_stmt = null;
}
@ -146,23 +161,24 @@ abstract class AbstractHydrator
* @param array $cache The cache to use.
* @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.
*/
abstract protected function _hydrateAll();
abstract protected function hydrateAllData();
/**
* Processes a row of the result set.
*
* 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
* 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 &$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,
* 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();
foreach ($data as $key => $value) {
// Parse each column name only once. Cache the results.
if ( ! isset($cache[$key])) {
if (isset($this->_rsm->scalarMappings[$key])) {
$cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key];
$cache[$key]['isScalar'] = true;
} else if (isset($this->_rsm->fieldMappings[$key])) {
$fieldName = $this->_rsm->fieldMappings[$key];
$classMetadata = $this->_em->getClassMetadata($this->_rsm->declaringClasses[$key]);
$cache[$key]['fieldName'] = $fieldName;
$cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']);
$cache[$key]['isIdentifier'] = $classMetadata->isIdentifier($fieldName);
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
} else if (!isset($this->_rsm->metaMappings[$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.
continue;
} else {
// Meta column (has meaning in relational schema only, i.e. foreign keys or discriminator columns).
$fieldName = $this->_rsm->metaMappings[$key];
$cache[$key]['isMetaColumn'] = true;
$cache[$key]['fieldName'] = $fieldName;
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
$classMetadata = $this->_em->getClassMetadata($this->_rsm->aliasMap[$cache[$key]['dqlAlias']]);
$cache[$key]['isIdentifier'] = isset($this->_rsm->isIdentifierColumn[$cache[$key]['dqlAlias']][$key]);
switch (true) {
// NOTE: Most of the times it's a field mapping, so keep it first!!!
case (isset($this->_rsm->fieldMappings[$key])):
$fieldName = $this->_rsm->fieldMappings[$key];
$classMetadata = $this->_em->getClassMetadata($this->_rsm->declaringClasses[$key]);
$cache[$key]['fieldName'] = $fieldName;
$cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']);
$cache[$key]['isIdentifier'] = $classMetadata->isIdentifier($fieldName);
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
break;
case (isset($this->_rsm->scalarMappings[$key])):
$cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key];
$cache[$key]['isScalar'] = true;
break;
case (isset($this->_rsm->metaMappings[$key])):
// Meta column (has meaning in relational schema only, i.e. foreign keys or discriminator columns).
$fieldName = $this->_rsm->metaMappings[$key];
$classMetadata = $this->_em->getClassMetadata($this->_rsm->aliasMap[$this->_rsm->columnOwnerMap[$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'])) {
$rowData['scalars'][$cache[$key]['fieldName']] = $value;
continue;
}
@ -216,13 +243,14 @@ abstract class AbstractHydrator
}
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;
}
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.
// 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) {
@ -241,6 +269,7 @@ abstract class AbstractHydrator
/**
* Processes a row of the result set.
*
* Used for HYDRATE_SCALAR. This is a variant of _gatherRowData() that
* simply converts column names to field names and properly converts the
* values according to their types. The resulting row has the same number
@ -248,52 +277,77 @@ abstract class AbstractHydrator
*
* @param array $data
* @param array $cache
*
* @return array The processed row.
*/
protected function _gatherScalarRowData(&$data, &$cache)
protected function gatherScalarRowData(&$data, &$cache)
{
$rowData = array();
foreach ($data as $key => $value) {
// Parse each column name only once. Cache the results.
if ( ! isset($cache[$key])) {
if (isset($this->_rsm->scalarMappings[$key])) {
$cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key];
$cache[$key]['isScalar'] = true;
} else if (isset($this->_rsm->fieldMappings[$key])) {
$fieldName = $this->_rsm->fieldMappings[$key];
$classMetadata = $this->_em->getClassMetadata($this->_rsm->declaringClasses[$key]);
$cache[$key]['fieldName'] = $fieldName;
$cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']);
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
} else if (!isset($this->_rsm->metaMappings[$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.
continue;
} else {
// 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];
switch (true) {
// NOTE: During scalar hydration, most of the times it's a scalar mapping, keep it first!!!
case (isset($this->_rsm->scalarMappings[$key])):
$cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key];
$cache[$key]['isScalar'] = true;
break;
case (isset($this->_rsm->fieldMappings[$key])):
$fieldName = $this->_rsm->fieldMappings[$key];
$classMetadata = $this->_em->getClassMetadata($this->_rsm->declaringClasses[$key]);
$cache[$key]['fieldName'] = $fieldName;
$cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']);
$cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key];
break;
case (isset($this->_rsm->metaMappings[$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'];
if (isset($cache[$key]['isScalar'])) {
$rowData[$fieldName] = $value;
} else if (isset($cache[$key]['isMetaColumn'])) {
$rowData[$cache[$key]['dqlAlias'] . '_' . $fieldName] = $value;
} else {
$rowData[$cache[$key]['dqlAlias'] . '_' . $fieldName] = $cache[$key]['type']
->convertToPHPValue($value, $this->_platform);
switch (true) {
case (isset($cache[$key]['isScalar'])):
$rowData[$fieldName] = $value;
break;
case (isset($cache[$key]['isMetaColumn'])):
$rowData[$cache[$key]['dqlAlias'] . '_' . $fieldName] = $value;
break;
default:
$value = $cache[$key]['type']->convertToPHPValue($value, $this->_platform);
$rowData[$cache[$key]['dqlAlias'] . '_' . $fieldName] = $value;
}
}
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) {
$id = array();
@ -311,6 +365,7 @@ abstract class AbstractHydrator
$id = array($class->identifier[0] => $data[$class->identifier[0]]);
}
}
$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)
* interchangeable with the corresponding object graph for read-only access.
*
* @since 2.0
* @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
{
@ -38,45 +44,55 @@ class ArrayHydrator extends AbstractHydrator
private $_idTemplate = array();
private $_resultCounter = 0;
/** @override */
protected function _prepare()
/**
* {@inheritdoc}
*/
protected function prepare()
{
$this->_isSimpleQuery = count($this->_rsm->aliasMap) <= 1;
$this->_identifierMap = array();
$this->_isSimpleQuery = count($this->_rsm->aliasMap) <= 1;
$this->_identifierMap = array();
$this->_resultPointers = array();
$this->_idTemplate = array();
$this->_resultCounter = 0;
$this->_idTemplate = array();
$this->_resultCounter = 0;
foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
$this->_identifierMap[$dqlAlias] = array();
$this->_identifierMap[$dqlAlias] = array();
$this->_resultPointers[$dqlAlias] = array();
$this->_idTemplate[$dqlAlias] = '';
$this->_idTemplate[$dqlAlias] = '';
}
}
/** @override */
protected function _hydrateAll()
/**
* {@inheritdoc}
*/
protected function hydrateAllData()
{
$result = array();
$cache = array();
$cache = array();
while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
$this->_hydrateRow($data, $cache, $result);
$this->hydrateRowData($data, $cache, $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
$id = $this->_idTemplate; // initialize the id-memory
$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.
if (isset($rowData['scalars'])) {
$scalars = $rowData['scalars'];
unset($rowData['scalars']);
if (empty($rowData)) {
++$this->_resultCounter;
}
@ -90,7 +106,7 @@ class ArrayHydrator extends AbstractHydrator
// It's a joined result
$parent = $this->_rsm->parentAliasMap[$dqlAlias];
$path = $parent . '.' . $dqlAlias;
$path = $parent . '.' . $dqlAlias;
// missing parent data, skipping as RIGHT JOIN hydration is not supported.
if ( ! isset($nonemptyComponents[$parent]) ) {
@ -109,39 +125,41 @@ class ArrayHydrator extends AbstractHydrator
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
continue;
}
$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)
if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) {
$oneToOne = false;
if (isset($nonemptyComponents[$dqlAlias])) {
if ( ! isset($baseElement[$relationAlias])) {
$baseElement[$relationAlias] = array();
}
$indexExists = isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]);
$index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false;
$indexExists = isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]);
$index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false;
$indexIsValid = $index !== false ? isset($baseElement[$relationAlias][$index]) : false;
if ( ! $indexExists || ! $indexIsValid) {
$element = $data;
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
$field = $this->_rsm->indexByMap[$dqlAlias];
$baseElement[$relationAlias][$element[$field]] = $element;
$baseElement[$relationAlias][$row[$this->_rsm->indexByMap[$dqlAlias]]] = $element;
} else {
$baseElement[$relationAlias][] = $element;
}
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])) {
$baseElement[$relationAlias] = array();
}
} else {
$oneToOne = true;
if ( ! isset($nonemptyComponents[$dqlAlias]) && ! isset($baseElement[$relationAlias])) {
$baseElement[$relationAlias] = null;
} else if ( ! isset($baseElement[$relationAlias])) {
@ -157,43 +175,42 @@ class ArrayHydrator extends AbstractHydrator
} else {
// It's a root result element
$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 ( ! isset($nonemptyComponents[$dqlAlias]) ) {
if ($this->_rsm->isMixed) {
$result[] = array(0 => null);
$result[] = array($entityKey => null);
} else {
$result[] = null;
}
$resultKey = $this->_resultCounter;
++$this->_resultCounter;
continue;
}
// Check for an existing element
if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
$element = $rowData[$dqlAlias];
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
$field = $this->_rsm->indexByMap[$dqlAlias];
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;
}
if ($this->_rsm->isMixed) {
$element = array($entityKey => $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 {
$index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
$resultKey = $index;
/*if ($this->_rsm->isMixed) {
$result[] =& $result[$index];
++$this->_resultCounter;
@ -205,8 +222,17 @@ class ArrayHydrator extends AbstractHydrator
// Append scalar values to mixed result sets
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) {
$result[$this->_resultCounter - 1][$name] = $value;
$result[$resultKey][$name] = $value;
}
}
}
@ -224,28 +250,45 @@ class ArrayHydrator extends AbstractHydrator
{
if ($coll === null) {
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
return;
}
if ($index !== false) {
$this->_resultPointers[$dqlAlias] =& $coll[$index];
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])) {
$this->_ce[$className] = $this->_em->getClassMetadata($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.");
}
public static function parentObjectOfRelationNotFound($alias, $parentAlias)
{
return new self("The parent object of entity result with alias '$alias' was not found."
. " 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.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
*
* @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
{
@ -53,57 +60,72 @@ class ObjectHydrator extends AbstractHydrator
/** @override */
protected function _prepare()
protected function prepare()
{
$this->_identifierMap =
$this->_resultPointers =
$this->_idTemplate = array();
$this->_resultCounter = 0;
if (!isset($this->_hints['deferEagerLoad'])) {
if ( ! isset($this->_hints['deferEagerLoad'])) {
$this->_hints['deferEagerLoad'] = true;
}
foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
$this->_identifierMap[$dqlAlias] = array();
$this->_idTemplate[$dqlAlias] = '';
$class = $this->_em->getClassMetadata($className);
$this->_idTemplate[$dqlAlias] = '';
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
// collection stubs or proxies and where not.
if (isset($this->_rsm->relationMap[$dqlAlias])) {
if ( ! isset($this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]])) {
throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $this->_rsm->parentAliasMap[$dqlAlias]);
if ( ! isset($this->_rsm->relationMap[$dqlAlias])) {
continue;
}
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]];
$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) {
// 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;
}
}
}
}
$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}
*/
protected function _cleanup()
protected function cleanup()
{
$eagerLoad = (isset($this->_hints['deferEagerLoad'])) && $this->_hints['deferEagerLoad'] == true;
parent::_cleanup();
parent::cleanup();
$this->_identifierMap =
$this->_initializedCollections =
$this->_existingCollections =
@ -131,13 +154,13 @@ class ObjectHydrator extends AbstractHydrator
/**
* {@inheritdoc}
*/
protected function _hydrateAll()
protected function hydrateAllData()
{
$result = array();
$cache = array();
$cache = array();
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
@ -156,31 +179,34 @@ class ObjectHydrator extends AbstractHydrator
*/
private function _initRelatedCollection($entity, $class, $fieldName)
{
$oid = spl_object_hash($entity);
$oid = spl_object_hash($entity);
$relation = $class->associationMappings[$fieldName];
$value = $class->reflFields[$fieldName]->getValue($entity);
$value = $class->reflFields[$fieldName]->getValue($entity);
if ($value === null) {
$value = new ArrayCollection;
}
if ( ! $value instanceof PersistentCollection) {
$value = new PersistentCollection(
$this->_em,
$this->_ce[$relation['targetEntity']],
$value
$this->_em, $this->_ce[$relation['targetEntity']], $value
);
$value->setOwner($entity, $relation);
$class->reflFields[$fieldName]->setValue($entity, $value);
$this->_uow->setOriginalEntityProperty($oid, $fieldName, $value);
$this->_initializedCollections[$oid . $fieldName] = $value;
} else if (isset($this->_hints[Query::HINT_REFRESH]) ||
isset($this->_hints['fetched'][$class->name][$fieldName]) &&
! $value->isInitialized()) {
} else if (
isset($this->_hints[Query::HINT_REFRESH]) ||
isset($this->_hints['fetched'][$class->name][$fieldName]) &&
! $value->isInitialized()
) {
// Is already PersistentCollection, but either REFRESH or FETCH-JOIN and UNINITIALIZED!
$value->setDirty(false);
$value->setInitialized(true);
$value->unwrap()->clear();
$this->_initializedCollections[$oid . $fieldName] = $value;
} else {
// Is already PersistentCollection, and DON'T REFRESH or FETCH-JOIN!
@ -200,15 +226,21 @@ class ObjectHydrator extends AbstractHydrator
private function _getEntity(array $data, $dqlAlias)
{
$className = $this->_rsm->aliasMap[$dqlAlias];
if (isset($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]];
unset($data[$discrColumn]);
}
if (isset($this->_hints[Query::HINT_REFRESH_ENTITY]) && isset($this->_rootAliases[$dqlAlias])) {
$class = $this->_ce[$className];
$this->registerManaged($class, $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
$this->registerManaged($this->_ce[$className], $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
}
return $this->_uow->createEntity($className, $data, $this->_hints);
@ -218,6 +250,7 @@ class ObjectHydrator extends AbstractHydrator
{
// TODO: Abstract this code and UnitOfWork::createEntity() equivalent?
$class = $this->_ce[$className];
/* @var $class ClassMetadata */
if ($class->isIdentifierComposite) {
$idHash = '';
@ -249,6 +282,7 @@ class ObjectHydrator extends AbstractHydrator
if ( ! isset($this->_ce[$className])) {
$this->_ce[$className] = $this->_em->getClassMetadata($className);
}
return $this->_ce[$className];
}
@ -273,13 +307,13 @@ class ObjectHydrator extends AbstractHydrator
* @param array $cache The cache to use.
* @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
$id = $this->_idTemplate; // initialize the id-memory
$nonemptyComponents = array();
// 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.
if (isset($rowData['scalars'])) {
@ -352,8 +386,7 @@ class ObjectHydrator extends AbstractHydrator
$element = $this->_getEntity($data, $dqlAlias);
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
$field = $this->_rsm->indexByMap[$dqlAlias];
$indexValue = $this->_ce[$entityName]->reflFields[$field]->getValue($element);
$indexValue = $row[$this->_rsm->indexByMap[$dqlAlias]];
$reflFieldValue->hydrateSet($indexValue, $element);
$this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $indexValue;
} else {
@ -380,6 +413,7 @@ class ObjectHydrator extends AbstractHydrator
$reflField->setValue($parentObject, $element);
$this->_uow->setOriginalEntityProperty($oid, $relationField, $element);
$targetClass = $this->_ce[$relation['targetEntity']];
if ($relation['isOwningSide']) {
//TODO: Just check hints['fetched'] here?
// If there is an inverse mapping on the target class its bidirectional
@ -410,14 +444,16 @@ class ObjectHydrator extends AbstractHydrator
} else {
// PATH C: Its a root result element
$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 ( ! isset($nonemptyComponents[$dqlAlias]) ) {
if ($this->_rsm->isMixed) {
$result[] = array(0 => null);
$result[] = array($entityKey => null);
} else {
$result[] = null;
}
$resultKey = $this->_resultCounter;
++$this->_resultCounter;
continue;
}
@ -425,35 +461,31 @@ class ObjectHydrator extends AbstractHydrator
// check for existing result from the iterations before
if ( ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
$element = $this->_getEntity($rowData[$dqlAlias], $dqlAlias);
if ($this->_rsm->isMixed) {
$element = array($entityKey => $element);
}
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
$field = $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;
}
$resultKey = $row[$this->_rsm->indexByMap[$dqlAlias]];
if (isset($this->_hints['collection'])) {
$this->_hints['collection']->hydrateSet($key, $element);
$this->_hints['collection']->hydrateSet($resultKey, $element);
}
$result[$resultKey] = $element;
} else {
if ($this->_rsm->isMixed) {
$element = array(0 => $element);
}
$result[] = $element;
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $this->_resultCounter;
$resultKey = $this->_resultCounter;
++$this->_resultCounter;
if (isset($this->_hints['collection'])) {
$this->_hints['collection']->hydrateAdd($element);
}
$result[] = $element;
}
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
// Update result pointer
$this->_resultPointers[$dqlAlias] = $element;
@ -461,6 +493,7 @@ class ObjectHydrator extends AbstractHydrator
// Update result pointer
$index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
$this->_resultPointers[$dqlAlias] = $result[$index];
$resultKey = $index;
/*if ($this->_rsm->isMixed) {
$result[] = $result[$index];
++$this->_resultCounter;
@ -471,8 +504,16 @@ class ObjectHydrator extends AbstractHydrator
// Append scalar values to mixed result sets
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) {
$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
* that column names are mapped to field names and data type conversions take place.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
*/
class ScalarHydrator extends AbstractHydrator
{
/** @override */
protected function _hydrateAll()
/**
* {@inheritdoc}
*/
protected function hydrateAllData()
{
$result = array();
$cache = array();
$cache = array();
while ($data = $this->_stmt->fetch(\PDO::FETCH_ASSOC)) {
$result[] = $this->_gatherScalarRowData($data, $cache);
$this->hydrateRowData($data, $cache, $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>.
*/
namespace Doctrine\ORM\Internal\Hydration;
use \PDO;
@ -32,15 +31,21 @@ class SimpleObjectHydrator extends AbstractHydrator
*/
private $class;
/**
* @var array
*/
private $declaringClasses = array();
protected function _hydrateAll()
/**
* {@inheritdoc}
*/
protected function hydrateAllData()
{
$result = array();
$cache = array();
while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
$this->_hydrateRow($row, $cache, $result);
$this->hydrateRowData($row, $cache, $result);
}
$this->_em->getUnitOfWork()->triggerEagerLoads();
@ -48,77 +53,71 @@ class SimpleObjectHydrator extends AbstractHydrator
return $result;
}
protected function _prepare()
/**
* {@inheritdoc}
*/
protected function prepare()
{
if (count($this->_rsm->aliasMap) == 1) {
$this->class = $this->_em->getClassMetadata(reset($this->_rsm->aliasMap));
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 (count($this->_rsm->aliasMap) !== 1) {
throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping that contains more than one object result.");
}
if ($this->_rsm->scalarMappings) {
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();
if ($this->class->inheritanceType == ClassMetadata::INHERITANCE_TYPE_NONE) {
foreach ($sqlResult as $column => $value) {
if (!isset($cache[$column])) {
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 {
$entityName = $this->class->name;
$data = array();
// We need to find the correct entity class name if we have inheritance in resultset
if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
$discrColumnName = $this->_platform->getSQLResultCasing($this->class->discriminatorColumn['name']);
if ($sqlResult[$discrColumnName] === '') {
throw HydrationException::emptyDiscriminatorValue(key($this->_rsm->aliasMap));
}
$entityName = $this->class->discriminatorMap[$sqlResult[$discrColumnName]];
unset($sqlResult[$discrColumnName]);
foreach ($sqlResult as $column => $value) {
if (!isset($cache[$column])) {
if (isset($this->_rsm->fieldMappings[$column])) {
$field = $this->_rsm->fieldMappings[$column];
$class = $this->declaringClasses[$column];
if ($class->name == $entityName || is_subclass_of($entityName, $class->name)) {
$cache[$column]['name'] = $field;
$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];
}
}
foreach ($sqlResult as $column => $value) {
// Hydrate column information if not yet present
if ( ! isset($cache[$column])) {
if (($info = $this->hydrateColumnInfo($entityName, $column)) === null) {
continue;
}
$cache[$column] = $info;
}
if (isset($cache[$column]['class'])) {
$value = Type::getType($cache[$column]['class']->fieldMappings[$cache[$column]['name']]['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)
if (isset($cache[$column]) && (!isset($data[$cache[$column]['name']]) || $value !== null)) {
$data[$cache[$column]['name']] = $value;
}
// Convert field to a valid PHP value
if (isset($cache[$column]['field'])) {
$type = Type::getType($cache[$column]['class']->fieldMappings[$cache[$column]['name']]['type']);
$value = $type->convertToPHPValue($value, $this->_platform);
}
// Prevent overwrite in case of inherit classes using same property name (See AbstractHydrator)
if (isset($cache[$column]) && ( ! isset($data[$cache[$column]['name']]) || $value !== null)) {
$data[$cache[$column]['name']] = $value;
}
}
@ -128,4 +127,52 @@ class SimpleObjectHydrator extends AbstractHydrator
$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;
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.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
*/
class SingleScalarHydrator extends AbstractHydrator
{
/** @override */
protected function _hydrateAll()
/**
* {@inheritdoc}
*/
protected function hydrateAllData()
{
$cache = array();
$result = $this->_stmt->fetchAll(\PDO::FETCH_ASSOC);
$num = count($result);
if ($num == 0) {
throw new \Doctrine\ORM\NoResultException;
} else if ($num > 1 || count($result[key($result)]) > 1) {
throw new \Doctrine\ORM\NonUniqueResultException;
$data = $this->_stmt->fetchAll(\PDO::FETCH_ASSOC);
$numRows = count($data);
if ($numRows === 0) {
throw new NoResultException();
}
$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);
}

View File

@ -312,6 +312,10 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
if ($parent && $parent->containsForeignIdentifier) {
$class->containsForeignIdentifier = true;
}
if ($parent && !empty ($parent->namedQueries)) {
$this->addInheritedNamedQueries($class, $parent);
}
$class->setParentClasses($visited);
@ -428,6 +432,25 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
$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

View File

@ -136,10 +136,6 @@ class ClassMetadataInfo implements ClassMetadata
* Identifies a many-to-one association.
*/
const MANY_TO_ONE = 2;
/**
* Combined bitmask for to-one (single-valued) associations.
*/
const TO_ONE = 3;
/**
* Identifies a one-to-many association.
*/
@ -148,6 +144,10 @@ class ClassMetadataInfo implements ClassMetadata
* Identifies a many-to-many association.
*/
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.
*/
@ -685,7 +685,7 @@ class ClassMetadataInfo implements ClassMetadata
if ( ! isset($this->namedQueries[$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()
{
if ($this->isIdentifierComposite) {
$columnNames = array();
foreach ($this->identifier as $idField) {
if (isset($this->associationMappings[$idField])) {
// no composite pk as fk entity assumption:
$columnNames[] = $this->associationMappings[$idField]['joinColumns'][0]['name'];
} else {
$columnNames[] = $this->fieldMappings[$idField]['columnName'];
}
$columnNames = array();
foreach ($this->identifier as $idProperty) {
if (isset($this->fieldMappings[$idProperty])) {
$columnNames[] = $this->fieldMappings[$idProperty]['columnName'];
continue;
}
return $columnNames;
} else if(isset($this->fieldMappings[$this->identifier[0]])) {
return array($this->fieldMappings[$this->identifier[0]]['columnName']);
} else {
// no composite pk as fk entity assumption:
return array($this->associationMappings[$this->identifier[0]]['joinColumns'][0]['name']);
// Association defined as Id field
$joinColumns = $this->associationMappings[$idProperty]['joinColumns'];
$assocColumnNames = array_map(function ($joinColumn) { return $joinColumn['name']; }, $joinColumns);
$columnNames = array_merge($columnNames, $assocColumnNames);
}
return $columnNames;
}
/**
* 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']])) {
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.
*
* @param AssociationMapping $assocMapping
* @param array $assocMapping
*/
protected function _storeAssociationMapping(array $assocMapping)
{
$sourceFieldName = $assocMapping['fieldName'];
if (isset($this->fieldMappings[$sourceFieldName]) || isset($this->associationMappings[$sourceFieldName])) {
throw MappingException::duplicateFieldMapping($this->name, $sourceFieldName);
}
$this->associationMappings[$sourceFieldName] = $assocMapping;
}
@ -1904,6 +1913,42 @@ class ClassMetadataInfo implements ClassMetadata
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
* in an SQL statement.
@ -1914,7 +1959,9 @@ class ClassMetadataInfo implements ClassMetadata
*/
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['cascade'] = $oneToOneAnnot->cascade;
$mapping['orphanRemoval'] = $oneToOneAnnot->orphanRemoval;
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToOneAnnot->fetch);
$mapping['fetch'] = $this->getFetchMode($className, $oneToOneAnnot->fetch);
$metadata->mapOneToOne($mapping);
} else if ($oneToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToMany')) {
$mapping['mappedBy'] = $oneToManyAnnot->mappedBy;
@ -339,7 +339,7 @@ class AnnotationDriver implements Driver
$mapping['cascade'] = $oneToManyAnnot->cascade;
$mapping['indexBy'] = $oneToManyAnnot->indexBy;
$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')) {
$mapping['orderBy'] = $orderByAnnot->value;
@ -355,7 +355,7 @@ class AnnotationDriver implements Driver
$mapping['cascade'] = $manyToOneAnnot->cascade;
$mapping['inversedBy'] = $manyToOneAnnot->inversedBy;
$mapping['targetEntity'] = $manyToOneAnnot->targetEntity;
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToOneAnnot->fetch);
$mapping['fetch'] = $this->getFetchMode($className, $manyToOneAnnot->fetch);
$metadata->mapManyToOne($mapping);
} else if ($manyToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToMany')) {
$joinTable = array();
@ -395,7 +395,7 @@ class AnnotationDriver implements Driver
$mapping['inversedBy'] = $manyToManyAnnot->inversedBy;
$mapping['cascade'] = $manyToManyAnnot->cascade;
$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')) {
$mapping['orderBy'] = $orderByAnnot->value;
@ -446,6 +446,10 @@ class AnnotationDriver implements Driver
if (isset($annotations['Doctrine\ORM\Mapping\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;
}
/**
* 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
*

View File

@ -387,3 +387,9 @@ final class PostRemove implements Annotation {}
* @Target("METHOD")
*/
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'])) {
$metadata->table['schema'] = (string)$xmlRoot['schema'];
}*/
if (isset($xmlRoot['inheritance-type'])) {
$inheritanceType = (string)$xmlRoot['inheritance-type'];
$metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceType));
@ -166,9 +166,12 @@ class XmlDriver extends AbstractFileDriver
foreach ($xmlRoot->field as $fieldMapping) {
$mapping = array(
'fieldName' => (string)$fieldMapping['name'],
'type' => (string)$fieldMapping['type']
);
if (isset($fieldMapping['type'])) {
$mapping['type'] = (string)$fieldMapping['type'];
}
if (isset($fieldMapping['column'])) {
$mapping['columnName'] = (string)$fieldMapping['column'];
}
@ -219,9 +222,12 @@ class XmlDriver extends AbstractFileDriver
$mapping = array(
'id' => true,
'fieldName' => (string)$idElement['name'],
'type' => (string)$idElement['type']
'fieldName' => (string)$idElement['name']
);
if (isset($fieldMapping['type'])) {
$mapping['type'] = (string)$idElement['type'];
}
if (isset($idElement['column'])) {
$mapping['columnName'] = (string)$idElement['column'];
@ -327,6 +333,8 @@ class XmlDriver extends AbstractFileDriver
if (isset($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);
@ -432,8 +440,10 @@ class XmlDriver extends AbstractFileDriver
$mapping['orderBy'] = $orderBy;
}
if (isset($manyToManyElement->{'index-by'})) {
$mapping['indexBy'] = (string)$manyToManyElement->{'index-by'};
if (isset($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);

View File

@ -165,15 +165,14 @@ class YamlDriver extends AbstractFileDriver
continue;
}
if (!isset($idElement['type'])) {
throw MappingException::propertyTypeIsRequired($className, $name);
}
$mapping = array(
'id' => true,
'fieldName' => $name,
'type' => $idElement['type']
'fieldName' => $name
);
if (isset($idElement['type'])) {
$mapping['type'] = $idElement['type'];
}
if (isset($idElement['column'])) {
$mapping['columnName'] = $idElement['column'];
@ -201,19 +200,21 @@ class YamlDriver extends AbstractFileDriver
// Evaluate fields
if (isset($element['fields'])) {
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(
'fieldName' => $name,
'type' => $fieldMapping['type']
'fieldName' => $name
);
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'])) {
$mapping['id'] = true;
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.");
}
}
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.
*
*
* @var boolean
*/
private $initialized = true;
/**
* The wrapped Collection instance.
*
*
* @var Collection
*/
private $coll;
/**
* Creates a new persistent collection.
*
*
* @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 array The collection elements.
@ -144,7 +144,7 @@ final class PersistentCollection implements Collection
{
return $this->owner;
}
public function getTypeClass()
{
return $this->typeClass;
@ -154,7 +154,7 @@ final class PersistentCollection implements Collection
* INTERNAL:
* Adds an element to a collection during hydration. This will automatically
* complete bidirectional associations in the case of a one-to-many association.
*
*
* @param mixed $element The element to add.
*/
public function hydrateAdd($element)
@ -172,7 +172,7 @@ final class PersistentCollection implements Collection
$this->owner);
}
}
/**
* INTERNAL:
* Sets a keyed element in the collection during hydration.
@ -271,7 +271,7 @@ final class PersistentCollection implements Collection
{
return $this->association;
}
/**
* Marks this collection as changed/dirty.
*/
@ -306,17 +306,17 @@ final class PersistentCollection implements Collection
{
$this->isDirty = $dirty;
}
/**
* Sets the initialized flag of the collection, forcing it into that state.
*
*
* @param boolean $bool
*/
public function setInitialized($bool)
{
$this->initialized = $bool;
}
/**
* Checks whether this collection has been initialized.
*
@ -377,7 +377,7 @@ final class PersistentCollection implements Collection
$this->em->getUnitOfWork()->getCollectionPersister($this->association)
->deleteRows($this, $element);
}*/
$this->initialize();
$removed = $this->coll->removeElement($element);
if ($removed) {
@ -410,7 +410,7 @@ final class PersistentCollection implements Collection
->getCollectionPersister($this->association)
->contains($this, $element);
}
$this->initialize();
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) {
return $this->em->getUnitOfWork()
->getCollectionPersister($this->association)
->count($this) + $this->coll->count();
->count($this) + ($this->isDirty ? $this->coll->count() : 0);
}
$this->initialize();
@ -503,7 +503,7 @@ final class PersistentCollection implements Collection
$this->initialize();
return $this->coll->isEmpty();
}
/**
* {@inheritdoc}
*/
@ -530,7 +530,7 @@ final class PersistentCollection implements Collection
$this->initialize();
return $this->coll->filter($p);
}
/**
* {@inheritdoc}
*/
@ -548,7 +548,7 @@ final class PersistentCollection implements Collection
$this->initialize();
return $this->coll->partition($p);
}
/**
* {@inheritdoc}
*/
@ -579,7 +579,7 @@ final class PersistentCollection implements Collection
$this->takeSnapshot();
}
}
/**
* Called by PHP when this collection is serialized. Ensures that only the
* elements are properly serialized.
@ -591,7 +591,7 @@ final class PersistentCollection implements Collection
{
return array('coll', 'initialized');
}
/* ArrayAccess implementation */
/**
@ -629,12 +629,12 @@ final class PersistentCollection implements Collection
{
return $this->remove($offset);
}
public function key()
{
return $this->coll->key();
}
/**
* Gets the element of the collection at the current iterator position.
*/
@ -642,7 +642,7 @@ final class PersistentCollection implements Collection
{
return $this->coll->current();
}
/**
* Moves the internal iterator position to the next element.
*/
@ -650,7 +650,7 @@ final class PersistentCollection implements Collection
{
return $this->coll->next();
}
/**
* Retrieves the wrapped Collection instance.
*/
@ -672,7 +672,10 @@ final class PersistentCollection implements Collection
*/
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()
->getCollectionPersister($this->association)
->slice($this, $offset, $length);

View File

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

View File

@ -1001,27 +1001,26 @@ class BasicEntityPersister
$columnList .= $assoc2ColumnSQL;
}
}
$this->_selectJoinSql .= ' LEFT JOIN'; // TODO: Inner join when all join columns are NOT nullable.
$first = true;
if ($assoc['isOwningSide']) {
$this->_selectJoinSql .= ' ' . $this->getJoinSQLForJoinColumns($assoc['joinColumns']);
$this->_selectJoinSql .= ' ' . $eagerEntity->getQuotedTableName($this->_platform) . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) .' ON ';
foreach ($assoc['sourceToTargetKeyColumns'] AS $sourceCol => $targetCol) {
if ( ! $first) {
$this->_selectJoinSql .= ' AND ';
}
$this->_selectJoinSql .= $this->_getSQLTableAlias($assoc['sourceEntity']) . '.' . $sourceCol . ' = '
. $this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias) . '.' . $targetCol . ' ';
$this->_selectJoinSql .= $this->_getSQLTableAlias($assoc['sourceEntity']) . '.' . $sourceCol . ' = '
. $this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias) . '.' . $targetCol;
$first = false;
}
} else {
$eagerEntity = $this->_em->getClassMetadata($assoc['targetEntity']);
$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 ';
foreach ($owningAssoc['sourceToTargetKeyColumns'] AS $sourceCol => $targetCol) {
@ -1030,7 +1029,7 @@ class BasicEntityPersister
}
$this->_selectJoinSql .= $this->_getSQLTableAlias($owningAssoc['sourceEntity'], $assocAlias) . '.' . $sourceCol . ' = '
. $this->_getSQLTableAlias($owningAssoc['targetEntity']) . '.' . $targetCol . ' ';
. $this->_getSQLTableAlias($owningAssoc['targetEntity']) . '.' . $targetCol;
$first = false;
}
}
@ -1060,9 +1059,8 @@ class BasicEntityPersister
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
if ($columnList) $columnList .= ', ';
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
$columnList .= $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) )
$resultColumnName = $this->getSQLColumnAlias($srcColumn);
$columnList .= $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) )
. '.' . $srcColumn . ' AS ' . $resultColumnName;
$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')
{
$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);
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
$columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]);
$this->_rsm->addFieldResult($alias, $columnAlias, $field);
@ -1500,4 +1497,37 @@ class BasicEntityPersister
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 = '';
$methodNames = array();
foreach ($class->reflClass->getMethods() as $method) {
/* @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;
}
$methodNames[$method->getName()] = true;
if ($method->isPublic() && ! $method->isFinal() && ! $method->isStatic()) {
$methods .= "\n" . ' public function ';
@ -210,8 +212,12 @@ class ProxyFactory
$methods .= $parameterString . ')';
$methods .= "\n" . ' {' . "\n";
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 .= ' return $this->_identifier["' . lcfirst(substr($method->getName(), 3)) . '"];' . "\n";
$methods .= ' return ' . $cast . '$this->_identifier["' . $identifier . '"];' . "\n";
$methods .= ' }' . "\n";
}
$methods .= ' $this->__load();' . "\n";
@ -230,13 +236,14 @@ class ProxyFactory
*/
private function isShortIdentifierGetter($method, $class)
{
$identifier = lcfirst(substr($method->getName(), 3));
$identifier = lcfirst(substr($method->getName(), 3));
return (
$method->getNumberOfParameters() == 0 &&
substr($method->getName(), 0, 3) == "get" &&
in_array($identifier, $class->identifier, true) &&
$class->hasField($identifier) &&
(($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 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)
{

View File

@ -39,30 +39,30 @@ class Composite extends Base
if ($this->count() === 1) {
return (string) $this->_parts[0];
}
$components = array();
foreach ($this->_parts as $part) {
$components[] = $this->processQueryPart($part);
}
return implode($this->_separator, $components);
}
private function processQueryPart($part)
{
$queryPart = (string) $part;
if (is_object($part) && $part instanceof self && $part->count() > 1) {
return $this->_preSeparator . $queryPart . $this->_postSeparator;
}
// 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 $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);
}
public static function invalidLockMode()
{
return new self('Invalid lock mode hint provided.');
}
public static function invalidParameterType($expected, $received)
{
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)
* reduce the size of serialized instances for more effective caching due to better (un-)serialization
* performance.
*
*
* <b>Users should use the public methods.</b>
*
* @author Roman Borschel <roman@code-factory.org>
@ -36,87 +36,79 @@ namespace Doctrine\ORM\Query;
class ResultSetMapping
{
/**
* Whether the result is mixed (contains scalar values together with field values).
*
* @ignore
* @var boolean
* @var boolean Whether the result is mixed (contains scalar values together with field values).
*/
public $isMixed = false;
/**
* Maps alias names to class names.
*
* @ignore
* @var array
* @var array Maps alias names to class names.
*/
public $aliasMap = array();
/**
* Maps alias names to related association field names.
*
* @ignore
* @var array
* @var array Maps alias names to related association field names.
*/
public $relationMap = array();
/**
* Maps alias names to parent alias names.
*
* @ignore
* @var array
* @var array Maps alias names to parent alias names.
*/
public $parentAliasMap = array();
/**
* Maps column names in the result set to field names for each class.
*
* @ignore
* @var array
* @var array Maps column names in the result set to field names for each class.
*/
public $fieldMappings = array();
/**
* Maps column names in the result set to the alias/field name to use in the mapped result.
*
* @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();
/**
* Maps column names of meta columns (foreign keys, discriminator columns, ...) to field names.
*
* @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();
/**
* Maps column names in the result set to the alias they belong to.
*
* @ignore
* @var array
* @var array Maps column names in the result set to the alias they belong to.
*/
public $columnOwnerMap = array();
/**
* List of columns in the result set that are used as discriminator columns.
*
* @ignore
* @var array
* @var array List of columns in the result set that are used as discriminator columns.
*/
public $discriminatorColumns = array();
/**
* Maps alias names to field names that should be used for indexing.
*
* @ignore
* @var array
* @var array Maps alias names to field names that should be used for indexing.
*/
public $indexByMap = array();
/**
* Map from column names to class names that declare the field the column is mapped to.
*
* @ignore
* @var array
* @var array Map from column names to class names that declare the field the column is mapped to.
*/
public $declaringClasses = array();
/**
* This is necessary to hydrate derivate foreign keys correctly.
*
* @var array
* @var array This is necessary to hydrate derivate foreign keys correctly.
*/
public $isIdentifierColumn = array();
@ -126,11 +118,15 @@ class ResultSetMapping
* @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
* 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
*/
public function addEntityResult($class, $alias)
public function addEntityResult($class, $alias, $resultAlias = null)
{
$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
* column should be used for.
* @param string $discrColumn The name of the discriminator column in the SQL result set.
*
* @todo Rename: addDiscriminatorColumn
*/
public function setDiscriminatorColumn($alias, $discrColumn)
@ -157,7 +154,51 @@ class ResultSetMapping
*/
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;
// field name => class name of declaring class
$this->declaringClasses[$columnName] = $declaringClass ?: $this->aliasMap[$alias];
if ( ! $this->isMixed && $this->scalarMappings) {
$this->isMixed = true;
}
@ -223,11 +265,11 @@ class ResultSetMapping
*/
public function addJoinedEntityResult($class, $alias, $parentAlias, $relation)
{
$this->aliasMap[$alias] = $class;
$this->aliasMap[$alias] = $class;
$this->parentAliasMap[$alias] = $parentAlias;
$this->relationMap[$alias] = $relation;
$this->relationMap[$alias] = $relation;
}
/**
* Adds a scalar result mapping.
*
@ -238,6 +280,7 @@ class ResultSetMapping
public function addScalarResult($columnName, $alias)
{
$this->scalarMappings[$columnName] = $alias;
if ( ! $this->isMixed && $this->fieldMappings) {
$this->isMixed = true;
}
@ -245,7 +288,7 @@ class ResultSetMapping
/**
* 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.
* @return boolean
* @todo Rename: isScalar
@ -384,10 +427,10 @@ class ResultSetMapping
{
return $this->isMixed;
}
/**
* Adds a meta column (foreign key or discriminator column) to the result set.
*
*
* @param string $alias
* @param string $columnName
* @param string $fieldName
@ -397,8 +440,9 @@ class ResultSetMapping
{
$this->metaMappings[$columnName] = $fieldName;
$this->columnOwnerMap[$columnName] = $alias;
if ($isIdentifierColumn) {
$this->isIdentifierColumn[$alias][$columnName] = true;
}
}
}
}

View File

@ -86,20 +86,22 @@ class ResultSetMappingBuilder extends ResultSetMapping
if (isset($renamedColumns[$columnName])) {
$columnName = $renamedColumns[$columnName];
}
$columnName = $platform->getSQLResultCasing($columnName);
if (isset($this->fieldMappings[$columnName])) {
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) {
if ($associationMapping['isOwningSide'] && $associationMapping['type'] & ClassMetadataInfo::TO_ONE) {
foreach ($associationMapping['joinColumns'] AS $joinColumn) {
$columnName = $joinColumn['name'];
$renamedColumnName = isset($renamedColumns[$columnName]) ? $renamedColumns[$columnName] : $columnName;
$renamedColumnName = $platform->getSQLResultCasing($renamedColumnName);
if (isset($this->metaMappings[$renamedColumnName])) {
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>
* @return <entity>
*/
public function <methodName>(<methodTypeHint>$<variableName>)
public function <methodName>(<methodTypeHint>$<variableName><variableDefault>)
{
<spaces>$this-><fieldName> = $<variableName>;
<spaces>return $this;
@ -406,7 +406,7 @@ public function <methodName>()
}
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 '';
@ -634,7 +634,8 @@ public function <methodName>()
foreach ($metadata->associationMappings as $associationMapping) {
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;
}
if ($code = $this->_generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
@ -653,6 +654,22 @@ public function <methodName>()
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)
{
if (isset($metadata->lifecycleCallbacks) && $metadata->lifecycleCallbacks) {
@ -707,7 +724,7 @@ public function <methodName>()
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") {
$addMethod = explode("\\", $typeHint);
@ -737,6 +754,7 @@ public function <methodName>()
'<variableName>' => Inflector::camelize($fieldName),
'<methodName>' => $methodName,
'<fieldName>' => $fieldName,
'<variableDefault>' => ($defaultValue !== null ) ? ('='.$defaultValue) : '',
'<entity>' => $this->_getClassName($metadata)
);
@ -805,7 +823,12 @@ public function <methodName>()
{
$lines = array();
$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) {
$lines[] = $this->_spaces . ' *';

View File

@ -67,7 +67,9 @@ class SchemaTool
/**
* Creates the database schema for the given array of ClassMetadata instances.
*
* @throws ToolsException
* @param array $classes
* @return void
*/
public function createSchema(array $classes)
{
@ -75,7 +77,11 @@ class SchemaTool
$conn = $this->_em->getConnection();
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.
*
*
* @param ClassMetadata $class
* @param array $processedClasses
* @return bool
@ -139,7 +145,7 @@ class SchemaTool
$this->_gatherRelationsSql($class, $table, $schema);
// Add the discriminator column
$discrColumnDef = $this->_getDiscriminatorColumnDefinition($class, $table);
$this->addDiscriminatorColumnDefinition($class, $table);
// Aggregate all the information from all classes in the hierarchy
foreach ($class->parentClasses as $parentClassName) {
@ -171,7 +177,7 @@ class SchemaTool
// Add the discriminator column only to the root table
if ($class->name == $class->rootEntityName) {
$discrColumnDef = $this->_getDiscriminatorColumnDefinition($class, $table);
$this->addDiscriminatorColumnDefinition($class, $table);
} else {
// Add an ID FK column to child tables
/* @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
* the DBAL.
*/
private function _getDiscriminatorColumnDefinition($class, $table)
private function addDiscriminatorColumnDefinition($class, $table)
{
$discrColumn = $class->discriminatorColumn;
@ -551,7 +557,7 @@ class SchemaTool
try {
$conn->executeQuery($sql);
} catch(\Exception $e) {
}
}
}
@ -589,7 +595,7 @@ class SchemaTool
/**
* Get SQL to drop the tables defined by the passed classes.
*
*
* @param array $classes
* @return array
*/
@ -615,7 +621,7 @@ class SchemaTool
}
}
}
if ($this->_platform->supportsSequences()) {
foreach ($schema->getSequences() AS $sequence) {
$visitor->acceptSequence($sequence);
@ -659,7 +665,7 @@ class SchemaTool
/**
* 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.
* 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.
*
* @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
* with this command. For example:
@ -69,150 +69,7 @@ class SchemaValidator
$classes = $cmf->getAllMetadata();
foreach ($classes AS $class) {
$ce = array();
/* @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) {
if ($ce = $this->validateClass($class)) {
$errors[$class->name] = $ce;
}
}
@ -220,6 +77,170 @@ class SchemaValidator
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.
*
@ -230,6 +251,6 @@ class SchemaValidator
$schemaTool = new SchemaTool($this->em);
$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
/*
* 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;
use Doctrine\ORM\ORMException;
/**
* Tools related Exceptions
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
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)
{
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 $_lastInsertId = 0;
private $_inserts = array();
public function __construct(array $params, $driver, $config = null, $eventManager = null)
{
$this->_platformMock = new DatabasePlatformMock();
@ -18,7 +18,7 @@ class ConnectionMock extends \Doctrine\DBAL\Connection
// Override possible assignment of platform to database platform mock
$this->_platform = $this->_platformMock;
}
/**
* @override
*/
@ -26,15 +26,15 @@ class ConnectionMock extends \Doctrine\DBAL\Connection
{
return $this->_platformMock;
}
/**
* @override
*/
public function insert($tableName, array $data)
public function insert($tableName, array $data, array $types = array())
{
$this->_inserts[$tableName][] = $data;
}
/**
* @override
*/
@ -50,7 +50,7 @@ class ConnectionMock extends \Doctrine\DBAL\Connection
{
return $this->_fetchOneResult;
}
/**
* @override
*/
@ -61,29 +61,29 @@ class ConnectionMock extends \Doctrine\DBAL\Connection
}
return $input;
}
/* Mock API */
public function setFetchOneResult($fetchOneResult)
{
$this->_fetchOneResult = $fetchOneResult;
}
public function setDatabasePlatform($platform)
{
$this->_platformMock = $platform;
}
public function setLastInsertId($id)
{
$this->_lastInsertId = $id;
}
public function getInserts()
{
return $this->_inserts;
}
public function reset()
{
$this->_inserts = array();

View File

@ -57,7 +57,7 @@ class DatabasePlatformMock extends \Doctrine\DBAL\Platforms\AbstractPlatform
/** @override */
public function getVarcharTypeDeclarationSQL(array $field) {}
/** @override */
public function getClobTypeDeclarationSQL(array $field) {}
@ -85,6 +85,13 @@ class DatabasePlatformMock extends \Doctrine\DBAL\Platforms\AbstractPlatform
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>
*/
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.
*
@ -21,7 +21,7 @@ class HydratorMockStatement implements \Doctrine\DBAL\Driver\Statement
{
$this->_resultSet = $resultSet;
}
/**
* Fetches all rows from the result set.
*
@ -31,7 +31,7 @@ class HydratorMockStatement implements \Doctrine\DBAL\Driver\Statement
{
return $this->_resultSet;
}
public function fetchColumn($columnNumber = 0)
{
$row = current($this->_resultSet);
@ -39,10 +39,10 @@ class HydratorMockStatement implements \Doctrine\DBAL\Driver\Statement
$val = array_shift($row);
return $val !== null ? $val : false;
}
/**
* Fetches the next row in the result set.
*
*
*/
public function fetch($fetchStyle = null)
{
@ -50,7 +50,7 @@ class HydratorMockStatement implements \Doctrine\DBAL\Driver\Statement
next($this->_resultSet);
return $current;
}
/**
* Closes the cursor, enabling the statement to be executed again.
*
@ -60,13 +60,13 @@ class HydratorMockStatement implements \Doctrine\DBAL\Driver\Statement
{
return true;
}
public function setResultSet(array $resultSet)
{
reset($resultSet);
$this->_resultSet = $resultSet;
}
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 columnCount()
{
}
@ -86,16 +86,26 @@ class HydratorMockStatement implements \Doctrine\DBAL\Driver\Statement
public function errorCode()
{
}
public function errorInfo()
{
}
public function execute($params = array())
{
}
public function rowCount()
{
}
}
public function getIterator()
{
return $this->_resultSet;
}
public function setFetchMode($fetchMode)
{
}
}

View File

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

View File

@ -9,6 +9,7 @@ class DDC117Article
{
/** @Id @Column(type="integer", name="article_id") @GeneratedValue */
private $id;
/** @Column */
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;
/**
* @Column(type="string", length=255)
* @Column(type="string", length=255, name="name")
*/
public $_name;
/**

View File

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

View File

@ -1,7 +1,5 @@
<?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
@ -33,11 +31,13 @@ require_once __DIR__ . '/../../TestInit.php';
* @link http://www.doctrine-project.org
* @since 2.0
*/
class CustomTreeWalkersTest extends \Doctrine\Tests\OrmFunctionalTestCase
class CustomTreeWalkersTest extends \Doctrine\Tests\OrmTestCase
{
protected function setUp() {
$this->useModelSet('cms');
parent::setUp();
private $_em;
protected function setUp()
{
$this->_em = $this->_getTestEntityManager();
}
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"
);
}
public function testSupportsQueriesWithSimpleConditionalExpression()
{
$this->assertSqlGeneration(
@ -94,7 +94,7 @@ class CustomTreeWalker extends Query\TreeWalkerAdapter
$dqlAliases[] = $dqlAlias;
}
}
// Create our conditions for all involved classes
$factors = array();
foreach ($dqlAliases as $alias) {
@ -108,7 +108,7 @@ class CustomTreeWalker extends Query\TreeWalkerAdapter
$factor = new Query\AST\ConditionalFactor($condPrimary);
$factors[] = $factor;
}
if (($whereClause = $selectStatement->whereClause) !== null) {
// There is already a WHERE clause, so append the conditions
$condExpr = $whereClause->conditionalExpression;
@ -119,18 +119,18 @@ class CustomTreeWalker extends Query\TreeWalkerAdapter
$whereClause->conditionalExpression = $condExpr;
}
$existingTerms = $whereClause->conditionalExpression->conditionalTerms;
if (count($existingTerms) > 1) {
// 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>"
$primary = new Query\AST\ConditionalPrimary;
$primary->conditionalExpression = new Query\AST\ConditionalExpression($existingTerms);
$existingFactor = new Query\AST\ConditionalFactor($primary);
$term = new Query\AST\ConditionalTerm(array_merge(array($existingFactor), $factors));
$selectStatement->whereClause->conditionalExpression->conditionalTerms = array($term);
} else {
// 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()
{
$this->_em->getConfiguration()->setEntityNamespaces(array());
if ($this->_em) {
$this->_em->getConfiguration()->setEntityNamespaces(array());
}
parent::tearDown();
}
@ -78,7 +80,7 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
return array($user->id, $address->id);
}
public function buildUser($name, $username, $status, $address)
{
$user = new CmsUser();
@ -89,10 +91,10 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->persist($user);
$this->_em->flush();
return $user;
}
public function buildAddress($country, $city, $street, $zip)
{
$address = new CmsAddress();
@ -103,7 +105,7 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->persist($address);
$this->_em->flush();
return $address;
}
@ -134,22 +136,22 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
$address1 = $this->buildAddress('Germany', 'Berlim', 'Foo st.', '123456');
$user1 = $this->buildUser('Benjamin', 'beberlei', 'dev', $address1);
$address2 = $this->buildAddress('Brazil', 'São Paulo', 'Bar st.', '654321');
$user2 = $this->buildUser('Guilherme', 'guilhermeblanco', 'freak', $address2);
$address3 = $this->buildAddress('USA', 'Nashville', 'Woo st.', '321654');
$user3 = $this->buildUser('Jonathan', 'jwage', 'dev', $address3);
unset($address1);
unset($address2);
unset($address3);
$this->_em->clear();
$repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress');
$addresses = $repository->findBy(array('user' => array($user1->getId(), $user2->getId())));
$this->assertEquals(2, count($addresses));
$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');
$user1 = $this->buildUser('Benjamin', 'beberlei', 'dev', $address1);
$address2 = $this->buildAddress('Brazil', 'São Paulo', 'Bar st.', '654321');
$user2 = $this->buildUser('Guilherme', 'guilhermeblanco', 'freak', $address2);
$address3 = $this->buildAddress('USA', 'Nashville', 'Woo st.', '321654');
$user3 = $this->buildUser('Jonathan', 'jwage', 'dev', $address3);
unset($address1);
unset($address2);
unset($address3);
$this->_em->clear();
$repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress');
$addresses = $repository->findBy(array('user' => array($user1, $user2)));
$this->assertEquals(2, count($addresses));
$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('dev', $users[0]->status);
}
public function testFindAll()
{
$user1Id = $this->loadFixture();
@ -280,7 +282,7 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$userId = $user->id;
$this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $userId);
$this->setExpectedException('Doctrine\ORM\OptimisticLockException');
$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()
{
$this->loadFixture();
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
$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[2], $usersDesc[0]);
}
/**
* @group DDC-753
*/
@ -465,19 +467,19 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$repos = $this->_em->getRepository('Doctrine\Tests\Models\DDC753\DDC753EntityWithDefaultCustomRepository');
$this->assertInstanceOf("Doctrine\Tests\Models\DDC753\DDC753DefaultRepository", $repos);
$this->assertTrue($repos->isDefaultRepository());
$repos = $this->_em->getRepository('Doctrine\Tests\Models\DDC753\DDC753EntityWithCustomRepository');
$this->assertInstanceOf("Doctrine\Tests\Models\DDC753\DDC753CustomRepository", $repos);
$this->assertTrue($repos->isCustomRepository());
$this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\Tests\Models\DDC753\DDC753DefaultRepository");
$this->_em->getConfiguration()->setDefaultRepositoryClassName("Doctrine\ORM\EntityRepository");
$this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\ORM\EntityRepository");
}
/**
* @group DDC-753
* @expectedException Doctrine\ORM\ORMException
@ -488,6 +490,6 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\ORM\EntityRepository");
$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->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY;
$this->loadFixture();
}
@ -137,9 +137,9 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
$this->assertFalse($user->groups->isInitialized(), "Pre-Condition: Collection is not initialized.");
$queryCount = $this->getCurrentQueryCount();
$someGroups = $user->groups->slice(0, 2);
$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.");
$article = $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId);
$queryCount = $this->getCurrentQueryCount();
$this->assertTrue($user->articles->contains($article));
$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.");
}
/**
* @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()
{
$user1 = new \Doctrine\Tests\Models\CMS\CmsUser();
@ -364,7 +407,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->persist($article1);
$this->_em->persist($article2);
$this->_em->flush();
$this->_em->clear();

View File

@ -43,6 +43,29 @@ class LifecycleCallbackTest extends \Doctrine\Tests\OrmFunctionalTestCase
$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()
{
$user = new LifecycleCallbackTestUser;
@ -190,6 +213,8 @@ class LifecycleCallbackTestEntity
public $postPersistCallbackInvoked = false;
public $postLoadCallbackInvoked = false;
public $preFlushCallbackInvoked = false;
/**
* @Id @Column(type="integer")
* @GeneratedValue(strategy="AUTO")
@ -233,6 +258,11 @@ class LifecycleCallbackTestEntity
public function doStuffOnPreUpdate() {
$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());
$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->assertInstanceOf('Doctrine\Tests\Models\DirectoryTree\Directory', $cleanFile->getParent()->getParent());
$this->assertEquals($root->getId(), $cleanFile->getParent()->getParent()->getId());

View File

@ -35,7 +35,7 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$user->status = 'dev';
$this->_em->persist($user);
$this->_em->flush();
$this->_em->clear();
$rsm = new ResultSetMapping;
@ -94,24 +94,24 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals($addr->street, $addresses[0]->street);
$this->assertTrue($addresses[0]->user instanceof CmsUser);
}
public function testJoinedOneToManyNativeQuery()
{
$user = new CmsUser;
$user->name = 'Roman';
$user->username = 'romanb';
$user->status = 'dev';
$phone = new CmsPhonenumber;
$phone->phonenumber = 424242;
$user->addPhonenumber($phone);
$this->_em->persist($user);
$this->_em->flush();
$this->_em->clear();
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$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->addJoinedEntityResult('Doctrine\Tests\Models\CMS\CmsPhonenumber', 'p', 'u', 'phonenumbers');
$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->setParameter(1, 'romanb');
@ -133,30 +133,30 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$phones = $users[0]->getPhonenumbers();
$this->assertEquals(424242, $phones[0]->phonenumber);
$this->assertTrue($phones[0]->getUser() === $users[0]);
}
public function testJoinedOneToOneNativeQuery()
{
$user = new CmsUser;
$user->name = 'Roman';
$user->username = 'romanb';
$user->status = 'dev';
$addr = new CmsAddress;
$addr->country = 'germany';
$addr->zip = 10827;
$addr->city = 'Berlin';
$user->setAddress($addr);
$this->_em->persist($user);
$this->_em->flush();
$this->_em->clear();
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$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('zip'), 'zip');
$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->setParameter(1, 'romanb');
$users = $query->getResult();
$this->assertEquals(1, count($users));
$this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[0]);
$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($routeB);
$this->setExpectedException('Exception'); // depends on the underyling Database Driver
$this->_em->flush(); // Exception
$exceptionThrown = false;
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(
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Train'),
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\TrainDriver'),
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\TrainOwner'),
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Waggon'),
));
} catch(\Exception $e) {}
@ -26,7 +27,7 @@ class OneToOneEagerLoadingTest extends \Doctrine\Tests\OrmFunctionalTestCase
public function testEagerLoadOneToOneOwningSide()
{
$train = new Train();
$train = new Train(new TrainOwner("Alexander"));
$driver = new TrainDriver("Benjamin");
$waggon = new Waggon();
@ -48,7 +49,7 @@ class OneToOneEagerLoadingTest extends \Doctrine\Tests\OrmFunctionalTestCase
public function testEagerLoadOneToOneNullOwningSide()
{
$train = new Train();
$train = new Train(new TrainOwner("Alexander"));
$this->_em->persist($train); // cascades
$this->_em->flush();
@ -65,9 +66,8 @@ class OneToOneEagerLoadingTest extends \Doctrine\Tests\OrmFunctionalTestCase
public function testEagerLoadOneToOneInverseSide()
{
$train = new Train();
$driver = new TrainDriver("Benjamin");
$train->setDriver($driver);
$owner = new TrainOwner("Alexander");
$train = new Train($owner);
$this->_em->persist($train); // cascades
$this->_em->flush();
@ -75,9 +75,9 @@ class OneToOneEagerLoadingTest extends \Doctrine\Tests\OrmFunctionalTestCase
$sqlCount = count($this->_sqlLoggerStack->queries);
$driver = $this->_em->find(get_class($driver), $driver->id);
$this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $driver->train);
$this->assertNotNull($driver->train);
$driver = $this->_em->find(get_class($owner), $owner->id);
$this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $owner->train);
$this->assertNotNull($owner->train);
$this->assertEquals($sqlCount + 1, count($this->_sqlLoggerStack->queries));
}
@ -103,7 +103,7 @@ class OneToOneEagerLoadingTest extends \Doctrine\Tests\OrmFunctionalTestCase
public function testEagerLoadManyToOne()
{
$train = new Train();
$train = new Train(new TrainOwner("Alexander"));
$waggon = new Waggon();
$train->addWaggon($waggon);
@ -115,6 +115,59 @@ class OneToOneEagerLoadingTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $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
* @OneToOne(targetEntity="TrainDriver", inversedBy="train", fetch="EAGER", cascade={"persist"})
* @JoinColumn(nullable=true)
*/
public $driver;
/**
* Owning side
* @OneToOne(targetEntity="TrainOwner", inversedBy="train", fetch="EAGER", cascade={"persist"})
*/
public $owner;
/**
* @oneToMany(targetEntity="Waggon", mappedBy="train", cascade={"persist"})
*/
public $waggons;
public function __construct()
public function __construct(TrainOwner $owner)
{
$this->waggons = new \Doctrine\Common\Collections\ArrayCollection();
$this->setOwner($owner);
}
public function setDriver(TrainDriver $driver)
@ -148,6 +208,12 @@ class Train
$driver->setTrain($this);
}
public function setOwner(TrainOwner $owner)
{
$this->owner = $owner;
$owner->setTrain($this);
}
public function addWaggon(Waggon $w)
{
$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
*/
@ -195,4 +287,4 @@ class Waggon
{
$this->train = $train;
}
}
}

View File

@ -27,14 +27,14 @@ class ReadOnlyTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->flush();
$readOnly->name = "Test2";
$readOnly->number = 4321;
$readOnly->numericValue = 4321;
$this->_em->flush();
$this->_em->clear();
$dbReadOnly = $this->_em->find('Doctrine\Tests\ORM\Functional\ReadOnlyEntity', $readOnly->id);
$this->assertEquals("Test1", $dbReadOnly->name);
$this->assertEquals(1234, $dbReadOnly->number);
$this->assertEquals(1234, $dbReadOnly->numericValue);
}
}
@ -51,11 +51,11 @@ class ReadOnlyEntity
/** @column(type="string") */
public $name;
/** @Column(type="integer") */
public $number;
public $numericValue;
public function __construct($name, $number)
{
$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\ProxyClassGenerator;
use Doctrine\Tests\Models\ECommerce\ECommerceProduct;
use Doctrine\Tests\Models\ECommerce\ECommerceShipping;
require_once __DIR__ . '/../../TestInit.php';
@ -97,7 +98,7 @@ class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertTrue($clone->isCloned);
$this->assertFalse($entity->isCloned);
}
/**
* @group DDC-733
*/
@ -107,12 +108,12 @@ class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase
/* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */
$entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id);
$this->assertFalse($entity->__isInitialized__, "Pre-Condition: Object is unitialized proxy.");
$this->_em->getUnitOfWork()->initializeObject($entity);
$this->assertTrue($entity->__isInitialized__, "Should be initialized after called UnitOfWork::initializeObject()");
}
/**
* @group DDC-1163
*/
@ -123,10 +124,10 @@ class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase
/* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */
$entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id);
$entity->setName('Doctrine 2 Cookbook');
$this->_em->flush();
$this->_em->clear();
$entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id);
$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.");
}
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()
{
$id = $this->createProduct();

View File

@ -21,7 +21,7 @@ class PostgreSqlSchemaToolTest extends \Doctrine\Tests\OrmFunctionalTestCase
$address = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress');
$this->assertEquals(1, $address->sequenceGeneratorDefinition['allocationSize']);
}
public function testGetCreateSchemaSql()
{
$classes = array(
@ -32,26 +32,30 @@ class PostgreSqlSchemaToolTest extends \Doctrine\Tests\OrmFunctionalTestCase
$tool = new SchemaTool($this->_em);
$sql = $tool->getCreateSchemaSql($classes);
$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_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_3AF03EC5F85E0677 ON cms_users (username)", $sql[3]);
$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 INDEX IDX_7EA9409AA76ED395 ON cms_users_groups (user_id)", $sql[5]);
$this->assertEquals("CREATE INDEX IDX_7EA9409AFE54D947 ON cms_users_groups (group_id)", $sql[6]);
$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_F21F790FA76ED395 ON cms_phonenumbers (user_id)", $sql[8]);
$this->assertEquals("CREATE SEQUENCE cms_addresses_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[9]);
$this->assertEquals("CREATE SEQUENCE cms_users_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[10]);
$this->assertEquals("ALTER TABLE cms_addresses ADD FOREIGN KEY (user_id) REFERENCES cms_users(id) NOT DEFERRABLE INITIALLY IMMEDIATE", $sql[11]);
$this->assertEquals("ALTER TABLE cms_users_groups ADD FOREIGN KEY (user_id) REFERENCES cms_users(id) NOT DEFERRABLE INITIALLY IMMEDIATE", $sql[12]);
$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_phonenumbers ADD FOREIGN KEY (user_id) REFERENCES cms_users(id) NOT DEFERRABLE INITIALLY IMMEDIATE", $sql[14]);
$this->assertEquals(count($sql), 15);
$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))", array_shift($sql));
$this->assertEquals("CREATE UNIQUE INDEX UNIQ_ACAC157BA76ED395 ON cms_addresses (user_id)", array_shift($sql));
$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 UNIQUE INDEX UNIQ_3AF03EC5F85E0677 ON cms_users (username)", array_shift($sql));
$this->assertEquals("CREATE UNIQUE INDEX UNIQ_3AF03EC5A832C1C9 ON cms_users (email_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))", array_shift($sql));
$this->assertEquals("CREATE INDEX IDX_7EA9409AA76ED395 ON cms_users_groups (user_id)", array_shift($sql));
$this->assertEquals("CREATE INDEX IDX_7EA9409AFE54D947 ON cms_users_groups (group_id)", array_shift($sql));
$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 INDEX IDX_F21F790FA76ED395 ON cms_phonenumbers (user_id)", array_shift($sql));
$this->assertEquals("CREATE SEQUENCE cms_addresses_id_seq INCREMENT BY 1 MINVALUE 1 START 1", array_shift($sql));
$this->assertEquals("CREATE SEQUENCE cms_users_id_seq INCREMENT BY 1 MINVALUE 1 START 1", array_shift($sql));
$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_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("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()
{
$classes = array(
@ -62,11 +66,11 @@ class PostgreSqlSchemaToolTest extends \Doctrine\Tests\OrmFunctionalTestCase
$sql = $tool->getCreateSchemaSql($classes);
$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 SEQUENCE decimal_model_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[1]);
}
public function testGetCreateSchemaSql3()
{
$classes = array(
@ -75,12 +79,12 @@ class PostgreSqlSchemaToolTest extends \Doctrine\Tests\OrmFunctionalTestCase
$tool = new SchemaTool($this->_em);
$sql = $tool->getCreateSchemaSql($classes);
$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 SEQUENCE boolean_model_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[1]);
}
public function testGetDropSchemaSql()
{
$classes = array(
@ -91,8 +95,8 @@ class PostgreSqlSchemaToolTest extends \Doctrine\Tests\OrmFunctionalTestCase
$tool = new SchemaTool($this->_em);
$sql = $tool->getDropSchemaSQL($classes);
$this->assertEquals(13, count($sql));
$this->assertEquals(14, count($sql));
$dropSequenceSQLs = 0;
foreach ($sql AS $stmt) {
if (strpos($stmt, "DROP SEQUENCE") === 0) {

View File

@ -24,7 +24,7 @@ class DDC1040Test extends \Doctrine\Tests\OrmFunctionalTestCase
$user->name = "John Galt";
$user->username = "jgalt";
$user->status = "inactive";
$article = new CmsArticle();
$article->topic = "This is John Galt speaking!";
$article->text = "Yadda Yadda!";
@ -44,11 +44,10 @@ class DDC1040Test extends \Doctrine\Tests\OrmFunctionalTestCase
->setParameter('author', $user)
->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)
->setParameter('author', $user)
->setParameter('topic', 'This is John Galt speaking!')
->setParameter('text', 'Yadda Yadda!')
->getSingleResult();
$this->assertSame($article, $farticle);
@ -70,12 +69,11 @@ class DDC1040Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->persist($article);
$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)
->setParameter(1, 'This is John Galt speaking!')
->setParameter(2, $user)
->setParameter(3, $user)
->setParameter(4, 'Yadda Yadda!')
->getSingleResult();
$this->assertSame($article, $farticle);

View File

@ -8,18 +8,18 @@ require_once __DIR__ . '/../../../TestInit.php';
* @group DDC-1151
*/
class DDC1151Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
{
public function testQuoteForeignKey()
{
if ($this->_em->getConnection()->getDatabasePlatform()->getName() != 'postgresql') {
$this->markTestSkipped("This test is useful for all databases, but designed only for postgresql.");
}
$sql = $this->_schemaTool->getCreateSchemaSql(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1151User'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1151Group'),
));
$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 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 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("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 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_88A3259AC5AD08A 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_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 */
public $id;
/** @ManyToMany(targetEntity="DDC1151Group") */
public $groups;
}

View File

@ -209,8 +209,15 @@ class DDC117Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->article1->addTranslation('en', 'Bar');
$this->article1->addTranslation('en', 'Baz');
$this->setExpectedException('Exception');
$this->_em->flush();
$exceptionThrown = false;
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
* @Column(type="datetime")
* @Column(type="datetime", name="somedate")
*/
private $date;

View File

@ -21,10 +21,10 @@ class DDC1225Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1225_TestEntity2'),
));
} catch(\PDOException $e) {
}
}
public function testIssue()
{
$qb = $this->_em->createQueryBuilder();
@ -32,10 +32,10 @@ class DDC1225Test extends \Doctrine\Tests\OrmFunctionalTestCase
->select('te1')
->where('te1.testEntity2 = ?1')
->setParameter(1, 0);
$this->assertEquals(
'SELECT t0_.test_entity2_id AS test_entity2_id0 FROM te1 t0_ WHERE t0_.test_entity2_id = ?',
$qb->getQuery()->getSQL()
strtolower('SELECT t0_.test_entity2_id AS test_entity2_id0 FROM te1 t0_ WHERE t0_.test_entity2_id = ?'),
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__ . '\\DDC1228Profile'),
));
} catch(\PDOException $e) {
} catch(\Exception $e) {
}
}
public function testOneToOnePersist()
{
$user = new DDC1228User;
$profile = new DDC1228Profile();
$profile->name = "Foo";
$user->profile = $profile;
$this->_em->persist($user);
$this->_em->persist($profile);
$this->_em->flush();
$this->_em->clear();
$user = $this->_em->find(__NAMESPACE__ . '\\DDC1228User', $user->id);
$this->assertFalse($user->getProfile()->__isInitialized__, "Proxy is not initialized");
$user->getProfile()->setName("Bar");
$this->assertTrue($user->getProfile()->__isInitialized__, "Proxy is not initialized");
$this->assertEquals("Bar", $user->getProfile()->getName());
$this->assertEquals(array("id" => 1, "name" => "Foo"), $this->_em->getUnitOfWork()->getOriginalEntityData($user->getProfile()));
$this->_em->flush();
$this->_em->clear();
$user = $this->_em->find(__NAMESPACE__ . '\\DDC1228User', $user->id);
$this->assertEquals("Bar", $user->getProfile()->getName());
}
public function testRefresh()
{
$user = new DDC1228User;
$profile = new DDC1228Profile();
$profile->name = "Foo";
$user->profile = $profile;
$this->_em->persist($user);
$this->_em->persist($profile);
$this->_em->flush();
$this->_em->clear();
$user = $this->_em->getReference(__NAMESPACE__ . '\\DDC1228User', $user->id);
$this->_em->refresh($user);
$user->name = "Baz";
$this->_em->flush();
$this->_em->clear();
$user = $this->_em->find(__NAMESPACE__ . '\\DDC1228User', $user->id);
$this->assertEquals("Baz", $user->name);
}
@ -88,20 +88,20 @@ class DDC1228User
* @var int
*/
public $id;
/**
* @column(type="string")
* @Column(type="string")
* @var string
*/
public $name = '';
public $name = 'Bar';
/**
* @OneToOne(targetEntity="DDC1228Profile")
* @var Profile
*/
public $profile;
public function getProfile()
public function getProfile()
{
return $this->profile;
}
@ -117,13 +117,13 @@ class DDC1228Profile
* @var int
*/
public $id;
/**
* @column(type="string")
* @var string
*/
public $name;
public function getName()
{
return $this->name;

View File

@ -19,49 +19,49 @@ class DDC1238Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1238User'),
));
} catch(\PDOException $e) {
} catch(\Exception $e) {
}
}
public function testIssue()
{
$user = new DDC1238User;
$user->setName("test");
$this->_em->persist($user);
$this->_em->flush();
$this->_em->clear();
$userId = $user->getId();
$this->_em->clear();
$user = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId);
$this->_em->clear();
$userId2 = $user->getId();
$this->assertEquals($userId, $userId2, "This proxy can still be initialized.");
}
public function testIssueProxyClear()
{
$user = new DDC1238User;
$user->setName("test");
$this->_em->persist($user);
$this->_em->flush();
$this->_em->clear();
// force proxy load, getId() doesn't work anymore
$user->getName();
$userId = $user->getId();
$this->_em->clear();
$user = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId);
$this->_em->clear();
$user2 = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId);
// force proxy load, getId() doesn't work anymore
$user->getName();
$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") */
private $id;
/**
* @Column
* @var string
*/
private $name;
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;

View File

@ -7,56 +7,56 @@ use DateTime;
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()
{
parent::setUp();
try {
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1135User'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1135Phone'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1335User'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1335Phone'),
));
$this->loadFixture();
} catch(\Exception $e) {
}
}
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);
$result = $query->getResult();
$this->assertEquals(sizeof($result), 3);
$this->assertArrayHasKey(1, $result);
$this->assertArrayHasKey(2, $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);
$result = $query->getResult();
$this->assertEquals(sizeof($result), 3);
$this->assertArrayHasKey('foo@foo.com', $result);
$this->assertArrayHasKey('bar@bar.com', $result);
$this->assertArrayHasKey('foobar@foobar.com', $result);
$this->assertEquals(sizeof($result['foo@foo.com']->phones), 3);
$this->assertEquals(sizeof($result['bar@bar.com']->phones), 3);
$this->assertEquals(sizeof($result['foobar@foobar.com']->phones), 3);
$this->assertArrayHasKey(1, $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(4, $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(7, $result['foobar@foobar.com']->phones->toArray());
$this->assertArrayHasKey(8, $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()
{
$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();
$result = $builder->getQuery()->getResult();
$this->assertEquals(sizeof($result), 3);
$this->assertArrayHasKey(1, $result);
$this->assertArrayHasKey(2, $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()
{
$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();
$result = $builder->getQuery()->getResult();
$this->assertEquals(sizeof($result), 3);
$this->assertArrayHasKey('foo@foo.com', $result);
$this->assertArrayHasKey('bar@bar.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()
{
$builder = $this->_em->createQueryBuilder();
$builder->select('u','p')
->from(__NAMESPACE__ . '\DDC1135User', 'u', 'u.email')
->from(__NAMESPACE__ . '\DDC1335User', 'u', 'u.email')
->join('u.phones', 'p', null, null, 'p.id');
$dql = $builder->getQuery()->getDQL();
$result = $builder->getQuery()->getResult();
$this->assertEquals(sizeof($result), 3);
$this->assertArrayHasKey('foo@foo.com', $result);
$this->assertArrayHasKey('bar@bar.com', $result);
$this->assertArrayHasKey('foobar@foobar.com', $result);
$this->assertEquals(sizeof($result['foo@foo.com']->phones), 3);
$this->assertEquals(sizeof($result['bar@bar.com']->phones), 3);
$this->assertEquals(sizeof($result['foobar@foobar.com']->phones), 3);
$this->assertArrayHasKey(1, $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(4, $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(7, $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->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()
{
$p1 = array('11 xxxx-xxxx','11 yyyy-yyyy','11 zzzz-zzzz');
$p2 = array('22 xxxx-xxxx','22 yyyy-yyyy','22 zzzz-zzzz');
$p3 = array('33 xxxx-xxxx','33 yyyy-yyyy','33 zzzz-zzzz');
$u1 = new DDC1135User("foo@foo.com", "Foo",$p1);
$u2 = new DDC1135User("bar@bar.com", "Bar",$p2);
$u3 = new DDC1135User("foobar@foobar.com", "Foo Bar",$p3);
$u1 = new DDC1335User("foo@foo.com", "Foo",$p1);
$u2 = new DDC1335User("bar@bar.com", "Bar",$p2);
$u3 = new DDC1335User("foobar@foobar.com", "Foo Bar",$p3);
$this->_em->persist($u1);
$this->_em->persist($u2);
$this->_em->persist($u3);
@ -148,7 +148,7 @@ class DDC1135Test extends \Doctrine\Tests\OrmFunctionalTestCase
/**
* @Entity
*/
class DDC1135User
class DDC1335User
{
/**
* @Id @Column(type="integer")
@ -160,25 +160,25 @@ class DDC1135User
* @Column(type="string", unique=true)
*/
public $email;
/**
* @Column(type="string")
*/
public $name;
/**
* @OneToMany(targetEntity="DDC1135Phone", mappedBy="user", cascade={"persist", "remove"})
* @OneToMany(targetEntity="DDC1335Phone", mappedBy="user", cascade={"persist", "remove"})
*/
public $phones;
public function __construct($email, $name, array $numbers = array())
{
$this->name = $name;
$this->email = $email;
$this->phones = new \Doctrine\Common\Collections\ArrayCollection();
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
*/
class DDC1135Phone
class DDC1335Phone
{
/**
* @Id
* @Column(name="id", type="integer")
* @GeneratedValue(strategy="AUTO")
* @GeneratedValue
*/
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)
*/
public $user;
@ -209,6 +209,6 @@ class DDC1135Phone
public function __construct($user, $number)
{
$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();
}
/**
* @group DDC-331
*/
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');
$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()
{
$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()
{
$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()
{
$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();
$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');
$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
{
/**
/**
* @Id @GeneratedValue
* @Column(type="integer")
* @Column(type="integer")
*/
protected $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));
$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->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.");
}
}

View File

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

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.
*
*
* @param string $dqlToBeTested
* @param string $sqlToBeConfirmed
* @param array $queryHints
* @param array $queryParams
* @param array $queryParams
*/
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)
->useQueryCache(false);
foreach ($queryHints AS $name => $value) {
$query->setHint($name, $value);
}
parent::assertEquals($sqlToBeConfirmed, $query->getSQL());
$query->free();
} 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')"
);
}
public function testSupportsInstanceOfExpressionInWherePartWithMultipleValues()
{
$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')"
);
}
/**
* @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')"
);
}
/**
* @group DDC-1194
*/
@ -563,7 +563,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
$this->_em->getClassMetadata(get_class($person))->setIdentifierValues($person, array('id' => 101));
$q3->setParameter('param', $person);
$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()
);
}
@ -606,7 +606,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
. ')'
);
}
public function testExistsExpressionWithSimpleSelectReturningScalar()
{
$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"
);
}
public function testOrderBySupportsSingleValuedPathExpressionOwningSide()
{
$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"
);
}
/**
* @expectedException Doctrine\ORM\Query\QueryException
*/
@ -746,12 +746,12 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
$this->assertSqlGeneration(
"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(
"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);
@ -894,7 +894,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
$this->assertSqlGeneration(
"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",
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'
);
}
public function testCaseContainingNullIf()
{
$this->assertSqlGeneration(
@ -956,7 +956,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
'SELECT NULLIF(c0_.id, c0_.name) AS sclr0 FROM cms_groups c0_'
);
}
public function testCaseContainingCoalesce()
{
$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"
);
}
public function testGeneralCaseWithSingleWhenClause()
{
$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_"
);
}
public function testGeneralCaseWithMultipleWhenClause()
{
$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_"
);
}
public function testSimpleCaseWithSingleWhenClause()
{
$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"
);
}
public function testSimpleCaseWithMultipleWhenClause()
{
$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"
);
}
public function testGeneralCaseWithSingleWhenClauseInSubselect()
{
$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_)"
);
}
public function testGeneralCaseWithMultipleWhenClauseInSubselect()
{
$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_)"
);
}
public function testSimpleCaseWithSingleWhenClauseInSubselect()
{
$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_)"
);
}
public function testSimpleCaseWithMultipleWhenClauseInSubselect()
{
$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_)"
);
}
/**
* @group DDC-1339
*/
public function testIdentityFunctionInSelectClause()
{
$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_"
);
}
/**
* @group DDC-1339
*/
public function testIdentityFunctionDoesNotAcceptStateField()
{
$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"
);
}
/**
* @group DDC-1389
*/
public function testInheritanceTypeJoinInRootClassWithDisabledForcePartialLoad()
{
$this->assertSqlGeneration(
'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 p FROM Doctrine\Tests\Models\Company\CompanyPerson p',
'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)
);
}
/**
* @group DDC-1389
*/
public function testInheritanceTypeJoinInRootClassWithEnabledForcePartialLoad()
{
$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_',
array(Query::HINT_FORCE_PARTIAL_LOAD => true)
);
}
/**
* @group DDC-1389
*/
public function testInheritanceTypeJoinInChildClassWithDisabledForcePartialLoad()
{
$this->assertSqlGeneration(
'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 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, 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)
);
}
/**
* @group DDC-1389
*/
public function testInheritanceTypeJoinInChildClassWithEnabledForcePartialLoad()
{
$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',
array(Query::HINT_FORCE_PARTIAL_LOAD => true)
);
}
/**
* @group DDC-1389
*/
public function testInheritanceTypeJoinInLeafClassWithDisabledForcePartialLoad()
{
$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',
array(Query::HINT_FORCE_PARTIAL_LOAD => false)
);
}
/**
* @group DDC-1389
*/
public function testInheritanceTypeJoinInLeafClassWithEnabledForcePartialLoad()
{
$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',
array(Query::HINT_FORCE_PARTIAL_LOAD => true)
);
}
/**
* @group DDC-1389
*/
public function testInheritanceTypeSingleTableInRootClassWithDisabledForcePartialLoad()
{
$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')",
array(Query::HINT_FORCE_PARTIAL_LOAD => false)
);
}
/**
* @group DDC-1389
*/
public function testInheritanceTypeSingleTableInRootClassWithEnabledForcePartialLoad()
{
$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')",
array(Query::HINT_FORCE_PARTIAL_LOAD => true)
);
}
/**
* @group DDC-1389
*/
public function testInheritanceTypeSingleTableInChildClassWithDisabledForcePartialLoad()
{
$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')",
array(Query::HINT_FORCE_PARTIAL_LOAD => false)
);
}
/**
* @group DDC-1389
*/
public function testInheritanceTypeSingleTableInChildClassWithEnabledForcePartialLoad()
{
$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')",
array(Query::HINT_FORCE_PARTIAL_LOAD => true)
);
}
/**
* @group DDC-1389
*/
public function testInheritanceTypeSingleTableInLeafClassWithDisabledForcePartialLoad()
{
$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')",
array(Query::HINT_FORCE_PARTIAL_LOAD => false)
);
}
/**
* @group DDC-1389
*/
public function testInheritanceTypeSingleTableInLeafClassWithEnabledForcePartialLoad()
{
$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')",
array(Query::HINT_FORCE_PARTIAL_LOAD => true)
);
}
/**
* @group DDC-1161
*/
public function testSelfReferenceWithOneToOneDoesNotDuplicateAlias()
{
$this->assertSqlGeneration(
'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 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, 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)
);
}
/**
* @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);
$this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$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();
}
/**
* @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>