AbstractMaterializedPath.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <?php
  2. namespace Gedmo\Tree\Strategy;
  3. use Gedmo\Tree\Strategy;
  4. use Doctrine\ORM\EntityManager;
  5. use Gedmo\Tree\TreeListener;
  6. use Doctrine\ORM\Mapping\ClassMetadataInfo;
  7. use Doctrine\ORM\Query;
  8. use Doctrine\Common\Persistence\ObjectManager;
  9. /**
  10. * This strategy makes tree using materialized path strategy
  11. *
  12. * @author Gustavo Falco <comfortablynumb84@gmail.com>
  13. * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
  14. * @package Gedmo.Tree.Strategy
  15. * @subpackage AbstractMaterializedPath
  16. * @link http://www.gediminasm.org
  17. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  18. */
  19. abstract class AbstractMaterializedPath implements Strategy
  20. {
  21. /**
  22. * TreeListener
  23. *
  24. * @var AbstractTreeListener
  25. */
  26. protected $listener = null;
  27. /**
  28. * Array of objects which were scheduled for path processes
  29. *
  30. * @var array
  31. */
  32. protected $scheduledForPathProcess = array();
  33. /**
  34. * {@inheritdoc}
  35. */
  36. public function __construct(TreeListener $listener)
  37. {
  38. $this->listener = $listener;
  39. }
  40. /**
  41. * {@inheritdoc}
  42. */
  43. public function getName()
  44. {
  45. return Strategy::MATERIALIZED_PATH;
  46. }
  47. /**
  48. * {@inheritdoc}
  49. */
  50. public function processScheduledUpdate($om, $node, $ea)
  51. {
  52. $meta = $om->getClassMetadata(get_class($node));
  53. $config = $this->listener->getConfiguration($om, $meta->name);
  54. $uow = $om->getUnitOfWork();
  55. $changeSet = $ea->getObjectChangeSet($uow, $node);
  56. if (isset($changeSet[$config['parent']]) || isset($changeSet[$config['path_source']])) {
  57. if (isset($changeSet[$config['path']])) {
  58. $originalPath = $changeSet[$config['path']][0];
  59. } else {
  60. $pathProp = $meta->getReflectionProperty($config['path']);
  61. $pathProp->setAccessible(true);
  62. $originalPath = $pathProp->getValue($node);
  63. }
  64. $this->updateNode($om, $node, $ea);
  65. $this->updateNodesChildren($om, $node, $ea, $originalPath);
  66. }
  67. }
  68. /**
  69. * {@inheritdoc}
  70. */
  71. public function processPostPersist($om, $node, $ea)
  72. {
  73. $this->updateNode($om, $node, $ea);
  74. }
  75. /**
  76. * {@inheritdoc}
  77. */
  78. public function onFlushEnd($om)
  79. {
  80. $this->alreadyProcessedObjects = array();
  81. $this->scheduledForPathProcess = array();
  82. }
  83. /**
  84. * {@inheritdoc}
  85. */
  86. public function processPreRemove($om, $node)
  87. {}
  88. /**
  89. * {@inheritdoc}
  90. */
  91. public function processPrePersist($om, $node)
  92. {}
  93. /**
  94. * {@inheritdoc}
  95. */
  96. public function processMetadataLoad($om, $meta)
  97. {}
  98. /**
  99. * {@inheritdoc}
  100. */
  101. public function processScheduledDelete($om, $node)
  102. {
  103. $meta = $om->getClassMetadata(get_class($node));
  104. $config = $this->listener->getConfiguration($om, $meta->name);
  105. $this->removeNode($om, $meta, $config, $node);
  106. }
  107. /**
  108. * Update the $node
  109. *
  110. * @param ObjectManager $om
  111. * @param object $node - target node
  112. * @param object $ea - event adapter
  113. * @return void
  114. */
  115. public function updateNode(ObjectManager $om, $node, $ea)
  116. {
  117. $oid = spl_object_hash($node);
  118. $meta = $om->getClassMetadata(get_class($node));
  119. $config = $this->listener->getConfiguration($om, $meta->name);
  120. $uow = $om->getUnitOfWork();
  121. $parentProp = $meta->getReflectionProperty($config['parent']);
  122. $parentProp->setAccessible(true);
  123. $parent = $parentProp->getValue($node);
  124. $pathProp = $meta->getReflectionProperty($config['path']);
  125. $pathProp->setAccessible(true);
  126. $pathSourceProp = $meta->getReflectionProperty($config['path_source']);
  127. $pathSourceProp->setAccessible(true);
  128. $path = $pathSourceProp->getValue($node).$config['path_separator'];
  129. if ($parent) {
  130. $changeSet = $uow->isScheduledForUpdate($parent) ? $ea->getObjectChangeSet($uow, $parent) : false;
  131. $pathOrPathSourceHasChanged = $changeSet && (isset($changeSet[$config['path_source']]) || isset($changeSet[$config['path']]));
  132. if ($pathOrPathSourceHasChanged || !$pathProp->getValue($parent)) {
  133. $this->updateNode($om, $parent, $ea);
  134. }
  135. $path = $pathProp->getValue($parent).$path;
  136. }
  137. $pathProp->setValue($node, $path);
  138. $uow->scheduleExtraUpdate($node, array(
  139. $config['path'] => array(null, $path)
  140. ));
  141. $ea->setOriginalObjectProperty($uow, $oid, $config['path'], $path);
  142. }
  143. /**
  144. * Update $node 's children
  145. *
  146. * @param ObjectManager $om
  147. * @param object $node - target node
  148. * @param object $ea - event adapter
  149. * @param mixed $originalPath - original path of object
  150. * @return void
  151. */
  152. public function updateNodesChildren(ObjectManager $om, $node, $ea, $originalPath)
  153. {
  154. $meta = $om->getClassMetadata(get_class($node));
  155. $config = $this->listener->getConfiguration($om, $meta->name);
  156. $children = $this->getChildren($om, $meta, $config, $originalPath);
  157. foreach ($children as $child) {
  158. $this->updateNode($om, $child, $ea);
  159. }
  160. }
  161. }