Compare commits

...

32 Commits
2.3.3 ... 2.3.4

Author SHA1 Message Date
Benjamin Eberlei
a41b02c080 Release 2.3.4 2013-05-11 09:51:12 +02:00
Benjamin Eberlei
8b3c206bc1 Bump dependency to 2.3.4 2013-05-11 09:47:19 +02:00
Benjamin Eberlei
e0feccc2e4 Merge branch 'DDC-2280' into 2.3 2013-05-09 18:17:03 +02:00
Benjamin Eberlei
818d3d27fe [DDC-2280] length attribute in <id> was not converted. 2013-05-09 18:16:55 +02:00
Benjamin Eberlei
98d3847a11 Merge branch 'DDC-2387' into 2.3 2013-05-09 12:11:23 +02:00
Benjamin Eberlei
63918f214b [DDC-2387] Fix DatabaseDriver not working with combinations of composite/association keys. 2013-05-09 12:11:04 +02:00
Benjamin Eberlei
acf21246c7 Merge branch 'DDC-2437' into 2.3 2013-05-09 11:04:14 +02:00
Vladislav Vlastovskiy
795e4a4b6b Added test complex inner join with indexBy 2013-05-09 11:03:36 +02:00
Vladislav Vlastovskiy
946a22f2c7 Swapped places indexBy and condition in accordance with EBNF 2013-05-09 11:03:36 +02:00
Benjamin Eberlei
bdd7482b3f Merge branch 'DDC-2423' into 2.3 2013-05-09 10:56:00 +02:00
Benjamin Eberlei
8e31107f86 [DDC-2423] Fixed bug with EntityGenerator not generating fetch="" attribute in association annotations. 2013-05-09 10:55:42 +02:00
Benjamin Eberlei
209090d338 Merge branch 'DDC-2267' into 2.3 2013-05-04 13:39:37 +02:00
Benjamin Eberlei
27117bbc98 [DDC-2267] Allow EntityManager#flush($entity) to be called on entities scheduled for removal. 2013-05-04 13:39:23 +02:00
Benjamin Eberlei
0f2be50d8f [DDC-2426] Missing length attribute in doctrine-mapping.xsd for <id> tag. 2013-05-04 12:59:02 +02:00
Benjamin Eberlei
193e74af05 Merge branch 'DDC-1984' into 2.3 2013-05-01 19:40:06 +02:00
Benjamin Eberlei
bb6e4f2074 [DDC-1984] Throw exception if passing null into UnitOfWork#lock() - which can happen when EntityManager#find() tries to lock entity that was just deleted by another process. 2013-05-01 19:39:48 +02:00
Benjamin Eberlei
6063fe4adf Merge branch 'DDC-2409' into 2.3 2013-05-01 11:01:17 +02:00
Benjamin Eberlei
846c6d2c5e Simplify condition of previous commit (5cdc73e) 2013-05-01 11:00:55 +02:00
Fabio B. Silva
1f257622a1 Fix DDC-2409 2013-05-01 11:00:55 +02:00
Benjamin Eberlei
84257c9454 Merge branch 'DBAL-483' into 2.3 2013-05-01 10:45:19 +02:00
Benjamin Eberlei
eedacc9822 [DBAL-483] Add sqlite check again as ALTER TABLE is only supported as of 2.4 2013-05-01 10:44:31 +02:00
Benjamin Eberlei
3d9099e33b [DBAL-483] Pass default values to DBAL mapping layer correctly to fix default comparision bug. 2013-05-01 10:42:53 +02:00
EuKov
ad7b5871bf Fixed typo in SQLFilter (use statement ClassMetadata) 2013-04-23 22:26:59 +02:00
Benjamin Eberlei
803f2740c9 [DDC-2346] Reapply changes lost in rebase onto 2.3 2013-04-14 09:52:39 +02:00
Stefan Kleff
ed3f375ef3 Added constant 2013-04-14 09:49:26 +02:00
Stefan Kleff
a188c88ef2 Added test based on e468ced00b 2013-04-14 09:48:09 +02:00
Benjamin Eberlei
86e40a692b Merge branch 'DDC-2252' into 2.3 2013-04-06 19:56:15 +02:00
Fabio B. Silva
36b79309bd Fix DDC-2252 2013-04-06 19:55:50 +02:00
Benjamin Eberlei
66b6b7169e Merge branch 'DDC-2224-2' into 2.3 2013-04-04 20:35:01 +02:00
Benjamin Eberlei
7c7a8abe40 [DDC-2224] Adjust ClassMetadata processing 2013-04-04 20:34:49 +02:00
Benjamin Eberlei
e5c68ab45c [DDC-2224] Rewrite instanceof feature with parameter needle ClassMetadata breaks caching of queries. 2013-04-04 20:32:04 +02:00
Benjamin Eberlei
868bb68cc8 Bump dev version to 2.3.4 2013-03-24 21:43:58 +01:00
30 changed files with 690 additions and 115 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "doctrine/orm",
"type": "library","version":"2.3.3",
"type": "library","version":"2.3.4",
"description": "Object-Relational-Mapper for PHP",
"keywords": ["orm", "database"],
"homepage": "http://www.doctrine-project.org",

