Compare commits

...

30 Commits
2.0.6 ... 2.0.7

Author SHA1 Message Date
Benjamin Eberlei
b7a15316a0 Release 2.0.7 2011-08-17 21:47:50 +00:00
Benjamin Eberlei
2b878fc15d Bump dependency DBAL to 2.0.7 2011-08-17 21:46:43 +00:00
Benjamin Eberlei
4fea26c833 Fix: YamlDriver does not support orphanRemoval 2011-08-17 21:23:13 +02:00
Benjamin Eberlei
bf3ae5f2cf Merge branch 'DDC-1302' into 2.0.x 2011-07-31 11:36:02 +02:00
Benjamin Eberlei
2836d14c31 DDC-1302 - Fix bug in XmlDriver not handling orphan removal 2011-07-31 11:35:50 +02:00
Benjamin Eberlei
a342c87a32 Merge branch 'DDC-1276' into 2.0.x 2011-07-26 22:18:21 +02:00
Benjamin Eberlei
192eedc6a7 DDC-1276 - Fix bug where merge managed and new entitiy share the same collection that is cascaded, cleared during the process and then empty afterwards. 2011-07-26 22:17:13 +02:00
Benjamin Eberlei
ed78cdb937 Merge remote-tracking branch 'origin/2.0.x' into 2.0.x 2011-07-12 22:52:35 +02:00
Benjamin Eberlei
793c383aa2 Merge branch 'DDC-1240' into 2.0.x 2011-07-12 22:52:18 +02:00
Benjamin Eberlei
7595b021cc DDC-1240 - Fix optimistic lock exception loosing the message 2011-07-12 22:52:09 +02:00
Benjamin Eberlei
f1bcb3cb80 Merge branch 'DDC-1257' into 2.0.x 2011-07-09 15:15:53 +02:00
Benjamin Eberlei
35ea4ed1fd DDC-1257 - Fix bug where validation callbacks are added multiple times in EntityGenerator 2011-07-09 15:15:34 +02:00
Benjamin Eberlei
ac8a36cda3 Merge branch 'DDC-1251' into 2.0.x 2011-07-09 14:55:12 +02:00
Benjamin Eberlei
0917ed5ced DDC-1251 - Fix bug in token parsing of EntityGenerator 2011-07-09 14:54:56 +02:00
Benjamin Eberlei
8068f34c66 DDC-1022 - Call __wakeup() with the same semantics then ClassMetadata::newInstance() does inside UnitOfWork 2011-07-09 14:34:21 +02:00
Benjamin Eberlei
91a9d4f27c Merge branch 'DDC-1230' into 2.0.x 2011-06-28 21:38:54 +02:00
Benjamin Eberlei
7c8590ea74 DDC-1230 - Fix bug where UnitOfWork does not set STATE_REMOVE when calling EntityManager#remove() on an entity 2011-06-28 21:38:44 +02:00
Benjamin Eberlei
d1cea4f77c Merge branch 'DDC-1224' into 2.0.x 2011-06-26 10:12:08 +02:00
Benjamin Eberlei
ae958e73d1 DDC-1224 - Bugfix with temporary table ids and tables in schema (in postgresql) 2011-06-26 10:11:57 +02:00
Benjamin Eberlei
3b841883d3 Merge branch 'DDC-1211' into 2.0.x 2011-06-19 10:27:21 +02:00
Benjamin Eberlei
cfe36f9a31 DDC-1211 - Fix bug with empty numeric literal 2011-06-19 10:26:36 +02:00
Benjamin Eberlei
d2eea18977 Merge branch 'DDC-1189' into 2.0.x 2011-06-19 09:44:21 +02:00
Benjamin Eberlei
247887ec0e DDC-1189 - Bugfix with PersistentCollection#clear() in combination with lazy loading 2011-06-19 09:43:33 +02:00
Benjamin Eberlei
2b309a3682 Merge remote-tracking branch 'origin/2.0.x' into 2.0.x 2011-06-16 22:47:28 +02:00
Benjamin Eberlei
5ebe7ca89e Merge branch 'DDC-1172' into 2.0.x 2011-06-16 22:47:08 +02:00
Benjamin Eberlei
c582b7790a DDC-1172 - Adjust patch to 2.0.x code base 2011-06-16 22:43:06 +02:00
Benjamin Eberlei
a98a21b269 DDC-1172 - Handle sequence dropping in SchemaTool. 2011-06-16 22:34:56 +02:00
Benjamin Eberlei
5c9b3d0b92 Bump Dev Version to 2.0.7-DEV 2011-06-15 21:45:09 +00:00
Benjamin Eberlei
a1bc743568 Merge branch 'DDC-1208' into 2.0.x 2011-06-15 18:33:24 +02:00
Benjamin Eberlei
20d8ebfd43 DDC-1208 - Allow namespace separator in <discriminator-mapping /> 2011-06-15 18:33:12 +02:00
25 changed files with 255 additions and 46 deletions

