Details
Description
getCommitOrder() does not add dependencies for all related classes. This causes database-level exceptions in certain cases, as insertion order can be calculated incorrectly, and foreign key constraints fail.
An example case in pseudocode:
A: ManyToOne to B, nullable=true B: ManyToOne to C, nullable=false C: no owning relations a = new A() em->persist(a) em->flush() // does CommitOrderCalculator->addClass(B), but does not add B's dependency to C c = new C() b = new B(c) em->persist(c) em->persist(b) em->flush() // CommitOrderCalculator->hasClass(B) == true, dependencies not added, foreign key constraint fails
Suggested fix against master:
diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php
index ea516f3..991acac 100644
--- a/lib/Doctrine/ORM/UnitOfWork.php
+++ b/lib/Doctrine/ORM/UnitOfWork.php
@@ -853,6 +853,7 @@ class UnitOfWork implements PropertyChangedListener
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
if ( ! $calc->hasClass($targetClass->name)) {
$calc->addClass($targetClass);
+ $newNodes[] = $targetClass;
}
$calc->addDependency($targetClass, $class);
// If the target class has mapped subclasses,
This $newNodes[] push is done for all new classes in $entityChangeSet (above) and $targetClass->subClasses (below), but not for $targetClass itself. I'm assuming this is a bug, not by design.
Fixed.