1
0
mirror of synced 2025-02-20 22:23:14 +03:00

Merge branch 'DDC-130'

This commit is contained in:
Benjamin Eberlei 2010-07-10 13:45:10 +02:00
commit bbaec5bf36
7 changed files with 156 additions and 8 deletions

View File

@ -68,6 +68,13 @@ class ManyToManyMapping extends AssociationMapping
*/
public $orderBy;
/**
* READ-ONLY: Are entries on the owning AND inverse side of this join-table deleted through a database onDelete="CASCADE" operation?
*
* @var bool
*/
public $isOnDeleteCascade = false;
/**
* {@inheritdoc}
*/
@ -115,11 +122,19 @@ class ManyToManyMapping extends AssociationMapping
}
foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) {
if (isset($joinColumn['onDelete']) && strtolower($joinColumn['onDelete']) == 'cascade') {
$this->isOnDeleteCascade = true;
}
$this->relationToSourceKeyColumns[$joinColumn['name']] = $joinColumn['referencedColumnName'];
$this->joinTableColumns[] = $joinColumn['name'];
}
foreach ($mapping['joinTable']['inverseJoinColumns'] as $inverseJoinColumn) {
if (isset($inverseJoinColumn['onDelete']) && strtolower($inverseJoinColumn['onDelete']) == 'cascade') {
$this->isOnDeleteCascade = true;
}
$this->relationToTargetKeyColumns[$inverseJoinColumn['name']] = $inverseJoinColumn['referencedColumnName'];
$this->joinTableColumns[] = $inverseJoinColumn['name'];
}
@ -169,6 +184,9 @@ class ManyToManyMapping extends AssociationMapping
$serialized[] = 'joinTableColumns';
$serialized[] = 'relationToSourceKeyColumns';
$serialized[] = 'relationToTargetKeyColumns';
if ($this->isOnDeleteCascade) {
$serialized[] = 'isOnDeleteCascade';
}
if ($this->orderBy) {
$serialized[] = 'orderBy';
}

View File

@ -335,6 +335,45 @@ class BasicEntityPersister
}
}
/**
* @todo Add check for platform if it supports foreign keys/cascading.
* @param array $identifier
* @return void
*/
protected function deleteJoinTableRecords($identifier)
{
foreach ($this->_class->associationMappings AS $mapping) {
/* @var $mapping \Doctrine\ORM\Mapping\AssociationMapping */
if ($mapping->isManyToMany()) {
// @Todo this only covers scenarios with no inheritance or of the same level. Is there something
// like self-referential relationship between different levels of an inheritance hierachy? I hope not!
$selfReferential = ($mapping->targetEntityName == $mapping->sourceEntityName);
if (!$mapping->isOwningSide) {
$relatedClass = $this->_em->getClassMetadata($mapping->targetEntityName);
$mapping = $relatedClass->associationMappings[$mapping->mappedBy];
$keys = array_keys($mapping->relationToTargetKeyColumns);
if ($selfReferential) {
$otherKeys = array_keys($mapping->relationToSourceKeyColumns);
}
} else {
$keys = array_keys($mapping->relationToSourceKeyColumns);
if ($selfReferential) {
$otherKeys = array_keys($mapping->relationToTargetKeyColumns);
}
}
if(!$mapping->isOnDeleteCascade) {
$this->_conn->delete($mapping->joinTable['name'], array_combine($keys, $identifier));
if ($selfReferential) {
$this->_conn->delete($mapping->joinTable['name'], array_combine($otherKeys, $identifier));
}
}
}
}
}
/**
* Deletes a managed entity.
*
@ -347,10 +386,10 @@ class BasicEntityPersister
*/
public function delete($entity)
{
$id = array_combine(
$this->_class->getIdentifierColumnNames(),
$this->_em->getUnitOfWork()->getEntityIdentifier($entity)
);
$identifier = $this->_em->getUnitOfWork()->getEntityIdentifier($entity);
$this->deleteJoinTableRecords($identifier);
$id = array_combine($this->_class->getIdentifierColumnNames(), $identifier);
$this->_conn->delete($this->_class->table['name'], $id);
}

