1
0
mirror of synced 2025-01-29 19:41:45 +03:00

Fixed bug with orphanRemoval not removing associated Entity on OneToMany and OneToOne relationships. As defined in ClassMatedataInfo, in these situations, when orphanRemoval=true, cascade=remove is implicit. This fixes DDC-1321.

This commit is contained in:
Guilherme Blanco 2011-09-06 01:58:16 -03:00
parent 6bbf2d9da3
commit 2cfc61db84
10 changed files with 147 additions and 23 deletions

View File

@ -908,9 +908,8 @@ class ClassMetadataInfo implements ClassMetadata
$mapping['targetToSourceKeyColumns'] = array_flip($mapping['sourceToTargetKeyColumns']);
}
//TODO: if orphanRemoval, cascade=remove is implicit!
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ?
(bool) $mapping['orphanRemoval'] : false;
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false;
$mapping['isCascadeRemove'] = $mapping['orphanRemoval'] ? true : $mapping['isCascadeRemove'];
if (isset($mapping['id']) && $mapping['id'] === true && !$mapping['isOwningSide']) {
throw MappingException::illegalInverseIdentifierAssocation($this->name, $mapping['fieldName']);
@ -935,9 +934,8 @@ class ClassMetadataInfo implements ClassMetadata
throw MappingException::oneToManyRequiresMappedBy($mapping['fieldName']);
}
//TODO: if orphanRemoval, cascade=remove is implicit!
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ?
(bool) $mapping['orphanRemoval'] : false;
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false;
$mapping['isCascadeRemove'] = $mapping['orphanRemoval'] ? true : $mapping['isCascadeRemove'];
if (isset($mapping['orderBy'])) {
if ( ! is_array($mapping['orderBy'])) {

View File

@ -31,7 +31,7 @@ class CmsUser
*/
public $name;
/**
* @OneToMany(targetEntity="CmsPhonenumber", mappedBy="user", cascade={"persist", "remove", "merge"}, orphanRemoval=true)
* @OneToMany(targetEntity="CmsPhonenumber", mappedBy="user", cascade={"persist", "merge"}, orphanRemoval=true)
*/
public $phonenumbers;
/**

View File

@ -0,0 +1,58 @@
<?php
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\Models\CMS\CmsUser,
Doctrine\Tests\Models\CMS\CmsAddress,
Doctrine\Tests\Models\CMS\CmsPhonenumber;
require_once __DIR__ . '/../../TestInit.php';
/**
* Tests a bidirectional one-to-many association mapping with orphan removal.
*/
class OneToManyOrphanRemovalTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
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->_em->clear();
$userProxy = $this->_em->getReference('Doctrine\Tests\Models\CMS\CmsUser', $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');
}
}

View File

@ -0,0 +1,60 @@
<?php
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\Models\CMS\CmsUser,
Doctrine\Tests\Models\CMS\CmsAddress,
Doctrine\Tests\Models\CMS\CmsPhonenumber;
require_once __DIR__ . '/../../TestInit.php';
/**
* Tests a bidirectional one-to-one association mapping with orphan removal.
*/
class OneToOneOrphanRemovalTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp()
{
$this->useModelSet('cms');
parent::setUp();
}
public function testOrphanRemoval()
{
$user = new CmsUser;
$user->status = 'dev';
$user->username = 'romanb';
$user->name = 'Roman B.';
$address = new CmsAddress;
$address->country = 'de';
$address->zip = 1234;
$address->city = 'Berlin';
$user->setAddress($address);
$this->_em->persist($user);
$this->_em->flush();
$userId = $user->getId();
$this->_em->clear();
$userProxy = $this->_em->getReference('Doctrine\Tests\Models\CMS\CmsUser', $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 a FROM Doctrine\Tests\Models\CMS\CmsAddress a');
$result = $query->getResult();
$this->assertEquals(0, count($result), 'CmsAddress should be removed by orphanRemoval');
}
}

View File

@ -182,7 +182,7 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
$this->assertTrue(isset($class->associationMappings['phonenumbers']));
$this->assertFalse($class->associationMappings['phonenumbers']['isOwningSide']);
$this->assertTrue($class->associationMappings['phonenumbers']['isCascadePersist']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRemove']);
$this->assertTrue($class->associationMappings['phonenumbers']['isCascadeRemove']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRefresh']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeDetach']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeMerge']);

View File

@ -219,10 +219,11 @@ abstract class AbstractClassMetadataExporterTest extends \Doctrine\Tests\OrmTest
$this->assertEquals('CASCADE', $class->associationMappings['address']['joinColumns'][0]['onDelete']);
$this->assertTrue($class->associationMappings['address']['isCascadeRemove']);
$this->assertFalse($class->associationMappings['address']['isCascadePersist']);
$this->assertTrue($class->associationMappings['address']['isCascadePersist']);
$this->assertFalse($class->associationMappings['address']['isCascadeRefresh']);
$this->assertFalse($class->associationMappings['address']['isCascadeMerge']);
$this->assertFalse($class->associationMappings['address']['isCascadeDetach']);
$this->assertTrue($class->associationMappings['address']['orphanRemoval']);
return $class;
}
@ -239,11 +240,12 @@ abstract class AbstractClassMetadataExporterTest extends \Doctrine\Tests\OrmTest
$this->assertEquals('user', $class->associationMappings['phonenumbers']['mappedBy']);
$this->assertEquals(array('number' => 'ASC'), $class->associationMappings['phonenumbers']['orderBy']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRemove']);
$this->assertTrue($class->associationMappings['phonenumbers']['isCascadeRemove']);
$this->assertTrue($class->associationMappings['phonenumbers']['isCascadePersist']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRefresh']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeMerge']);
$this->assertTrue($class->associationMappings['phonenumbers']['isCascadeMerge']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeDetach']);
$this->assertTrue($class->associationMappings['phonenumbers']['orphanRemoval']);
return $class;
}
@ -300,9 +302,11 @@ abstract class AbstractClassMetadataExporterTest extends \Doctrine\Tests\OrmTest
public function testCascadeIsExported($class)
{
$this->assertTrue($class->associationMappings['phonenumbers']['isCascadePersist']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeMerge']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRemove']);
$this->assertTrue($class->associationMappings['phonenumbers']['isCascadeMerge']);
$this->assertTrue($class->associationMappings['phonenumbers']['isCascadeRemove']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRefresh']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeDetach']);
$this->assertTrue($class->associationMappings['phonenumbers']['orphanRemoval']);
return $class;
}