View File

@@ -168,7 +168,7 @@
<xs:complexType name="discriminator-mapping">
<xs:attribute name="value" type="xs:NMTOKEN" use="required"/>
<xs:attribute name="class" type="xs:NMTOKEN" use="required"/>
<xs:attribute name="class" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="discriminator-map">

View File

@@ -1137,7 +1137,8 @@ class ClassMetadataInfo
*/
public function getTemporaryIdTableName()
{
return $this->table['name'] . '_id_tmp';
// replace dots with underscores because PostgreSQL creates temporary tables in a special schema
return str_replace('.', '_', $this->table['name'] . '_id_tmp');
}
/**

View File

@@ -262,8 +262,8 @@ class XmlDriver extends AbstractFileDriver
$mapping['cascade'] = $this->_getCascadeMappings($oneToOneElement->cascade);
}
if (isset($oneToOneElement->{'orphan-removal'})) {
$mapping['orphanRemoval'] = (bool)$oneToOneElement->{'orphan-removal'};
if (isset($oneToOneElement['orphan-removal'])) {
$mapping['orphanRemoval'] = (bool)$oneToOneElement['orphan-removal'];
}
$metadata->mapOneToOne($mapping);
@@ -287,8 +287,8 @@ class XmlDriver extends AbstractFileDriver
$mapping['cascade'] = $this->_getCascadeMappings($oneToManyElement->cascade);
}
if (isset($oneToManyElement->{'orphan-removal'})) {
$mapping['orphanRemoval'] = (bool)$oneToManyElement->{'orphan-removal'};
if (isset($oneToManyElement['orphan-removal'])) {
$mapping['orphanRemoval'] = (bool)$oneToManyElement['orphan-removal'];
}
if (isset($oneToManyElement->{'order-by'})) {

View File

@@ -266,6 +266,10 @@ class YamlDriver extends AbstractFileDriver
$mapping['cascade'] = $oneToOneElement['cascade'];
}
if (isset($oneToOneElement['orphanRemoval'])) {
$mapping['orphanRemoval'] = (bool)$oneToOneElement['orphanRemoval'];
}
$metadata->mapOneToOne($mapping);
}
}
@@ -283,6 +287,10 @@ class YamlDriver extends AbstractFileDriver
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToManyElement['fetch']);
}
if (isset($oneToManyElement['orphanRemoval'])) {
$mapping['orphanRemoval'] = (bool)$oneToManyElement['orphanRemoval'];
}
if (isset($oneToManyElement['cascade'])) {
$mapping['cascade'] = $oneToManyElement['cascade'];
}

View File

@@ -33,6 +33,7 @@ class OptimisticLockException extends ORMException
public function __construct($msg, $entity)
{
parent::__construct($msg);
$this->entity = $entity;
}

View File

@@ -576,6 +576,7 @@ final class PersistentCollection implements Collection
}
}
$this->coll->clear();
$this->initialized = true; // direct call, {@link initialize()} is too expensive
if ($this->association['isOwningSide']) {
$this->changed();
$this->em->getUnitOfWork()->scheduleCollectionDeletion($this);

View File

@@ -274,6 +274,14 @@ class <proxyClassName> extends \<className> implements \Doctrine\ORM\Proxy\Proxy
{
if (!$this->__isInitialized__ && $this->_entityPersister) {
$this->__isInitialized__ = true;
if (method_exists($this, "__wakeup")) {
// call this after __isInitialized__to avoid infinite recursion
// but before loading to emulate what ClassMetadata::newInstance()
// provides.
$this->__wakeup();
}
if ($this->_entityPersister->load($this->_identifier, $this) === null) {
throw new \Doctrine\ORM\EntityNotFoundException();
}

View File

@@ -55,7 +55,7 @@ abstract class Base
public function add($arg)
{
if ( ! empty($arg) || ($arg instanceof self && $arg->count() > 0)) {
if ( $arg !== null || ($arg instanceof self && $arg->count() > 0)) {
// If we decide to keep Expr\Base instances, we can use this check
if ( ! is_string($arg)) {
$class = get_class($arg);

View File

@@ -439,7 +439,7 @@ public function <methodName>()
} else if ($token[0] == T_FUNCTION) {
if ($tokens[$i+2][0] == T_STRING) {
$this->_staticReflection[$lastSeenClass]['methods'][] = $tokens[$i+2][1];
} else if ($tokens[$i+2][0] == T_AMPERSAND && $tokens[$i+3][0] == T_STRING) {
} else if ($tokens[$i+2] == "&" && $tokens[$i+3][0] == T_STRING) {
$this->_staticReflection[$lastSeenClass]['methods'][] = $tokens[$i+3][1];
}
} else if (in_array($token[0], array(T_VAR, T_PUBLIC, T_PRIVATE, T_PROTECTED)) && $tokens[$i+2][0] != T_FUNCTION) {
@@ -679,6 +679,7 @@ public function <methodName>()
if ($this->_hasMethod($methodName, $metadata)) {
return;
}
$this->_staticReflection[$metadata->name]['methods'][] = $methodName;
$var = sprintf('_%sMethodTemplate', $type);
$template = self::$$var;
@@ -711,6 +712,7 @@ public function <methodName>()
if ($this->_hasMethod($methodName, $metadata)) {
return;
}
$this->_staticReflection[$metadata->name]['methods'][] = $methodName;
$replacements = array(
'<name>' => $this->_annotationsPrefix . $name,

View File

@@ -570,6 +570,26 @@ class SchemaTool
}
}
}
if ($this->_platform->supportsSequences()) {
foreach ($schema->getSequences() AS $sequence) {
$visitor->acceptSequence($sequence);
}
foreach ($schema->getTables() AS $table) {
/* @var $sequence Table */
foreach ($table->getIndexes() AS $index) {
if ($index->isPrimary()) {
$columns = $index->getColumns();
if (count($columns) == 1) {
$checkSequence = $table->getName() . "_" . $columns[0] . "_seq";
if ($fullSchema->hasSequence($checkSequence)) {
$visitor->acceptSequence($fullSchema->getSequence($checkSequence));
}
}
}
}
}
}
return $visitor->getQueries();
}