View File

@ -206,10 +206,10 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
*/
public function delete($entity)
{
$id = array_combine(
$this->_class->getIdentifierColumnNames(),
$this->_em->getUnitOfWork()->getEntityIdentifier($entity)
);
$identifier = $this->_em->getUnitOfWork()->getEntityIdentifier($entity);
$this->deleteJoinTableRecords($identifier);
$id = array_combine($this->_class->getIdentifierColumnNames(), $identifier);
// If the database platform supports FKs, just
// delete the row from the root table. Cascades do the rest.

View File

@ -294,4 +294,33 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
->getResult()) > 0);
}
/**
* @group DDC-130
*/
public function testDeleteJoinTableRecords()
{
#$this->markTestSkipped('Nightmare! friends adds both ID 6-7 and 7-6 into two rows of the join table. How to detect this?');
$employee1 = new CompanyEmployee();
$employee1->setName('gblanco');
$employee1->setSalary(0);
$employee1->setDepartment('IT');
$employee2 = new CompanyEmployee();
$employee2->setName('jwage');
$employee2->setSalary(0);
$employee2->setDepartment('IT');
$employee1->addFriend($employee2);
$this->_em->persist($employee1);
$this->_em->persist($employee2);
$this->_em->flush();
$this->_em->remove($employee1);
$this->_em->flush();
$this->assertNull($this->_em->find(get_class($employee1), $employee1->getId()));
}
}

View File

@ -203,6 +203,37 @@ class ManyToManyBasicAssociationTest extends \Doctrine\Tests\OrmFunctionalTestCa
$this->assertEquals(3, count($freshUser->getGroups()));
}
/**
* @group DDC-130
*/
public function testRemoveUserWithManyGroups()
{
$user = $this->addCmsUserGblancoWithGroups(2);
$this->_em->remove($user);
$this->_em->flush();
$newUser = $this->_em->find(get_class($user), $user->getId());
$this->assertNull($newUser);
}
/**
* @group DDC-130
*/
public function testRemoveGroupWithUser()
{
$user = $this->addCmsUserGblancoWithGroups(2);
foreach ($user->getGroups() AS $group) {
$this->_em->remove($group);
}
$this->_em->flush();
$this->_em->clear();
$newUser = $this->_em->find(get_class($user), $user->getId());
$this->assertEquals(0, count($newUser->getGroups()));
}
/**
* @param int $groupCount
* @return CmsUser

View File

@ -294,4 +294,18 @@ class SingleTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertFalse($contracts[0]->isCompleted(), "Only non completed contracts should be left.");
}
/**
* @group DDC-130
*/
public function testDeleteJoinTableRecords()
{
$this->loadFullFixture();
// remove managed copy of the fix contract
$this->_em->remove($this->_em->find(get_class($this->fix), $this->fix->getId()));
$this->_em->flush();
$this->assertNull($this->_em->find(get_class($this->fix), $this->fix->getId()), "Contract should not be present in the database anymore.");
}
}

View File

@ -107,6 +107,23 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
'joinColumns' => array(array('name' => 'CmsUser_id', 'referencedColumnName' => 'id', 'onDelete' => 'CASCADE')),
'inverseJoinColumns' => array(array('name' => 'CmsGroup_id', 'referencedColumnName' => 'id', 'onDelete' => 'CASCADE'))
), $assoc->joinTable);
$this->assertTrue($assoc->isOnDeleteCascade);
}
public function testSerializeManyToManyJoinTableCascade()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->mapManyToMany(
array(
'fieldName' => 'groups',
'targetEntity' => 'CmsGroup'
));
/* @var $assoc \Doctrine\ORM\Mapping\ManyToManyMapping */
$assoc = $cm->associationMappings['groups'];
$assoc = unserialize(serialize($assoc));
$this->assertTrue($assoc->isOnDeleteCascade);
}
/**