From 6e47d7b16d91c2859bf23bdf98c2c6c5854159a6 Mon Sep 17 00:00:00 2001
From: Dominik Liebler <dominik@liebler-web.de>
Date: Sun, 14 Aug 2011 16:12:12 +0200
Subject: [PATCH] DDC-1278 - EntityManager::clear($entity) support

added test case and modified test data CmsUser to cascade detach address and articles (testing collections and single entites)
---
 lib/Doctrine/ORM/UnitOfWork.php               | 23 ++++-----
 tests/Doctrine/Tests/Models/CMS/CmsUser.php   |  4 +-
 .../ORM/Functional/BasicFunctionalTest.php    | 50 +++++++++++++++++++
 3 files changed, 62 insertions(+), 15 deletions(-)

diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php
index 64bca53cf..1e4310efc 100644
--- a/lib/Doctrine/ORM/UnitOfWork.php
+++ b/lib/Doctrine/ORM/UnitOfWork.php
@@ -1515,9 +1515,9 @@ class UnitOfWork implements PropertyChangedListener
      * 
      * @param object $entity
      * @param array $visited
-     * @param string $entityName detach only entities of this type when given
+     * @param boolean $noCascade if true, don't cascade detach operation
      */
-    private function doDetach($entity, array &$visited, $entityName = null)
+    private function doDetach($entity, array &$visited, $noCascade = false)
     {
         $oid = spl_object_hash($entity);
         if (isset($visited[$oid])) {
@@ -1539,8 +1539,10 @@ class UnitOfWork implements PropertyChangedListener
             case self::STATE_DETACHED:
                 return;
         }
-        
-        $this->cascadeDetach($entity, $visited, $entityName);
+
+        if (!$noCascade) {
+            $this->cascadeDetach($entity, $visited);
+        }
     }
     
     /**
@@ -1618,9 +1620,8 @@ class UnitOfWork implements PropertyChangedListener
      *
      * @param object $entity
      * @param array $visited
-     * @param string $entityName detach only entities of this type when given
      */
-    private function cascadeDetach($entity, array &$visited, $entityName = null)
+    private function cascadeDetach($entity, array &$visited)
     {
         $class = $this->em->getClassMetadata(get_class($entity));
         foreach ($class->associationMappings as $assoc) {
@@ -1634,14 +1635,10 @@ class UnitOfWork implements PropertyChangedListener
                     $relatedEntities = $relatedEntities->unwrap();
                 }
                 foreach ($relatedEntities as $relatedEntity) {
-                    if ($entityName === null || get_class($relatedEntity) == $entityName) {
-                        $this->doDetach($relatedEntity, $visited, $entityName);
-                    }
+                    $this->doDetach($relatedEntity, $visited);
                 }
             } else if ($relatedEntities !== null) {
-                if ($entityName === null || get_class($relatedEntities) == $entityName) {
-                    $this->doDetach($relatedEntities, $visited, $entityName);
-                }
+                $this->doDetach($relatedEntities, $visited);
             }
         }
     }
@@ -1823,7 +1820,7 @@ class UnitOfWork implements PropertyChangedListener
             foreach ($this->identityMap as $className => $entities) {
                 if ($className === $entityName) {
                     foreach ($entities as $entity) {
-                        $this->doDetach($entity, $visited, $entityName);
+                        $this->doDetach($entity, $visited, true);
                     }
                 }
             }
diff --git a/tests/Doctrine/Tests/Models/CMS/CmsUser.php b/tests/Doctrine/Tests/Models/CMS/CmsUser.php
index d9ac982ff..6b298c477 100644
--- a/tests/Doctrine/Tests/Models/CMS/CmsUser.php
+++ b/tests/Doctrine/Tests/Models/CMS/CmsUser.php
@@ -35,7 +35,7 @@ class CmsUser
      */
     public $phonenumbers;
     /**
-     * @OneToMany(targetEntity="CmsArticle", mappedBy="user")
+     * @OneToMany(targetEntity="CmsArticle", mappedBy="user", cascade={"detach"})
      */
     public $articles;
     /**
@@ -43,7 +43,7 @@ class CmsUser
      */
     public $address;
     /**
-     * @ManyToMany(targetEntity="CmsGroup", inversedBy="users", cascade={"persist", "merge"})
+     * @ManyToMany(targetEntity="CmsGroup", inversedBy="users", cascade={"persist", "merge", "detach"})
      * @JoinTable(name="cms_users_groups",
      *      joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
      *      inverseJoinColumns={@JoinColumn(name="group_id", referencedColumnName="id")}
diff --git a/tests/Doctrine/Tests/ORM/Functional/BasicFunctionalTest.php b/tests/Doctrine/Tests/ORM/Functional/BasicFunctionalTest.php
index d94aa253d..e189e8408 100644
--- a/tests/Doctrine/Tests/ORM/Functional/BasicFunctionalTest.php
+++ b/tests/Doctrine/Tests/ORM/Functional/BasicFunctionalTest.php
@@ -981,4 +981,54 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
         $this->assertTrue($article->user->__isInitialized__, "...but its initialized!");
         $this->assertEquals($qc+2, $this->getCurrentQueryCount());
     }
+
+    /**
+     * @group DDC-1278
+     */
+    public function testClearWithEntityName()
+    {
+        $user = new CmsUser;
+        $user->name = 'Dominik';
+        $user->username = 'domnikl';
+        $user->status = 'developer';
+
+        $address = new CmsAddress();
+        $address->city = "Springfield";
+        $address->zip = "12354";
+        $address->country = "Germany";
+        $address->street = "Foo Street";
+        $address->user = $user;
+        $user->address = $address;
+
+        $article1 = new CmsArticle();
+        $article1->topic = 'Foo';
+        $article1->text = 'Foo Text';
+
+        $article2 = new CmsArticle();
+        $article2->topic = 'Bar';
+        $article2->text = 'Bar Text';
+
+        $user->addArticle($article1);
+        $user->addArticle($article2);
+
+        $this->_em->persist($article1);
+        $this->_em->persist($article2);
+        $this->_em->persist($address);
+        $this->_em->persist($user);
+        $this->_em->flush();
+
+        $unitOfWork = $this->_em->getUnitOfWork();
+
+        $this->_em->clear('Doctrine\Tests\Models\CMS\CmsUser');
+
+        $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_DETACHED, $unitOfWork->getEntityState($user));
+
+        $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $unitOfWork->getEntityState($address));
+        $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $unitOfWork->getEntityState($article1));
+        $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $unitOfWork->getEntityState($article2));
+
+        $this->_em->clear();
+
+        $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_DETACHED, $unitOfWork->getEntityState($address));
+    }
 }