Skip to content

Commit 570c39d

Browse files
authored
Merge pull request #1813 from YaoOcelotl/v2.4.x
[Sortable] Fix #1809 position field is not set correctly when the Entity uses
2 parents 8f0123a + b0db127 commit 570c39d

File tree

6 files changed

+199
-68
lines changed

6 files changed

+199
-68
lines changed

lib/Gedmo/Mapping/MappedEventSubscriber.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Doctrine\Common\EventSubscriber;
88
use Doctrine\Common\Persistence\ObjectManager;
99
use Doctrine\Common\EventArgs;
10+
use Gedmo\Mapping\Event\AdapterInterface;
1011

1112
/**
1213
* This is extension of event subscriber class and is
@@ -259,4 +260,24 @@ private function getDefaultAnnotationReader()
259260

260261
return self::$defaultAnnotationReader;
261262
}
263+
264+
/**
265+
* Sets the value for a mapped field
266+
*
267+
* @param AdapterInterface $adapter
268+
* @param object $object
269+
* @param string $field
270+
* @param mixed $oldValue
271+
* @param mixed $newValue
272+
*/
273+
protected function setFieldValue(AdapterInterface $adapter, $object, $field, $oldValue, $newValue)
274+
{
275+
$manager = $adapter->getObjectManager();
276+
$meta = $manager->getClassMetadata(get_class($object));
277+
$uow = $manager->getUnitOfWork();
278+
279+
$meta->getReflectionProperty($field)->setValue($object, $newValue);
280+
$uow->propertyChanged($object, $field, $oldValue, $newValue);
281+
$adapter->recomputeSingleObjectChangeSet($uow, $meta, $object);
282+
}
262283
}

lib/Gedmo/Sortable/SortableListener.php

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,7 @@ private function processInsert(SortableAdapter $ea, array $config, $meta, $objec
211211

212212
// Set new position
213213
if ($old < 0 || is_null($old)) {
214-
$meta->getReflectionProperty($config['position'])->setValue($object, $newPosition);
215-
$ea->recomputeSingleObjectChangeSet($uow, $meta, $object);
214+
$this->setFieldValue($ea, $object, $config['position'], $old, $newPosition);
216215
}
217216
}
218217

@@ -353,8 +352,7 @@ private function processUpdate(SortableAdapter $ea, array $config, $meta, $objec
353352
}
354353

355354
// Set new position
356-
$meta->getReflectionProperty($config['position'])->setValue($object, $newPosition);
357-
$ea->recomputeSingleObjectChangeSet($uow, $meta, $object);
355+
$this->setFieldValue($ea, $object, $config['position'], $oldPosition, $newPosition);
358356
}
359357

360358
/**
@@ -475,8 +473,7 @@ public function postFlush(EventArgs $args)
475473
$value = next($relocation['groups']);
476474
}
477475
if ($matches) {
478-
$meta->getReflectionProperty($config['position'])->setValue($object, $pos + $delta['delta']);
479-
$ea->setOriginalObjectProperty($uow, $oid, $config['position'], $pos + $delta['delta']);
476+
$this->setFieldValue($ea, $object, $config['position'], $pos, $pos + $delta['delta']);
480477
}
481478
}
482479
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
namespace Sortable\Fixture;
4+
5+
use Gedmo\Mapping\Annotation as Gedmo;
6+
use Doctrine\ORM\Mapping as ORM;
7+
8+
/**
9+
* @ORM\MappedSuperclass
10+
*/
11+
class AbstractNode
12+
{
13+
/**
14+
* @ORM\Id
15+
* @ORM\GeneratedValue
16+
* @ORM\Column(type="integer")
17+
*/
18+
protected $id;
19+
20+
/**
21+
* @ORM\Column(type="string", length=255)
22+
*/
23+
protected $name;
24+
25+
/**
26+
* @Gedmo\SortableGroup
27+
* @ORM\Column(type="string", length=255)
28+
*/
29+
protected $path;
30+
31+
/**
32+
* @Gedmo\SortablePosition
33+
* @ORM\Column(type="integer")
34+
*/
35+
protected $position;
36+
37+
public function getId()
38+
{
39+
return $this->id;
40+
}
41+
42+
public function setName($name)
43+
{
44+
$this->name = $name;
45+
}
46+
47+
public function getName()
48+
{
49+
return $this->name;
50+
}
51+
52+
public function setPath($path)
53+
{
54+
$this->path = $path;
55+
}
56+
57+
public function getPath()
58+
{
59+
return $this->path;
60+
}
61+
62+
public function setPosition($position)
63+
{
64+
$this->position = $position;
65+
}
66+
67+
public function getPosition()
68+
{
69+
return $this->position;
70+
}
71+
}

tests/Gedmo/Sortable/Fixture/Node.php

Lines changed: 4 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,70 +2,14 @@
22

33
namespace Sortable\Fixture;
44

5-
use Gedmo\Mapping\Annotation as Gedmo;
65
use Doctrine\ORM\Mapping as ORM;
76