View File

@@ -975,7 +975,7 @@ class UnitOfWork implements PropertyChangedListener
if ($this->isInIdentityMap($entity)) {
$this->removeFromIdentityMap($entity);
}
unset($this->entityInsertions[$oid]);
unset($this->entityInsertions[$oid], $this->entityStates[$oid]);
return; // entity has not been persisted yet, so nothing more to do.
}
@@ -990,6 +990,7 @@ class UnitOfWork implements PropertyChangedListener
}
if ( ! isset($this->entityDeletions[$oid])) {
$this->entityDeletions[$oid] = $entity;
$this->entityStates[$oid] = self::STATE_REMOVED;
}
}
@@ -1446,7 +1447,8 @@ class UnitOfWork implements PropertyChangedListener
}
if ($assoc2['isCascadeMerge']) {
$managedCol->initialize();
if (!$managedCol->isEmpty()) {
// clear and set dirty a managed collection if its not also the same collection to merge from.
if (!$managedCol->isEmpty() && $managedCol != $mergeCol) {
$managedCol->unwrap()->clear();
$managedCol->setDirty(true);
if ($assoc2['isOwningSide'] && $assoc2['type'] == ClassMetadata::MANY_TO_MANY && $class->isChangeTrackingNotify()) {
@@ -1645,6 +1647,10 @@ class UnitOfWork implements PropertyChangedListener
}
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
if ($relatedEntities instanceof Collection) {
if ($relatedEntities === $class->reflFields[$assoc['fieldName']]->getValue($managedCopy)) {
continue;
}
if ($relatedEntities instanceof PersistentCollection) {
// Unwrap so that foreach() does not initialize
$relatedEntities = $relatedEntities->unwrap();

View File

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

View File

@@ -56,6 +56,7 @@ class ECommerceProduct
private $related;
public $isCloned = false;
public $wakeUp = false;
public function __construct()
{
@@ -166,4 +167,12 @@ class ECommerceProduct
{
$this->isCloned = true;
}
/**
* Testing docblock contents here
*/
public function __wakeup()
{
$this->wakeUp = true;
}
}

View File

@@ -140,6 +140,40 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertFalse($user2->address instanceof \Doctrine\ORM\Proxy\Proxy);
}
/**
* @group DDC-1230
*/
public function testRemove()
{
$user = new CmsUser;
$user->name = 'Guilherme';
$user->username = 'gblanco';
$user->status = 'developer';
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($user));
$this->_em->persist($user);
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $this->_em->getUnitOfWork()->getEntityState($user));
$this->_em->remove($user);
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($user));
$this->_em->persist($user);
$this->_em->flush();
$id = $user->getId();
$this->_em->remove($user);
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_REMOVED, $this->_em->getUnitOfWork()->getEntityState($user));
$this->_em->flush();
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($user));
$this->assertNull($this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $id));
}
public function testOneToManyOrphanRemoval()
{
$user = new CmsUser;
@@ -827,36 +861,6 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals(0, $this->_em->getConnection()->fetchColumn("select count(*) from cms_addresses where id=".$addressId.""));
}
public function testClearingCollectionDoesNotInitialize()
{
$user = new CmsUser();
$user->username = "beberlei";
$user->name = "Benjamin E.";
$user->status = 'active';
$grp = new CmsGroup();
$grp->setName("The Dudes");
$grp->addUser($user);
$user->addGroup($grp);
$this->_em->persist($user);
$this->_em->persist($grp);
$this->_em->flush();
$this->_em->clear();
$this->assertEquals(1, $this->_em->getConnection()->fetchColumn("select count(*) from cms_users_groups"));
$user2 = $this->_em->find(get_class($user), $user->id);
$this->assertFalse($user2->groups->isInitialized());
$user2->groups->clear();
$this->assertFalse($user2->groups->isInitialized());
$this->_em->flush();
$this->assertFalse($user2->groups->isInitialized());
$this->assertEquals(0, $this->_em->getConnection()->fetchColumn("select count(*) from cms_users_groups"));
}
public function testGetPartialReferenceToUpdateObjectWithoutLoadingIt()
{
//$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);

View File

@@ -357,4 +357,24 @@ class ManyToManyBasicAssociationTest extends \Doctrine\Tests\OrmFunctionalTestCa
$this->_em->getUnitOfWork()->initializeObject($user->groups);
$this->assertTrue($user->groups->isInitialized(), "Collection should be initialized after calling UnitOfWork::initializeObject()");
}
/**
* @group DDC-1189
* @group DDC-956
*/
public function testClearBeforeLazyLoad()
{
$user = $this->addCmsUserGblancoWithGroups(4);
$this->_em->clear();
$user = $this->_em->find(get_class($user), $user->id);
$user->groups->clear();
$this->assertEquals(0, count($user->groups));
$this->_em->flush();
$user = $this->_em->find(get_class($user), $user->id);
$this->assertEquals(0, count($user->groups));
}
}

