diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index 828bd19ed..8287d1fa7 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -832,6 +832,17 @@ class UnitOfWork implements PropertyChangedListener $calc->addClass($targetClass); } $calc->addDependency($targetClass, $class); + // If the target class has mapped subclasses, + // these share the same dependency. + if ($targetClass->subClasses) { + foreach ($targetClass->subClasses as $subClassName) { + $targetSubClass = $this->_em->getClassMetadata($subClassName); + if ( ! $calc->hasClass($subClassName)) { + $calc->addClass($targetSubClass); + } + $calc->addDependency($targetSubClass, $class); + } + } } } } diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC599Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC599Test.php new file mode 100644 index 000000000..82bd020d3 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC599Test.php @@ -0,0 +1,131 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC599Subitem'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC599Item'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC599Child'), + )); + } catch (\Exception $ignored) {} + } + + public function testCascadeRemoveOnInheritanceHierachy() + { + $item = new DDC599Subitem; + $item->elem = "foo"; + $child = new DDC599Child; + $child->parent = $item; + $item->getChildren()->add($child); + $this->_em->persist($item); + $this->_em->persist($child); + $this->_em->flush(); + $this->_em->clear(); + + $item = $this->_em->find(__NAMESPACE__ . '\DDC599Item', $item->id); + + $this->_em->remove($item); + $this->_em->flush(); // Should not fail + + $this->assertFalse($this->_em->contains($item)); + $children = $item->getChildren(); + $this->assertFalse($this->_em->contains($children[0])); + + $this->_em->clear(); + + + $item2 = new DDC599Subitem; + $item2->elem = "bar"; + $this->_em->persist($item2); + $this->_em->flush(); + + $child2 = new DDC599Child; + $child2->parent = $item2; + $item2->getChildren()->add($child2); + $this->_em->persist($child2); + $this->_em->flush(); + + $this->_em->remove($item2); + $this->_em->flush(); // should not fail + + $this->assertFalse($this->_em->contains($item)); + $children = $item->getChildren(); + $this->assertFalse($this->_em->contains($children[0])); + } + + public function testCascadeRemoveOnChildren() + { + $class = $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC599Subitem'); + + $this->assertArrayHasKey('children', $class->associationMappings); + $this->assertTrue($class->associationMappings['children']->isCascadeRemove); + } +} + +/** + * @Entity + * @InheritanceType("SINGLE_TABLE") + * @DiscriminatorColumn(name="type", type="integer") + * @DiscriminatorMap({"0" = "DDC599Item", "1" = "DDC599Subitem"}) + */ +class DDC599Item +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; + + /** + * @OneToMany(targetEntity="DDC599Child", mappedBy="parent", cascade={"remove"}) + */ + protected $children; + + public function __construct() + { + $this->children = new \Doctrine\Common\Collections\ArrayCollection; + } + + public function getChildren() + { + return $this->children; + } +} + +/** + * @Entity + */ +class DDC599Subitem extends DDC599Item +{ + /** + * @Column(type="string") + */ + public $elem; +} + +/** + * @Entity + */ +class DDC599Child +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; + + /** + * @ManyToOne(targetEntity="DDC599Item", inversedBy="children") + * @JoinColumn(name="parentId", referencedColumnName="id") + */ + public $parent; +} \ No newline at end of file