Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
68027e1b5f
3
.gitignore
vendored
3
.gitignore
vendored
@ -7,3 +7,6 @@ download/
|
||||
lib/api/
|
||||
lib/Doctrine/Common
|
||||
lib/Doctrine/DBAL
|
||||
/.settings/
|
||||
.buildpath
|
||||
.project
|
||||
|
19
.travis.yml
Normal file
19
.travis.yml
Normal 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
|
@ -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)
|
||||
|
||||
|
@ -199,6 +199,7 @@ class EntityManager implements ObjectManager
|
||||
* the transaction is rolled back, the EntityManager closed and the exception re-thrown.
|
||||
*
|
||||
* @param Closure $func The function to execute transactionally.
|
||||
* @return mixed Returns the non-empty value returned from the closure or true instead
|
||||
*/
|
||||
public function transactional(Closure $func)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
53
lib/Doctrine/ORM/Event/PreFlushEventArgs.php
Normal file
53
lib/Doctrine/ORM/Event/PreFlushEventArgs.php
Normal 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;
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,7 +46,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
$this->_sequenceName = $sequenceName;
|
||||
$this->_allocationSize = $allocationSize;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates an ID for the given entity.
|
||||
*
|
||||
@ -60,11 +60,11 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
// Allocate new values
|
||||
$conn = $em->getConnection();
|
||||
$sql = $conn->getDatabasePlatform()->getSequenceNextValSQL($this->_sequenceName);
|
||||
|
||||
$this->_nextValue = $conn->fetchColumn($sql);
|
||||
|
||||
$this->_nextValue = (int)$conn->fetchColumn($sql);
|
||||
$this->_maxValue = $this->_nextValue + $this->_allocationSize;
|
||||
}
|
||||
|
||||
|
||||
return $this->_nextValue++;
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
$array = unserialize($serialized);
|
||||
|
||||
|
||||
$this->_sequenceName = $array['sequenceName'];
|
||||
$this->_allocationSize = $array['allocationSize'];
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ abstract class AbstractHydrator
|
||||
*
|
||||
* @param object $stmt
|
||||
* @param object $resultSetMapping
|
||||
*
|
||||
*
|
||||
* @return IterableResult
|
||||
*/
|
||||
public function iterate($stmt, $resultSetMapping, array $hints = array())
|
||||
@ -82,9 +82,9 @@ abstract class AbstractHydrator
|
||||
$this->_stmt = $stmt;
|
||||
$this->_rsm = $resultSetMapping;
|
||||
$this->_hints = $hints;
|
||||
|
||||
|
||||
$this->prepare();
|
||||
|
||||
|
||||
return new IterableResult($this);
|
||||
}
|
||||
|
||||
@ -100,13 +100,13 @@ abstract class AbstractHydrator
|
||||
$this->_stmt = $stmt;
|
||||
$this->_rsm = $resultSetMapping;
|
||||
$this->_hints = $hints;
|
||||
|
||||
|
||||
$this->prepare();
|
||||
|
||||
|
||||
$result = $this->hydrateAllData();
|
||||
|
||||
|
||||
$this->cleanup();
|
||||
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@ -119,17 +119,17 @@ abstract class AbstractHydrator
|
||||
public function hydrateRow()
|
||||
{
|
||||
$row = $this->_stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
|
||||
if ( ! $row) {
|
||||
$this->cleanup();
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
$result = array();
|
||||
|
||||
|
||||
$this->hydrateRowData($row, $this->_cache, $result);
|
||||
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@ -147,7 +147,7 @@ abstract class AbstractHydrator
|
||||
protected function cleanup()
|
||||
{
|
||||
$this->_rsm = null;
|
||||
|
||||
|
||||
$this->_stmt->closeCursor();
|
||||
$this->_stmt = null;
|
||||
}
|
||||
@ -195,34 +195,44 @@ abstract class AbstractHydrator
|
||||
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;
|
||||
}
|
||||
|
||||
@ -233,10 +243,10 @@ 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;
|
||||
}
|
||||
|
||||
@ -259,7 +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
|
||||
@ -267,7 +277,7 @@ abstract class AbstractHydrator
|
||||
*
|
||||
* @param array $data
|
||||
* @param array $cache
|
||||
*
|
||||
*
|
||||
* @return array The processed row.
|
||||
*/
|
||||
protected function gatherScalarRowData(&$data, &$cache)
|
||||
@ -277,48 +287,65 @@ abstract class AbstractHydrator
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register entity as managed in UnitOfWork.
|
||||
*
|
||||
*
|
||||
* @param Doctrine\ORM\Mapping\ClassMetadata $class
|
||||
* @param object $entity
|
||||
* @param array $data
|
||||
* @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)
|
||||
{
|
||||
@ -338,7 +365,7 @@ abstract class AbstractHydrator
|
||||
$id = array($class->identifier[0] => $data[$class->identifier[0]]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$this->_em->getUnitOfWork()->registerManaged($entity, $id, $data);
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,11 @@ use PDO, Doctrine\DBAL\Connection, Doctrine\ORM\Mapping\ClassMetadata;
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @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
|
||||
{
|
||||
@ -39,8 +44,8 @@ class ArrayHydrator extends AbstractHydrator
|
||||
private $_idTemplate = array();
|
||||
private $_resultCounter = 0;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepare()
|
||||
{
|
||||
@ -49,7 +54,7 @@ class ArrayHydrator extends AbstractHydrator
|
||||
$this->_resultPointers = array();
|
||||
$this->_idTemplate = array();
|
||||
$this->_resultCounter = 0;
|
||||
|
||||
|
||||
foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
|
||||
$this->_identifierMap[$dqlAlias] = array();
|
||||
$this->_resultPointers[$dqlAlias] = array();
|
||||
@ -57,14 +62,14 @@ class ArrayHydrator extends AbstractHydrator
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function hydrateAllData()
|
||||
{
|
||||
$result = array();
|
||||
$cache = array();
|
||||
|
||||
|
||||
while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$this->hydrateRowData($data, $cache, $result);
|
||||
}
|
||||
@ -85,8 +90,9 @@ class ArrayHydrator extends AbstractHydrator
|
||||
// Extract scalar values. They're appended at the end.
|
||||
if (isset($rowData['scalars'])) {
|
||||
$scalars = $rowData['scalars'];
|
||||
|
||||
unset($rowData['scalars']);
|
||||
|
||||
|
||||
if (empty($rowData)) {
|
||||
++$this->_resultCounter;
|
||||
}
|
||||
@ -100,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]) ) {
|
||||
@ -119,22 +125,23 @@ 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];
|
||||
|
||||
// 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])) {
|
||||
@ -142,15 +149,17 @@ class ArrayHydrator extends AbstractHydrator
|
||||
} 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])) {
|
||||
@ -166,13 +175,14 @@ 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;
|
||||
}
|
||||
@ -180,12 +190,12 @@ class ArrayHydrator extends AbstractHydrator
|
||||
++$this->_resultCounter;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Check for an existing element
|
||||
if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
|
||||
$element = $rowData[$dqlAlias];
|
||||
if ($this->_rsm->isMixed) {
|
||||
$element = array(0 => $element);
|
||||
$element = array($entityKey => $element);
|
||||
}
|
||||
|
||||
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
|
||||
@ -240,37 +250,37 @@ class ArrayHydrator extends AbstractHydrator
|
||||
{
|
||||
if ($coll === null) {
|
||||
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ($index !== false) {
|
||||
$this->_resultPointers[$dqlAlias] =& $coll[$index];
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( ! $coll) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ($oneToOne) {
|
||||
$this->_resultPointers[$dqlAlias] =& $coll;
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
end($coll);
|
||||
$this->_resultPointers[$dqlAlias] =& $coll[key($coll)];
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve ClassMetadata associated to entity class name.
|
||||
*
|
||||
*
|
||||
* @param string $className
|
||||
*
|
||||
*
|
||||
* @return Doctrine\ORM\Mapping\ClassMetadata
|
||||
*/
|
||||
private function getClassMetadata($className)
|
||||
@ -278,7 +288,7 @@ class ArrayHydrator extends AbstractHydrator
|
||||
if ( ! isset($this->_ce[$className])) {
|
||||
$this->_ce[$className] = $this->_em->getClassMetadata($className);
|
||||
}
|
||||
|
||||
|
||||
return $this->_ce[$className];
|
||||
}
|
||||
}
|
@ -32,8 +32,13 @@ use PDO,
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @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
|
||||
{
|
||||
@ -60,54 +65,58 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$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'][$this->_rsm->parentAliasMap[$dqlAlias]][$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'][$dqlAlias][$assoc['mappedBy']] = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// handle fetch-joined owning side bi-directional one-to-one associations
|
||||
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'][$dqlAlias][$inverseAssoc['fieldName']] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -120,7 +129,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$eagerLoad = (isset($this->_hints['deferEagerLoad'])) && $this->_hints['deferEagerLoad'] == true;
|
||||
|
||||
parent::cleanup();
|
||||
|
||||
|
||||
$this->_identifierMap =
|
||||
$this->_initializedCollections =
|
||||
$this->_existingCollections =
|
||||
@ -137,7 +146,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
protected function hydrateAllData()
|
||||
{
|
||||
$result = array();
|
||||
$cache = array();
|
||||
$cache = array();
|
||||
|
||||
while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$this->hydrateRowData($row, $cache, $result);
|
||||
@ -155,35 +164,40 @@ class ObjectHydrator extends AbstractHydrator
|
||||
* Initializes a related collection.
|
||||
*
|
||||
* @param object $entity The entity to which the collection belongs.
|
||||
* @param ClassMetadata $class
|
||||
* @param string $name The name of the field on the entity that holds the collection.
|
||||
* @param string $parentDqlAlias Alias of the parent fetch joining this collection.
|
||||
*/
|
||||
private function _initRelatedCollection($entity, $class, $fieldName)
|
||||
private function _initRelatedCollection($entity, $class, $fieldName, $parentDqlAlias)
|
||||
{
|
||||
$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'][$parentDqlAlias][$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!
|
||||
@ -203,6 +217,7 @@ 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]];
|
||||
|
||||
@ -211,14 +226,15 @@ class ObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
$this->_hints['fetchAlias'] = $dqlAlias;
|
||||
return $this->_uow->createEntity($className, $data, $this->_hints);
|
||||
}
|
||||
|
||||
@ -226,6 +242,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
{
|
||||
// TODO: Abstract this code and UnitOfWork::createEntity() equivalent?
|
||||
$class = $this->_ce[$className];
|
||||
|
||||
/* @var $class ClassMetadata */
|
||||
if ($class->isIdentifierComposite) {
|
||||
$idHash = '';
|
||||
@ -257,6 +274,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
if ( ! isset($this->_ce[$className])) {
|
||||
$this->_ce[$className] = $this->_em->getClassMetadata($className);
|
||||
}
|
||||
|
||||
return $this->_ce[$className];
|
||||
}
|
||||
|
||||
@ -292,7 +310,9 @@ class ObjectHydrator extends AbstractHydrator
|
||||
// Extract scalar values. They're appended at the end.
|
||||
if (isset($rowData['scalars'])) {
|
||||
$scalars = $rowData['scalars'];
|
||||
|
||||
unset($rowData['scalars']);
|
||||
|
||||
if (empty($rowData)) {
|
||||
++$this->_resultCounter;
|
||||
}
|
||||
@ -319,7 +339,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
// Get a reference to the parent object to which the joined element belongs.
|
||||
if ($this->_rsm->isMixed && isset($this->_rootAliases[$parentAlias])) {
|
||||
$first = reset($this->_resultPointers);
|
||||
$parentObject = $this->_resultPointers[$parentAlias][key($first)];
|
||||
$parentObject = $first[key($first)];
|
||||
} else if (isset($this->_resultPointers[$parentAlias])) {
|
||||
$parentObject = $this->_resultPointers[$parentAlias];
|
||||
} else {
|
||||
@ -341,7 +361,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
if (isset($this->_initializedCollections[$collKey])) {
|
||||
$reflFieldValue = $this->_initializedCollections[$collKey];
|
||||
} else if ( ! isset($this->_existingCollections[$collKey])) {
|
||||
$reflFieldValue = $this->_initRelatedCollection($parentObject, $parentClass, $relationField);
|
||||
$reflFieldValue = $this->_initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
|
||||
}
|
||||
|
||||
$indexExists = isset($this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]]);
|
||||
@ -376,7 +396,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$this->_resultPointers[$dqlAlias] = $reflFieldValue[$index];
|
||||
}
|
||||
} else if ( ! $reflField->getValue($parentObject)) {
|
||||
$reflFieldValue = $this->_initRelatedCollection($parentObject, $parentClass, $relationField);
|
||||
$reflFieldValue = $this->_initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
|
||||
}
|
||||
} else {
|
||||
// PATH B: Single-valued association
|
||||
@ -387,6 +407,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
|
||||
@ -417,11 +438,12 @@ 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;
|
||||
}
|
||||
@ -434,7 +456,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
if ( ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
|
||||
$element = $this->_getEntity($rowData[$dqlAlias], $dqlAlias);
|
||||
if ($this->_rsm->isMixed) {
|
||||
$element = array(0 => $element);
|
||||
$element = array($entityKey => $element);
|
||||
}
|
||||
|
||||
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
|
||||
|
@ -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
|
||||
|
@ -20,6 +20,7 @@
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
@ -119,7 +120,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
const FETCH_LAZY = 2;
|
||||
/**
|
||||
* Specifies that an association is to be fetched when the owner of the
|
||||
* association is fetched.
|
||||
* association is fetched.
|
||||
*/
|
||||
const FETCH_EAGER = 3;
|
||||
/**
|
||||
@ -206,7 +207,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
|
||||
/**
|
||||
* READ-ONLY: The named queries allowed to be called directly from Repository.
|
||||
*
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $namedQueries = array();
|
||||
@ -361,7 +362,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* - <b>mappedBy</b> (string, required for bidirectional associations)
|
||||
* The name of the field that completes the bidirectional association on the owning side.
|
||||
* This key must be specified on the inverse side of a bidirectional association.
|
||||
*
|
||||
*
|
||||
* - <b>inversedBy</b> (string, required for bidirectional associations)
|
||||
* The name of the field that completes the bidirectional association on the inverse side.
|
||||
* This key must be specified on the owning side of a bidirectional association.
|
||||
@ -388,7 +389,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* Specification of a field on target-entity that is used to index the collection by.
|
||||
* This field HAS to be either the primary key or a unique column. Otherwise the collection
|
||||
* does not contain all the entities that are actually related.
|
||||
*
|
||||
*
|
||||
* A join table definition has the following structure:
|
||||
* <pre>
|
||||
* array(
|
||||
@ -430,7 +431,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
/**
|
||||
* READ-ONLY: The definition of the sequence generator of this class. Only used for the
|
||||
* SEQUENCE generation strategy.
|
||||
*
|
||||
*
|
||||
* The definition has the following structure:
|
||||
* <code>
|
||||
* array(
|
||||
@ -685,7 +686,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'];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -746,6 +747,14 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
$this->isIdentifierComposite = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Type::hasType($mapping['type']) && Type::getType($mapping['type'])->canRequireSQLConversion()) {
|
||||
if (isset($mapping['id']) && $mapping['id'] === true) {
|
||||
throw MappingException::sqlConversionNotAllowedForIdentifiers($this->name, $mapping['fieldName'], $mapping['type']);
|
||||
}
|
||||
|
||||
$mapping['requireSQLConversion'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -774,15 +783,22 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
// If targetEntity is unqualified, assume it is in the same namespace as
|
||||
// the sourceEntity.
|
||||
$mapping['sourceEntity'] = $this->name;
|
||||
|
||||
|
||||
if (isset($mapping['targetEntity'])) {
|
||||
if (strlen($this->namespace) > 0 && strpos($mapping['targetEntity'], '\\') === false) {
|
||||
$mapping['targetEntity'] = $this->namespace . '\\' . $mapping['targetEntity'];
|
||||
}
|
||||
|
||||
|
||||
$mapping['targetEntity'] = ltrim($mapping['targetEntity'], '\\');
|
||||
}
|
||||
|
||||
if ( ($mapping['type'] & (self::MANY_TO_ONE|self::MANY_TO_MANY)) > 0 &&
|
||||
isset($mapping['orphanRemoval']) &&
|
||||
$mapping['orphanRemoval'] == true) {
|
||||
|
||||
throw MappingException::illegalOrphanRemoval($this->name, $mapping['fieldName']);
|
||||
}
|
||||
|
||||
// Complete id mapping
|
||||
if (isset($mapping['id']) && $mapping['id'] === true) {
|
||||
if (isset($mapping['orphanRemoval']) && $mapping['orphanRemoval'] == true) {
|
||||
@ -813,7 +829,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
if ( ! isset($mapping['targetEntity'])) {
|
||||
throw MappingException::missingTargetEntity($mapping['fieldName']);
|
||||
}
|
||||
|
||||
|
||||
// Mandatory and optional attributes for either side
|
||||
if ( ! $mapping['mappedBy']) {
|
||||
if (isset($mapping['joinTable']) && $mapping['joinTable']) {
|
||||
@ -829,7 +845,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
if (isset($mapping['id']) && $mapping['id'] === true && $mapping['type'] & self::TO_MANY) {
|
||||
throw MappingException::illegalToManyIdentifierAssoaction($this->name, $mapping['fieldName']);
|
||||
}
|
||||
|
||||
|
||||
// Fetch mode. Default fetch mode to LAZY, if not set.
|
||||
if ( ! isset($mapping['fetch'])) {
|
||||
$mapping['fetch'] = self::FETCH_LAZY;
|
||||
@ -837,18 +853,18 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
|
||||
// Cascades
|
||||
$cascades = isset($mapping['cascade']) ? array_map('strtolower', $mapping['cascade']) : array();
|
||||
|
||||
|
||||
if (in_array('all', $cascades)) {
|
||||
$cascades = array('remove', 'persist', 'refresh', 'merge', 'detach');
|
||||
}
|
||||
|
||||
|
||||
$mapping['cascade'] = $cascades;
|
||||
$mapping['isCascadeRemove'] = in_array('remove', $cascades);
|
||||
$mapping['isCascadePersist'] = in_array('persist', $cascades);
|
||||
$mapping['isCascadeRefresh'] = in_array('refresh', $cascades);
|
||||
$mapping['isCascadeMerge'] = in_array('merge', $cascades);
|
||||
$mapping['isCascadeDetach'] = in_array('detach', $cascades);
|
||||
|
||||
|
||||
return $mapping;
|
||||
}
|
||||
|
||||
@ -862,11 +878,11 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
protected function _validateAndCompleteOneToOneMapping(array $mapping)
|
||||
{
|
||||
$mapping = $this->_validateAndCompleteAssociationMapping($mapping);
|
||||
|
||||
|
||||
if (isset($mapping['joinColumns']) && $mapping['joinColumns']) {
|
||||
$mapping['isOwningSide'] = true;
|
||||
}
|
||||
|
||||
|
||||
if ($mapping['isOwningSide']) {
|
||||
if ( ! isset($mapping['joinColumns']) || ! $mapping['joinColumns']) {
|
||||
// Apply default join column
|
||||
@ -933,7 +949,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
if ( ! isset($mapping['mappedBy'])) {
|
||||
throw MappingException::oneToManyRequiresMappedBy($mapping['fieldName']);
|
||||
}
|
||||
|
||||
|
||||
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false;
|
||||
$mapping['isCascadeRemove'] = $mapping['orphanRemoval'] ? true : $mapping['isCascadeRemove'];
|
||||
|
||||
@ -942,7 +958,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
throw new \InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $mapping;
|
||||
}
|
||||
|
||||
@ -960,7 +976,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
} else {
|
||||
$targetShortName = strtolower($mapping['targetEntity']);
|
||||
}
|
||||
|
||||
|
||||
// owning side MUST have a join table
|
||||
if ( ! isset($mapping['joinTable']['name'])) {
|
||||
$mapping['joinTable']['name'] = $sourceShortName .'_' . $targetShortName;
|
||||
@ -1112,24 +1128,24 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
public function getIdentifierColumnNames()
|
||||
{
|
||||
$columnNames = array();
|
||||
|
||||
|
||||
foreach ($this->identifier as $idProperty) {
|
||||
if (isset($this->fieldMappings[$idProperty])) {
|
||||
$columnNames[] = $this->fieldMappings[$idProperty]['columnName'];
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// 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.
|
||||
*/
|
||||
@ -1369,11 +1385,11 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
$this->table['name'] = $table['name'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isset($table['indexes'])) {
|
||||
$this->table['indexes'] = $table['indexes'];
|
||||
}
|
||||
|
||||
|
||||
if (isset($table['uniqueConstraints'])) {
|
||||
$this->table['uniqueConstraints'] = $table['uniqueConstraints'];
|
||||
}
|
||||
@ -1448,8 +1464,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
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1509,11 +1532,11 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1524,7 +1547,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
public function setCustomRepositoryClass($repositoryClassName)
|
||||
{
|
||||
if ($repositoryClassName !== null && strpos($repositoryClassName, '\\') === false
|
||||
if ($repositoryClassName !== null && strpos($repositoryClassName, '\\') === false
|
||||
&& strlen($this->namespace) > 0) {
|
||||
$repositoryClassName = $this->namespace . '\\' . $repositoryClassName;
|
||||
}
|
||||
@ -1724,7 +1747,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
|
||||
/**
|
||||
* Return the single association join column (if any).
|
||||
*
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @return string
|
||||
*/
|
||||
@ -1766,7 +1789,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
foreach ($this->associationMappings AS $assocName => $mapping) {
|
||||
if ($this->isAssociationWithSingleJoinColumn($assocName) &&
|
||||
$this->associationMappings[$assocName]['joinColumns'][0]['name'] == $columnName) {
|
||||
|
||||
|
||||
return $assocName;
|
||||
}
|
||||
}
|
||||
@ -1856,34 +1879,34 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
{
|
||||
$this->isReadOnly = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A numerically indexed list of field names of this persistent class.
|
||||
*
|
||||
*
|
||||
* This array includes identifier fields if present on this class.
|
||||
*
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFieldNames()
|
||||
{
|
||||
return array_keys($this->fieldMappings);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A numerically indexed list of association names of this persistent class.
|
||||
*
|
||||
*
|
||||
* This array includes identifier associations if present on this class.
|
||||
*
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAssociationNames()
|
||||
{
|
||||
return array_keys($this->associationMappings);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the target class name of the given association.
|
||||
*
|
||||
*
|
||||
* @param string $assocName
|
||||
* @return string
|
||||
*/
|
||||
@ -1892,13 +1915,13 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
if ( ! isset($this->associationMappings[$assocName])) {
|
||||
throw new \InvalidArgumentException("Association name expected, '" . $assocName ."' is not an association.");
|
||||
}
|
||||
|
||||
|
||||
return $this->associationMappings[$assocName]['targetEntity'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get fully-qualified class name of this persistent class.
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
@ -1908,59 +1931,59 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
|
||||
/**
|
||||
* 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'])
|
||||
$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'])
|
||||
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.
|
||||
*
|
||||
*
|
||||
* @param string $field
|
||||
* @param AbstractPlatform $platform
|
||||
* @return string
|
||||
*/
|
||||
public function getQuotedColumnName($field, $platform)
|
||||
{
|
||||
return isset($this->fieldMappings[$field]['quoted'])
|
||||
? $platform->quoteIdentifier($this->fieldMappings[$field]['columnName'])
|
||||
return isset($this->fieldMappings[$field]['quoted'])
|
||||
? $platform->quoteIdentifier($this->fieldMappings[$field]['columnName'])
|
||||
: $this->fieldMappings[$field]['columnName'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the (possibly quoted) primary table name of this class for safe use
|
||||
* in an SQL statement.
|
||||
*
|
||||
*
|
||||
* @param AbstractPlatform $platform
|
||||
* @return string
|
||||
*/
|
||||
@ -1979,4 +2002,22 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
{
|
||||
return isset($assoc['joinTable']['quoted']) ? $platform->quoteIdentifier($assoc['joinTable']['name']) : $assoc['joinTable']['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fieldName
|
||||
* @return bool
|
||||
*/
|
||||
public function isAssociationInverseSide($fieldName)
|
||||
{
|
||||
return isset($this->associationMappings[$fieldName]) && ! $this->associationMappings[$fieldName]['isOwningSide'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fieldName
|
||||
* @return string
|
||||
*/
|
||||
public function getAssociationMappedByTargetField($fieldName)
|
||||
{
|
||||
return $this->associationMappings[$fieldName]['mappedBy'];
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -387,3 +387,9 @@ final class PostRemove implements Annotation {}
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
final class PostLoad implements Annotation {}
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
final class PreFlush implements Annotation {}
|
||||
|
@ -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,10 +222,13 @@ class XmlDriver extends AbstractFileDriver
|
||||
|
||||
$mapping = array(
|
||||
'id' => true,
|
||||
'fieldName' => (string)$idElement['name'],
|
||||
'type' => (string)$idElement['type']
|
||||
'fieldName' => (string)$idElement['name']
|
||||
);
|
||||
|
||||
if (isset($idElement['type'])) {
|
||||
$mapping['type'] = (string)$idElement['type'];
|
||||
}
|
||||
|
||||
if (isset($idElement['column'])) {
|
||||
$mapping['columnName'] = (string)$idElement['column'];
|
||||
}
|
||||
@ -371,10 +377,6 @@ class XmlDriver extends AbstractFileDriver
|
||||
$mapping['cascade'] = $this->_getCascadeMappings($manyToOneElement->cascade);
|
||||
}
|
||||
|
||||
if (isset($manyToOneElement->{'orphan-removal'})) {
|
||||
$mapping['orphanRemoval'] = (bool)$manyToOneElement->{'orphan-removal'};
|
||||
}
|
||||
|
||||
$metadata->mapManyToOne($mapping);
|
||||
}
|
||||
}
|
||||
@ -422,10 +424,6 @@ class XmlDriver extends AbstractFileDriver
|
||||
$mapping['cascade'] = $this->_getCascadeMappings($manyToManyElement->cascade);
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement->{'orphan-removal'})) {
|
||||
$mapping['orphanRemoval'] = (bool)$manyToManyElement->{'orphan-removal'};
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement->{'order-by'})) {
|
||||
$orderBy = array();
|
||||
foreach ($manyToManyElement->{'order-by'}->{'order-by-field'} AS $orderByField) {
|
||||
|
@ -47,7 +47,7 @@ class YamlDriver extends AbstractFileDriver
|
||||
|
||||
if ($element['type'] == 'entity') {
|
||||
if (isset($element['repositoryClass'])) {
|
||||
$metadata->setCustomRepositoryClass($element['repositoryClass']);
|
||||
$metadata->setCustomRepositoryClass($element['repositoryClass']);
|
||||
}
|
||||
if (isset($element['readOnly']) && $element['readOnly'] == true) {
|
||||
$metadata->markReadOnly();
|
||||
@ -165,16 +165,15 @@ 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);
|
||||
|
||||
$mapping = array(
|
||||
'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);
|
||||
}
|
||||
}
|
||||
|
||||
$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']
|
||||
);
|
||||
if (isset($fieldMapping['id'])) {
|
||||
$mapping['id'] = true;
|
||||
if (isset($fieldMapping['generator']['strategy'])) {
|
||||
@ -378,10 +379,6 @@ class YamlDriver extends AbstractFileDriver
|
||||
$mapping['cascade'] = $manyToOneElement['cascade'];
|
||||
}
|
||||
|
||||
if (isset($manyToOneElement['orphanRemoval'])) {
|
||||
$mapping['orphanRemoval'] = (bool)$manyToOneElement['orphanRemoval'];
|
||||
}
|
||||
|
||||
$metadata->mapManyToOne($mapping);
|
||||
}
|
||||
}
|
||||
@ -437,10 +434,6 @@ class YamlDriver extends AbstractFileDriver
|
||||
$mapping['cascade'] = $manyToManyElement['cascade'];
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement['orphanRemoval'])) {
|
||||
$mapping['orphanRemoval'] = (bool)$manyToManyElement['orphanRemoval'];
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement['orderBy'])) {
|
||||
$mapping['orderBy'] = $manyToManyElement['orderBy'];
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ class MappingException extends \Doctrine\ORM\ORMException
|
||||
if ( ! empty($path)) {
|
||||
$path = '[' . $path . ']';
|
||||
}
|
||||
|
||||
|
||||
return new self(
|
||||
'File mapping drivers must have a valid directory path, ' .
|
||||
'however the given path ' . $path . ' seems to be incorrect!'
|
||||
@ -226,6 +226,11 @@ class MappingException extends \Doctrine\ORM\ORMException
|
||||
return new self("Setting Id field '$fieldName' as versionale in entity class '$className' is not supported.");
|
||||
}
|
||||
|
||||
public static function sqlConversionNotAllowedForIdentifiers($className, $fieldName, $type)
|
||||
{
|
||||
return new self("It is not possible to set id field '$fieldName' to type '$type' in entity class '$className'. The type '$type' requires conversion SQL which is not allowed for identifiers.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @param string $columnName
|
||||
@ -270,6 +275,12 @@ class MappingException extends \Doctrine\ORM\ORMException
|
||||
"part of the identifier in '$className#$field'.");
|
||||
}
|
||||
|
||||
public static function illegalOrphanRemoval($className, $field)
|
||||
{
|
||||
return new self("Orphan removal is only allowed on one-to-one and one-to-many ".
|
||||
"associations, but " . $className."#" .$field . " is not.");
|
||||
}
|
||||
|
||||
public static function illegalInverseIdentifierAssocation($className, $field)
|
||||
{
|
||||
return new self("An inverse association is not allowed to be identifier in '$className#$field'.");
|
||||
@ -279,12 +290,12 @@ class MappingException extends \Doctrine\ORM\ORMException
|
||||
{
|
||||
return new self("Many-to-many or one-to-many associations are not allowed to be identifier in '$className#$field'.");
|
||||
}
|
||||
|
||||
|
||||
public static function noInheritanceOnMappedSuperClass($className)
|
||||
{
|
||||
return new self("Its not supported to define inheritance information on a mapped superclass '" . $className . "'.");
|
||||
}
|
||||
|
||||
|
||||
public static function mappedClassNotPartOfDiscriminatorMap($className, $rootClassName)
|
||||
{
|
||||
return new self(
|
||||
|
@ -59,6 +59,15 @@ class ORMException extends Exception
|
||||
return new self("Unrecognized field: $field");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @param string $field
|
||||
*/
|
||||
public static function invalidOrientation($className, $field)
|
||||
{
|
||||
return new self("Invalid order by orientation specified for " . $className . "#" . $field);
|
||||
}
|
||||
|
||||
public static function invalidFlushMode($mode)
|
||||
{
|
||||
return new self("'$mode' is an invalid flush mode.");
|
||||
|
@ -567,6 +567,9 @@ final class PersistentCollection implements Collection
|
||||
return;
|
||||
}
|
||||
if ($this->association['type'] == ClassMetadata::ONE_TO_MANY && $this->association['orphanRemoval']) {
|
||||
// we need to initialize here, as orphan removal acts like implicit cascadeRemove,
|
||||
// hence for event listeners we need the objects in memory.
|
||||
$this->initialize();
|
||||
foreach ($this->coll as $element) {
|
||||
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
|
||||
}
|
||||
|
@ -65,6 +65,11 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
|
||||
$columnAlias = $this->getSQLColumnAlias($columnName);
|
||||
$this->_rsm->addFieldResult($alias, $columnAlias, $field, $class->name);
|
||||
|
||||
if (isset($class->fieldMappings[$field]['requireSQLConversion'])) {
|
||||
$type = Type::getType($class->getTypeOfField($field));
|
||||
$sql = $type->convertToPHPValueSQL($sql, $this->_platform);
|
||||
}
|
||||
|
||||
return $sql . ' AS ' . $columnAlias;
|
||||
}
|
||||
|
||||
|
@ -338,10 +338,19 @@ class BasicEntityPersister
|
||||
$set = $params = $types = array();
|
||||
|
||||
foreach ($updateData as $columnName => $value) {
|
||||
$set[] = (isset($this->_class->fieldNames[$columnName]))
|
||||
? $this->_class->getQuotedColumnName($this->_class->fieldNames[$columnName], $this->_platform) . ' = ?'
|
||||
: $columnName . ' = ?';
|
||||
$column = $columnName;
|
||||
$placeholder = '?';
|
||||
|
||||
if (isset($this->_class->fieldNames[$columnName])) {
|
||||
$column = $this->_class->getQuotedColumnName($this->_class->fieldNames[$columnName], $this->_platform);
|
||||
|
||||
if (isset($this->_class->fieldMappings[$this->_class->fieldNames[$columnName]]['requireSQLConversion'])) {
|
||||
$type = Type::getType($this->_columnTypes[$columnName]);
|
||||
$placeholder = $type->convertToDatabaseValueSQL('?', $this->_platform);
|
||||
}
|
||||
}
|
||||
|
||||
$set[] = $column . ' = ' . $placeholder;
|
||||
$params[] = $value;
|
||||
$types[] = $this->_columnTypes[$columnName];
|
||||
}
|
||||
@ -628,13 +637,7 @@ class BasicEntityPersister
|
||||
$hints = array();
|
||||
|
||||
if ($isInverseSingleValued) {
|
||||
$hints['fetched'][$targetClass->name][$assoc['inversedBy']] = true;
|
||||
|
||||
if ($targetClass->subClasses) {
|
||||
foreach ($targetClass->subClasses as $targetSubclassName) {
|
||||
$hints['fetched'][$targetSubclassName][$assoc['inversedBy']] = true;
|
||||
}
|
||||
}
|
||||
$hints['fetched']["r"][$assoc['inversedBy']] = true;
|
||||
}
|
||||
|
||||
/* cascade read-only status
|
||||
@ -912,7 +915,6 @@ class BasicEntityPersister
|
||||
* @param array $orderBy
|
||||
* @param string $baseTableAlias
|
||||
* @return string
|
||||
* @todo Rename: _getOrderBySQL
|
||||
*/
|
||||
protected final function _getOrderBySQL(array $orderBy, $baseTableAlias)
|
||||
{
|
||||
@ -923,6 +925,11 @@ class BasicEntityPersister
|
||||
throw ORMException::unrecognizedField($fieldName);
|
||||
}
|
||||
|
||||
$orientation = strtoupper(trim($orientation));
|
||||
if ($orientation != 'ASC' && $orientation != 'DESC') {
|
||||
throw ORMException::invalidOrientation($this->_class->name, $fieldName);
|
||||
}
|
||||
|
||||
$tableAlias = isset($this->_class->fieldMappings[$fieldName]['inherited']) ?
|
||||
$this->_getSQLTableAlias($this->_class->fieldMappings[$fieldName]['inherited'])
|
||||
: $baseTableAlias;
|
||||
@ -1011,7 +1018,7 @@ class BasicEntityPersister
|
||||
if ( ! $first) {
|
||||
$this->_selectJoinSql .= ' AND ';
|
||||
}
|
||||
$this->_selectJoinSql .= $this->_getSQLTableAlias($assoc['sourceEntity']) . '.' . $sourceCol . ' = '
|
||||
$this->_selectJoinSql .= $this->_getSQLTableAlias($assoc['sourceEntity']) . '.' . $sourceCol . ' = '
|
||||
. $this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias) . '.' . $targetCol;
|
||||
$first = false;
|
||||
}
|
||||
@ -1020,7 +1027,7 @@ class BasicEntityPersister
|
||||
$owningAssoc = $eagerEntity->getAssociationMapping($assoc['mappedBy']);
|
||||
|
||||
$this->_selectJoinSql .= ' LEFT JOIN';
|
||||
$this->_selectJoinSql .= ' ' . $eagerEntity->getQuotedTableName($this->_platform) . ' '
|
||||
$this->_selectJoinSql .= ' ' . $eagerEntity->getQuotedTableName($this->_platform) . ' '
|
||||
. $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) . ' ON ';
|
||||
|
||||
foreach ($owningAssoc['sourceToTargetKeyColumns'] AS $sourceCol => $targetCol) {
|
||||
@ -1060,7 +1067,7 @@ class BasicEntityPersister
|
||||
if ($columnList) $columnList .= ', ';
|
||||
|
||||
$resultColumnName = $this->getSQLColumnAlias($srcColumn);
|
||||
$columnList .= $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) )
|
||||
$columnList .= $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) )
|
||||
. '.' . $srcColumn . ' AS ' . $resultColumnName;
|
||||
$this->_rsm->addMetaResult($alias, $resultColumnName, $srcColumn, isset($assoc['id']) && $assoc['id'] === true);
|
||||
}
|
||||
@ -1123,7 +1130,19 @@ class BasicEntityPersister
|
||||
);
|
||||
} else {
|
||||
$columns = array_unique($columns);
|
||||
$values = array_fill(0, count($columns), '?');
|
||||
|
||||
$values = array();
|
||||
foreach ($columns AS $column) {
|
||||
$placeholder = '?';
|
||||
|
||||
if (isset($this->_columnTypes[$column]) &&
|
||||
isset($this->_class->fieldMappings[$this->_class->fieldNames[$column]]['requireSQLConversion'])) {
|
||||
$type = Type::getType($this->_columnTypes[$column]);
|
||||
$placeholder = $type->convertToDatabaseValueSQL('?', $this->_platform);
|
||||
}
|
||||
|
||||
$values[] = $placeholder;
|
||||
}
|
||||
|
||||
$insertSql = 'INSERT INTO ' . $this->_class->getQuotedTableName($this->_platform)
|
||||
. ' (' . implode(', ', $columns) . ') VALUES (' . implode(', ', $values) . ')';
|
||||
@ -1162,6 +1181,7 @@ class BasicEntityPersister
|
||||
}
|
||||
} else if ($this->_class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY || $this->_class->identifier[0] != $name) {
|
||||
$columns[] = $this->_class->getQuotedColumnName($name, $this->_platform);
|
||||
$this->_columnTypes[$name] = $this->_class->fieldMappings[$name]['type'];
|
||||
}
|
||||
}
|
||||
|
||||
@ -1178,12 +1198,17 @@ class BasicEntityPersister
|
||||
*/
|
||||
protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r')
|
||||
{
|
||||
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias)
|
||||
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias)
|
||||
. '.' . $class->getQuotedColumnName($field, $this->_platform);
|
||||
$columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]);
|
||||
|
||||
$this->_rsm->addFieldResult($alias, $columnAlias, $field);
|
||||
|
||||
if (isset($class->fieldMappings[$field]['requireSQLConversion'])) {
|
||||
$type = Type::getType($class->getTypeOfField($field));
|
||||
$sql = $type->convertToPHPValueSQL($sql, $this->_platform);
|
||||
}
|
||||
|
||||
return $sql . ' AS ' . $columnAlias;
|
||||
}
|
||||
|
||||
@ -1265,6 +1290,8 @@ class BasicEntityPersister
|
||||
|
||||
foreach ($criteria as $field => $value) {
|
||||
$conditionSql .= $conditionSql ? ' AND ' : '';
|
||||
|
||||
$placeholder = '?';
|
||||
|
||||
if (isset($this->_class->columnNames[$field])) {
|
||||
$className = (isset($this->_class->fieldMappings[$field]['inherited']))
|
||||
@ -1272,6 +1299,11 @@ class BasicEntityPersister
|
||||
: $this->_class->name;
|
||||
|
||||
$conditionSql .= $this->_getSQLTableAlias($className) . '.' . $this->_class->getQuotedColumnName($field, $this->_platform);
|
||||
|
||||
if (isset($this->_class->fieldMappings[$field]['requireSQLConversion'])) {
|
||||
$type = Type::getType($this->_class->getTypeOfField($field));
|
||||
$placeholder = $type->convertToDatabaseValueSQL($placeholder, $this->_platform);
|
||||
}
|
||||
} else if (isset($this->_class->associationMappings[$field])) {
|
||||
if ( ! $this->_class->associationMappings[$field]['isOwningSide']) {
|
||||
throw ORMException::invalidFindByInverseAssociation($this->_class->name, $field);
|
||||
@ -1292,7 +1324,7 @@ class BasicEntityPersister
|
||||
throw ORMException::unrecognizedField($field);
|
||||
}
|
||||
|
||||
$conditionSql .= (is_array($value)) ? ' IN (?)' : (($value === null) ? ' IS NULL' : ' = ?');
|
||||
$conditionSql .= (is_array($value)) ? ' IN (?)' : (($value === null) ? ' IS NULL' : ' = ' . $placeholder);
|
||||
}
|
||||
return $conditionSql;
|
||||
}
|
||||
|
@ -131,4 +131,4 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
|
||||
|
||||
return $conditionSql;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 ';
|
||||
@ -234,7 +236,7 @@ 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" &&
|
||||
|
@ -44,28 +44,28 @@ final class Query extends AbstractQuery
|
||||
* is called.
|
||||
*/
|
||||
const STATE_DIRTY = 2;
|
||||
|
||||
|
||||
/* Query HINTS */
|
||||
/**
|
||||
* The refresh hint turns any query into a refresh query with the result that
|
||||
* any local changes in entities are overridden with the fetched values.
|
||||
*
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const HINT_REFRESH = 'doctrine.refresh';
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Internal hint: is set to the proxy entity that is currently triggered for loading
|
||||
*
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const HINT_REFRESH_ENTITY = 'doctrine.refresh.entity';
|
||||
|
||||
|
||||
/**
|
||||
* The forcePartialLoad query hint forces a particular query to return
|
||||
* partial objects.
|
||||
*
|
||||
*
|
||||
* @var string
|
||||
* @todo Rename: HINT_OPTIMIZE
|
||||
*/
|
||||
@ -73,9 +73,9 @@ final class Query extends AbstractQuery
|
||||
/**
|
||||
* The includeMetaColumns query hint causes meta columns like foreign keys and
|
||||
* discriminator columns to be selected and returned as part of the query result.
|
||||
*
|
||||
*
|
||||
* This hint does only apply to non-object queries.
|
||||
*
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const HINT_INCLUDE_META_COLUMNS = 'doctrine.includeMetaColumns';
|
||||
@ -122,12 +122,12 @@ final class Query extends AbstractQuery
|
||||
* @var Doctrine\ORM\Query\ParserResult The parser result that holds DQL => SQL information.
|
||||
*/
|
||||
private $_parserResult;
|
||||
|
||||
|
||||
/**
|
||||
* @var integer The first result to return (the "offset").
|
||||
*/
|
||||
private $_firstResult = null;
|
||||
|
||||
|
||||
/**
|
||||
* @var integer The maximum number of results to return (the "limit").
|
||||
*/
|
||||
@ -147,7 +147,7 @@ final class Query extends AbstractQuery
|
||||
* @var int Query Cache lifetime.
|
||||
*/
|
||||
private $_queryCacheTTL;
|
||||
|
||||
|
||||
/**
|
||||
* @var boolean Whether to use a query cache, if available. Defaults to TRUE.
|
||||
*/
|
||||
@ -191,7 +191,7 @@ final class Query extends AbstractQuery
|
||||
|
||||
/**
|
||||
* Parses the DQL query, if necessary, and stores the parser result.
|
||||
*
|
||||
*
|
||||
* Note: Populates $this->_parserResult as a side-effect.
|
||||
*
|
||||
* @return Doctrine\ORM\Query\ParserResult
|
||||
@ -201,12 +201,12 @@ final class Query extends AbstractQuery
|
||||
if ($this->_state === self::STATE_CLEAN) {
|
||||
return $this->_parserResult;
|
||||
}
|
||||
|
||||
|
||||
// Check query cache.
|
||||
if ($this->_useQueryCache && ($queryCache = $this->getQueryCacheDriver())) {
|
||||
$hash = $this->_getQueryCacheId();
|
||||
$cached = $this->_expireQueryCache ? false : $queryCache->fetch($hash);
|
||||
|
||||
|
||||
if ($cached === false) {
|
||||
// Cache miss.
|
||||
$parser = new Parser($this);
|
||||
@ -220,9 +220,9 @@ final class Query extends AbstractQuery
|
||||
$parser = new Parser($this);
|
||||
$this->_parserResult = $parser->parse();
|
||||
}
|
||||
|
||||
|
||||
$this->_state = self::STATE_CLEAN;
|
||||
|
||||
|
||||
return $this->_parserResult;
|
||||
}
|
||||
|
||||
@ -244,55 +244,62 @@ final class Query extends AbstractQuery
|
||||
}
|
||||
|
||||
list($sqlParams, $types) = $this->processParameterMappings($paramMappings);
|
||||
|
||||
|
||||
if ($this->_resultSetMapping === null) {
|
||||
$this->_resultSetMapping = $this->_parserResult->getResultSetMapping();
|
||||
}
|
||||
|
||||
return $executor->execute($this->_em->getConnection(), $sqlParams, $types);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes query parameter mappings
|
||||
*
|
||||
*
|
||||
* @param array $paramMappings
|
||||
* @return array
|
||||
*/
|
||||
private function processParameterMappings($paramMappings)
|
||||
{
|
||||
$sqlParams = $types = array();
|
||||
|
||||
|
||||
foreach ($this->_params as $key => $value) {
|
||||
if ( ! isset($paramMappings[$key])) {
|
||||
throw QueryException::unknownParameter($key);
|
||||
}
|
||||
|
||||
|
||||
if (isset($this->_paramTypes[$key])) {
|
||||
foreach ($paramMappings[$key] as $position) {
|
||||
$types[$position] = $this->_paramTypes[$key];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$sqlPositions = $paramMappings[$key];
|
||||
$value = array_values($this->processParameterValue($value));
|
||||
$countValue = count($value);
|
||||
|
||||
|
||||
for ($i = 0, $l = count($sqlPositions); $i < $l; $i++) {
|
||||
$sqlParams[$sqlPositions[$i]] = $value[($i % $countValue)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (count($sqlParams) != count($types)) {
|
||||
throw QueryException::parameterTypeMissmatch();
|
||||
}
|
||||
|
||||
if ($sqlParams) {
|
||||
ksort($sqlParams);
|
||||
$sqlParams = array_values($sqlParams);
|
||||
|
||||
ksort($types);
|
||||
$types = array_values($types);
|
||||
}
|
||||
|
||||
return array($sqlParams, $types);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process an individual parameter value
|
||||
*
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return array
|
||||
*/
|
||||
@ -308,7 +315,7 @@ final class Query extends AbstractQuery
|
||||
}
|
||||
|
||||
return array($value);
|
||||
|
||||
|
||||
case is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value)):
|
||||
if ($this->_em->getUnitOfWork()->getEntityState($value) === UnitOfWork::STATE_MANAGED) {
|
||||
return array_values($this->_em->getUnitOfWork()->getEntityIdentifier($value));
|
||||
@ -317,7 +324,7 @@ final class Query extends AbstractQuery
|
||||
$class = $this->_em->getClassMetadata(get_class($value));
|
||||
|
||||
return array_values($class->getIdentifierValues($value));
|
||||
|
||||
|
||||
default:
|
||||
return array($value);
|
||||
}
|
||||
@ -334,10 +341,10 @@ final class Query extends AbstractQuery
|
||||
$this->_queryCache = $queryCache;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Defines whether the query should make use of a query cache, if available.
|
||||
*
|
||||
*
|
||||
* @param boolean $bool
|
||||
* @return @return Query This query instance.
|
||||
*/
|
||||
@ -471,7 +478,7 @@ final class Query extends AbstractQuery
|
||||
{
|
||||
return stripos($this->getDQL(), $dql) === false ? false : true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the position of the first result to retrieve (the "offset").
|
||||
*
|
||||
@ -484,21 +491,21 @@ final class Query extends AbstractQuery
|
||||
$this->_state = self::STATE_DIRTY;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the position of the first result the query object was set to retrieve (the "offset").
|
||||
* Returns NULL if {@link setFirstResult} was not applied to this query.
|
||||
*
|
||||
*
|
||||
* @return integer The position of the first result.
|
||||
*/
|
||||
public function getFirstResult()
|
||||
{
|
||||
return $this->_firstResult;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the maximum number of results to retrieve (the "limit").
|
||||
*
|
||||
*
|
||||
* @param integer $maxResults
|
||||
* @return Query This query object.
|
||||
*/
|
||||
@ -508,11 +515,11 @@ final class Query extends AbstractQuery
|
||||
$this->_state = self::STATE_DIRTY;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the maximum number of results the query object was set to retrieve (the "limit").
|
||||
* Returns NULL if {@link setMaxResults} was not applied to this query.
|
||||
*
|
||||
*
|
||||
* @return integer Maximum number of results.
|
||||
*/
|
||||
public function getMaxResults()
|
||||
@ -533,7 +540,7 @@ final class Query extends AbstractQuery
|
||||
$this->setHint(self::HINT_INTERNAL_ITERATION, true);
|
||||
return parent::iterate($params, $hydrationMode);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -542,7 +549,7 @@ final class Query extends AbstractQuery
|
||||
$this->_state = self::STATE_DIRTY;
|
||||
return parent::setHint($name, $value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -597,7 +604,7 @@ final class Query extends AbstractQuery
|
||||
ksort($this->_hints);
|
||||
|
||||
return md5(
|
||||
$this->getDql() . var_export($this->_hints, true) .
|
||||
$this->getDql() . var_export($this->_hints, true) .
|
||||
'&firstResult=' . $this->_firstResult . '&maxResult=' . $this->_maxResults .
|
||||
'&hydrationMode='.$this->_hydrationMode.'DOCTRINE_QUERY_CACHE_SALT'
|
||||
);
|
||||
|
@ -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
@ -77,6 +77,11 @@ class QueryException extends \Doctrine\ORM\ORMException
|
||||
return new self("Invalid parameter: token ".$key." is not defined in the query.");
|
||||
}
|
||||
|
||||
public static function parameterTypeMissmatch()
|
||||
{
|
||||
return new self("DQL Query parameter and type numbers missmatch, but have to be exactly equal.");
|
||||
}
|
||||
|
||||
public static function invalidPathExpression($pathExpr)
|
||||
{
|
||||
return new self(
|
||||
@ -140,7 +145,7 @@ class QueryException extends \Doctrine\ORM\ORMException
|
||||
"in the query."
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function instanceOfUnrelatedClass($className, $rootClass)
|
||||
{
|
||||
return new self("Cannot check if a child of '" . $rootClass . "' is instanceof '" . $className . "', " .
|
||||
|
@ -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,19 @@ 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;
|
||||
|
||||
if ($resultAlias !== null) {
|
||||
$this->isMixed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -141,6 +141,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)
|
||||
@ -158,20 +159,27 @@ class ResultSetMapping
|
||||
public function addIndexBy($alias, $fieldName)
|
||||
{
|
||||
$found = false;
|
||||
|
||||
foreach ($this->fieldMappings AS $columnName => $columnFieldName) {
|
||||
if ($columnFieldName === $fieldName && $this->columnOwnerMap[$columnName] == $alias) {
|
||||
$this->addIndexByColumn($alias, $columnName);
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
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) {
|
||||
throw new \LogicException("Cannot add index by for dql alias " . $alias . " and field " .
|
||||
$fieldName . " without calling addFieldResult() for them before.");
|
||||
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);
|
||||
}
|
||||
*/
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
@ -244,6 +252,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;
|
||||
}
|
||||
@ -260,11 +269,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.
|
||||
*
|
||||
@ -275,6 +284,7 @@ class ResultSetMapping
|
||||
public function addScalarResult($columnName, $alias)
|
||||
{
|
||||
$this->scalarMappings[$columnName] = $alias;
|
||||
|
||||
if ( ! $this->isMixed && $this->fieldMappings) {
|
||||
$this->isMixed = true;
|
||||
}
|
||||
@ -282,7 +292,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
|
||||
@ -421,10 +431,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
|
||||
@ -434,6 +444,7 @@ class ResultSetMapping
|
||||
{
|
||||
$this->metaMappings[$columnName] = $fieldName;
|
||||
$this->columnOwnerMap[$columnName] = $alias;
|
||||
|
||||
if ($isIdentifierColumn) {
|
||||
$this->isIdentifierColumn[$alias][$columnName] = true;
|
||||
}
|
||||
|
@ -20,17 +20,20 @@
|
||||
namespace Doctrine\ORM\Query;
|
||||
|
||||
use Doctrine\DBAL\LockMode,
|
||||
Doctrine\DBAL\Types\Type,
|
||||
Doctrine\ORM\Mapping\ClassMetadata,
|
||||
Doctrine\ORM\Query,
|
||||
Doctrine\ORM\Query\QueryException;
|
||||
Doctrine\ORM\Query\QueryException,
|
||||
Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
|
||||
/**
|
||||
* The SqlWalker is a TreeWalker that walks over a DQL AST and constructs
|
||||
* the corresponding SQL.
|
||||
*
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @since 2.0
|
||||
* @since 2.0
|
||||
* @todo Rename: SQLWalker
|
||||
*/
|
||||
class SqlWalker implements TreeWalker
|
||||
@ -257,13 +260,13 @@ class SqlWalker implements TreeWalker
|
||||
// If this is a joined association we must use left joins to preserve the correct result.
|
||||
$sql .= isset($this->_queryComponents[$dqlAlias]['relation']) ? ' LEFT ' : ' INNER ';
|
||||
$sql .= 'JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
|
||||
|
||||
|
||||
$sqlParts = array();
|
||||
|
||||
foreach ($class->getQuotedIdentifierColumnNames($this->_platform) as $columnName) {
|
||||
$sqlParts[] = $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName;
|
||||
}
|
||||
|
||||
|
||||
$sql .= implode(' AND ', $sqlParts);
|
||||
}
|
||||
|
||||
@ -271,7 +274,7 @@ class SqlWalker implements TreeWalker
|
||||
if ($this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
|
||||
return $sql;
|
||||
}
|
||||
|
||||
|
||||
// LEFT JOIN child class tables
|
||||
foreach ($class->subClasses as $subClassName) {
|
||||
$subClass = $this->_em->getClassMetadata($subClassName);
|
||||
@ -294,18 +297,19 @@ class SqlWalker implements TreeWalker
|
||||
private function _generateOrderedCollectionOrderByItems()
|
||||
{
|
||||
$sqlParts = array();
|
||||
|
||||
foreach ($this->_selectedClasses AS $dqlAlias => $class) {
|
||||
$qComp = $this->_queryComponents[$dqlAlias];
|
||||
|
||||
foreach ($this->_selectedClasses AS $selectedClass) {
|
||||
$dqlAlias = $selectedClass['dqlAlias'];
|
||||
$qComp = $this->_queryComponents[$dqlAlias];
|
||||
|
||||
if ( ! isset($qComp['relation']['orderBy'])) continue;
|
||||
|
||||
|
||||
foreach ($qComp['relation']['orderBy'] AS $fieldName => $orientation) {
|
||||
$columnName = $qComp['metadata']->getQuotedColumnName($fieldName, $this->_platform);
|
||||
$tableName = ($qComp['metadata']->isInheritanceTypeJoined())
|
||||
? $this->_em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName)
|
||||
? $this->_em->getUnitOfWork()->getEntityPersister($qComp['metadata']->name)->getOwningTable($fieldName)
|
||||
: $qComp['metadata']->getTableName();
|
||||
|
||||
|
||||
$sqlParts[] = $this->getSQLTableAlias($tableName, $dqlAlias) . '.' . $columnName . ' ' . $orientation;
|
||||
}
|
||||
}
|
||||
@ -327,7 +331,7 @@ class SqlWalker implements TreeWalker
|
||||
$class = $this->_queryComponents[$dqlAlias]['metadata'];
|
||||
|
||||
if ( ! $class->isInheritanceTypeSingleTable()) continue;
|
||||
|
||||
|
||||
$conn = $this->_em->getConnection();
|
||||
$values = array();
|
||||
|
||||
@ -344,7 +348,7 @@ class SqlWalker implements TreeWalker
|
||||
}
|
||||
|
||||
$sql = implode(' AND ', $sqlParts);
|
||||
|
||||
|
||||
return (count($sqlParts) > 1) ? '(' . $sql . ')' : $sql;
|
||||
}
|
||||
|
||||
@ -376,19 +380,19 @@ class SqlWalker implements TreeWalker
|
||||
case LockMode::PESSIMISTIC_READ:
|
||||
$sql .= ' ' . $this->_platform->getReadLockSQL();
|
||||
break;
|
||||
|
||||
|
||||
case LockMode::PESSIMISTIC_WRITE:
|
||||
$sql .= ' ' . $this->_platform->getWriteLockSQL();
|
||||
break;
|
||||
|
||||
|
||||
case LockMode::PESSIMISTIC_OPTIMISTIC:
|
||||
foreach ($this->_selectedClasses AS $class) {
|
||||
foreach ($this->_selectedClasses AS $selectedClass) {
|
||||
if ( ! $class->isVersioned) {
|
||||
throw \Doctrine\ORM\OptimisticLockException::lockFailed($class->name);
|
||||
throw \Doctrine\ORM\OptimisticLockException::lockFailed($selectedClass['class']->name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
throw \Doctrine\ORM\Query\QueryException::invalidLockMode();
|
||||
}
|
||||
@ -521,13 +525,18 @@ class SqlWalker implements TreeWalker
|
||||
$this->_query->getHydrationMode() != Query::HYDRATE_OBJECT &&
|
||||
$this->_query->getHint(Query::HINT_INCLUDE_META_COLUMNS);
|
||||
|
||||
foreach ($this->_selectedClasses as $dqlAlias => $class) {
|
||||
foreach ($this->_selectedClasses as $selectedClass) {
|
||||
$class = $selectedClass['class'];
|
||||
$dqlAlias = $selectedClass['dqlAlias'];
|
||||
$resultAlias = $selectedClass['resultAlias'];
|
||||
|
||||
// Register as entity or joined entity result
|
||||
if ($this->_queryComponents[$dqlAlias]['relation'] === null) {
|
||||
$this->_rsm->addEntityResult($class->name, $dqlAlias);
|
||||
$this->_rsm->addEntityResult($class->name, $dqlAlias, $resultAlias);
|
||||
} else {
|
||||
$this->_rsm->addJoinedEntityResult(
|
||||
$class->name, $dqlAlias,
|
||||
$class->name,
|
||||
$dqlAlias,
|
||||
$this->_queryComponents[$dqlAlias]['parent'],
|
||||
$this->_queryComponents[$dqlAlias]['relation']['fieldName']
|
||||
);
|
||||
@ -545,10 +554,10 @@ class SqlWalker implements TreeWalker
|
||||
$this->_rsm->setDiscriminatorColumn($dqlAlias, $columnAlias);
|
||||
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $discrColumn['fieldName']);
|
||||
}
|
||||
|
||||
|
||||
// Add foreign key columns to SQL, if necessary
|
||||
if ( ! $addMetaColumns) continue;
|
||||
|
||||
|
||||
// Add foreign key columns of class and also parent classes
|
||||
foreach ($class->associationMappings as $assoc) {
|
||||
if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE)) continue;
|
||||
@ -564,7 +573,7 @@ class SqlWalker implements TreeWalker
|
||||
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn, (isset($assoc['id']) && $assoc['id'] === true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add foreign key columns of subclasses
|
||||
foreach ($class->subClasses as $subClassName) {
|
||||
$subClass = $this->_em->getClassMetadata($subClassName);
|
||||
@ -573,12 +582,12 @@ class SqlWalker implements TreeWalker
|
||||
foreach ($subClass->associationMappings as $assoc) {
|
||||
// Skip if association is inherited
|
||||
if (isset($assoc['inherited'])) continue;
|
||||
|
||||
|
||||
if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE)) continue;
|
||||
|
||||
|
||||
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
|
||||
$columnAlias = $this->getSQLColumnAlias($srcColumn);
|
||||
|
||||
|
||||
$sqlSelectExpressions[] = $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias;
|
||||
|
||||
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn);
|
||||
@ -661,11 +670,11 @@ class SqlWalker implements TreeWalker
|
||||
public function walkOrderByClause($orderByClause)
|
||||
{
|
||||
$orderByItems = array_map(array($this, 'walkOrderByItem'), $orderByClause->orderByItems);
|
||||
|
||||
|
||||
if (($collectionOrderByItems = $this->_generateOrderedCollectionOrderByItems()) !== '') {
|
||||
$orderByItems = array_merge($orderByItems, (array) $collectionOrderByItems);
|
||||
}
|
||||
|
||||
|
||||
return ' ORDER BY ' . implode(', ', $orderByItems);
|
||||
}
|
||||
|
||||
@ -709,7 +718,7 @@ class SqlWalker implements TreeWalker
|
||||
$sql = ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER)
|
||||
? ' LEFT JOIN '
|
||||
: ' INNER JOIN ';
|
||||
|
||||
|
||||
if ($joinVarDecl->indexBy) {
|
||||
// For Many-To-One or One-To-One associations this obviously makes no sense, but is ignored silently.
|
||||
$this->_rsm->addIndexBy(
|
||||
@ -994,16 +1003,23 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
$sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias);
|
||||
$columnName = $class->getQuotedColumnName($fieldName, $this->_platform);
|
||||
$columnAlias = $this->getSQLColumnAlias($columnName);
|
||||
|
||||
$sql .= $sqlTableAlias . '.' . $columnName . ' AS ' . $columnAlias;
|
||||
$columnAlias = $this->getSQLColumnAlias($columnName);
|
||||
|
||||
$col = $sqlTableAlias . '.' . $columnName;
|
||||
|
||||
if (isset($class->fieldMappings[$fieldName]['requireSQLConversion'])) {
|
||||
$type = Type::getType($class->getTypeOfField($fieldName));
|
||||
$col = $type->convertToPHPValueSQL($col, $this->_conn->getDatabasePlatform());
|
||||
}
|
||||
|
||||
$sql .= $col . ' AS ' . $columnAlias;
|
||||
|
||||
if ( ! $hidden) {
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
$this->_scalarFields[$dqlAlias][$fieldName] = $columnAlias;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case ($expr instanceof AST\AggregateExpression):
|
||||
case ($expr instanceof AST\Functions\FunctionNode):
|
||||
case ($expr instanceof AST\SimpleArithmeticExpression):
|
||||
@ -1017,29 +1033,29 @@ class SqlWalker implements TreeWalker
|
||||
case ($expr instanceof AST\SimpleCaseExpression):
|
||||
$columnAlias = $this->getSQLColumnAlias('sclr');
|
||||
$resultAlias = $selectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++;
|
||||
|
||||
|
||||
$sql .= $expr->dispatch($this) . ' AS ' . $columnAlias;
|
||||
|
||||
|
||||
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||
|
||||
if ( ! $hidden) {
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case ($expr instanceof AST\Subselect):
|
||||
$columnAlias = $this->getSQLColumnAlias('sclr');
|
||||
$resultAlias = $selectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++;
|
||||
|
||||
$sql .= '(' . $this->walkSubselect($expr) . ') AS '.$columnAlias;
|
||||
|
||||
|
||||
$sql .= '(' . $this->walkSubselect($expr) . ') AS ' . $columnAlias;
|
||||
|
||||
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||
|
||||
if ( ! $hidden) {
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
// IdentificationVariable or PartialObjectExpression
|
||||
if ($expr instanceof AST\PartialObjectExpression) {
|
||||
@ -1050,18 +1066,23 @@ class SqlWalker implements TreeWalker
|
||||
$partialFieldSet = array();
|
||||
}
|
||||
|
||||
$queryComp = $this->_queryComponents[$dqlAlias];
|
||||
$class = $queryComp['metadata'];
|
||||
$queryComp = $this->_queryComponents[$dqlAlias];
|
||||
$class = $queryComp['metadata'];
|
||||
$resultAlias = $selectExpression->fieldIdentificationVariable ?: null;
|
||||
|
||||
if ( ! isset($this->_selectedClasses[$dqlAlias])) {
|
||||
$this->_selectedClasses[$dqlAlias] = $class;
|
||||
$this->_selectedClasses[$dqlAlias] = array(
|
||||
'class' => $class,
|
||||
'dqlAlias' => $dqlAlias,
|
||||
'resultAlias' => $resultAlias
|
||||
);
|
||||
}
|
||||
|
||||
$beginning = true;
|
||||
$sqlParts = array();
|
||||
|
||||
// Select all fields from the queried class
|
||||
foreach ($class->fieldMappings as $fieldName => $mapping) {
|
||||
if ($partialFieldSet && !in_array($fieldName, $partialFieldSet)) {
|
||||
if ($partialFieldSet && ! in_array($fieldName, $partialFieldSet)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1069,12 +1090,18 @@ class SqlWalker implements TreeWalker
|
||||
? $this->_em->getClassMetadata($mapping['inherited'])->getTableName()
|
||||
: $class->getTableName();
|
||||
|
||||
if ($beginning) $beginning = false; else $sql .= ', ';
|
||||
$sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias);
|
||||
$columnAlias = $this->getSQLColumnAlias($mapping['columnName']);
|
||||
$quotedColumnName = $class->getQuotedColumnName($fieldName, $this->_platform);
|
||||
|
||||
$sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias);
|
||||
$columnAlias = $this->getSQLColumnAlias($mapping['columnName']);
|
||||
$sql .= $sqlTableAlias . '.' . $class->getQuotedColumnName($fieldName, $this->_platform)
|
||||
. ' AS ' . $columnAlias;
|
||||
$col = $sqlTableAlias . '.' . $quotedColumnName;
|
||||
|
||||
if (isset($class->fieldMappings[$fieldName]['requireSQLConversion'])) {
|
||||
$type = Type::getType($class->getTypeOfField($fieldName));
|
||||
$col = $type->convertToPHPValueSQL($col, $this->_platform);
|
||||
}
|
||||
|
||||
$sqlParts[] = $col . ' AS '. $columnAlias;
|
||||
|
||||
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $class->name);
|
||||
}
|
||||
@ -1085,7 +1112,7 @@ class SqlWalker implements TreeWalker
|
||||
// since it requires outer joining subtables.
|
||||
if ($class->isInheritanceTypeSingleTable() || ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
|
||||
foreach ($class->subClasses as $subClassName) {
|
||||
$subClass = $this->_em->getClassMetadata($subClassName);
|
||||
$subClass = $this->_em->getClassMetadata($subClassName);
|
||||
$sqlTableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias);
|
||||
|
||||
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
|
||||
@ -1093,16 +1120,24 @@ class SqlWalker implements TreeWalker
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($beginning) $beginning = false; else $sql .= ', ';
|
||||
$columnAlias = $this->getSQLColumnAlias($mapping['columnName']);
|
||||
$quotedColumnName = $subClass->getQuotedColumnName($fieldName, $this->_platform);
|
||||
|
||||
$columnAlias = $this->getSQLColumnAlias($mapping['columnName']);
|
||||
$sql .= $sqlTableAlias . '.' . $subClass->getQuotedColumnName($fieldName, $this->_platform)
|
||||
. ' AS ' . $columnAlias;
|
||||
$col = $sqlTableAlias . '.' . $quotedColumnName;
|
||||
|
||||
if (isset($subClass->fieldMappings[$fieldName]['requireSQLConversion'])) {
|
||||
$type = Type::getType($subClass->getTypeOfField($fieldName));
|
||||
$col = $type->convertToPHPValueSQL($col, $this->_platform);
|
||||
}
|
||||
|
||||
$sqlParts[] = $col . ' AS ' . $columnAlias;
|
||||
|
||||
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $subClassName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sql .= implode(', ', $sqlParts);
|
||||
}
|
||||
|
||||
return $sql;
|
||||
@ -1116,8 +1151,7 @@ class SqlWalker implements TreeWalker
|
||||
*/
|
||||
public function walkQuantifiedExpression($qExpr)
|
||||
{
|
||||
return ' ' . strtoupper($qExpr->type)
|
||||
. '(' . $this->walkSubselect($qExpr->subselect) . ')';
|
||||
return ' ' . strtoupper($qExpr->type) . '(' . $this->walkSubselect($qExpr->subselect) . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1128,20 +1162,21 @@ class SqlWalker implements TreeWalker
|
||||
*/
|
||||
public function walkSubselect($subselect)
|
||||
{
|
||||
$useAliasesBefore = $this->_useSqlTableAliases;
|
||||
$useAliasesBefore = $this->_useSqlTableAliases;
|
||||
$rootAliasesBefore = $this->_rootAliases;
|
||||
|
||||
$this->_rootAliases = array(); // reset the rootAliases for the subselect
|
||||
$this->_useSqlTableAliases = true;
|
||||
|
||||
$sql = $this->walkSimpleSelectClause($subselect->simpleSelectClause);
|
||||
$sql = $this->walkSimpleSelectClause($subselect->simpleSelectClause);
|
||||
$sql .= $this->walkSubselectFromClause($subselect->subselectFromClause);
|
||||
$sql .= $this->walkWhereClause($subselect->whereClause);
|
||||
|
||||
$sql .= $subselect->groupByClause ? $this->walkGroupByClause($subselect->groupByClause) : '';
|
||||
$sql .= $subselect->havingClause ? $this->walkHavingClause($subselect->havingClause) : '';
|
||||
$sql .= $subselect->orderByClause ? $this->walkOrderByClause($subselect->orderByClause) : '';
|
||||
|
||||
$this->_rootAliases = $rootAliasesBefore; // put the main aliases back
|
||||
$this->_rootAliases = $rootAliasesBefore; // put the main aliases back
|
||||
$this->_useSqlTableAliases = $useAliasesBefore;
|
||||
|
||||
return $sql;
|
||||
@ -1162,7 +1197,7 @@ class SqlWalker implements TreeWalker
|
||||
$sql = '';
|
||||
|
||||
$rangeDecl = $subselectIdVarDecl->rangeVariableDeclaration;
|
||||
$dqlAlias = $rangeDecl->aliasIdentificationVariable;
|
||||
$dqlAlias = $rangeDecl->aliasIdentificationVariable;
|
||||
|
||||
$class = $this->_em->getClassMetadata($rangeDecl->abstractSchemaName);
|
||||
$sql .= $class->getQuotedTableName($this->_platform) . ' '
|
||||
@ -1290,11 +1325,18 @@ class SqlWalker implements TreeWalker
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($this->_queryComponents[$groupByItem]['metadata']->identifier AS $idField) {
|
||||
$groupByItem = new AST\PathExpression(AST\PathExpression::TYPE_STATE_FIELD, $groupByItem, $idField);
|
||||
$groupByItem->type = AST\PathExpression::TYPE_STATE_FIELD;
|
||||
|
||||
$sqlParts[] = $this->walkGroupByItem($groupByItem);
|
||||
foreach ($this->_queryComponents[$groupByItem]['metadata']->fieldNames AS $field) {
|
||||
$item = new AST\PathExpression(AST\PathExpression::TYPE_STATE_FIELD, $groupByItem, $field);
|
||||
$item->type = AST\PathExpression::TYPE_STATE_FIELD;
|
||||
$sqlParts[] = $this->walkGroupByItem($item);
|
||||
}
|
||||
|
||||
foreach ($this->_queryComponents[$groupByItem]['metadata']->associationMappings AS $mapping) {
|
||||
if ($mapping['isOwningSide'] && $mapping['type'] & ClassMetadataInfo::TO_ONE) {
|
||||
$item = new AST\PathExpression(AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $groupByItem, $mapping['fieldName']);
|
||||
$item->type = AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION;
|
||||
$sqlParts[] = $this->walkGroupByItem($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ class QueryBuilder
|
||||
* @var string The complete DQL string for this query.
|
||||
*/
|
||||
private $_dql;
|
||||
|
||||
|
||||
/**
|
||||
* @var array The query parameters.
|
||||
*/
|
||||
@ -84,12 +84,12 @@ class QueryBuilder
|
||||
* @var array The parameter type map of this query.
|
||||
*/
|
||||
private $_paramTypes = array();
|
||||
|
||||
|
||||
/**
|
||||
* @var integer The index of the first result to retrieve.
|
||||
*/
|
||||
private $_firstResult = null;
|
||||
|
||||
|
||||
/**
|
||||
* @var integer The maximum number of results to retrieve.
|
||||
*/
|
||||
@ -97,7 +97,7 @@ class QueryBuilder
|
||||
|
||||
/**
|
||||
* Initializes a new <tt>QueryBuilder</tt> that uses the given <tt>EntityManager</tt>.
|
||||
*
|
||||
*
|
||||
* @param EntityManager $em The EntityManager to use.
|
||||
*/
|
||||
public function __construct(EntityManager $em)
|
||||
@ -217,7 +217,7 @@ class QueryBuilder
|
||||
->setFirstResult($this->_firstResult)
|
||||
->setMaxResults($this->_maxResults);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the FIRST root alias of the query. This is the first entity alias involved
|
||||
* in the construction of the query.
|
||||
@ -256,7 +256,7 @@ class QueryBuilder
|
||||
public function getRootAliases()
|
||||
{
|
||||
$aliases = array();
|
||||
|
||||
|
||||
foreach ($this->_dqlParts['from'] as &$fromClause) {
|
||||
if (is_string($fromClause)) {
|
||||
$spacePos = strrpos($fromClause, ' ');
|
||||
@ -265,10 +265,10 @@ class QueryBuilder
|
||||
|
||||
$fromClause = new Query\Expr\From($from, $alias);
|
||||
}
|
||||
|
||||
|
||||
$aliases[] = $fromClause->getAlias();
|
||||
}
|
||||
|
||||
|
||||
return $aliases;
|
||||
}
|
||||
|
||||
@ -289,7 +289,7 @@ class QueryBuilder
|
||||
public function getRootEntities()
|
||||
{
|
||||
$entities = array();
|
||||
|
||||
|
||||
foreach ($this->_dqlParts['from'] as &$fromClause) {
|
||||
if (is_string($fromClause)) {
|
||||
$spacePos = strrpos($fromClause, ' ');
|
||||
@ -298,10 +298,10 @@ class QueryBuilder
|
||||
|
||||
$fromClause = new Query\Expr\From($from, $alias);
|
||||
}
|
||||
|
||||
|
||||
$entities[] = $fromClause->getFrom();
|
||||
}
|
||||
|
||||
|
||||
return $entities;
|
||||
}
|
||||
|
||||
@ -313,7 +313,7 @@ class QueryBuilder
|
||||
* ->select('u')
|
||||
* ->from('User', 'u')
|
||||
* ->where('u.id = :user_id')
|
||||
* ->setParameter(':user_id', 1);
|
||||
* ->setParameter('user_id', 1);
|
||||
* </code>
|
||||
*
|
||||
* @param string|integer $key The parameter position or name.
|
||||
@ -324,17 +324,17 @@ class QueryBuilder
|
||||
public function setParameter($key, $value, $type = null)
|
||||
{
|
||||
$key = trim($key, ':');
|
||||
|
||||
|
||||
if ($type === null) {
|
||||
$type = Query\ParameterTypeInferer::inferType($value);
|
||||
}
|
||||
|
||||
|
||||
$this->_paramTypes[$key] = $type;
|
||||
$this->_params[$key] = $value;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets a collection of query parameters for the query being constructed.
|
||||
*
|
||||
@ -344,8 +344,8 @@ class QueryBuilder
|
||||
* ->from('User', 'u')
|
||||
* ->where('u.id = :user_id1 OR u.id = :user_id2')
|
||||
* ->setParameters(array(
|
||||
* ':user_id1' => 1,
|
||||
* ':user_id2' => 2
|
||||
* 'user_id1' => 1,
|
||||
* 'user_id2' => 2
|
||||
* ));
|
||||
* </code>
|
||||
*
|
||||
@ -376,7 +376,7 @@ class QueryBuilder
|
||||
|
||||
/**
|
||||
* Gets a (previously set) query parameter of the query being constructed.
|
||||
*
|
||||
*
|
||||
* @param mixed $key The key (index or name) of the bound parameter.
|
||||
* @return mixed The value of the bound parameter.
|
||||
*/
|
||||
@ -400,17 +400,17 @@ class QueryBuilder
|
||||
/**
|
||||
* Gets the position of the first result the query object was set to retrieve (the "offset").
|
||||
* Returns NULL if {@link setFirstResult} was not applied to this QueryBuilder.
|
||||
*
|
||||
*
|
||||
* @return integer The position of the first result.
|
||||
*/
|
||||
public function getFirstResult()
|
||||
{
|
||||
return $this->_firstResult;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the maximum number of results to retrieve (the "limit").
|
||||
*
|
||||
*
|
||||
* @param integer $maxResults The maximum number of results to retrieve.
|
||||
* @return QueryBuilder This QueryBuilder instance.
|
||||
*/
|
||||
@ -419,11 +419,11 @@ class QueryBuilder
|
||||
$this->_maxResults = $maxResults;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the maximum number of results the query object was set to retrieve (the "limit").
|
||||
* Returns NULL if {@link setMaxResults} was not applied to this query builder.
|
||||
*
|
||||
*
|
||||
* @return integer Maximum number of results.
|
||||
*/
|
||||
public function getMaxResults()
|
||||
@ -437,15 +437,15 @@ class QueryBuilder
|
||||
* The available parts are: 'select', 'from', 'join', 'set', 'where',
|
||||
* 'groupBy', 'having' and 'orderBy'.
|
||||
*
|
||||
* @param string $dqlPartName
|
||||
* @param string $dqlPart
|
||||
* @param string $append
|
||||
* @param string $dqlPartName
|
||||
* @param string $dqlPart
|
||||
* @param string $append
|
||||
* @return QueryBuilder This QueryBuilder instance.
|
||||
*/
|
||||
public function add($dqlPartName, $dqlPart, $append = false)
|
||||
{
|
||||
$isMultiple = is_array($this->_dqlParts[$dqlPartName]);
|
||||
|
||||
|
||||
// This is introduced for backwards compatibility reasons.
|
||||
// TODO: Remove for 3.0
|
||||
if ($dqlPartName == 'join') {
|
||||
@ -459,11 +459,11 @@ class QueryBuilder
|
||||
}
|
||||
$dqlPart = $newDqlPart;
|
||||
}
|
||||
|
||||
|
||||
if ($append && $isMultiple) {
|
||||
if (is_array($dqlPart)) {
|
||||
$key = key($dqlPart);
|
||||
|
||||
|
||||
$this->_dqlParts[$dqlPartName][$key][] = $dqlPart[$key];
|
||||
} else {
|
||||
$this->_dqlParts[$dqlPartName][] = $dqlPart;
|
||||
@ -494,11 +494,11 @@ class QueryBuilder
|
||||
public function select($select = null)
|
||||
{
|
||||
$this->_type = self::SELECT;
|
||||
|
||||
|
||||
if (empty($select)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
$selects = is_array($select) ? $select : func_get_args();
|
||||
|
||||
return $this->add('select', new Expr\Select($selects), false);
|
||||
@ -521,11 +521,11 @@ class QueryBuilder
|
||||
public function addSelect($select = null)
|
||||
{
|
||||
$this->_type = self::SELECT;
|
||||
|
||||
|
||||
if (empty($select)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
$selects = is_array($select) ? $select : func_get_args();
|
||||
|
||||
return $this->add('select', new Expr\Select($selects), true);
|
||||
@ -539,7 +539,7 @@ class QueryBuilder
|
||||
* $qb = $em->createQueryBuilder()
|
||||
* ->delete('User', 'u')
|
||||
* ->where('u.id = :user_id');
|
||||
* ->setParameter(':user_id', 1);
|
||||
* ->setParameter('user_id', 1);
|
||||
* </code>
|
||||
*
|
||||
* @param string $delete The class/type whose instances are subject to the deletion.
|
||||
@ -631,7 +631,7 @@ class QueryBuilder
|
||||
|
||||
/**
|
||||
* Creates and adds a join over an entity association to the query.
|
||||
*
|
||||
*
|
||||
* The entities in the joined association will be fetched as part of the query
|
||||
* result if the alias used for the joined association is placed in the select
|
||||
* expressions.
|
||||
@ -655,7 +655,7 @@ class QueryBuilder
|
||||
if (!in_array($rootAlias, $this->getRootAliases())) {
|
||||
$rootAlias = $this->getRootAlias();
|
||||
}
|
||||
|
||||
|
||||
return $this->add('join', array(
|
||||
$rootAlias => new Expr\Join(Expr\Join::INNER_JOIN, $join, $alias, $conditionType, $condition, $indexBy)
|
||||
), true);
|
||||
@ -688,7 +688,7 @@ class QueryBuilder
|
||||
if (!in_array($rootAlias, $this->getRootAliases())) {
|
||||
$rootAlias = $this->getRootAlias();
|
||||
}
|
||||
|
||||
|
||||
return $this->add('join', array(
|
||||
$rootAlias => new Expr\Join(Expr\Join::LEFT_JOIN, $join, $alias, $conditionType, $condition, $indexBy)
|
||||
), true);
|
||||
@ -743,7 +743,7 @@ class QueryBuilder
|
||||
if ( ! (func_num_args() == 1 && $predicates instanceof Expr\Composite)) {
|
||||
$predicates = new Expr\Andx(func_get_args());
|
||||
}
|
||||
|
||||
|
||||
return $this->add('where', $predicates);
|
||||
}
|
||||
|
||||
@ -767,14 +767,14 @@ class QueryBuilder
|
||||
{
|
||||
$where = $this->getDQLPart('where');
|
||||
$args = func_get_args();
|
||||
|
||||
|
||||
if ($where instanceof Expr\Andx) {
|
||||
$where->addMultiple($args);
|
||||
} else {
|
||||
} else {
|
||||
array_unshift($args, $where);
|
||||
$where = new Expr\Andx($args);
|
||||
}
|
||||
|
||||
|
||||
return $this->add('where', $where, true);
|
||||
}
|
||||
|
||||
@ -798,14 +798,14 @@ class QueryBuilder
|
||||
{
|
||||
$where = $this->getDqlPart('where');
|
||||
$args = func_get_args();
|
||||
|
||||
|
||||
if ($where instanceof Expr\Orx) {
|
||||
$where->addMultiple($args);
|
||||
} else {
|
||||
} else {
|
||||
array_unshift($args, $where);
|
||||
$where = new Expr\Orx($args);
|
||||
}
|
||||
|
||||
|
||||
return $this->add('where', $where, true);
|
||||
}
|
||||
|
||||
@ -860,7 +860,7 @@ class QueryBuilder
|
||||
if ( ! (func_num_args() == 1 && ($having instanceof Expr\Andx || $having instanceof Expr\Orx))) {
|
||||
$having = new Expr\Andx(func_get_args());
|
||||
}
|
||||
|
||||
|
||||
return $this->add('having', $having);
|
||||
}
|
||||
|
||||
@ -875,14 +875,14 @@ class QueryBuilder
|
||||
{
|
||||
$having = $this->getDqlPart('having');
|
||||
$args = func_get_args();
|
||||
|
||||
|
||||
if ($having instanceof Expr\Andx) {
|
||||
$having->addMultiple($args);
|
||||
} else {
|
||||
} else {
|
||||
array_unshift($args, $having);
|
||||
$having = new Expr\Andx($args);
|
||||
}
|
||||
|
||||
|
||||
return $this->add('having', $having);
|
||||
}
|
||||
|
||||
@ -897,10 +897,10 @@ class QueryBuilder
|
||||
{
|
||||
$having = $this->getDqlPart('having');
|
||||
$args = func_get_args();
|
||||
|
||||
|
||||
if ($having instanceof Expr\Orx) {
|
||||
$having->addMultiple($args);
|
||||
} else {
|
||||
} else {
|
||||
array_unshift($args, $having);
|
||||
$having = new Expr\Orx($args);
|
||||
}
|
||||
@ -977,15 +977,15 @@ class QueryBuilder
|
||||
private function _getDQLForSelect()
|
||||
{
|
||||
$dql = 'SELECT' . $this->_getReducedDQLQueryPart('select', array('pre' => ' ', 'separator' => ', '));
|
||||
|
||||
|
||||
$fromParts = $this->getDQLPart('from');
|
||||
$joinParts = $this->getDQLPart('join');
|
||||
$fromClauses = array();
|
||||
|
||||
|
||||
// Loop through all FROM clauses
|
||||
if ( ! empty($fromParts)) {
|
||||
$dql .= ' FROM ';
|
||||
|
||||
|
||||
foreach ($fromParts as $from) {
|
||||
$fromClause = (string) $from;
|
||||
|
||||
@ -998,24 +998,24 @@ class QueryBuilder
|
||||
$fromClauses[] = $fromClause;
|
||||
}
|
||||
}
|
||||
|
||||
$dql .= implode(', ', $fromClauses)
|
||||
|
||||
$dql .= implode(', ', $fromClauses)
|
||||
. $this->_getReducedDQLQueryPart('where', array('pre' => ' WHERE '))
|
||||
. $this->_getReducedDQLQueryPart('groupBy', array('pre' => ' GROUP BY ', 'separator' => ', '))
|
||||
. $this->_getReducedDQLQueryPart('having', array('pre' => ' HAVING '))
|
||||
. $this->_getReducedDQLQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', '));
|
||||
|
||||
|
||||
return $dql;
|
||||
}
|
||||
|
||||
private function _getReducedDQLQueryPart($queryPartName, $options = array())
|
||||
{
|
||||
$queryPart = $this->getDQLPart($queryPartName);
|
||||
|
||||
|
||||
if (empty($queryPart)) {
|
||||
return (isset($options['empty']) ? $options['empty'] : '');
|
||||
}
|
||||
|
||||
|
||||
return (isset($options['pre']) ? $options['pre'] : '')
|
||||
. (is_array($queryPart) ? implode($options['separator'], $queryPart) : $queryPart)
|
||||
. (isset($options['post']) ? $options['post'] : '');
|
||||
|
@ -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 . ' *';
|
||||
|
@ -279,6 +279,9 @@ class XmlExporter extends AbstractExporter
|
||||
if ($associationMapping['isCascadeDetach']) {
|
||||
$cascade[] = 'cascade-detach';
|
||||
}
|
||||
if (count($cascade) === 5) {
|
||||
$cascade = array('cascade-all');
|
||||
}
|
||||
if ($cascade) {
|
||||
$cascadeXml = $associationMappingXml->addChild('cascade');
|
||||
foreach ($cascade as $type) {
|
||||
|
@ -147,6 +147,9 @@ class YamlExporter extends AbstractExporter
|
||||
if ($associationMapping['isCascadeDetach']) {
|
||||
$cascade[] = 'detach';
|
||||
}
|
||||
if (count($cascade) === 5) {
|
||||
$cascade = array('all');
|
||||
}
|
||||
$associationMappingArray = array(
|
||||
'targetEntity' => $associationMapping['targetEntity'],
|
||||
'cascade' => $cascade,
|
||||
|
@ -173,14 +173,14 @@ class SchemaValidator
|
||||
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(), $assoc['relationToTargetKeyColumns'])) .
|
||||
"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(), $assoc['relationToSourceKeyColumns'])) .
|
||||
"however '" . implode(", ", array_diff($class->getIdentifierColumnNames(), array_values($assoc['relationToSourceKeyColumns']))) .
|
||||
"' are missing.";
|
||||
}
|
||||
|
||||
@ -200,9 +200,14 @@ class SchemaValidator
|
||||
}
|
||||
|
||||
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(), $assoc['joinColumns'])) .
|
||||
"however '" . implode(", ", array_diff($class->getIdentifierColumnNames(), $ids)) .
|
||||
"' are missing.";
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
2
lib/vendor/doctrine-common
vendored
2
lib/vendor/doctrine-common
vendored
@ -1 +1 @@
|
||||
Subproject commit b2fd909b4b5476df01744c9d34c7a23723a687b6
|
||||
Subproject commit 9c880cf9ae2c14102568520b5ee885b03bda93e4
|
34
tests/Doctrine/Tests/DbalTypes/NegativeToPositiveType.php
Normal file
34
tests/Doctrine/Tests/DbalTypes/NegativeToPositiveType.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\DbalTypes;
|
||||
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
|
||||
class NegativeToPositiveType extends Type
|
||||
{
|
||||
public function getName()
|
||||
{
|
||||
return 'negative_to_positive';
|
||||
}
|
||||
|
||||
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
|
||||
{
|
||||
return $platform->getIntegerTypeDeclarationSQL($fieldDeclaration);
|
||||
}
|
||||
|
||||
public function canRequireSQLConversion()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform)
|
||||
{
|
||||
return 'ABS(' . $sqlExpr . ')';
|
||||
}
|
||||
|
||||
public function convertToPHPValueSQL($sqlExpr, $platform)
|
||||
{
|
||||
return '-(' . $sqlExpr . ')';
|
||||
}
|
||||
}
|
29
tests/Doctrine/Tests/DbalTypes/UpperCaseStringType.php
Normal file
29
tests/Doctrine/Tests/DbalTypes/UpperCaseStringType.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\DbalTypes;
|
||||
|
||||
use Doctrine\DBAL\Types\StringType;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
|
||||
class UpperCaseStringType extends StringType
|
||||
{
|
||||
public function getName()
|
||||
{
|
||||
return 'upper_case_string';
|
||||
}
|
||||
|
||||
public function canRequireSQLConversion()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform)
|
||||
{
|
||||
return 'UPPER(' . $sqlExpr . ')';
|
||||
}
|
||||
|
||||
public function convertToPHPValueSQL($sqlExpr, $platform)
|
||||
{
|
||||
return 'LOWER(' . $sqlExpr . ')';
|
||||
}
|
||||
}
|
@ -8,7 +8,8 @@ class ConnectionMock extends \Doctrine\DBAL\Connection
|
||||
private $_platformMock;
|
||||
private $_lastInsertId = 0;
|
||||
private $_inserts = array();
|
||||
|
||||
private $_executeUpdates = array();
|
||||
|
||||
public function __construct(array $params, $driver, $config = null, $eventManager = null)
|
||||
{
|
||||
$this->_platformMock = new DatabasePlatformMock();
|
||||
@ -18,7 +19,7 @@ class ConnectionMock extends \Doctrine\DBAL\Connection
|
||||
// Override possible assignment of platform to database platform mock
|
||||
$this->_platform = $this->_platformMock;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
@ -26,15 +27,23 @@ 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
|
||||
*/
|
||||
public function executeUpdate($query, array $params = array(), array $types = array())
|
||||
{
|
||||
$this->_executeUpdates[] = array('query' => $query, 'params' => $params, 'types' => $types);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
@ -50,7 +59,7 @@ class ConnectionMock extends \Doctrine\DBAL\Connection
|
||||
{
|
||||
return $this->_fetchOneResult;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
@ -61,29 +70,34 @@ 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 getExecuteUpdates()
|
||||
{
|
||||
return $this->_executeUpdates;
|
||||
}
|
||||
|
||||
public function reset()
|
||||
{
|
||||
$this->_inserts = array();
|
||||
|
@ -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__);
|
||||
}
|
||||
}
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
21
tests/Doctrine/Tests/Models/CustomType/CustomTypeChild.php
Normal file
21
tests/Doctrine/Tests/Models/CustomType/CustomTypeChild.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\Models\CustomType;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="customtype_children")
|
||||
*/
|
||||
class CustomTypeChild
|
||||
{
|
||||
/**
|
||||
* @Id @Column(type="integer")
|
||||
* @GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @Column(type="upper_case_string")
|
||||
*/
|
||||
public $lowerCaseString = 'foo';
|
||||
}
|
68
tests/Doctrine/Tests/Models/CustomType/CustomTypeParent.php
Normal file
68
tests/Doctrine/Tests/Models/CustomType/CustomTypeParent.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\Models\CustomType;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="customtype_parents")
|
||||
*/
|
||||
class CustomTypeParent
|
||||
{
|
||||
/**
|
||||
* @Id @Column(type="integer")
|
||||
* @GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @Column(type="negative_to_positive", nullable=true)
|
||||
*/
|
||||
public $customInteger;
|
||||
|
||||
/**
|
||||
* @OneToOne(targetEntity="Doctrine\Tests\Models\CustomType\CustomTypeChild", cascade={"persist", "remove"})
|
||||
*/
|
||||
public $child;
|
||||
|
||||
/**
|
||||
* @ManyToMany(targetEntity="Doctrine\Tests\Models\CustomType\CustomTypeParent", mappedBy="myFriends")
|
||||
*/
|
||||
private $friendsWithMe;
|
||||
|
||||
/**
|
||||
* @ManyToMany(targetEntity="Doctrine\Tests\Models\CustomType\CustomTypeParent", inversedBy="friendsWithMe")
|
||||
* @JoinTable(
|
||||
* name="customtype_parent_friends",
|
||||
* joinColumns={@JoinColumn(name="customtypeparent_id", referencedColumnName="id")},
|
||||
* inverseJoinColumns={@JoinColumn(name="friend_customtypeparent_id", referencedColumnName="id")}
|
||||
* )
|
||||
*/
|
||||
private $myFriends;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->friendsWithMe = new \Doctrine\Common\Collections\ArrayCollection();
|
||||
$this->myFriends = new \Doctrine\Common\Collections\ArrayCollection();
|
||||
}
|
||||
|
||||
public function addMyFriend(CustomTypeParent $friend)
|
||||
{
|
||||
$this->getMyFriends()->add($friend);
|
||||
$friend->addFriendWithMe($this);
|
||||
}
|
||||
|
||||
public function getMyFriends()
|
||||
{
|
||||
return $this->myFriends;
|
||||
}
|
||||
|
||||
public function addFriendWithMe(CustomTypeParent $friend)
|
||||
{
|
||||
$this->getFriendsWithMe()->add($friend);
|
||||
}
|
||||
|
||||
public function getFriendsWithMe()
|
||||
{
|
||||
return $this->friendsWithMe;
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\Models\CustomType;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="customtype_uppercases")
|
||||
*/
|
||||
class CustomTypeUpperCase
|
||||
{
|
||||
/**
|
||||
* @Id @Column(type="integer")
|
||||
* @GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @Column(type="upper_case_string")
|
||||
*/
|
||||
public $lowerCaseString;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -491,5 +491,15 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_em->getConfiguration()->setDefaultRepositoryClassName("Doctrine\Tests\Models\DDC753\DDC753InvalidRepository");
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1500
|
||||
*/
|
||||
public function testInvalidOrientation()
|
||||
{
|
||||
$this->setExpectedException('Doctrine\ORM\ORMException', 'Invalid order by orientation specified for Doctrine\Tests\Models\CMS\CmsUser#username');
|
||||
|
||||
$repo = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$repo->findBy(array('status' => 'test'), array('username' => 'INVALID'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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());
|
||||
|
@ -13,46 +13,63 @@ require_once __DIR__ . '/../../TestInit.php';
|
||||
*/
|
||||
class OneToManyOrphanRemovalTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected $userId;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->useModelSet('cms');
|
||||
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testOrphanRemoval()
|
||||
{
|
||||
|
||||
$user = new CmsUser;
|
||||
$user->status = 'dev';
|
||||
$user->username = 'romanb';
|
||||
$user->name = 'Roman B.';
|
||||
|
||||
|
||||
$phone = new CmsPhonenumber;
|
||||
$phone->phonenumber = '123456';
|
||||
|
||||
|
||||
$user->addPhonenumber($phone);
|
||||
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
|
||||
$userId = $user->getId();
|
||||
|
||||
|
||||
$this->userId = $user->getId();
|
||||
$this->_em->clear();
|
||||
|
||||
$userProxy = $this->_em->getReference('Doctrine\Tests\Models\CMS\CmsUser', $userId);
|
||||
|
||||
}
|
||||
|
||||
public function testOrphanRemoval()
|
||||
{
|
||||
$userProxy = $this->_em->getReference('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
|
||||
$this->_em->remove($userProxy);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$query = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u');
|
||||
$result = $query->getResult();
|
||||
|
||||
|
||||
$this->assertEquals(0, count($result), 'CmsUser should be removed by EntityManager');
|
||||
|
||||
|
||||
$query = $this->_em->createQuery('SELECT p FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p');
|
||||
$result = $query->getResult();
|
||||
|
||||
|
||||
$this->assertEquals(0, count($result), 'CmsPhonenumber should be removed by orphanRemoval');
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1496
|
||||
*/
|
||||
public function testOrphanRemovalUnitializedCollection()
|
||||
{
|
||||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
|
||||
$user->phonenumbers->clear();
|
||||
$this->_em->flush();
|
||||
|
||||
$query = $this->_em->createQuery('SELECT p FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p');
|
||||
$result = $query->getResult();
|
||||
|
||||
$this->assertEquals(0, count($result), 'CmsPhonenumber should be removed by orphanRemoval');
|
||||
}
|
||||
}
|
105
tests/Doctrine/Tests/ORM/Functional/PersistentObjectTest.php
Normal file
105
tests/Doctrine/Tests/ORM/Functional/PersistentObjectTest.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\Common\Persistence\PersistentObject;
|
||||
|
||||
/**
|
||||
* Test that Doctrine ORM correctly works with the ObjectManagerAware and PersistentObject
|
||||
* classes from Common.
|
||||
*
|
||||
* @group DDC-1448
|
||||
*/
|
||||
class PersistentObjectTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
try {
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\PersistentEntity'),
|
||||
));
|
||||
} catch (\Exception $e) {
|
||||
|
||||
}
|
||||
PersistentObject::setObjectManager($this->_em);
|
||||
}
|
||||
|
||||
public function testPersist()
|
||||
{
|
||||
$entity = new PersistentEntity();
|
||||
$entity->setName("test");
|
||||
|
||||
$this->_em->persist($entity);
|
||||
$this->_em->flush();
|
||||
}
|
||||
|
||||
public function testFind()
|
||||
{
|
||||
$entity = new PersistentEntity();
|
||||
$entity->setName("test");
|
||||
|
||||
$this->_em->persist($entity);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$entity = $this->_em->find(__NAMESPACE__ . '\PersistentEntity', $entity->getId());
|
||||
|
||||
$this->assertEquals('test', $entity->getName());
|
||||
$entity->setName('foobar');
|
||||
|
||||
$this->_em->flush();
|
||||
}
|
||||
|
||||
public function testGetReference()
|
||||
{
|
||||
$entity = new PersistentEntity();
|
||||
$entity->setName("test");
|
||||
|
||||
$this->_em->persist($entity);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$entity = $this->_em->getReference(__NAMESPACE__ . '\PersistentEntity', $entity->getId());
|
||||
|
||||
$this->assertEquals('test', $entity->getName());
|
||||
}
|
||||
|
||||
public function testSetAssociation()
|
||||
{
|
||||
$entity = new PersistentEntity();
|
||||
$entity->setName("test");
|
||||
$entity->setParent($entity);
|
||||
|
||||
$this->_em->persist($entity);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$entity = $this->_em->getReference(__NAMESPACE__ . '\PersistentEntity', $entity->getId());
|
||||
$this->assertSame($entity, $entity->getParent());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class PersistentEntity extends PersistentObject
|
||||
{
|
||||
/**
|
||||
* @Id @Column(type="integer") @GeneratedValue
|
||||
* @var int
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @Column(type="string")
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @ManyToOne(targetEntity="PersistentEntity")
|
||||
* @var PersistentEntity
|
||||
*/
|
||||
protected $parent;
|
||||
}
|
@ -34,9 +34,9 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_em->clear();
|
||||
|
||||
$query = $this->_em->createQuery("select u, upper(u.name) from Doctrine\Tests\Models\CMS\CmsUser u where u.username = 'gblanco'");
|
||||
|
||||
|
||||
$result = $query->getResult();
|
||||
|
||||
|
||||
$this->assertEquals(1, count($result));
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0][0]);
|
||||
$this->assertEquals('Guilherme', $result[0][0]->name);
|
||||
@ -109,7 +109,7 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$q = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = ?0');
|
||||
$q->setParameter(0, 'jwage');
|
||||
$user = $q->getSingleResult();
|
||||
|
||||
|
||||
$this->assertNotNull($user);
|
||||
}
|
||||
|
||||
@ -216,7 +216,7 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$identityMap = $this->_em->getUnitOfWork()->getIdentityMap();
|
||||
$identityMapCount = count($identityMap['Doctrine\Tests\Models\CMS\CmsArticle']);
|
||||
$this->assertTrue($identityMapCount>$iteratedCount);
|
||||
|
||||
|
||||
$iteratedCount++;
|
||||
}
|
||||
|
||||
@ -235,7 +235,7 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$query = $this->_em->createQuery("SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.articles a");
|
||||
$articles = $query->iterate();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @expectedException Doctrine\ORM\NoResultException
|
||||
*/
|
||||
@ -366,7 +366,7 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $result[0]->user);
|
||||
$this->assertFalse($result[0]->user->__isInitialized__);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @group DDC-952
|
||||
*/
|
||||
@ -386,11 +386,11 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
}
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$articles = $this->_em->createQuery('select a from Doctrine\Tests\Models\CMS\CmsArticle a')
|
||||
->setFetchMode('Doctrine\Tests\Models\CMS\CmsArticle', 'user', ClassMetadata::FETCH_EAGER)
|
||||
->getResult();
|
||||
|
||||
|
||||
$this->assertEquals(10, count($articles));
|
||||
foreach ($articles AS $article) {
|
||||
$this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $article);
|
||||
@ -456,7 +456,43 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$query = $this->_em->createQuery("select u.username from Doctrine\Tests\Models\CMS\CmsUser u where u.username = 'gblanco'");
|
||||
$this->assertNull($query->getOneOrNullResult(Query::HYDRATE_SCALAR));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @group DBAL-171
|
||||
*/
|
||||
public function testParameterOrder()
|
||||
{
|
||||
$user1 = new CmsUser;
|
||||
$user1->name = 'Benjamin';
|
||||
$user1->username = 'beberlei';
|
||||
$user1->status = 'developer';
|
||||
$this->_em->persist($user1);
|
||||
|
||||
$user2 = new CmsUser;
|
||||
$user2->name = 'Roman';
|
||||
$user2->username = 'romanb';
|
||||
$user2->status = 'developer';
|
||||
$this->_em->persist($user2);
|
||||
|
||||
$user3 = new CmsUser;
|
||||
$user3->name = 'Jonathan';
|
||||
$user3->username = 'jwage';
|
||||
$user3->status = 'developer';
|
||||
$this->_em->persist($user3);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$query = $this->_em->createQuery("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.status = :a AND u.id IN (:b)");
|
||||
$query->setParameters(array(
|
||||
'b' => array($user1->id, $user2->id, $user3->id),
|
||||
'a' => 'developer',
|
||||
));
|
||||
$result = $query->getResult();
|
||||
|
||||
$this->assertEquals(3, count($result));
|
||||
}
|
||||
|
||||
public function testDqlWithAutoInferOfParameters()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
@ -464,30 +500,30 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$user->username = 'beberlei';
|
||||
$user->status = 'developer';
|
||||
$this->_em->persist($user);
|
||||
|
||||
|
||||
$user = new CmsUser;
|
||||
$user->name = 'Roman';
|
||||
$user->username = 'romanb';
|
||||
$user->status = 'developer';
|
||||
$this->_em->persist($user);
|
||||
|
||||
|
||||
$user = new CmsUser;
|
||||
$user->name = 'Jonathan';
|
||||
$user->username = 'jwage';
|
||||
$user->status = 'developer';
|
||||
$this->_em->persist($user);
|
||||
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$query = $this->_em->createQuery("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username IN (?0)");
|
||||
$query->setParameter(0, array('beberlei', 'jwage'));
|
||||
|
||||
|
||||
$users = $query->execute();
|
||||
|
||||
|
||||
$this->assertEquals(2, count($users));
|
||||
}
|
||||
|
||||
|
||||
public function testQueryBuilderWithStringWhereClauseContainingOrAndConditionalPrimary()
|
||||
{
|
||||
$qb = $this->_em->createQueryBuilder();
|
||||
@ -495,13 +531,13 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u')
|
||||
->innerJoin('u.articles', 'a')
|
||||
->where('(u.id = 0) OR (u.id IS NULL)');
|
||||
|
||||
|
||||
$query = $qb->getQuery();
|
||||
$users = $query->execute();
|
||||
|
||||
|
||||
$this->assertEquals(0, count($users));
|
||||
}
|
||||
|
||||
|
||||
public function testQueryWithArrayOfEntitiesAsParameter()
|
||||
{
|
||||
$userA = new CmsUser;
|
||||
@ -509,31 +545,31 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$userA->username = 'beberlei';
|
||||
$userA->status = 'developer';
|
||||
$this->_em->persist($userA);
|
||||
|
||||
|
||||
$userB = new CmsUser;
|
||||
$userB->name = 'Roman';
|
||||
$userB->username = 'romanb';
|
||||
$userB->status = 'developer';
|
||||
$this->_em->persist($userB);
|
||||
|
||||
|
||||
$userC = new CmsUser;
|
||||
$userC->name = 'Jonathan';
|
||||
$userC->username = 'jwage';
|
||||
$userC->status = 'developer';
|
||||
$this->_em->persist($userC);
|
||||
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$query = $this->_em->createQuery("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u IN (?0) OR u.username = ?1");
|
||||
$query->setParameter(0, array($userA, $userC));
|
||||
$query->setParameter(1, 'beberlei');
|
||||
|
||||
|
||||
$users = $query->execute();
|
||||
|
||||
|
||||
$this->assertEquals(2, count($users));
|
||||
}
|
||||
|
||||
|
||||
public function testQueryWithHiddenAsSelectExpression()
|
||||
{
|
||||
$userA = new CmsUser;
|
||||
@ -541,25 +577,25 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$userA->username = 'beberlei';
|
||||
$userA->status = 'developer';
|
||||
$this->_em->persist($userA);
|
||||
|
||||
|
||||
$userB = new CmsUser;
|
||||
$userB->name = 'Roman';
|
||||
$userB->username = 'romanb';
|
||||
$userB->status = 'developer';
|
||||
$this->_em->persist($userB);
|
||||
|
||||
|
||||
$userC = new CmsUser;
|
||||
$userC->name = 'Jonathan';
|
||||
$userC->username = 'jwage';
|
||||
$userC->status = 'developer';
|
||||
$this->_em->persist($userC);
|
||||
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$query = $this->_em->createQuery("SELECT u, (SELECT COUNT(u2.id) FROM Doctrine\Tests\Models\CMS\CmsUser u2) AS HIDDEN total FROM Doctrine\Tests\Models\CMS\CmsUser u");
|
||||
$users = $query->execute();
|
||||
|
||||
|
||||
$this->assertEquals(3, count($users));
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[0]);
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertTrue($clone->isCloned);
|
||||
$this->assertFalse($entity->isCloned);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @group DDC-733
|
||||
*/
|
||||
@ -108,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
|
||||
*/
|
||||
@ -124,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());
|
||||
}
|
||||
@ -180,7 +180,7 @@ class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$entity = $product->getShipping();
|
||||
$this->assertFalse($entity->__isInitialized__, "Pre-Condition: Object is unitialized proxy.");
|
||||
$this->assertEquals($id, $entity->getId());
|
||||
$this->assertTrue($id === $entity->getId(), "Check that the id's are the same value, and type.");
|
||||
$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.");
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -49,17 +49,21 @@ class DDC1335Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$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());
|
||||
$foo = $result['foo@foo.com']->phones->toArray();
|
||||
$bar = $result['bar@bar.com']->phones->toArray();
|
||||
$foobar = $result['foobar@foobar.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(1, $foo);
|
||||
$this->assertArrayHasKey(2, $foo);
|
||||
$this->assertArrayHasKey(3, $foo);
|
||||
|
||||
$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->assertArrayHasKey(4, $bar);
|
||||
$this->assertArrayHasKey(5, $bar);
|
||||
$this->assertArrayHasKey(6, $bar);
|
||||
|
||||
$this->assertArrayHasKey(7, $foobar);
|
||||
$this->assertArrayHasKey(8, $foobar);
|
||||
$this->assertArrayHasKey(9, $foobar);
|
||||
}
|
||||
|
||||
public function testTicket()
|
||||
|
136
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1400Test.php
Normal file
136
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1400Test.php
Normal file
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
require_once __DIR__ . '/../../../TestInit.php';
|
||||
|
||||
/**
|
||||
* @group DDC-1400
|
||||
*/
|
||||
class DDC1400Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
try {
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1400Article'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1400User'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1400UserState'),
|
||||
));
|
||||
} catch (\Exception $ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public function testFailingCase()
|
||||
{
|
||||
$article = new DDC1400Article;
|
||||
$user1 = new DDC1400User;
|
||||
$user2 = new DDC1400User;
|
||||
|
||||
$this->_em->persist($article);
|
||||
$this->_em->persist($user1);
|
||||
$this->_em->persist($user2);
|
||||
$this->_em->flush();
|
||||
|
||||
$userState1 = new DDC1400UserState;
|
||||
$userState1->article = $article;
|
||||
$userState1->articleId = $article->id;
|
||||
$userState1->user = $user1;
|
||||
$userState1->userId = $user1->id;
|
||||
|
||||
$userState2 = new DDC1400UserState;
|
||||
$userState2->article = $article;
|
||||
$userState2->articleId = $article->id;
|
||||
$userState2->user = $user2;
|
||||
$userState2->userId = $user2->id;
|
||||
|
||||
$this->_em->persist($userState1);
|
||||
$this->_em->persist($userState2);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$user1 = $this->_em->getReference(__NAMESPACE__.'\DDC1400User', $user1->id);
|
||||
|
||||
$q = $this->_em->createQuery("SELECT a, s FROM ".__NAMESPACE__."\DDC1400Article a JOIN a.userStates s WITH s.user = :activeUser");
|
||||
$q->setParameter('activeUser', $user1);
|
||||
$articles = $q->getResult();
|
||||
|
||||
var_dump(array_keys($articles[0]->userStates->toArray()));
|
||||
|
||||
$this->_em->flush();
|
||||
var_dump($this->_sqlLoggerStack);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1400Article
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @OneToMany(targetEntity="DDC1400UserState", mappedBy="article", indexBy="userId", fetch="EXTRA_LAZY")
|
||||
*/
|
||||
public $userStates;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1400User
|
||||
{
|
||||
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @OneToMany(targetEntity="DDC1400UserState", mappedBy="user", indexBy="articleId", fetch="EXTRA_LAZY")
|
||||
*/
|
||||
public $userStates;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1400UserState
|
||||
{
|
||||
|
||||
/**
|
||||
* @Id
|
||||
* @ManyToOne(targetEntity="DDC1400Article", inversedBy="userStates")
|
||||
*/
|
||||
public $article;
|
||||
|
||||
/**
|
||||
* @Id
|
||||
* @ManyToOne(targetEntity="DDC1400User", inversedBy="userStates")
|
||||
*/
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* @Column(name="user_id", type="integer")
|
||||
*/
|
||||
public $userId;
|
||||
|
||||
/**
|
||||
* @Column(name="article_id", type="integer")
|
||||
*/
|
||||
public $articleId;
|
||||
|
||||
}
|
129
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1404Test.php
Normal file
129
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1404Test.php
Normal 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;
|
||||
}
|
||||
|
||||
}
|
297
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1430Test.php
Normal file
297
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1430Test.php
Normal file
@ -0,0 +1,297 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
require_once __DIR__ . '/../../../TestInit.php';
|
||||
|
||||
/**
|
||||
* @group DDC-1430
|
||||
*/
|
||||
class DDC1430Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
try {
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1430Order'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1430OrderProduct'),
|
||||
));
|
||||
$this->loadFixtures();
|
||||
} catch (\Exception $exc) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function testOrderByFields()
|
||||
{
|
||||
$repository = $this->_em->getRepository(__NAMESPACE__ . '\DDC1430Order');
|
||||
$builder = $repository->createQueryBuilder('o');
|
||||
$query = $builder->select('o.id, o.date, COUNT(p.id) AS p_count')
|
||||
->leftJoin('o.products', 'p')
|
||||
->groupBy('o.id, o.date')
|
||||
->orderBy('o.id')
|
||||
->getQuery();
|
||||
|
||||
$this->assertEquals('SELECT o.id, o.date, COUNT(p.id) AS p_count FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1430Order o LEFT JOIN o.products p GROUP BY o.id, o.date ORDER BY o.id ASC', $query->getDQL());
|
||||
$this->assertEquals('SELECT d0_.order_id AS order_id0, d0_.created_at AS created_at1, COUNT(d1_.id) AS sclr2 FROM DDC1430Order d0_ LEFT JOIN DDC1430OrderProduct d1_ ON d0_.order_id = d1_.order_id GROUP BY d0_.order_id, d0_.created_at ORDER BY d0_.order_id ASC', $query->getSQL());
|
||||
|
||||
|
||||
$result = $query->getResult();
|
||||
|
||||
$this->assertEquals(2, sizeof($result));
|
||||
|
||||
$this->assertArrayHasKey('id', $result[0]);
|
||||
$this->assertArrayHasKey('id', $result[1]);
|
||||
|
||||
$this->assertArrayHasKey('p_count', $result[0]);
|
||||
$this->assertArrayHasKey('p_count', $result[1]);
|
||||
|
||||
$this->assertEquals(1, $result[0]['id']);
|
||||
$this->assertEquals(2, $result[1]['id']);
|
||||
|
||||
$this->assertEquals(2, $result[0]['p_count']);
|
||||
$this->assertEquals(3, $result[1]['p_count']);
|
||||
}
|
||||
|
||||
public function testOrderByAllObjectFields()
|
||||
{
|
||||
$repository = $this->_em->getRepository(__NAMESPACE__ . '\DDC1430Order');
|
||||
$builder = $repository->createQueryBuilder('o');
|
||||
$query = $builder->select('o, COUNT(p.id) AS p_count')
|
||||
->leftJoin('o.products', 'p')
|
||||
->groupBy('o.id, o.date, o.status')
|
||||
->orderBy('o.id')
|
||||
->getQuery();
|
||||
|
||||
|
||||
$this->assertEquals('SELECT o, COUNT(p.id) AS p_count FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1430Order o LEFT JOIN o.products p GROUP BY o.id, o.date, o.status ORDER BY o.id ASC', $query->getDQL());
|
||||
$this->assertEquals('SELECT d0_.order_id AS order_id0, d0_.created_at AS created_at1, d0_.order_status AS order_status2, COUNT(d1_.id) AS sclr3 FROM DDC1430Order d0_ LEFT JOIN DDC1430OrderProduct d1_ ON d0_.order_id = d1_.order_id GROUP BY d0_.order_id, d0_.created_at, d0_.order_status ORDER BY d0_.order_id ASC', $query->getSQL());
|
||||
|
||||
$result = $query->getResult();
|
||||
|
||||
|
||||
$this->assertEquals(2, sizeof($result));
|
||||
|
||||
$this->assertTrue($result[0][0] instanceof DDC1430Order);
|
||||
$this->assertTrue($result[1][0] instanceof DDC1430Order);
|
||||
|
||||
$this->assertEquals($result[0][0]->getId(), 1);
|
||||
$this->assertEquals($result[1][0]->getId(), 2);
|
||||
|
||||
$this->assertEquals($result[0]['p_count'], 2);
|
||||
$this->assertEquals($result[1]['p_count'], 3);
|
||||
}
|
||||
|
||||
public function testTicket()
|
||||
{
|
||||
$repository = $this->_em->getRepository(__NAMESPACE__ . '\DDC1430Order');
|
||||
$builder = $repository->createQueryBuilder('o');
|
||||
$query = $builder->select('o, COUNT(p.id) AS p_count')
|
||||
->leftJoin('o.products', 'p')
|
||||
->groupBy('o')
|
||||
->orderBy('o.id')
|
||||
->getQuery();
|
||||
|
||||
|
||||
$this->assertEquals('SELECT o, COUNT(p.id) AS p_count FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1430Order o LEFT JOIN o.products p GROUP BY o ORDER BY o.id ASC', $query->getDQL());
|
||||
$this->assertEquals('SELECT d0_.order_id AS order_id0, d0_.created_at AS created_at1, d0_.order_status AS order_status2, COUNT(d1_.id) AS sclr3 FROM DDC1430Order d0_ LEFT JOIN DDC1430OrderProduct d1_ ON d0_.order_id = d1_.order_id GROUP BY d0_.order_id, d0_.created_at, d0_.order_status ORDER BY d0_.order_id ASC', $query->getSQL());
|
||||
|
||||
|
||||
$result = $query->getResult();
|
||||
|
||||
$this->assertEquals(2, sizeof($result));
|
||||
|
||||
$this->assertTrue($result[0][0] instanceof DDC1430Order);
|
||||
$this->assertTrue($result[1][0] instanceof DDC1430Order);
|
||||
|
||||
$this->assertEquals($result[0][0]->getId(), 1);
|
||||
$this->assertEquals($result[1][0]->getId(), 2);
|
||||
|
||||
$this->assertEquals($result[0]['p_count'], 2);
|
||||
$this->assertEquals($result[1]['p_count'], 3);
|
||||
}
|
||||
|
||||
public function loadFixtures()
|
||||
{
|
||||
$o1 = new DDC1430Order('NEW');
|
||||
$o2 = new DDC1430Order('OK');
|
||||
|
||||
$o1->addProduct(new DDC1430OrderProduct(1.1));
|
||||
$o1->addProduct(new DDC1430OrderProduct(1.2));
|
||||
|
||||
$o2->addProduct(new DDC1430OrderProduct(2.1));
|
||||
$o2->addProduct(new DDC1430OrderProduct(2.2));
|
||||
$o2->addProduct(new DDC1430OrderProduct(2.3));
|
||||
|
||||
$this->_em->persist($o1);
|
||||
$this->_em->persist($o2);
|
||||
|
||||
$this->_em->flush();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1430Order
|
||||
{
|
||||
|
||||
/**
|
||||
* @Id
|
||||
* @Column(name="order_id", type="integer")
|
||||
* @GeneratedValue()
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @Column(name="created_at", type="datetime")
|
||||
*/
|
||||
private $date;
|
||||
|
||||
/**
|
||||
* @Column(name="order_status", type="string")
|
||||
*/
|
||||
private $status;
|
||||
|
||||
/**
|
||||
* @OneToMany(targetEntity="DDC1430OrderProduct", mappedBy="order", cascade={"persist", "remove"})
|
||||
*
|
||||
* @var \Doctrine\Common\Collections\ArrayCollection $products
|
||||
*/
|
||||
private $products;
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function __construct($status)
|
||||
{
|
||||
$this->status = $status;
|
||||
$this->date = new \DateTime();
|
||||
$this->products = new \Doctrine\Common\Collections\ArrayCollection();
|
||||
}
|
||||
/**
|
||||
* @return \DateTime
|
||||
*/
|
||||
public function getDate()
|
||||
{
|
||||
return $this->date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getStatus()
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $status
|
||||
*/
|
||||
public function setStatus($status)
|
||||
{
|
||||
$this->status = $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Doctrine\Common\Collections\ArrayCollection
|
||||
*/
|
||||
public function getProducts()
|
||||
{
|
||||
return $this->products;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DDC1430OrderProduct $product
|
||||
*/
|
||||
public function addProduct(DDC1430OrderProduct $product)
|
||||
{
|
||||
$product->setOrder($this);
|
||||
$this->products->add($product);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1430OrderProduct
|
||||
{
|
||||
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue()
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @var DDC1430Order $order
|
||||
*
|
||||
* @ManyToOne(targetEntity="DDC1430Order", inversedBy="products")
|
||||
* @JoinColumn(name="order_id", referencedColumnName="order_id", nullable = false)
|
||||
*/
|
||||
private $order;
|
||||
|
||||
/**
|
||||
* @column(type="float")
|
||||
*/
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* @param float $value
|
||||
*/
|
||||
public function __construct($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DDC1430Order
|
||||
*/
|
||||
public function getOrder()
|
||||
{
|
||||
return $this->order;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DDC1430Order $order
|
||||
*/
|
||||
public function setOrder(DDC1430Order $order)
|
||||
{
|
||||
$this->order = $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $value
|
||||
*/
|
||||
public function setValue($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
}
|
89
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1436Test.php
Normal file
89
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1436Test.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
/**
|
||||
* @group DDC-1436
|
||||
*/
|
||||
class DDC1436Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
try {
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1436Page'),
|
||||
));
|
||||
} catch (\Exception $ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public function testIdentityMap()
|
||||
{
|
||||
// fixtures
|
||||
$parent = null;
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$page = new DDC1436Page();
|
||||
$page->setParent($parent);
|
||||
$this->_em->persist($page);
|
||||
$parent = $page;
|
||||
}
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$id = $parent->getId();
|
||||
|
||||
// step 1
|
||||
$page = $this->_em
|
||||
->createQuery('SELECT p, parent FROM ' . __NAMESPACE__ . '\DDC1436Page p LEFT JOIN p.parent parent WHERE p.id = :id')
|
||||
->setParameter('id', $id)
|
||||
->getOneOrNullResult();
|
||||
|
||||
$this->assertInstanceOf(__NAMESPACE__ . '\DDC1436Page', $page);
|
||||
|
||||
// step 2
|
||||
$page = $this->_em->find(__NAMESPACE__ . '\DDC1436Page', $id);
|
||||
$this->assertInstanceOf(__NAMESPACE__ . '\DDC1436Page', $page);
|
||||
$this->assertInstanceOf(__NAMESPACE__ . '\DDC1436Page', $page->getParent());
|
||||
$this->assertInstanceOf(__NAMESPACE__ . '\DDC1436Page', $page->getParent()->getParent());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1436Page
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @GeneratedValue
|
||||
* @Column(type="integer", name="id")
|
||||
*/
|
||||
protected $id;
|
||||
/**
|
||||
* @ManyToOne(targetEntity="DDC1436Page")
|
||||
* @JoinColumn(name="pid", referencedColumnName="id")
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DDC1436Page
|
||||
*/
|
||||
public function getParent()
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
public function setParent($parent)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
}
|
||||
}
|
||||
|
127
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1452Test.php
Normal file
127
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1452Test.php
Normal file
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
require_once __DIR__ . '/../../../TestInit.php';
|
||||
|
||||
/**
|
||||
* @group DDC-1452
|
||||
*/
|
||||
class DDC1452Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
$this->useModelSet('cms');
|
||||
parent::setUp();
|
||||
|
||||
try {
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1452EntityA'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1452EntityB'),
|
||||
));
|
||||
} catch (\Exception $ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public function testIssue()
|
||||
{
|
||||
$a1 = new DDC1452EntityA();
|
||||
$a1->title = "foo";
|
||||
|
||||
$a2 = new DDC1452EntityA();
|
||||
$a2->title = "bar";
|
||||
|
||||
$b = new DDC1452EntityB();
|
||||
$b->entityAFrom = $a1;
|
||||
$b->entityATo = $a2;
|
||||
|
||||
$this->_em->persist($a1);
|
||||
$this->_em->persist($a2);
|
||||
$this->_em->persist($b);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$dql = "SELECT a, b, ba FROM " . __NAMESPACE__ . "\DDC1452EntityA AS a LEFT JOIN a.entitiesB AS b LEFT JOIN b.entityATo AS ba";
|
||||
$results = $this->_em->createQuery($dql)->setMaxResults(1)->getResult();
|
||||
|
||||
$this->assertSame($results[0], $results[0]->entitiesB[0]->entityAFrom);
|
||||
$this->assertFalse( $results[0]->entitiesB[0]->entityATo instanceof \Doctrine\ORM\Proxy\Proxy );
|
||||
$this->assertInstanceOf('Doctrine\Common\Collections\Collection', $results[0]->entitiesB[0]->entityATo->getEntitiesB());
|
||||
}
|
||||
|
||||
public function testFetchJoinOneToOneFromInverse()
|
||||
{
|
||||
$address = new \Doctrine\Tests\Models\CMS\CmsAddress();
|
||||
$address->city = "Bonn";
|
||||
$address->country = "Germany";
|
||||
$address->street = "Somestreet";
|
||||
$address->zip = 12345;
|
||||
|
||||
$user = new \Doctrine\Tests\Models\CMS\CmsUser();
|
||||
$user->name = "beberlei";
|
||||
$user->username = "beberlei";
|
||||
$user->status = "active";
|
||||
$user->address = $address;
|
||||
$address->user = $user;
|
||||
|
||||
$this->_em->persist($address);
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$dql = "SELECT a, u FROM Doctrine\Tests\Models\CMS\CmsAddress a INNER JOIN a.user u";
|
||||
$data = $this->_em->createQuery($dql)->getResult();
|
||||
$this->_em->clear();
|
||||
|
||||
$this->assertFalse($data[0]->user instanceof \Doctrine\ORM\Proxy\Proxy);
|
||||
|
||||
$dql = "SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.address a";
|
||||
$data = $this->_em->createQuery($dql)->getResult();
|
||||
|
||||
$this->assertFalse($data[0]->address instanceof \Doctrine\ORM\Proxy\Proxy);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1452EntityA
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
/** @Column */
|
||||
public $title;
|
||||
/** @ManyToMany(targetEntity="DDC1452EntityB", mappedBy="entityAFrom") */
|
||||
public $entitiesB;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->entitiesB = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getEntitiesB()
|
||||
{
|
||||
return $this->entitiesB;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1452EntityB
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @ManyToOne(targetEntity="DDC1452EntityA", inversedBy="entitiesB")
|
||||
*/
|
||||
public $entityAFrom;
|
||||
/**
|
||||
* @ManyToOne(targetEntity="DDC1452EntityA")
|
||||
*/
|
||||
public $entityATo;
|
||||
}
|
131
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1458Test.php
Normal file
131
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1458Test.php
Normal 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;
|
||||
}
|
||||
}
|
86
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1461Test.php
Normal file
86
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1461Test.php
Normal 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;
|
||||
}
|
105
tests/Doctrine/Tests/ORM/Functional/TypeValueSqlTest.php
Normal file
105
tests/Doctrine/Tests/ORM/Functional/TypeValueSqlTest.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\Tests\Models\CustomType\CustomTypeChild;
|
||||
use Doctrine\Tests\Models\CustomType\CustomTypeParent;
|
||||
use Doctrine\Tests\Models\CustomType\CustomTypeUpperCase;
|
||||
use Doctrine\DBAL\Types\Type as DBALType;
|
||||
|
||||
require_once __DIR__ . '/../../TestInit.php';
|
||||
|
||||
class TypeValueSqlTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
if (DBALType::hasType('upper_case_string')) {
|
||||
DBALType::overrideType('upper_case_string', '\Doctrine\Tests\DbalTypes\UpperCaseStringType');
|
||||
} else {
|
||||
DBALType::addType('upper_case_string', '\Doctrine\Tests\DbalTypes\UpperCaseStringType');
|
||||
}
|
||||
|
||||
if (DBALType::hasType('negative_to_positive')) {
|
||||
DBALType::overrideType('negative_to_positive', '\Doctrine\Tests\DbalTypes\NegativeToPositiveType');
|
||||
} else {
|
||||
DBALType::addType('negative_to_positive', '\Doctrine\Tests\DbalTypes\NegativeToPositiveType');
|
||||
}
|
||||
|
||||
$this->useModelSet('customtype');
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testUpperCaseStringType()
|
||||
{
|
||||
$entity = new CustomTypeUpperCase();
|
||||
$entity->lowerCaseString = 'foo';
|
||||
|
||||
$this->_em->persist($entity);
|
||||
$this->_em->flush();
|
||||
|
||||
$id = $entity->id;
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$entity = $this->_em->find('\Doctrine\Tests\Models\CustomType\CustomTypeUpperCase', $id);
|
||||
|
||||
$this->assertEquals('foo', $entity->lowerCaseString, 'Entity holds lowercase string');
|
||||
$this->assertEquals('FOO', $this->_em->getConnection()->fetchColumn("select lowerCaseString from customtype_uppercases where id=".$entity->id.""), 'Database holds uppercase string');
|
||||
}
|
||||
|
||||
public function testTypeValueSqlWithAssociations()
|
||||
{
|
||||
$parent = new CustomTypeParent();
|
||||
$parent->customInteger = -1;
|
||||
$parent->child = new CustomTypeChild();
|
||||
|
||||
$friend1 = new CustomTypeParent();
|
||||
$friend2 = new CustomTypeParent();
|
||||
|
||||
$parent->addMyFriend($friend1);
|
||||
$parent->addMyFriend($friend2);
|
||||
|
||||
$this->_em->persist($parent);
|
||||
$this->_em->persist($friend1);
|
||||
$this->_em->persist($friend2);
|
||||
$this->_em->flush();
|
||||
|
||||
$parentId = $parent->id;
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$entity = $this->_em->find('Doctrine\Tests\Models\CustomType\CustomTypeParent', $parentId);
|
||||
|
||||
$this->assertTrue($entity->customInteger < 0, 'Fetched customInteger negative');
|
||||
$this->assertEquals(1, $this->_em->getConnection()->fetchColumn("select customInteger from customtype_parents where id=".$entity->id.""), 'Database has stored customInteger positive');
|
||||
|
||||
$this->assertNotNull($parent->child, 'Child attached');
|
||||
$this->assertCount(2, $entity->getMyFriends(), '2 friends attached');
|
||||
}
|
||||
|
||||
public function testSelectDQL()
|
||||
{
|
||||
$parent = new CustomTypeParent();
|
||||
$parent->customInteger = -1;
|
||||
$parent->child = new CustomTypeChild();
|
||||
|
||||
$this->_em->persist($parent);
|
||||
$this->_em->flush();
|
||||
|
||||
$parentId = $parent->id;
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$query = $this->_em->createQuery("SELECT p, p.customInteger, c from Doctrine\Tests\Models\CustomType\CustomTypeParent p JOIN p.child c where p.id = " . $parentId);
|
||||
|
||||
$result = $query->getResult();
|
||||
|
||||
$this->assertEquals(1, count($result));
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\CustomType\CustomTypeParent', $result[0][0]);
|
||||
$this->assertEquals(-1, $result[0][0]->customInteger);
|
||||
|
||||
$this->assertEquals(-1, $result[0]['customInteger']);
|
||||
|
||||
$this->assertEquals('foo', $result[0][0]->child->lowerCaseString);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -64,7 +64,7 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
$this->assertArrayHasKey('uniqueConstraints', $class->table,
|
||||
'ClassMetadata should have uniqueConstraints key in table property when Unique Constraints are set.');
|
||||
|
||||
|
||||
$this->assertEquals(array(
|
||||
"search_idx" => array("columns" => array("name", "user_email"))
|
||||
), $class->table['uniqueConstraints']);
|
||||
@ -138,6 +138,7 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
|
||||
public function testIdentifier($class)
|
||||
{
|
||||
$this->assertEquals(array('id'), $class->identifier);
|
||||
$this->assertEquals('integer', $class->fieldMappings['id']['type']);
|
||||
$this->assertEquals(ClassMetadata::GENERATOR_TYPE_AUTO, $class->generatorType, "ID-Generator is not ClassMetadata::GENERATOR_TYPE_AUTO");
|
||||
|
||||
return $class;
|
||||
@ -291,7 +292,7 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
|
||||
$class->discriminatorColumn
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @group DDC-869
|
||||
*/
|
||||
@ -300,33 +301,78 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
|
||||
$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\DDC869\DDC869CreditCardPayment');
|
||||
|
||||
|
||||
$this->assertTrue(isset($class->fieldMappings['id']));
|
||||
$this->assertTrue(isset($class->fieldMappings['value']));
|
||||
$this->assertTrue(isset($class->fieldMappings['creditCardNumber']));
|
||||
$this->assertEquals($class->customRepositoryClassName, "Doctrine\Tests\Models\DDC869\DDC869PaymentRepository");
|
||||
$this->assertInstanceOf("Doctrine\Tests\Models\DDC869\DDC869PaymentRepository",
|
||||
$this->assertInstanceOf("Doctrine\Tests\Models\DDC869\DDC869PaymentRepository",
|
||||
$em->getRepository("Doctrine\Tests\Models\DDC869\DDC869CreditCardPayment"));
|
||||
$this->assertTrue($em->getRepository("Doctrine\Tests\Models\DDC869\DDC869ChequePayment")->isTrue());
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$class = $factory->getMetadataFor('Doctrine\Tests\Models\DDC869\DDC869ChequePayment');
|
||||
|
||||
|
||||
$this->assertTrue(isset($class->fieldMappings['id']));
|
||||
$this->assertTrue(isset($class->fieldMappings['value']));
|
||||
$this->assertTrue(isset($class->fieldMappings['serialNumber']));
|
||||
$this->assertEquals($class->customRepositoryClassName, "Doctrine\Tests\Models\DDC869\DDC869PaymentRepository");
|
||||
$this->assertInstanceOf("Doctrine\Tests\Models\DDC869\DDC869PaymentRepository",
|
||||
$this->assertInstanceOf("Doctrine\Tests\Models\DDC869\DDC869PaymentRepository",
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -435,15 +481,15 @@ class User
|
||||
$metadata->mapOneToOne(array(
|
||||
'fieldName' => 'address',
|
||||
'targetEntity' => 'Doctrine\\Tests\\ORM\\Mapping\\Address',
|
||||
'cascade' =>
|
||||
'cascade' =>
|
||||
array(
|
||||
0 => 'remove',
|
||||
),
|
||||
'mappedBy' => NULL,
|
||||
'inversedBy' => 'user',
|
||||
'joinColumns' =>
|
||||
'joinColumns' =>
|
||||
array(
|
||||
0 =>
|
||||
0 =>
|
||||
array(
|
||||
'name' => 'address_id',
|
||||
'referencedColumnName' => 'id',
|
||||
@ -455,13 +501,13 @@ class User
|
||||
$metadata->mapOneToMany(array(
|
||||
'fieldName' => 'phonenumbers',
|
||||
'targetEntity' => 'Doctrine\\Tests\\ORM\\Mapping\\Phonenumber',
|
||||
'cascade' =>
|
||||
'cascade' =>
|
||||
array(
|
||||
1 => 'persist',
|
||||
),
|
||||
'mappedBy' => 'user',
|
||||
'orphanRemoval' => true,
|
||||
'orderBy' =>
|
||||
'orderBy' =>
|
||||
array(
|
||||
'number' => 'ASC',
|
||||
),
|
||||
@ -469,7 +515,7 @@ class User
|
||||
$metadata->mapManyToMany(array(
|
||||
'fieldName' => 'groups',
|
||||
'targetEntity' => 'Doctrine\\Tests\\ORM\\Mapping\\Group',
|
||||
'cascade' =>
|
||||
'cascade' =>
|
||||
array(
|
||||
0 => 'remove',
|
||||
1 => 'persist',
|
||||
@ -478,12 +524,12 @@ class User
|
||||
4 => 'detach',
|
||||
),
|
||||
'mappedBy' => NULL,
|
||||
'joinTable' =>
|
||||
'joinTable' =>
|
||||
array(
|
||||
'name' => 'cms_users_groups',
|
||||
'joinColumns' =>
|
||||
'joinColumns' =>
|
||||
array(
|
||||
0 =>
|
||||
0 =>
|
||||
array(
|
||||
'name' => 'user_id',
|
||||
'referencedColumnName' => 'id',
|
||||
@ -491,9 +537,9 @@ class User
|
||||
'nullable' => false,
|
||||
),
|
||||
),
|
||||
'inverseJoinColumns' =>
|
||||
'inverseJoinColumns' =>
|
||||
array(
|
||||
0 =>
|
||||
0 =>
|
||||
array(
|
||||
'name' => 'group_id',
|
||||
'referencedColumnName' => 'id',
|
||||
@ -531,7 +577,7 @@ abstract class Animal
|
||||
|
||||
public static function loadMetadata(ClassMetadataInfo $metadata)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -540,7 +586,7 @@ class Cat extends Animal
|
||||
{
|
||||
public static function loadMetadata(ClassMetadataInfo $metadata)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -549,6 +595,6 @@ class Dog extends Animal
|
||||
{
|
||||
public static function loadMetadata(ClassMetadataInfo $metadata)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -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()
|
||||
|
@ -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);
|
@ -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>
|
@ -0,0 +1,8 @@
|
||||
Doctrine\Tests\Models\DDC1476\DDC1476EntityWithDefaultFieldType:
|
||||
type: entity
|
||||
id:
|
||||
id:
|
||||
generator:
|
||||
strategy: NONE
|
||||
fields:
|
||||
name:
|
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\DBAL\Types\Type as DBALType;
|
||||
use Doctrine\ORM\Persisters\BasicEntityPersister;
|
||||
use Doctrine\Tests\Models\CustomType\CustomTypeParent;
|
||||
use Doctrine\Tests\Models\CustomType\CustomTypeChild;
|
||||
use Doctrine\Tests\Models\CustomType\CustomTypeFriend;
|
||||
|
||||
require_once __DIR__ . '/../../TestInit.php';
|
||||
|
||||
class BasicEntityPersisterTypeValueSqlTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
protected $_persister;
|
||||
protected $_em;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (DBALType::hasType('negative_to_positive')) {
|
||||
DBALType::overrideType('negative_to_positive', '\Doctrine\Tests\DbalTypes\NegativeToPositiveType');
|
||||
} else {
|
||||
DBALType::addType('negative_to_positive', '\Doctrine\Tests\DbalTypes\NegativeToPositiveType');
|
||||
}
|
||||
|
||||
if (DBALType::hasType('upper_case_string')) {
|
||||
DBALType::overrideType('upper_case_string', '\Doctrine\Tests\DbalTypes\UpperCaseStringType');
|
||||
} else {
|
||||
DBALType::addType('upper_case_string', '\Doctrine\Tests\DbalTypes\UpperCaseStringType');
|
||||
}
|
||||
|
||||
$this->_em = $this->_getTestEntityManager();
|
||||
|
||||
$this->_persister = new BasicEntityPersister($this->_em, $this->_em->getClassMetadata("Doctrine\Tests\Models\CustomType\CustomTypeParent"));
|
||||
}
|
||||
|
||||
public function testGetInsertSQLUsesTypeValuesSQL()
|
||||
{
|
||||
$method = new \ReflectionMethod($this->_persister, '_getInsertSQL');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$sql = $method->invoke($this->_persister);
|
||||
|
||||
$this->assertEquals('INSERT INTO customtype_parents (customInteger, child_id) VALUES (ABS(?), ?)', $sql);
|
||||
}
|
||||
|
||||
public function testUpdateUsesTypeValuesSQL()
|
||||
{
|
||||
$child = new CustomTypeChild();
|
||||
|
||||
$parent = new CustomTypeParent();
|
||||
$parent->customInteger = 1;
|
||||
$parent->child = $child;
|
||||
|
||||
$this->_em->getUnitOfWork()->registerManaged($parent, array('id' => 1), array('customInteger' => 0, 'child' => null));
|
||||
$this->_em->getUnitOfWork()->registerManaged($child, array('id' => 1), array());
|
||||
|
||||
$this->_em->getUnitOfWork()->propertyChanged($parent, 'customInteger', 0, 1);
|
||||
$this->_em->getUnitOfWork()->propertyChanged($parent, 'child', null, $child);
|
||||
|
||||
$this->_persister->update($parent);
|
||||
|
||||
$executeUpdates = $this->_em->getConnection()->getExecuteUpdates();
|
||||
|
||||
$this->assertEquals('UPDATE customtype_parents SET customInteger = ABS(?), child_id = ? WHERE id = ?', $executeUpdates[0]['query']);
|
||||
}
|
||||
|
||||
public function testGetSelectConditionSQLUsesTypeValuesSQL()
|
||||
{
|
||||
$method = new \ReflectionMethod($this->_persister, '_getSelectConditionSQL');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$sql = $method->invoke($this->_persister, array('customInteger' => 1, 'child' => 1));
|
||||
|
||||
$this->assertEquals('t0.customInteger = ABS(?) AND t0.child_id = ?', $sql);
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Doctrine\Tests\ORM\Query;
|
||||
|
||||
use Doctrine\DBAL\Types\Type as DBALType;
|
||||
use Doctrine\ORM\Query;
|
||||
|
||||
require_once __DIR__ . '/../../TestInit.php';
|
||||
@ -945,7 +946,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT g, count(u.id) FROM Doctrine\Tests\Models\CMS\CmsGroup g JOIN g.users u GROUP BY g',
|
||||
'SELECT c0_.id AS id0, c0_.name AS name1, count(c1_.id) AS sclr2 FROM cms_groups c0_ INNER JOIN cms_users_groups c2_ ON c0_.id = c2_.group_id INNER JOIN cms_users c1_ ON c1_.id = c2_.user_id GROUP BY c0_.id'
|
||||
'SELECT c0_.id AS id0, c0_.name AS name1, count(c1_.id) AS sclr2 FROM cms_groups c0_ INNER JOIN cms_users_groups c2_ ON c0_.id = c2_.group_id INNER JOIN cms_users c1_ ON c1_.id = c2_.user_id GROUP BY c0_.id, c0_.name'
|
||||
);
|
||||
}
|
||||
|
||||
@ -1301,6 +1302,94 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
"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)"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1474
|
||||
*/
|
||||
public function testSelectWithArithmeticExpressionBeforeField()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT - e.value AS value, e.id FROM ' . __NAMESPACE__ . '\DDC1474Entity e',
|
||||
'SELECT -d0_.value AS sclr0, d0_.id AS id1 FROM DDC1474Entity d0_'
|
||||
);
|
||||
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT e.id, + e.value AS value FROM ' . __NAMESPACE__ . '\DDC1474Entity e',
|
||||
'SELECT d0_.id AS id0, +d0_.value AS sclr1 FROM DDC1474Entity d0_'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1430
|
||||
*/
|
||||
public function testGroupByAllFieldsWhenObjectHasForeignKeys()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY u',
|
||||
'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ GROUP BY c0_.id, c0_.status, c0_.username, c0_.name, c0_.email_id'
|
||||
);
|
||||
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT e FROM Doctrine\Tests\Models\CMS\CmsEmployee e GROUP BY e',
|
||||
'SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_employees c0_ GROUP BY c0_.id, c0_.name, c0_.spouse_id'
|
||||
);
|
||||
}
|
||||
|
||||
public function testCustomTypeValueSql()
|
||||
{
|
||||
if (DBALType::hasType('negative_to_positive')) {
|
||||
DBALType::overrideType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType');
|
||||
} else {
|
||||
DBALType::addType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType');
|
||||
}
|
||||
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT p.customInteger FROM Doctrine\Tests\Models\CustomType\CustomTypeParent p WHERE p.id = 1',
|
||||
'SELECT -(c0_.customInteger) AS customInteger0 FROM customtype_parents c0_ WHERE c0_.id = 1'
|
||||
);
|
||||
}
|
||||
|
||||
public function testCustomTypeValueSqlIgnoresIdentifierColumn()
|
||||
{
|
||||
if (DBALType::hasType('negative_to_positive')) {
|
||||
DBALType::overrideType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType');
|
||||
} else {
|
||||
DBALType::addType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType');
|
||||
}
|
||||
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT p.id FROM Doctrine\Tests\Models\CustomType\CustomTypeParent p WHERE p.id = 1',
|
||||
'SELECT c0_.id AS id0 FROM customtype_parents c0_ WHERE c0_.id = 1'
|
||||
);
|
||||
}
|
||||
|
||||
public function testCustomTypeValueSqlForAllFields()
|
||||
{
|
||||
if (DBALType::hasType('negative_to_positive')) {
|
||||
DBALType::overrideType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType');
|
||||
} else {
|
||||
DBALType::addType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType');
|
||||
}
|
||||
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT p FROM Doctrine\Tests\Models\CustomType\CustomTypeParent p',
|
||||
'SELECT c0_.id AS id0, -(c0_.customInteger) AS customInteger1 FROM customtype_parents c0_'
|
||||
);
|
||||
}
|
||||
|
||||
public function testCustomTypeValueSqlForPartialObject()
|
||||
{
|
||||
if (DBALType::hasType('negative_to_positive')) {
|
||||
DBALType::overrideType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType');
|
||||
} else {
|
||||
DBALType::addType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType');
|
||||
}
|
||||
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT partial p.{id, customInteger} FROM Doctrine\Tests\Models\CustomType\CustomTypeParent p',
|
||||
'SELECT c0_.id AS id0, -(c0_.customInteger) AS customInteger1 FROM customtype_parents c0_'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1343,3 +1432,57 @@ class DDC1384Model
|
||||
*/
|
||||
protected $aVeryLongIdentifierThatShouldBeShortenedByTheSQLWalker_fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1474Entity
|
||||
{
|
||||
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue()
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @column(type="float")
|
||||
*/
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* @param string $float
|
||||
*/
|
||||
public function __construct($float)
|
||||
{
|
||||
$this->value = $float;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $value
|
||||
*/
|
||||
public function setValue($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
namespace Doctrine\Tests\ORM\Query;
|
||||
|
||||
use Doctrine\DBAL\Types\Type as DBALType;
|
||||
|
||||
require_once __DIR__ . '/../../TestInit.php';
|
||||
|
||||
/**
|
||||
@ -42,6 +44,12 @@ class UpdateSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
private $_em;
|
||||
|
||||
protected function setUp() {
|
||||
if (DBALType::hasType('negative_to_positive')) {
|
||||
DBALType::overrideType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType');
|
||||
} else {
|
||||
DBALType::addType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType');
|
||||
}
|
||||
|
||||
$this->_em = $this->_getTestEntityManager();
|
||||
}
|
||||
|
||||
@ -186,4 +194,12 @@ class UpdateSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
"UPDATE cms_users SET status = 'inactive' WHERE (SELECT COUNT(*) FROM cms_users_groups c0_ WHERE c0_.user_id = cms_users.id) = 10"
|
||||
);
|
||||
}
|
||||
|
||||
public function testCustomTypeValueSqlCompletelyIgnoredInUpdateStatements()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'UPDATE Doctrine\Tests\Models\CustomType\CustomTypeParent p SET p.customInteger = 1 WHERE p.id = 1',
|
||||
'UPDATE customtype_parents SET customInteger = 1 WHERE id = 1'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -324,7 +324,33 @@ abstract class AbstractClassMetadataExporterTest extends \Doctrine\Tests\OrmTest
|
||||
{
|
||||
$this->assertEquals('user', $class->associationMappings['address']['inversedBy']);
|
||||
}
|
||||
/**
|
||||
* @depends testExportDirectoryAndFilesAreCreated
|
||||
*/
|
||||
public function testCascadeAllCollapsed()
|
||||
{
|
||||
$type = $this->_getType();
|
||||
if ($type == 'xml') {
|
||||
$xml = simplexml_load_file(__DIR__ . '/export/'.$type.'/Doctrine.Tests.ORM.Tools.Export.ExportedUser.dcm.xml');
|
||||
|
||||
$xml->registerXPathNamespace("d", "http://doctrine-project.org/schemas/orm/doctrine-mapping");
|
||||
$nodes = $xml->xpath("/d:doctrine-mapping/d:entity/d:one-to-many[@field='interests']/d:cascade/d:*");
|
||||
$this->assertEquals(1, count($nodes));
|
||||
|
||||
$this->assertEquals('cascade-all', $nodes[0]->getName());
|
||||
} elseif ($type == 'yaml') {
|
||||
|
||||
$yaml = new \Symfony\Component\Yaml\Parser();
|
||||
$value = $yaml->parse(file_get_contents(__DIR__ . '/export/'.$type.'/Doctrine.Tests.ORM.Tools.Export.ExportedUser.dcm.yml'));
|
||||
|
||||
$this->assertTrue(isset($value['Doctrine\Tests\ORM\Tools\Export\ExportedUser']['oneToMany']['interests']['cascade']));
|
||||
$this->assertEquals(1, count($value['Doctrine\Tests\ORM\Tools\Export\ExportedUser']['oneToMany']['interests']['cascade']));
|
||||
$this->assertEquals('all', $value['Doctrine\Tests\ORM\Tools\Export\ExportedUser']['oneToMany']['interests']['cascade'][0]);
|
||||
|
||||
} else {
|
||||
$this->markTestSkipped('Test aviable only for '.$type.' dirver');
|
||||
}
|
||||
}
|
||||
public function __destruct()
|
||||
{
|
||||
# $this->_deleteDirectory(__DIR__ . '/export/'.$this->_getType());
|
||||
|
@ -35,6 +35,16 @@
|
||||
</order-by>
|
||||
</one-to-many>
|
||||
|
||||
<one-to-many field="interests" target-entity="Doctrine\Tests\ORM\Tools\Export\Interests" mapped-by="user" orphan-removal="true">
|
||||
<cascade>
|
||||
<cascade-refresh/>
|
||||
<cascade-persist/>
|
||||
<cascade-merge/>
|
||||
<cascade-detach/>
|
||||
<cascade-remove/>
|
||||
</cascade>
|
||||
</one-to-many>
|
||||
|
||||
<many-to-many field="groups" target-entity="Doctrine\Tests\ORM\Tools\Export\Group">
|
||||
<cascade>
|
||||
<cascade-all/>
|
||||
|
@ -34,6 +34,11 @@ Doctrine\Tests\ORM\Tools\Export\User:
|
||||
number: ASC
|
||||
cascade: [ persist, merge ]
|
||||
orphanRemoval: true
|
||||
interests:
|
||||
targetEntity: Doctrine\Tests\ORM\Tools\Export\Interests
|
||||
mappedBy: user
|
||||
cascade: [ persist, merge, remove, refresh, detach ]
|
||||
orphanRemoval: true
|
||||
manyToMany:
|
||||
groups:
|
||||
targetEntity: Doctrine\Tests\ORM\Tools\Export\Group
|
||||
|
@ -112,6 +112,11 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
|
||||
'Doctrine\Tests\Models\Legacy\LegacyArticle',
|
||||
'Doctrine\Tests\Models\Legacy\LegacyCar',
|
||||
),
|
||||
'customtype' => array(
|
||||
'Doctrine\Tests\Models\CustomType\CustomTypeChild',
|
||||
'Doctrine\Tests\Models\CustomType\CustomTypeParent',
|
||||
'Doctrine\Tests\Models\CustomType\CustomTypeUpperCase',
|
||||
),
|
||||
);
|
||||
|
||||
protected function useModelSet($setName)
|
||||
@ -219,6 +224,13 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
|
||||
$conn->executeUpdate('DELETE FROM legacy_users');
|
||||
}
|
||||
|
||||
if (isset($this->_usedModelSets['customtype'])) {
|
||||
$conn->executeUpdate('DELETE FROM customtype_parent_friends');
|
||||
$conn->executeUpdate('DELETE FROM customtype_parents');
|
||||
$conn->executeUpdate('DELETE FROM customtype_children');
|
||||
$conn->executeUpdate('DELETE FROM customtype_uppercases');
|
||||
}
|
||||
|
||||
$this->_em->clear();
|
||||
}
|
||||
|
||||
|
32
tests/travis/mysql.travis.xml
Normal file
32
tests/travis/mysql.travis.xml
Normal 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>
|
||||
|
34
tests/travis/pgsql.travis.xml
Normal file
34
tests/travis/pgsql.travis.xml
Normal 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>
|
15
tests/travis/sqlite.travis.xml
Normal file
15
tests/travis/sqlite.travis.xml
Normal 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>
|
Loading…
x
Reference in New Issue
Block a user