Merge branch 'DDC-130'
This commit is contained in:
commit
bbaec5bf36
@ -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';
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user