Skip to content

Commit 7586b5b

Browse files
author
Charles J. C. Elling Espejel
committed
[Sortable] Fix position field is not set correctly when the Entity uses
the "NOTIFY" change tracking policy
1 parent 8f0123a commit 7586b5b

File tree

8 files changed

+226
-77
lines changed

8 files changed

+226
-77
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040
"require": {
4141
"php": ">=5.3.2",
4242
"behat/transliterator": "~1.2",
43-
"doctrine/common": "~2.4"
43+
"doctrine/common": "~2.4",
44+
"symfony/property-access": "~2.7|~3.0"
4445
},
4546
"require-dev": {
4647
"doctrine/mongodb-odm": ">=1.0.2",

composer7.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040
"require": {
4141
"php": ">=5.4",
4242
"behat/transliterator": "~1.2",
43-
"doctrine/common": "~2.4"
43+
"doctrine/common": "~2.4",
44+
"symfony/property-access": "~2.7|~3.0"
4445
},
4546
"replace": {
4647
"ext-mongo": "1.6.12"

lib/Gedmo/Mapping/MappedEventSubscriber.php

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
use Doctrine\Common\EventSubscriber;
88
use Doctrine\Common\Persistence\ObjectManager;
99
use Doctrine\Common\EventArgs;
10+
use Symfony\Component\PropertyAccess\PropertyAccessor;
11+
use Symfony\Component\PropertyAccess\PropertyAccess;
1012

1113
/**
1214
* This is extension of event subscriber class and is
@@ -64,7 +66,13 @@ abstract class MappedEventSubscriber implements EventSubscriber
6466
* @var \Doctrine\Common\Annotations\AnnotationReader
6567
*/
6668
private static $defaultAnnotationReader;
67-
69+
70+
/**
71+
*
72+
* @var PropertyAccessor
73+
*/
74+
private $propertyAccessor;
75+
6876
/**
6977
* Constructor
7078
*/
@@ -259,4 +267,25 @@ private function getDefaultAnnotationReader()
259267

260268
return self::$defaultAnnotationReader;
261269
}
270+
271+
/**
272+
* @return \Symfony\Component\PropertyAccess\PropertyAccessor
273+
*/
274+
public function getPropertyAccessor()
275+
{
276+
if($this->propertyAccessor === null)
277+
{
278+
$this->propertyAccessor = PropertyAccess::createPropertyAccessor();
279+
}
280+
return $this->propertyAccessor;
281+
}
282+
283+
/**
284+
* @param \Symfony\Component\PropertyAccess\PropertyAccessor $propertyAccessor
285+
*/
286+
public function setPropertyAccessor($propertyAccessor)
287+
{
288+
$this->propertyAccessor = $propertyAccessor;
289+
}
290+
262291
}