87
/**
8+
* @author Charles J. C. Elling, 2017-07-31
9+
*
910
* @ORM\Entity(repositoryClass="Gedmo\Sortable\Entity\Repository\SortableRepository")
1011
*/
11-
class Node
12+
class Node extends AbstractNode
1213
{
13-
/**
14-
* @ORM\Id
15-
* @ORM\GeneratedValue
16-
* @ORM\Column(type="integer")
17-
*/
18-
private $id;
19-
20-
/**
21-
* @ORM\Column(type="string", length=255)
22-
*/
23-
private $name;
24-
25-
/**
26-
* @Gedmo\SortableGroup
27-
* @ORM\Column(type="string", length=255)
28-
*/
29-
private $path;
30-
31-
/**
32-
* @Gedmo\SortablePosition
33-
* @ORM\Column(type="integer")
34-
*/
35-
private $position;
36-
37-
public function getId()
38-
{
39-
return $this->id;
40-
}
41-
42-
public function setName($name)
43-
{
44-
$this->name = $name;
45-
}
46-
47-
public function getName()
48-
{
49-
return $this->name;
50-
}
51-
52-
public function setPath($path)
53-
{
54-
$this->path = $path;
55-
}
56-
57-
public function getPath()
58-
{
59-
return $this->path;
60-
}
61-
62-
public function setPosition($position)
63-
{
64-
$this->position = $position;
65-
}
66-
67-
public function getPosition()
68-
{
69-
return $this->position;
70-
}
14+
7115
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
namespace Sortable\Fixture;
3+
4+
use Doctrine\ORM\Mapping as ORM;
5+
use Doctrine\Common\NotifyPropertyChanged;
6+
use Doctrine\Common\PropertyChangedListener;
7+
8+
/**
9+
* @author Charles J. C. Elling, 2017-07-31
10+
*
11+
* @ORM\Entity(repositoryClass="Gedmo\Sortable\Entity\Repository\SortableRepository")
12+
* @ORM\ChangeTrackingPolicy("NOTIFY")
13+
*/
14+
class NotifyNode extends AbstractNode implements NotifyPropertyChanged
15+
{
16+
/**
17+
* Listeners that want to be notified about property changes.
18+
*
19+
* @var PropertyChangedListener[]
20+
*/
21+
private $_propertyChangedListeners = [];
22+
23+
/**
24+
* Adds a listener that wants to be notified about property changes.
25+
*
26+
* @see \Doctrine\Common\NotifyPropertyChanged::addPropertyChangedListener()
27+
*/
28+
public function addPropertyChangedListener(PropertyChangedListener $listener)
29+
{
30+
$this->_propertyChangedListeners[] = $listener;
31+
}
32+
33+
/**
34+
* Notify property change event to listeners
35+
*
36+
* @param string $propName
37+
* @param mixed $oldValue
38+
* @param mixed $newValue
39+
*/
40+
protected function triggerPropertyChanged($propName, $oldValue, $newValue)
41+
{
42+
foreach ($this->_propertyChangedListeners as $listener)
43+
{
44+
$listener->propertyChanged($this, $propName, $oldValue, $newValue);
45+
}
46+
}
47+
48+
protected function setProperty($property, $newValue)
49+
{
50+
$oldValue = $this->{$property};
51+
if($oldValue !== $newValue)
52+
{
53+
$this->triggerPropertyChanged($property, $oldValue, $newValue);
54+
$this->{$property} = $newValue;
55+
}
56+
}
57+
58+
public function setName($name)
59+
{
60+
$this->setProperty('name', $name);
61+
}
62+
63+
public function setPath($path)
64+
{
65+
$this->setProperty('path', $path);
66+
}
67+
68+
public function setPosition($position)
69+
{
70+
$this->setProperty('position', $position);
71+
}
72+
}
73+

tests/Gedmo/Sortable/SortableTest.php

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Sortable\Fixture\Event;
1515
use Sortable\Fixture\Customer;
1616
use Sortable\Fixture\CustomerType;
17+
use Sortable\Fixture\NotifyNode;
1718

1819
/**
1920
* These are tests for sortable behavior
@@ -25,6 +26,7 @@
2526
class SortableTest extends BaseTestCaseORM
2627
{
2728
const NODE = 'Sortable\\Fixture\\Node';
29+
const NOTIFY_NODE = 'Sortable\\Fixture\\NotifyNode';
2830
const ITEM = 'Sortable\\Fixture\\Item';
2931
const CATEGORY = 'Sortable\\Fixture\\Category';
3032
const SIMPLE_LIST_ITEM = 'Sortable\\Fixture\\SimpleListItem';
@@ -790,11 +792,34 @@ public function testSetOutOfBoundsHighPosition()
790792

791793
$this->assertEquals(4, $nodes[4]->getPosition());
792794
}
795+
796+
/**
797+
* @test
798+
*/
799+
public function shouldFixIssue1809()
800+
{
801+
$manager = $this->em;
802+
$nodes = [];
803+
for ($i = 1; $i <= 3; $i++) {
804+
$node = new NotifyNode();
805+
$node->setName("Node".$i);
806+
$node->setPath("/");
807+
$manager->persist($node);
808+
$nodes[] = $node;
809+
$manager->flush();
810+
}
811+
foreach($nodes as $i => $node)
812+
{
813+
$position = $node->getPosition();
814+
$this->assertEquals($i, $position);
815+
}
816+
}
793817

794818
protected function getUsedEntityFixtures()
795819
{
796-
return array(
820+
return [
797821
self::NODE,
822+
self::NOTIFY_NODE,
798823
self::ITEM,
799824
self::CATEGORY,
800825
self::SIMPLE_LIST_ITEM,
@@ -803,7 +828,7 @@ protected function getUsedEntityFixtures()
803828
self::EVENT,
804829
self::CUSTOMER,
805830
self::CUSTOMER_TYPE,
806-
);
831+
];
807832
}
808833

809834
private function populate()

0 commit comments

Comments
 (0)