Lukas Botsch 13 tahun lalu
induk
melakukan
21ffa5ca75

+ 58 - 1
lib/Gedmo/Sortable/SortableListener.php

@@ -33,7 +33,8 @@ class SortableListener extends MappedEventSubscriber
     {
         return array(
             'onFlush',
-            'loadClassMetadata'
+            'loadClassMetadata',
+            'prePersist',
         );
     }
 
@@ -89,6 +90,35 @@ class SortableListener extends MappedEventSubscriber
         $this->processRelocations($om);
     }
 
+    /**
+     * Update maxPositions as needed
+     */
+    public function prePersist(EventArgs $args)
+    {
+        $ea = $this->getEventAdapter($args);
+        $om = $ea->getObjectManager();
+        $uow = $om->getUnitOfWork();
+        $object = $ea->getObject();
+        $meta = $om->getClassMetadata(get_class($object));
+
+        if ($config = $this->getConfiguration($om, $meta->name)) {
+            // Get groups
+            $groups = array();
+            if (isset($config['groups'])) {
+                foreach ($config['groups'] as $group) {
+                    $groups[$group] = $meta->getReflectionProperty($group)->getValue($object);
+                }
+            }
+            // Get hash
+            $hash = $this->getHash($meta, $groups, $object, $config);
+
+            // Get max position
+            if (!isset($this->maxPositions[$hash])) {
+                $this->maxPositions[$hash] = $this->getMaxPosition($om, $meta, $config, $object);
+            }
+        }
+    }
+
     /**
      * Computes node positions and updates the sort field in memory and in the db
      * @param object $em ObjectManager
@@ -318,7 +348,34 @@ class SortableListener extends MappedEventSubscriber
 
     private function getMaxPosition($em, $meta, $config, $object)
     {
+        $uow = $em->getUnitOfWork();
         $maxPos = null;
+        
+        // Get groups
+        $groups = array();
+        if (isset($config['groups'])) {
+            foreach ($config['groups'] as $group) {
+                $groups[$group] = $meta->getReflectionProperty($group)->getValue($object);
+            }
+        }
+
+        // Get hash
+        $hash = $this->getHash($meta, $groups, $object, $config);
+        
+        // Check for cached max position
+        if (isset($this->maxPositions[$hash])) {
+            return $this->maxPositions[$hash];
+        }
+        
+        // Check for groups that are associations. If the value is an object and is
+        // scheduled for insert, it has no identifier yet and is obviously new
+        // see issue #226
+        foreach ($groups as $group => $val) {
+            if (is_object($val) && $uow->isScheduledForInsert($val)) {
+                return 0;
+            }
+        }
+
         $groups = isset($config["groups"]) ? $config["groups"] : array();
         $qb = $em->createQueryBuilder();
         $qb->select('MAX(n.'.$config['position'].')')

+ 42 - 0
tests/Gedmo/Sortable/SortableTest.php

@@ -8,6 +8,8 @@ use Sortable\Fixture\Node;
 use Sortable\Fixture\Item;
 use Sortable\Fixture\Category;
 use Sortable\Fixture\SimpleListItem;
+use Sortable\Fixture\Author;
+use Sortable\Fixture\Paper;
 
 /**
  * These are tests for sluggable behavior
@@ -23,6 +25,9 @@ class SortableTest extends BaseTestCaseORM
     const ITEM = 'Sortable\\Fixture\\Item';
     const CATEGORY = 'Sortable\\Fixture\\Category';
     const SIMPLE_LIST_ITEM = 'Sortable\\Fixture\\SimpleListItem';
+    const AUTHOR = 'Sortable\\Fixture\\Author';
+    const PAPER = 'Sortable\\Fixture\\Paper';
+
     private $nodeId;
     
     protected function setUp()
@@ -278,6 +283,41 @@ class SortableTest extends BaseTestCaseORM
         $this->em->flush();
         $this->em->clear();
     }
+
+    /**
+     * Test for issue #226
+     */
+    public function test226()
+    {
+        $paper1 = new Paper();
+        $paper1->setName("Paper1");
+        $this->em->persist($paper1);
+
+        $paper2 = new Paper();
+        $paper2->setName("Paper2");
+        $this->em->persist($paper2);
+
+        $author1 = new Author();
+        $author1->setName("Author1");
+        $author1->setPaper($paper1);
+        
+        $author2 = new Author();
+        $author2->setName("Author2");
+        $author2->setPaper($paper1);
+
+        $author3 = new Author();
+        $author3->setName("Author3");
+        $author3->setPaper($paper2);
+
+        $this->em->persist($author1);
+        $this->em->persist($author2);
+        $this->em->persist($author3);
+        $this->em->flush();
+
+        $this->assertEquals(1, $author1->getPosition());
+        $this->assertEquals(2, $author2->getPosition());
+        $this->assertEquals(1, $author3->getPosition());
+    }
     
     protected function getUsedEntityFixtures()
     {
@@ -286,6 +326,8 @@ class SortableTest extends BaseTestCaseORM
             self::ITEM,
             self::CATEGORY,
             self::SIMPLE_LIST_ITEM,
+            self::AUTHOR,
+            self::PAPER,
         );
     }