View File

@@ -130,4 +130,21 @@ class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase
$entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id);
$this->assertEquals('Doctrine 2 Cookbook', $entity->getName());
}
/**
* @group DDC-1022
*/
public function testWakeupCalledOnProxy()
{
$id = $this->createProduct();
/* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */
$entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id);
$this->assertFalse($entity->wakeUp);
$entity->setName('Doctrine 2 Cookbook');
$this->assertTrue($entity->wakeUp, "Loading the proxy should call __wakeup().");
}
}

View File

@@ -80,4 +80,25 @@ class PostgreSqlSchemaToolTest extends \Doctrine\Tests\OrmFunctionalTestCase
$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(
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'),
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'),
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'),
);
$tool = new SchemaTool($this->_em);
$sql = $tool->getDropSchemaSQL($classes);
$this->assertEquals(13, count($sql));
$dropSequenceSQLs = 0;
foreach ($sql AS $stmt) {
if (strpos($stmt, "DROP SEQUENCE") === 0) {
$dropSequenceSQLs++;
}
}
$this->assertEquals(4, $dropSequenceSQLs, "Expect 4 sequences to be dropped.");
}
}

View File

@@ -0,0 +1,50 @@
<?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';
/**
* @group DDC-1276
*/
class DDC1276Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
public function setUp()
{
$this->useModelSet('cms');
parent::setUp();
}
public function testIssue()
{
$user = new CmsUser();
$user->name = "Benjamin";
$user->username = "beberlei";
$user->status = "active";
$this->_em->persist($user);
for ($i = 0; $i < 2; $i++) {
$group = new CmsGroup();
$group->name = "group".$i;
$user->groups[] = $group;
$this->_em->persist($group);
}
$this->_em->flush();
$this->_em->clear();
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $user->id);
$cloned = clone $user;
$this->assertSame($user->groups, $cloned->groups);
$this->assertEquals(2, count($user->groups));
$this->_em->merge($cloned);
$this->assertEquals(2, count($user->groups));
$this->_em->flush();
}
}