View File

@@ -329,6 +329,7 @@
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
<xs:attribute name="type" type="xs:NMTOKEN" />
<xs:attribute name="column" type="xs:NMTOKEN" />
<xs:attribute name="length" type="xs:NMTOKEN" />
<xs:attribute name="association-key" type="xs:boolean" default="false" />
<xs:attribute name="column-definition" type="xs:string" />
<xs:anyAttribute namespace="##other"/>

View File

@@ -26,6 +26,7 @@ use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\ORM\Query\QueryException;
use Doctrine\ORM\Mapping;
/**
* Base contract for ORM queries. Base class for Query and NativeQuery.
@@ -259,6 +260,9 @@ abstract class AbstractQuery
case is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value)):
return $this->convertObjectParameterToScalarValue($value);
case ($value instanceof Mapping\ClassMetadata):
return $value->name;
default:
return $value;
}

View File

@@ -27,6 +27,7 @@ use PDO,
Doctrine\ORM\Events,
Doctrine\Common\Collections\ArrayCollection,
Doctrine\Common\Collections\Collection,
Doctrine\ORM\UnitOfWork,
Doctrine\ORM\Proxy\Proxy;
/**
@@ -65,8 +66,8 @@ class ObjectHydrator extends AbstractHydrator
$this->_resultCounter = 0;
if ( ! isset($this->_hints['deferEagerLoad'])) {
$this->_hints['deferEagerLoad'] = true;
if ( ! isset($this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD])) {
$this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD] = true;
}
foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
@@ -123,7 +124,7 @@ class ObjectHydrator extends AbstractHydrator
*/
protected function cleanup()
{
$eagerLoad = (isset($this->_hints['deferEagerLoad'])) && $this->_hints['deferEagerLoad'] == true;
$eagerLoad = (isset($this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD])) && $this->_hints[UnitOfWork::HINT_DEFEREAGERLOAD] == true;
parent::cleanup();

View File