View File

@ -23,14 +23,14 @@ class User
public $email;
/**
* @OneToOne(targetEntity="Doctrine\Tests\ORM\Tools\Export\Address", cascade={"remove"}, inversedBy="user")
* @OneToOne(targetEntity="Doctrine\Tests\ORM\Tools\Export\Address", inversedBy="user", cascade={"persist"}, orphanRemoval=true)
* @JoinColumn(name="address_id", onDelete="CASCADE")
*/
public $address;
/**
*
* @OneToMany(targetEntity="Doctrine\Tests\ORM\Tools\Export\Phonenumber", mappedBy="user", cascade={"persist"})
* @OneToMany(targetEntity="Doctrine\Tests\ORM\Tools\Export\Phonenumber", mappedBy="user", cascade={"persist", "merge"}, orphanRemoval=true)
* @OrderBy({"number"="ASC"})
*/
public $phonenumbers;

View File

@ -37,7 +37,7 @@ $metadata->mapOneToOne(array(
'inversedBy' => 'user',
'cascade' =>
array(
0 => 'remove',
0 => 'persist',
),
'mappedBy' => NULL,
'joinColumns' =>
@ -49,7 +49,7 @@ $metadata->mapOneToOne(array(
'onDelete' => 'CASCADE',
),
),
'orphanRemoval' => false,
'orphanRemoval' => true,
));
$metadata->mapOneToMany(array(
'fieldName' => 'phonenumbers',
@ -57,9 +57,10 @@ $metadata->mapOneToMany(array(
'cascade' =>
array(
1 => 'persist',
2 => 'merge',
),
'mappedBy' => 'user',
'orphanRemoval' => false,
'orphanRemoval' => true,
'orderBy' =>
array(
'number' => 'ASC',

View File

@ -20,14 +20,15 @@
<field name="name" column="name" type="string" length="50" nullable="true" unique="true" />
<field name="email" column="user_email" type="string" column-definition="CHAR(32) NOT NULL" />
<one-to-one field="address" target-entity="Doctrine\Tests\ORM\Tools\Export\Address" inversed-by="user">
<cascade><cascade-remove /></cascade>
<one-to-one field="address" target-entity="Doctrine\Tests\ORM\Tools\Export\Address" inversed-by="user" orphan-removal="true">
<cascade><cascade-persist /></cascade>
<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="Doctrine\Tests\ORM\Tools\Export\Phonenumber" mapped-by="user">
<one-to-many field="phonenumbers" target-entity="Doctrine\Tests\ORM\Tools\Export\Phonenumber" mapped-by="user" orphan-removal="true">
<cascade>
<cascade-persist/>
<cascade-merge/>
</cascade>
<order-by>
<order-by-field name="number" direction="ASC" />

View File

@ -23,15 +23,17 @@ Doctrine\Tests\ORM\Tools\Export\User:
name: address_id
referencedColumnName: id
onDelete: CASCADE
cascade: [ remove ]
cascade: [ persist ]
inversedBy: user
orphanRemoval: true
oneToMany:
phonenumbers:
targetEntity: Doctrine\Tests\ORM\Tools\Export\Phonenumber
mappedBy: user
orderBy:
number: ASC
cascade: [ persist ]
cascade: [ persist, merge ]
orphanRemoval: true
manyToMany:
groups:
targetEntity: Doctrine\Tests\ORM\Tools\Export\Group