Merge branch 'DDC-1654'
This commit is contained in:
commit
a32948b20f
@ -371,6 +371,7 @@
|
||||
<xs:attribute name="index-by" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="inversed-by" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
|
||||
<xs:attribute name="orphan-removal" type="xs:boolean" default="false" />
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
|
@ -1115,7 +1115,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
$mapping['targetEntity'] = ltrim($mapping['targetEntity'], '\\');
|
||||
}
|
||||
|
||||
if ( ($mapping['type'] & (self::MANY_TO_ONE|self::MANY_TO_MANY)) > 0 &&
|
||||
if ( ($mapping['type'] & self::MANY_TO_ONE) > 0 &&
|
||||
isset($mapping['orphanRemoval']) &&
|
||||
$mapping['orphanRemoval'] == true) {
|
||||
|
||||
@ -1335,6 +1335,8 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
}
|
||||
}
|
||||
|
||||
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false;
|
||||
|
||||
if (isset($mapping['orderBy'])) {
|
||||
if ( ! is_array($mapping['orderBy'])) {
|
||||
throw new \InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
|
||||
|
@ -412,6 +412,7 @@ class AnnotationDriver implements Driver
|
||||
$mapping['inversedBy'] = $manyToManyAnnot->inversedBy;
|
||||
$mapping['cascade'] = $manyToManyAnnot->cascade;
|
||||
$mapping['indexBy'] = $manyToManyAnnot->indexBy;
|
||||
$mapping['orphanRemoval'] = $manyToManyAnnot->orphanRemoval;
|
||||
$mapping['fetch'] = $this->getFetchMode($className, $manyToManyAnnot->fetch);
|
||||
|
||||
if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
|
||||
|
@ -402,6 +402,10 @@ class XmlDriver extends AbstractFileDriver
|
||||
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string)$manyToManyElement['fetch']);
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement['orphan-removal'])) {
|
||||
$mapping['orphanRemoval'] = (bool)$manyToManyElement['orphan-removal'];
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement['mapped-by'])) {
|
||||
$mapping['mappedBy'] = (string)$manyToManyElement['mapped-by'];
|
||||
} else if (isset($manyToManyElement->{'join-table'})) {
|
||||
|
@ -451,6 +451,10 @@ class YamlDriver extends AbstractFileDriver
|
||||
$mapping['indexBy'] = $manyToManyElement['indexBy'];
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement['orphanRemoval'])) {
|
||||
$mapping['orphanRemoval'] = (bool)$manyToManyElement['orphanRemoval'];
|
||||
}
|
||||
|
||||
$metadata->mapManyToMany($mapping);
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,8 @@ final class ManyToMany implements Annotation
|
||||
public $cascade;
|
||||
/** @var string */
|
||||
public $fetch = 'LAZY';
|
||||
/** @var boolean */
|
||||
public $orphanRemoval = false;
|
||||
/** @var string */
|
||||
public $indexBy;
|
||||
}
|
||||
|
@ -388,7 +388,7 @@ final class PersistentCollection implements Collection
|
||||
$this->changed();
|
||||
|
||||
if ($this->association !== null &&
|
||||
$this->association['type'] == ClassMetadata::ONE_TO_MANY &&
|
||||
$this->association['type'] & ClassMetadata::TO_MANY &&
|
||||
$this->association['orphanRemoval']) {
|
||||
$this->em->getUnitOfWork()->scheduleOrphanRemoval($removed);
|
||||
}
|
||||
@ -426,7 +426,7 @@ final class PersistentCollection implements Collection
|
||||
$this->changed();
|
||||
|
||||
if ($this->association !== null &&
|
||||
$this->association['type'] === ClassMetadata::ONE_TO_MANY &&
|
||||
$this->association['type'] & ClassMetadata::TO_MANY &&
|
||||
$this->association['orphanRemoval']) {
|
||||
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
|
||||
}
|
||||
@ -631,7 +631,7 @@ final class PersistentCollection implements Collection
|
||||
|
||||
$uow = $this->em->getUnitOfWork();
|
||||
|
||||
if ($this->association['type'] === ClassMetadata::ONE_TO_MANY && $this->association['orphanRemoval']) {
|
||||
if ($this->association['type'] & ClassMetadata::TO_MANY && $this->association['orphanRemoval']) {
|
||||
// we need to initialize here, as orphan removal acts like implicit cascadeRemove,
|
||||
// hence for event listeners we need the objects in memory.
|
||||
$this->initialize();
|
||||
|
103
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1654Test.php
Normal file
103
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1654Test.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
/**
|
||||
* @group DDC-1654
|
||||
*/
|
||||
class DDC1654Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->setUpEntitySchema(array(
|
||||
__NAMESPACE__ . '\\DDC1654Post',
|
||||
__NAMESPACE__ . '\\DDC1654Comment',
|
||||
));
|
||||
}
|
||||
|
||||
public function testManyToManyRemoveFromCollectionOrphanRemoval()
|
||||
{
|
||||
$post = new DDC1654Post();
|
||||
$post->comments[] = new DDC1654Comment();
|
||||
$post->comments[] = new DDC1654Comment();
|
||||
|
||||
$this->_em->persist($post);
|
||||
$this->_em->flush();
|
||||
|
||||
$post->comments->remove(0);
|
||||
$post->comments->remove(1);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$comments = $this->_em->getRepository(__NAMESPACE__ . '\\DDC1654Comment')->findAll();
|
||||
$this->assertEquals(0, count($comments));
|
||||
}
|
||||
|
||||
public function testManyToManyRemoveElementFromCollectionOrphanRemoval()
|
||||
{
|
||||
$post = new DDC1654Post();
|
||||
$post->comments[] = new DDC1654Comment();
|
||||
$post->comments[] = new DDC1654Comment();
|
||||
|
||||
$this->_em->persist($post);
|
||||
$this->_em->flush();
|
||||
|
||||
$post->comments->removeElement($post->comments[0]);
|
||||
$post->comments->removeElement($post->comments[1]);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$comments = $this->_em->getRepository(__NAMESPACE__ . '\\DDC1654Comment')->findAll();
|
||||
$this->assertEquals(0, count($comments));
|
||||
}
|
||||
|
||||
public function testManyToManyClearCollectionOrphanRemoval()
|
||||
{
|
||||
$post = new DDC1654Post();
|
||||
$post->comments[] = new DDC1654Comment();
|
||||
$post->comments[] = new DDC1654Comment();
|
||||
|
||||
$this->_em->persist($post);
|
||||
$this->_em->flush();
|
||||
|
||||
$post->comments->clear();
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$comments = $this->_em->getRepository(__NAMESPACE__ . '\\DDC1654Comment')->findAll();
|
||||
$this->assertEquals(0, count($comments));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1654Post
|
||||
{
|
||||
/**
|
||||
* @Id @Column(type="integer") @GeneratedValue
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @ManyToMany(targetEntity="DDC1654Comment", orphanRemoval=true,
|
||||
* cascade={"persist"})
|
||||
*/
|
||||
public $comments = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1654Comment
|
||||
{
|
||||
/**
|
||||
* @Id @Column(type="integer") @GeneratedValue
|
||||
*/
|
||||
public $id;
|
||||
}
|
@ -377,6 +377,7 @@ class ClassMetadataBuilderTest extends \Doctrine\Tests\OrmTestCase
|
||||
array(
|
||||
'user_id' => 'id',
|
||||
),
|
||||
'orphanRemoval' => false,
|
||||
),
|
||||
), $this->cm->associationMappings);
|
||||
}
|
||||
|
@ -38,6 +38,12 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
|
||||
/** Whether the database schema has already been created. */
|
||||
protected static $_tablesCreated = array();
|
||||
|
||||
/**
|
||||
* Array of entity class name to their tables that were created.
|
||||
* @var array
|
||||
*/
|
||||
protected static $_entityTablesCreated = array();
|
||||
|
||||
/** List of model sets and their classes. */
|
||||
protected static $_modelSets = array(
|
||||
'cms' => array(
|
||||
@ -235,6 +241,25 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
|
||||
$this->_em->clear();
|
||||
}
|
||||
|
||||
protected function setUpEntitySchema(array $classNames)
|
||||
{
|
||||
if ($this->_em === null) {
|
||||
throw new \RuntimeException("EntityManager not set, you have to call parent::setUp() before invoking this method.");
|
||||
}
|
||||
|
||||
$classes = array();
|
||||
foreach ($classNames as $className) {
|
||||
if ( ! isset(static::$_entityTablesCreated[$className])) {
|
||||
static::$_entityTablesCreated[$className] = true;
|
||||
$classes[] = $this->_em->getClassMetadata($className);
|
||||
}
|
||||
}
|
||||
|
||||
if ($classes) {
|
||||
$this->_schemaTool->createSchema($classes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a connection to the test database, if there is none yet, and
|
||||
* creates the necessary tables.
|
||||
|
Loading…
x
Reference in New Issue
Block a user