lib/Gedmo/Sortable/SortableListener.php

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,10 @@ private function processInsert(SortableAdapter $ea, array $config, $meta, $objec
159159
{
160160
$em = $ea->getObjectManager();
161161
$uow = $em->getUnitOfWork();
162+
$accessor = $this->getPropertyAccessor();
162163

163-
$old = $meta->getReflectionProperty($config['position'])->getValue($object);
164-
$newPosition = $meta->getReflectionProperty($config['position'])->getValue($object);
165-
164+
$old = $accessor->getValue($object, $config['position']);
165+
$newPosition = $accessor->getValue($object, $config['position']);
166166
if (is_null($newPosition)) {
167167
$newPosition = -1;
168168
}
@@ -211,7 +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);
214+
$accessor->setValue($object, $config['position'], $newPosition);
215215
$ea->recomputeSingleObjectChangeSet($uow, $meta, $object);
216216
}
217217
}
@@ -228,6 +228,7 @@ private function processUpdate(SortableAdapter $ea, array $config, $meta, $objec
228228
{
229229
$em = $ea->getObjectManager();
230230
$uow = $em->getUnitOfWork();
231+
$accessor = $this->getPropertyAccessor();
231232

232233
$changed = false;
233234
$groupHasChanged = false;
@@ -251,7 +252,7 @@ private function processUpdate(SortableAdapter $ea, array $config, $meta, $objec
251252
if (array_key_exists($config['position'], $changeSet)) {
252253
$oldPosition = $changeSet[$config['position']][0];
253254
} else {
254-
$oldPosition = $meta->getReflectionProperty($config['position'])->getValue($object);
255+
$oldPosition = $accessor->getValue($object, $config['position']);
255256
}
256257
$this->addRelocation($oldHash, $config['useObjectClass'], $oldGroups, $oldPosition + 1, $this->maxPositions[$oldHash] + 1, -1);
257258
$groupHasChanged = true;
@@ -353,7 +354,7 @@ private function processUpdate(SortableAdapter $ea, array $config, $meta, $objec
353354
}
354355

355356
// Set new position
356-
$meta->getReflectionProperty($config['position'])->setValue($object, $newPosition);
357+
$accessor->setValue($object, $config['position'], $newPosition);
357358
$ea->recomputeSingleObjectChangeSet($uow, $meta, $object);
358359
}
359360

@@ -367,7 +368,8 @@ private function processUpdate(SortableAdapter $ea, array $config, $meta, $objec
367368
*/
368369
private function processDeletion(SortableAdapter $ea, array $config, $meta, $object)
369370
{
370-
$position = $meta->getReflectionProperty($config['position'])->getValue($object);
371+
$accessor = $this->getPropertyAccessor();
372+
$position = $accessor->getValue($object, $config['position']);
371373

372374
// Get groups
373375
$groups = $this->getGroups($meta, $config, $object);
@@ -415,6 +417,7 @@ public function postFlush(EventArgs $args)
415417
{
416418
$ea = $this->getEventAdapter($args);
417419
$em = $ea->getObjectManager();
420+
$accessor = $this->getPropertyAccessor();
418421
foreach ($this->relocations as $hash => $relocation) {
419422
$config = $this->getConfiguration($em, $relocation['name']);
420423
foreach ($relocation['deltas'] as $delta) {
@@ -452,12 +455,12 @@ public function postFlush(EventArgs $args)
452455
}
453456

454457
$oid = spl_object_hash($object);
455-
$pos = $meta->getReflectionProperty($config['position'])->getValue($object);
458+
$pos = $accessor->getValue($object, $config['position']);
456459
$matches = $pos >= $delta['start'];
457460
$matches = $matches && ($delta['stop'] <= 0 || $pos < $delta['stop']);
458461
$value = reset($relocation['groups']);
459462
while ($matches && ($group = key($relocation['groups']))) {
460-
$gr = $meta->getReflectionProperty($group)->getValue($object);
463+
$gr = $accessor->getValue($object, $group);
461464
if (null === $value) {
462465
$matches = $gr === null;
463466
} elseif (is_object($gr) && is_object($value) && $gr !== $value) {
@@ -475,8 +478,9 @@ public function postFlush(EventArgs $args)
475478
$value = next($relocation['groups']);
476479
}
477480
if ($matches) {
478-
$meta->getReflectionProperty($config['position'])->setValue($object, $pos + $delta['delta']);
479-
$ea->setOriginalObjectProperty($uow, $oid, $config['position'], $pos + $delta['delta']);
481+
$newValue = $pos + $delta['delta'];
482+
$accessor->setValue($object, $config['position'], $newValue);
483+
$ea->setOriginalObjectProperty($uow, $oid, $config['position'], $newValue);
480484
}
481485
}
482486
}
@@ -580,10 +584,11 @@ private function addRelocation($hash, $class, $groups, $start, $stop, $delta, ar
580584
*/
581585
private function getGroups($meta, $config, $object)
582586
{
587+
$accessor = $this->getPropertyAccessor();
583588
$groups = array();
584589
if (isset($config['groups'])) {
585590
foreach ($config['groups'] as $group) {
586-
$groups[$group] = $meta->getReflectionProperty($group)->getValue($object);
591+
$groups[$group] = $accessor->getValue($object, $group);
587592
}
588593
}
589594

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+

0 commit comments

Comments
 (0)