diff --git a/src/UnitOfWork.php b/src/UnitOfWork.php index 0f775910d8..2c95149652 100644 --- a/src/UnitOfWork.php +++ b/src/UnitOfWork.php @@ -2390,29 +2390,27 @@ private function doDetach( $visited[$oid] = $entity; // mark visited - switch ($this->getEntityState($entity, self::STATE_DETACHED)) { - case self::STATE_MANAGED: - if ($this->isInIdentityMap($entity)) { - $this->removeFromIdentityMap($entity); - } + $state = $this->getEntityState($entity, self::STATE_DETACHED); + if (! $noCascade && $state === self::STATE_MANAGED) { + $this->cascadeDetach($entity, $visited); + } - unset( - $this->entityInsertions[$oid], - $this->entityUpdates[$oid], - $this->entityDeletions[$oid], - $this->entityIdentifiers[$oid], - $this->entityStates[$oid], - $this->originalEntityData[$oid] - ); - break; - case self::STATE_NEW: - case self::STATE_DETACHED: - return; + if ($state !== self::STATE_MANAGED) { + return; } - if (! $noCascade) { - $this->cascadeDetach($entity, $visited); + if ($this->isInIdentityMap($entity)) { + $this->removeFromIdentityMap($entity); } + + unset( + $this->entityInsertions[$oid], + $this->entityUpdates[$oid], + $this->entityDeletions[$oid], + $this->entityIdentifiers[$oid], + $this->entityStates[$oid], + $this->originalEntityData[$oid] + ); } /** @@ -2548,11 +2546,7 @@ static function ($assoc) { $relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity); switch (true) { - case $relatedEntities instanceof PersistentCollection: - // Unwrap so that foreach() does not initialize - $relatedEntities = $relatedEntities->unwrap(); - // break; is commented intentionally! - + // in order to detach the entities in the collection, initialization is needed (no unwrap) case $relatedEntities instanceof Collection: case is_array($relatedEntities): foreach ($relatedEntities as $relatedEntity) { diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/LazyEagerCollectionTest.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/LazyEagerCollectionTest.php index 926e052315..ee93041f2e 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/LazyEagerCollectionTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/LazyEagerCollectionTest.php @@ -56,6 +56,36 @@ public function testRefreshRefreshesBothLazyAndEagerCollections(): void self::assertSame('12345', $ph->data); self::assertSame('6789', $ad->data); } + + public function testCascadeDetachBothLazyAndEagerCollections(): void + { + $user = new LazyEagerCollectionUser(); + $user->data = 'Guilherme'; + + $ph = new LazyEagerCollectionPhone(); + $ph->data = '12345'; + $user->addPhone($ph); + + $ad = new LazyEagerCollectionAddress(); + $ad->data = '6789'; + $user->addAddress($ad); + + $this->_em->persist($user); + $this->_em->persist($ad); + $this->_em->persist($ph); + $this->_em->flush(); + $this->_em->clear(); + + $user = $this->_em->find(LazyEagerCollectionUser::class, $user->id); + $this->_em->detach($user); + + $ph = $user->phones[0]; + $ad = $user->addresses[0]; + + self::assertFalse($this->_em->contains($user)); + self::assertFalse($this->_em->contains($ph)); + self::assertFalse($this->_em->contains($ad)); + } } /** @@ -78,14 +108,14 @@ class LazyEagerCollectionUser public $data; /** - * @ORM\OneToMany(targetEntity="LazyEagerCollectionPhone", cascade={"refresh"}, fetch="EAGER", mappedBy="user") + * @ORM\OneToMany(targetEntity="LazyEagerCollectionPhone", cascade={"refresh", "detach"}, fetch="EAGER", mappedBy="user") * * @var LazyEagerCollectionPhone[] */ public $phones; /** - * @ORM\OneToMany(targetEntity="LazyEagerCollectionAddress", cascade={"refresh"}, mappedBy="user") + * @ORM\OneToMany(targetEntity="LazyEagerCollectionAddress", cascade={"refresh", "detach"}, mappedBy="user") * * @var LazyEagerCollectionAddress[] */