@@ -217,7 +217,8 @@ class DatabaseDriver implements MappingDriver
}
if ($ids) {
if (count($ids) == 1) {
// We need to check for the columns here, because we might have associations as id as well.
if (count($primaryKeyColumns) == 1) {
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
}

View File

@@ -790,7 +790,7 @@ class BasicEntityPersister
$hydrator = $this->_em->newHydrator(($this->_selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
return $hydrator->hydrateAll($stmt, $this->_rsm, array('deferEagerLoads' => true));
return $hydrator->hydrateAll($stmt, $this->_rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true));
}
/**
@@ -845,7 +845,7 @@ class BasicEntityPersister
$hydrator = $this->_em->newHydrator(($this->_selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
return $hydrator->hydrateAll($stmt, $this->_rsm, array('deferEagerLoads' => true));
return $hydrator->hydrateAll($stmt, $this->_rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true));
}
/**
@@ -874,7 +874,7 @@ class BasicEntityPersister
*/
private function loadArrayFromStatement($assoc, $stmt)
{
$hints = array('deferEagerLoads' => true);
$hints = array(UnitOfWork::HINT_DEFEREAGERLOAD => true);
if (isset($assoc['indexBy'])) {
$rsm = clone ($this->_rsm); // this is necessary because the "default rsm" should be changed.
@@ -899,7 +899,7 @@ class BasicEntityPersister
*/
private function loadCollectionFromStatement($assoc, $stmt, $coll)
{
$hints = array('deferEagerLoads' => true, 'collection' => $coll);
$hints = array(UnitOfWork::HINT_DEFEREAGERLOAD => true, 'collection' => $coll);
if (isset($assoc['indexBy'])) {
$rsm = clone ($this->_rsm); // this is necessary because the "default rsm" should be changed.

View File

@@ -186,22 +186,22 @@ class ManyToManyPersister extends AbstractCollectionPersister
*/
protected function _getDeleteSQLParameters(PersistentCollection $coll)
{
$identifier = $this->_uow->getEntityIdentifier($coll->getOwner());
$mapping = $coll->getMapping();
$params = array();
$identifier = $this->_uow->getEntityIdentifier($coll->getOwner());
// Optimization for single column identifier
if (count($mapping['relationToSourceKeyColumns']) === 1) {
$params[] = array_pop($identifier);
return $params;
return array(reset($identifier));
}
// Composite identifier
$sourceClass = $this->_em->getClassMetadata(get_class($coll->getOwner()));
$params = array();
foreach ($mapping['relationToSourceKeyColumns'] as $srcColumn) {
$params[] = $identifier[$sourceClass->fieldNames[$srcColumn]];
foreach ($mapping['relationToSourceKeyColumns'] as $columnName => $refColumnName) {
$params[] = isset($sourceClass->fieldNames[$refColumnName])
? $identifier[$sourceClass->fieldNames[$refColumnName]]
: $identifier[$sourceClass->getFieldForColumn($columnName)];
}
return $params;

View File

@@ -141,7 +141,7 @@ class Join
{
return strtoupper($this->joinType) . ' JOIN ' . $this->join
. ($this->alias ? ' ' . $this->alias : '')
. ($this->condition ? ' ' . strtoupper($this->conditionType) . ' ' . $this->condition : '')
. ($this->indexBy ? ' INDEX BY ' . $this->indexBy : '');
. ($this->indexBy ? ' INDEX BY ' . $this->indexBy : '')
. ($this->condition ? ' ' . strtoupper($this->conditionType) . ' ' . $this->condition : '');
}
}

View File

@@ -19,9 +19,9 @@
namespace Doctrine\ORM\Query\Filter;
use Doctrine\ORM\EntityManager,
Doctrine\ORM\Mapping\ClassMetaData,
Doctrine\ORM\Query\ParameterTypeInferer;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\ParameterTypeInferer;
/**
* The base class that user defined filters should extend.

View File

@@ -1916,31 +1916,22 @@ class SqlWalker implements TreeWalker
foreach ($instanceOfExpr->value as $parameter) {
if ($parameter instanceof AST\InputParameter) {
// We need to modify the parameter value to be its correspondent mapped value
$dqlParamKey = $parameter->name;
$dqlParam = $this->query->getParameter($dqlParamKey);
$paramValue = $this->query->processParameterValue($dqlParam->getValue());
if ( ! ($paramValue instanceof \Doctrine\ORM\Mapping\ClassMetadata)) {
throw QueryException::invalidParameterType('ClassMetadata', get_class($paramValue));
}
$entityClassName = $paramValue->name;
$sqlParameterList[] = $this->walkInputParameter($parameter);
} else {
// Get name from ClassMetadata to resolve aliases.
$entityClassName = $this->em->getClassMetadata($parameter)->name;
}
if ($entityClassName == $class->name) {
$sqlParameterList[] = $this->conn->quote($class->discriminatorValue);
} else {
$discrMap = array_flip($class->discriminatorMap);
if ($entityClassName == $class->name) {
$sqlParameterList[] = $this->conn->quote($class->discriminatorValue);
} else {
$discrMap = array_flip($class->discriminatorMap);
if (!isset($discrMap[$entityClassName])) {
throw QueryException::instanceOfUnrelatedClass($entityClassName, $class->rootEntityName);
if (!isset($discrMap[$entityClassName])) {
throw QueryException::instanceOfUnrelatedClass($entityClassName, $class->rootEntityName);
}
$sqlParameterList[] = $this->conn->quote($discrMap[$entityClassName]);
}
$sqlParameterList[] = $this->conn->quote($discrMap[$entityClassName]);
}
}

View File

@@ -1089,6 +1089,15 @@ public function __construct()
$typeOptions[] = 'orphanRemoval=' . ($associationMapping['orphanRemoval'] ? 'true' : 'false');
}
if (isset($associationMapping['fetch']) && $associationMapping['fetch'] !== ClassMetadataInfo::FETCH_LAZY) {
$fetchMap = array(
ClassMetadataInfo::FETCH_EXTRA_LAZY => 'EXTRA_LAZY',
ClassMetadataInfo::FETCH_EAGER => 'EAGER',
);
$typeOptions[] = 'fetch="' . $fetchMap[$associationMapping['fetch']] . '"';
}
$lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . '' . $type . '(' . implode(', ', $typeOptions) . ')';
if (isset($associationMapping['joinColumns']) && $associationMapping['joinColumns']) {

View File

@@ -140,9 +140,15 @@ class XmlExporter extends AbstractExporter
if (isset($field['columnName'])) {
$idXml->addAttribute('column', $field['columnName']);
}
if (isset($field['length'])) {
$idXml->addAttribute('length', $field['length']);
}
if (isset($field['associationKey']) && $field['associationKey']) {
$idXml->addAttribute('association-key', 'true');
}
if ($idGeneratorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) {
$generatorXml = $idXml->addChild('generator');
$generatorXml->addAttribute('strategy', $idGeneratorType);

View File

@@ -385,22 +385,14 @@ class SchemaTool
}
if (isset($mapping['options'])) {
if (isset($mapping['options']['comment'])) {
$options['comment'] = $mapping['options']['comment'];
$knownOptions = array('comment', 'unsigned', 'fixed', 'default');
unset($mapping['options']['comment']);
}
foreach ($knownOptions as $knownOption) {
if ( isset($mapping['options'][$knownOption])) {
$options[$knownOption] = $mapping['options'][$knownOption];
if (isset($mapping['options']['unsigned'])) {
$options['unsigned'] = $mapping['options']['unsigned'];
unset($mapping['options']['unsigned']);
}
if (isset($mapping['options']['fixed'])) {
$options['fixed'] = $mapping['options']['fixed'];
unset($mapping['options']['fixed']);
unset($mapping['options'][$knownOption]);
}
}
$options['customSchemaOptions'] = $mapping['options'];

View File

@@ -67,6 +67,13 @@ class UnitOfWork implements PropertyChangedListener
*/
const STATE_REMOVED = 4;
/**
* Hint used to collect all primary keys of associated entities during hydration
* and execute it in a dedicated query afterwards
* @see https://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html?highlight=eager#temporarily-change-fetch-mode-in-dql
*/
const HINT_DEFEREAGERLOAD = 'deferEagerLoad';
/**
* The identity map that holds references to all managed entities that have
* an identity. The entities are grouped by their class name.
@@ -400,13 +407,15 @@ class UnitOfWork implements PropertyChangedListener
*/
private function computeSingleEntityChangeSet($entity)
{
if ( $this->getEntityState($entity) !== self::STATE_MANAGED) {
throw new \InvalidArgumentException("Entity has to be managed for single computation " . self::objToStr($entity));
$state = $this->getEntityState($entity);
if ($state !== self::STATE_MANAGED && $state !== self::STATE_REMOVED) {
throw new \InvalidArgumentException("Entity has to be managed or scheduled for removal for single computation " . self::objToStr($entity));
}
$class = $this->em->getClassMetadata(get_class($entity));
if ($class->isChangeTrackingDeferredImplicit()) {
if ($state === self::STATE_MANAGED && $class->isChangeTrackingDeferredImplicit()) {
$this->persist($entity);
}
@@ -1824,7 +1833,7 @@ class UnitOfWork implements PropertyChangedListener
// do not merge fields marked lazy that have not been fetched.
continue;
} else if ( ! $assoc2['isCascadeMerge']) {
if ($this->getEntityState($other, self::STATE_DETACHED) !== self::STATE_MANAGED) {
if ($this->getEntityState($other) === self::STATE_DETACHED) {
$targetClass = $this->em->getClassMetadata($assoc2['targetEntity']);
$relatedId = $targetClass->getIdentifierValues($other);
@@ -1835,6 +1844,7 @@ class UnitOfWork implements PropertyChangedListener
$this->registerManaged($other, $relatedId, array());
}
}
$prop->setValue($managedCopy, $other);
}
} else {
@@ -2226,6 +2236,10 @@ class UnitOfWork implements PropertyChangedListener
*/
public function lock($entity, $lockMode, $lockVersion = null)
{
if ($entity === null) {
throw new \InvalidArgumentException("No entity passed to UnitOfWork#lock().");
}
if ($this->getEntityState($entity, self::STATE_DETACHED) != self::STATE_MANAGED) {
throw ORMInvalidArgumentException::entityNotManaged($entity);
}
@@ -2552,7 +2566,7 @@ class UnitOfWork implements PropertyChangedListener
// this association is marked as eager fetch, and its an uninitialized proxy (wtf!)
// then we can append this entity for eager loading!
if ($hints['fetchMode'][$class->name][$field] == ClassMetadata::FETCH_EAGER &&
isset($hints['deferEagerLoad']) &&
isset($hints[self::HINT_DEFEREAGERLOAD]) &&
!$targetClass->isIdentifierComposite &&
$newValue instanceof Proxy &&
$newValue->__isInitialized__ === false) {
@@ -2577,7 +2591,7 @@ class UnitOfWork implements PropertyChangedListener
break;
// Deferred eager load only works for single identifier classes
case (isset($hints['deferEagerLoad']) && ! $targetClass->isIdentifierComposite):
case (isset($hints[self::HINT_DEFEREAGERLOAD]) && ! $targetClass->isIdentifierComposite):
// TODO: Is there a faster approach?
$this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($associatedId);

View File

@@ -36,7 +36,7 @@ class Version
/**
* Current Doctrine Version
*/
const VERSION = '2.3.3';
const VERSION = '2.3.4';
/**
* Compares a Doctrine version with the current one.

View File

@@ -1118,7 +1118,7 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
$user->username = 'domnikl';
$user->status = 'developer';
$this->setExpectedException('InvalidArgumentException', 'Entity has to be managed for single computation');
$this->setExpectedException('InvalidArgumentException', 'Entity has to be managed or scheduled for removal for single computation');
$this->_em->flush($user);
}
@@ -1202,8 +1202,9 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
/**
* @group DDC-720
* @group DDC-1612
* @group DDC-2267
*/
public function testFlushSingleNewEntity()
public function testFlushSingleNewEntityThenRemove()
{
$user = new CmsUser;
$user->name = 'Dominik';
@@ -1212,6 +1213,14 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->persist($user);
$this->_em->flush($user);
$userId = $user->id;
$this->_em->remove($user);
$this->_em->flush($user);
$this->_em->clear();
$this->assertNull($this->_em->find(get_class($user), $userId));
}
/**

View File

@@ -2,12 +2,9 @@
namespace Doctrine\Tests\ORM\Functional;
require_once __DIR__ . '/../../TestInit.php';
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Mapping\ClassMetadataInfo,
Doctrine\Common\Util\Inflector;
class DatabaseDriverTest extends \Doctrine\Tests\OrmFunctionalTestCase
class DatabaseDriverTest extends DatabaseDriverTestCase
{
/**
* @var \Doctrine\DBAL\Schema\AbstractSchemaManager
@@ -148,44 +145,4 @@ class DatabaseDriverTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals(0, count($metadatas['DbdriverBaz']->associationMappings), "no association mappings should be detected.");
}
protected function convertToClassMetadata(array $entityTables, array $manyTables = array())
{
$driver = new \Doctrine\ORM\Mapping\Driver\DatabaseDriver($this->_sm);
$driver->setTables($entityTables, $manyTables);
$metadatas = array();
foreach ($driver->getAllClassNames() AS $className) {
$class = new ClassMetadataInfo($className);
$driver->loadMetadataForClass($className, $class);
$metadatas[$className] = $class;
}
return $metadatas;
}
/**
* @param string $className
* @return ClassMetadata
*/
protected function extractClassMetadata(array $classNames)
{
$classNames = array_map('strtolower', $classNames);
$metadatas = array();
$driver = new \Doctrine\ORM\Mapping\Driver\DatabaseDriver($this->_sm);
foreach ($driver->getAllClassNames() as $className) {
if (!in_array(strtolower($className), $classNames)) {
continue;
}
$class = new ClassMetadataInfo($className);
$driver->loadMetadataForClass($className, $class);
$metadatas[$className] = $class;
}
if (count($metadatas) != count($classNames)) {
$this->fail("Have not found all classes matching the names '" . implode(", ", $classNames) . "' only tables " . implode(", ", array_keys($metadatas)));
}
return $metadatas;
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\OrmFunctionalTestCase;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
/**
* Common BaseClass for DatabaseDriver Tests
*/
abstract class DatabaseDriverTestCase extends OrmFunctionalTestCase
{
protected function convertToClassMetadata(array $entityTables, array $manyTables = array())
{
$sm = $this->_em->getConnection()->getSchemaManager();
$driver = new \Doctrine\ORM\Mapping\Driver\DatabaseDriver($sm);
$driver->setTables($entityTables, $manyTables);
$metadatas = array();
foreach ($driver->getAllClassNames() AS $className) {
$class = new ClassMetadataInfo($className);
$driver->loadMetadataForClass($className, $class);
$metadatas[$className] = $class;
}
return $metadatas;
}
/**
* @param string $className
* @return ClassMetadata
*/
protected function extractClassMetadata(array $classNames)
{
$classNames = array_map('strtolower', $classNames);
$metadatas = array();
$sm = $this->_em->getConnection()->getSchemaManager();
$driver = new \Doctrine\ORM\Mapping\Driver\DatabaseDriver($sm);
foreach ($driver->getAllClassNames() as $className) {
if (!in_array(strtolower($className), $classNames)) {
continue;
}
$class = new ClassMetadataInfo($className);
$driver->loadMetadataForClass($className, $class);
$metadatas[$className] = $class;
}
if (count($metadatas) != count($classNames)) {
$this->fail("Have not found all classes matching the names '" . implode(", ", $classNames) . "' only tables " . implode(", ", array_keys($metadatas)));
}
return $metadatas;
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace Doctrine\Tests\ORM\Functional\SchemaTool;
use Doctrine\ORM\Tools;
class DBAL483Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
public function setUp()
{
parent::setUp();
$conn = $this->_em->getConnection();
if ($conn->getDatabasePlatform()->getName() === 'sqlite') {
$this->markTestSkipped('Sqlite does not support ALTER TABLE');
}
$this->schemaTool = new Tools\SchemaTool($this->_em);
}
/**
* @group DBAL-483
*/
public function testDefaultValueIsComparedCorrectly()
{
$class = $this->_em->getClassMetadata(__NAMESPACE__ . '\\DBAL483Default');
$this->schemaTool->createSchema(array($class));
$updateSql = $this->schemaTool->getUpdateSchemaSql(array($class));
$updateSql = array_filter($updateSql, function ($sql) {
return strpos($sql, 'DBAL483') !== false;
});
$this->assertEquals(0, count($updateSql));
}
}
/**
* @Entity
*/
class DBAL483Default
{
/**
* @Id @Column(type="integer") @GeneratedValue
*/
public $id;
/**
* @Column(type="integer", options={"default": 0})
*/
public $num;
/**
* @Column(type="string", options={"default": "foo"})
*/
public $str = "foo";
}

View File

@@ -4,9 +4,6 @@ namespace Doctrine\Tests\ORM\Functional\SchemaTool;
use Doctrine\ORM\Tools;
require_once __DIR__ . '/../../../TestInit.php';
/**
* WARNING: This test should be run as last test! It can affect others very easily!
*/
@@ -15,7 +12,8 @@ class DDC214Test extends \Doctrine\Tests\OrmFunctionalTestCase
private $classes = array();
private $schemaTool = null;
public function setUp() {
public function setUp()
{
parent::setUp();
$conn = $this->_em->getConnection();
@@ -88,4 +86,4 @@ class DDC214Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals(0, count($sql), "SQL: " . implode(PHP_EOL, $sql));
}
}
}

View File

@@ -0,0 +1,229 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Common\Collections\ArrayCollection;
/**
* @group DDC-2252
*/
class DDC2252Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
private $user;
private $merchant;
private $membership;
private $privileges = array();
protected function setUp()
{
parent::setUp();
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Ticket\DDC2252User'),
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Ticket\DDC2252Privilege'),
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Ticket\DDC2252Membership'),
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Ticket\DDC2252MerchantAccount'),
));
$this->loadFixtures();
}
public function loadFixtures()
{
$this->user = new DDC2252User;
$this->merchant = new DDC2252MerchantAccount;
$this->membership = new DDC2252Membership($this->user, $this->merchant);
$this->privileges[] = new DDC2252Privilege;
$this->privileges[] = new DDC2252Privilege;
$this->privileges[] = new DDC2252Privilege;
$this->membership->addPrivilege($this->privileges[0]);
$this->membership->addPrivilege($this->privileges[1]);
$this->membership->addPrivilege($this->privileges[2]);
$this->_em->persist($this->user);
$this->_em->persist($this->merchant);
$this->_em->persist($this->privileges[0]);
$this->_em->persist($this->privileges[1]);
$this->_em->persist($this->privileges[2]);
$this->_em->flush();
$this->_em->persist($this->membership);
$this->_em->flush();
$this->_em->clear();
}
public function testIssue()
{
$identifier = array(
'merchantAccount' => $this->merchant->getAccountid(),
'userAccount' => $this->user->getUid(),
);
$class = 'Doctrine\Tests\ORM\Functional\Ticket\DDC2252Membership';
$membership = $this->_em->find($class, $identifier);
$this->assertInstanceOf($class, $membership);
$this->assertCount(3, $membership->getPrivileges());
$membership->getPrivileges()->remove(2);
$this->_em->persist($membership);
$this->_em->flush();
$this->_em->clear();
$membership = $this->_em->find($class, $identifier);
$this->assertInstanceOf($class, $membership);
$this->assertCount(2, $membership->getPrivileges());
$membership->getPrivileges()->clear();
$this->_em->persist($membership);
$this->_em->flush();
$this->_em->clear();
$membership = $this->_em->find($class, $identifier);
$this->assertInstanceOf($class, $membership);
$this->assertCount(0, $membership->getPrivileges());
$membership->addPrivilege($privilege3 = new DDC2252Privilege);
$this->_em->persist($privilege3);
$this->_em->persist($membership);
$this->_em->flush();
$this->_em->clear();
$membership = $this->_em->find($class, $identifier);
$this->assertInstanceOf($class, $membership);
$this->assertCount(1, $membership->getPrivileges());
}
}
/**
* @Entity()
* @Table(name="ddc2252_acl_privilege")
*/
class DDC2252Privilege
{
/**
* @Id
* @GeneratedValue
* @Column(type="integer")
*/
protected $privilegeid;
public function getPrivilegeid()
{
return $this->privilegeid;
}
}
/**
* @Entity
* @Table(name="ddc2252_mch_account")
*/
class DDC2252MerchantAccount
{
/**
* @Id
* @Column(type="integer")
*/
protected $accountid = 111;
public function getAccountid()
{
return $this->accountid;
}
}
/**
* @Entity
* @Table(name="ddc2252_user_account")
*/
class DDC2252User {
/**
* @Id
* @Column(type="integer")
*/
protected $uid = 222;
/**
* @OneToMany(targetEntity="DDC2252Membership", mappedBy="userAccount", cascade={"persist"})
* @JoinColumn(name="uid", referencedColumnName="uid")
*/
protected $memberships;
public function __construct()
{
$this->memberships = new ArrayCollection;
}
public function getUid()
{
return $this->uid;
}
public function getMemberships()
{
return $this->memberships;
}
public function addMembership(DDC2252Membership $membership)
{
$this->memberships[] = $membership;
}
}
/**
* @Entity
* @Table(name="ddc2252_mch_account_member")
* @HasLifecycleCallbacks
*/
class DDC2252Membership
{
/**
* @Id
* @ManyToOne(targetEntity="DDC2252User", inversedBy="memberships")
* @JoinColumn(name="uid", referencedColumnName="uid")
*/
protected $userAccount;
/**
* @Id
* @ManyToOne(targetEntity="DDC2252MerchantAccount")
* @JoinColumn(name="mch_accountid", referencedColumnName="accountid")
*/
protected $merchantAccount;
/**
* @ManyToMany(targetEntity="DDC2252Privilege", indexBy="privilegeid")
* @JoinTable(name="ddc2252_user_mch_account_privilege",
* joinColumns={
* @JoinColumn(name="mch_accountid", referencedColumnName="mch_accountid"),
* @JoinColumn(name="uid", referencedColumnName="uid")
* },
* inverseJoinColumns={
* @JoinColumn(name="privilegeid", referencedColumnName="privilegeid")
* }
* )
*/
protected $privileges;
public function __construct(DDC2252User $user, DDC2252MerchantAccount $merchantAccount)
{
$this->userAccount = $user;
$this->merchantAccount = $merchantAccount;
$this->privileges = new ArrayCollection();
}
public function addPrivilege($privilege)
{
$this->privileges[] = $privilege;
}
public function getPrivileges()
{
return $this->privileges;
}
}

View File

@@ -0,0 +1,109 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\DBAL\Logging\DebugStack;
/**
* @group DDC-2346
*/
class DDC2346Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
/**
* @var \Doctrine\DBAL\Logging\DebugStack
*/
protected $logger;
/**
* {@inheritDoc}
*/
protected function setup()
{
parent::setup();
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2346Foo'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2346Bar'),
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2346Baz'),
));
$this->logger = new DebugStack();
}
/**
* Verifies that fetching a OneToMany association with fetch="EAGER" does not cause N+1 queries
*/
public function testIssue()
{
$foo1 = new DDC2346Foo();
$foo2 = new DDC2346Foo();
$baz1 = new DDC2346Baz();
$baz2 = new DDC2346Baz();
$baz1->foo = $foo1;
$baz2->foo = $foo2;
$foo1->bars[] = $baz1;
$foo1->bars[] = $baz2;
$this->_em->persist($foo1);
$this->_em->persist($foo2);
$this->_em->persist($baz1);
$this->_em->persist($baz2);
$this->_em->flush();
$this->_em->clear();
$this->_em->getConnection()->getConfiguration()->setSQLLogger($this->logger);
$fetchedBazs = $this->_em->getRepository(__NAMESPACE__ . '\\DDC2346Baz')->findAll();
$this->assertCount(2, $fetchedBazs);
$this->assertCount(2, $this->logger->queries, 'The total number of executed queries is 2, and not n+1');
}
}
/** @Entity */
class DDC2346Foo
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
/**
* @var DDC2346Bar[]|\Doctrine\Common\Collections\Collection
*
* @OneToMany(targetEntity="DDC2346Bar", mappedBy="foo")
*/
public $bars;
/** Constructor */
public function __construct() {
$this->bars = new ArrayCollection();
}
}
/**
* @Entity
* @InheritanceType("JOINED")
* @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"baz" = "DDC2346Baz"})
*/
class DDC2346Bar
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
/** @ManyToOne(targetEntity="DDC2346Foo", inversedBy="bars", fetch="EAGER") */
public $foo;
}
/**
* @Entity
*/
class DDC2346Baz extends DDC2346Bar
{
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Tests\ORM\Functional\DatabaseDriverTestCase;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
class DDC2387Test extends DatabaseDriverTestCase
{
/**
* @group DDC-2387
*/
public function testCompositeAssociationKeyDetection()
{
$product = new \Doctrine\DBAL\Schema\Table('ddc2387_product');
$product->addColumn('id', 'integer');
$product->setPrimaryKey(array('id'));
$attributes = new \Doctrine\DBAL\Schema\Table('ddc2387_attributes');
$attributes->addColumn('product_id', 'integer');
$attributes->addColumn('attribute_name', 'string');
$attributes->setPrimaryKey(array('product_id', 'attribute_name'));
$attributes->addForeignKeyConstraint('ddc2387_product', array('product_id'), array('product_id'));
$metadata = $this->convertToClassMetadata(array($product, $attributes), array());
$this->assertEquals(ClassMetadataInfo::GENERATOR_TYPE_NONE, $metadata['Ddc2387Attributes']->generatorType);
$this->assertEquals(ClassMetadataInfo::GENERATOR_TYPE_AUTO, $metadata['Ddc2387Product']->generatorType);
}
}

View File

@@ -0,0 +1,72 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\ORM\UnitOfWork;
use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\Tests\Models\CMS\CmsArticle;
/**
* @group DDC-2409
*/
class DDC2409Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
public function setUp()
{
$this->useModelSet('cms');
parent::setUp();
}
public function testIssue()
{
$em = $this->_em;
$uow = $em->getUnitOfWork();
$originalArticle = new CmsArticle();
$originalUser = new CmsUser();
$originalArticle->topic = 'Unit Test';
$originalArticle->text = 'How to write a test';
$originalUser->name = 'Doctrine Bot';
$originalUser->username = 'DoctrineBot';
$originalUser->status = 'active';
$originalUser->addArticle($originalArticle);
$em->persist($originalUser);
$em->persist($originalArticle);
$em->flush();
$em->clear();
$article = $em->find('Doctrine\Tests\Models\CMS\CmsArticle', $originalArticle->id);
$user = new CmsUser();
$user->name = 'Doctrine Bot 2.0';
$user->username = 'BotDoctrine2';
$user->status = 'new';
$article->setAuthor($user);
$this->assertEquals(UnitOfWork::STATE_DETACHED, $uow->getEntityState($originalArticle));
$this->assertEquals(UnitOfWork::STATE_DETACHED, $uow->getEntityState($originalUser));
$this->assertEquals(UnitOfWork::STATE_MANAGED, $uow->getEntityState($article));
$this->assertEquals(UnitOfWork::STATE_NEW, $uow->getEntityState($user));
$em->detach($user);
$em->detach($article);
$userMerged = $em->merge($user);
$articleMerged = $em->merge($article);
$this->assertEquals(UnitOfWork::STATE_NEW, $uow->getEntityState($user));
$this->assertEquals(UnitOfWork::STATE_DETACHED, $uow->getEntityState($article));
$this->assertEquals(UnitOfWork::STATE_MANAGED, $uow->getEntityState($userMerged));
$this->assertEquals(UnitOfWork::STATE_MANAGED, $uow->getEntityState($articleMerged));
$this->assertNotSame($user, $userMerged);
$this->assertNotSame($article, $articleMerged);
$this->assertNotSame($userMerged, $articleMerged->user);
$this->assertSame($user, $articleMerged->user);
}
}

View File

@@ -163,4 +163,16 @@ class QueryTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals('cities', $parameter->getName());
$this->assertEquals($cities, $parameter->getValue());
}
/**
* @group DDC-2224
*/
public function testProcessParameterValueClassMetadata()
{
$query = $this->_em->createQuery("SELECT a FROM Doctrine\Tests\Models\CMS\CmsAddress a WHERE a.city IN (:cities)");
$this->assertEquals(
'Doctrine\Tests\Models\CMS\CmsAddress',
$query->processParameterValue($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'))
);
}
}

View File

@@ -474,7 +474,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
{
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF ?1",
"SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee')",
"SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN (?)",
array(), array(1 => $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyEmployee'))
);
}

View File

@@ -137,6 +137,19 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase
'SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles a ON u.id = a.author_id'
);
}
public function testComplexInnerJoinWithIndexBy()
{
$qb = $this->_em->createQueryBuilder()
->select('u', 'a')
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u')
->innerJoin('u.articles', 'a', 'ON', 'u.id = a.author_id', 'a.name');
$this->assertValidQueryBuilder(
$qb,
'SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles a INDEX BY a.name ON u.id = a.author_id'
);
}
public function testLeftJoin()
{

View File

@@ -64,6 +64,7 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase
$metadata->mapManyToMany(array(
'fieldName' => 'comments',
'targetEntity' => 'Doctrine\Tests\ORM\Tools\EntityGeneratorComment',
'fetch' => ClassMetadataInfo::FETCH_EXTRA_LAZY,
'joinTable' => array(
'name' => 'book_comment',
'joinColumns' => array(array('name' => 'book_id', 'referencedColumnName' => 'id')),
@@ -223,6 +224,8 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals($cm->identifier, $metadata->identifier);
$this->assertEquals($cm->idGenerator, $metadata->idGenerator);
$this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName);
$this->assertEquals(ClassMetadataInfo::FETCH_EXTRA_LAZY, $cm->associationMappings['comments']['fetch']);
}
public function testLoadPrefixedMetadata()

View File

@@ -227,6 +227,15 @@ class UnitOfWorkTest extends \Doctrine\Tests\OrmTestCase
// This commit should not raise an E_NOTICE
$this->_unitOfWork->commit();
}
/**
* @group DDC-1984
*/
public function testLockWithoutEntityThrowsException()
{
$this->setExpectedException('InvalidArgumentException');
$this->_unitOfWork->lock(null, null, null);
}
}
/**