View File

@@ -186,6 +186,7 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRefresh']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeDetach']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeMerge']);
$this->assertTrue($class->associationMappings['phonenumbers']['orphanRemoval']);
// Test Order By
$this->assertEquals(array('number' => 'ASC'), $class->associationMappings['phonenumbers']['orderBy']);
@@ -329,7 +330,7 @@ class User
public $address;
/**
* @OneToMany(targetEntity="Phonenumber", mappedBy="user", cascade={"persist"})
* @OneToMany(targetEntity="Phonenumber", mappedBy="user", cascade={"persist"}, orphanRemoval=true)
* @OrderBy({"number"="ASC"})
*/
public $phonenumbers;
@@ -425,7 +426,7 @@ class User
1 => 'persist',
),
'mappedBy' => 'user',
'orphanRemoval' => false,
'orphanRemoval' => true,
'orderBy' =>
array(
'number' => 'ASC',

View File

@@ -232,6 +232,17 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException');
$cm->mapField(array('fieldName' => 'name', 'columnName' => 'name'));
}
/**
* @group DDC-1224
*/
public function testGetTemporaryTableNameSchema()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->setTableName('foo.bar');
$this->assertEquals('foo_bar_id_tmp', $cm->getTemporaryIdTableName());
}
public function testDefaultTableName()
{

View File

@@ -60,7 +60,7 @@ $metadata->mapOneToMany(array(
1 => 'persist',
),
'mappedBy' => 'user',
'orphanRemoval' => false,
'orphanRemoval' => true,
'orderBy' =>
array(
'number' => 'ASC',

View File

@@ -35,7 +35,7 @@
<join-column name="address_id" referenced-column-name="id" on-delete="CASCADE" on-update="CASCADE"/>
</one-to-one>
<one-to-many field="phonenumbers" target-entity="Phonenumber" mapped-by="user">
<one-to-many field="phonenumbers" target-entity="Phonenumber" mapped-by="user" orphan-removal="true">
<cascade>
<cascade-persist/>
</cascade>

View File

@@ -33,6 +33,7 @@ Doctrine\Tests\ORM\Mapping\User:
oneToMany:
phonenumbers:
targetEntity: Phonenumber
orphanRemoval: true
mappedBy: user
orderBy:
number: ASC

View File

@@ -589,4 +589,32 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals(2, $expr->count(), "Modifying the second query should affect the first one.");
}
/**
* @group DDC-1211
*/
public function testEmptyStringLiteral()
{
$expr = $this->_em->getExpressionBuilder();
$qb = $this->_em->createQueryBuilder()
->select('u')
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u')
->where($expr->eq('u.username', $expr->literal("")));
$this->assertEquals("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = ''", $qb->getDQL());
}
/**
* @group DDC-1211
*/
public function testEmptyNumericLiteral()
{
$expr = $this->_em->getExpressionBuilder();
$qb = $this->_em->createQueryBuilder()
->select('u')
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u')
->where($expr->eq('u.username', $expr->literal(0)));
$this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 0', $qb->getDQL());
}
}