RepositoryUtils.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. <?php
  2. namespace Gedmo\Tree;
  3. use Doctrine\Common\Persistence\Mapping\ClassMetadata;
  4. use Doctrine\Common\Persistence\ObjectManager;
  5. use Gedmo\Exception\InvalidArgumentException;
  6. class RepositoryUtils implements RepositoryUtilsInterface
  7. {
  8. /** @var \Doctrine\Common\Persistence\Mapping\ClassMetadata */
  9. protected $meta;
  10. /** @var \Gedmo\Tree\TreeListener */
  11. protected $listener;
  12. /** @var \Doctrine\Common\Persistence\ObjectManager */
  13. protected $om;
  14. /** @var \Gedmo\Tree\RepositoryInterface */
  15. protected $repo;
  16. public function __construct(ObjectManager $om, ClassMetadata $meta, $listener, $repo)
  17. {
  18. $this->om = $om;
  19. $this->meta = $meta;
  20. $this->listener = $listener;
  21. $this->repo = $repo;
  22. }
  23. public function getClassMetadata()
  24. {
  25. return $this->meta;
  26. }
  27. /**
  28. * {@inheritDoc}
  29. */
  30. public function childrenHierarchy($node = null, $direct = false, array $options = array(), $includeNode = false)
  31. {
  32. $meta = $this->getClassMetadata();
  33. $config = $this->listener->getConfiguration($this->om, $meta->name);
  34. if ($node !== null) {
  35. if ($node instanceof $meta->name) {
  36. $wrapperClass = $this->om instanceof \Doctrine\ORM\EntityManager ?
  37. '\Gedmo\Tool\Wrapper\EntityWrapper' :
  38. '\Gedmo\Tool\Wrapper\MongoDocumentWrapper';
  39. $wrapped = new $wrapperClass($node, $this->om);
  40. if (!$wrapped->hasValidIdentifier()) {
  41. throw new InvalidArgumentException("Node is not managed by UnitOfWork");
  42. }
  43. }
  44. } else {
  45. $includeNode = true;
  46. }
  47. // Gets the array of $node results. It must be ordered by depth
  48. $nodes = $this->repo->getNodesHierarchy($node, $direct, $config, $options, $includeNode);
  49. return $this->buildTree($nodes, $options);
  50. }
  51. /**
  52. * {@inheritDoc}
  53. */
  54. public function buildTree(array $nodes, array $options = array())
  55. {
  56. $meta = $this->getClassMetadata();
  57. $nestedTree = $this->repo->buildTreeArray($nodes);
  58. $default = array(
  59. 'decorate' => false,
  60. 'rootOpen' => '<ul>',
  61. 'rootClose' => '</ul>',
  62. 'childOpen' => '<li>',
  63. 'childClose' => '</li>',
  64. 'nodeDecorator' => function ($node) use ($meta) {
  65. // override and change it, guessing which field to use
  66. if ($meta->hasField('title')) {
  67. $field = 'title';
  68. } elseif ($meta->hasField('name')) {
  69. $field = 'name';
  70. } else {
  71. throw new InvalidArgumentException("Cannot find any representation field");
  72. }
  73. return $node[$field];
  74. }
  75. );
  76. $options = array_merge($default, $options);
  77. // If you don't want any html output it will return the nested array
  78. if (!$options['decorate']) {
  79. return $nestedTree;
  80. }
  81. if (!count($nestedTree)) {
  82. return '';
  83. }
  84. $build = function($tree) use (&$build, &$options) {
  85. $output = is_string($options['rootOpen']) ? $options['rootOpen'] : $options['rootOpen']($tree);
  86. foreach ($tree as $node) {
  87. $output .= is_string($options['childOpen']) ? $options['childOpen'] : $options['childOpen']($node);
  88. $output .= $options['nodeDecorator']($node);
  89. if (count($node['__children']) > 0) {
  90. $output .= $build($node['__children']);
  91. }
  92. $output .= $options['childClose'];
  93. }
  94. return $output . $options['rootClose'];
  95. };
  96. return $build($nestedTree);
  97. }
  98. /**
  99. * {@inheritDoc}
  100. */
  101. public function buildTreeArray(array $nodes)
  102. {
  103. $meta = $this->getClassMetadata();
  104. $config = $this->listener->getConfiguration($this->om, $meta->name);
  105. $nestedTree = array();
  106. $l = 0;
  107. if (count($nodes) > 0) {
  108. // Node Stack. Used to help building the hierarchy
  109. $stack = array();
  110. foreach ($nodes as $child) {
  111. $item = $child;
  112. $item['__children'] = array();
  113. // Number of stack items
  114. $l = count($stack);
  115. // Check if we're dealing with different levels
  116. while($l > 0 && $stack[$l - 1][$config['level']] >= $item[$config['level']]) {
  117. array_pop($stack);
  118. $l--;
  119. }
  120. // Stack is empty (we are inspecting the root)
  121. if ($l == 0) {
  122. // Assigning the root child
  123. $i = count($nestedTree);
  124. $nestedTree[$i] = $item;
  125. $stack[] = &$nestedTree[$i];
  126. } else {
  127. // Add child to parent
  128. $i = count($stack[$l - 1]['__children']);
  129. $stack[$l - 1]['__children'][$i] = $item;
  130. $stack[] = &$stack[$l - 1]['__children'][$i];
  131. }
  132. }
  133. }
  134. return $nestedTree;
  135. }
  136. }