diff --git a/src/SortableListener.php b/src/SortableListener.php index 79cca6f..9710836 100644 --- a/src/SortableListener.php +++ b/src/SortableListener.php @@ -20,6 +20,7 @@ class SortableListener extends Object implements Subscriber private $reflCache = []; + public function getSubscribedEvents() { return [Events::preUpdate, Events::postPersist, Events::preRemove]; @@ -101,17 +102,31 @@ public function postPersist(LifecycleEventArgs $args) if (!$args->getEntity() instanceof ISortable) { return; } + /** @var ISortable $entity */ $entity = $args->getEntity(); $em = $args->getEntityManager(); - $pos = $this->getMaxPosition($em, $entity); - $rp = $this->getPropReflection($entity); - $rp->setValue($entity, $pos); - $uow = $em->getUnitOfWork(); + $maxPos = $this->getMaxPosition($em, $entity); + $meta = $em->getClassMetadata(get_class($entity)); - $uow->recomputeSingleEntityChangeSet($meta, $entity); - //todo: use extraUpdates - $uow->getEntityPersister(get_class($entity))->update($entity); - $uow->setOriginalEntityProperty(spl_object_hash($entity), 'position', $pos); + if (!$entity->getPosition() || $entity->getPosition() > $maxPos) { + $rp = $this->getPropReflection($entity); + $rp->setValue($entity, $maxPos); + $uow = $em->getUnitOfWork(); + $uow->recomputeSingleEntityChangeSet($meta, $entity); + //todo: use extraUpdates + $uow->getEntityPersister(get_class($entity))->update($entity); + $uow->setOriginalEntityProperty(spl_object_hash($entity), 'position', $maxPos); + } else { + $pos = $entity->getPosition(); + $qb = $this->createBaseQb($args->getEntityManager(), $entity); + $qb->update() + ->andWhere('e.position >= :from') + ->setParameter('from', $pos) + ->andWhere('e.id <> :id') + ->setParameter('id', $entity->id) + ->set('e.position', 'e.position + 1') + ->getQuery()->getResult(); + } } diff --git a/tests/src/SortableTestCase.phpt b/tests/src/SortableTestCase.phpt index 1bb194c..9a4fc19 100644 --- a/tests/src/SortableTestCase.phpt +++ b/tests/src/SortableTestCase.phpt @@ -37,6 +37,47 @@ class SortableTestCase extends TestCase } + public function testPersistSetPosition() + { + $categories = $this->createCategories(); + $categories[] = $cat = new Category('New category'); + $cat->setPosition(2); + $this->em->persist($cat); + $this->em->flush(); + $this->refresh($categories); //todo: update entities without refresh + Assert::same(1, $categories[1]->getPosition()); + Assert::same(3, $categories[2]->getPosition()); + Assert::same(4, $categories[3]->getPosition()); + Assert::same(5, $categories[4]->getPosition()); + Assert::same(6, $categories[5]->getPosition()); + Assert::same(7, $categories[6]->getPosition()); + Assert::same(2, $categories[7]->getPosition()); + } + + + public function testPersistSetPositionMultiple() + { + //failing + $categories = $this->createCategories(); + $categories[] = $cat = new Category('New category'); + $cat->setPosition(2); + $categories[] = $cat2 = new Category('New category 2'); + $cat2->setPosition(3); + $this->em->persist($cat); + $this->em->persist($cat2); + $this->em->flush(); + $this->refresh($categories); //todo: update entities without refresh + Assert::same(1, $categories[1]->getPosition()); + Assert::same(4, $categories[2]->getPosition()); + Assert::same(5, $categories[3]->getPosition()); + Assert::same(6, $categories[4]->getPosition()); + Assert::same(7, $categories[5]->getPosition()); + Assert::same(8, $categories[6]->getPosition()); + Assert::same(2, $categories[7]->getPosition()); + Assert::same(3, $categories[8]->getPosition()); + } + + public function testMoveUp() { $categories = $this->createCategories(); @@ -67,6 +108,21 @@ class SortableTestCase extends TestCase } + public function testMoveMultipleSamePosition() + { + $categories = $this->createCategories(); + $categories[5]->setPosition(2); + $categories[6]->setPosition(2); + $this->em->flush(); + $this->refresh($categories); //todo: update entities without refresh + Assert::same(1, $categories[1]->getPosition()); + Assert::same(4, $categories[2]->getPosition()); + Assert::same(5, $categories[3]->getPosition()); + Assert::same(6, $categories[4]->getPosition()); + Assert::same(3, $categories[5]->getPosition()); + Assert::same(2, $categories[6]->getPosition()); + } + public function testRemove() { $categories = $this->createCategories(); @@ -107,4 +163,4 @@ class SortableTestCase extends TestCase } -run(new SortableTestCase()); \ No newline at end of file +run(new SortableTestCase());