fork download
  1. <?php
  2.  
  3. class Tree
  4. {
  5. const FORMAT_TEXT = 0;
  6. const FORMAT_HTML = 1;
  7.  
  8. protected $rootIds;
  9.  
  10. protected $template;
  11.  
  12. /** @var array Template, indexed by nodes ids */
  13. protected $nodes;
  14.  
  15. protected $adjacencyList;
  16.  
  17.  
  18. public function __construct($template)
  19. {
  20. $this->setTemplate($template);
  21. }
  22.  
  23. public function setTemplate($template)
  24. {
  25. $this->template = $template;
  26. $this->nodes = $this->getNodes($template);
  27. $this->rootIds = $this->getRootIds($template);
  28. $this->adjacencyList = $this->buildAdjacencyList($template);
  29. }
  30.  
  31. public function format($format)
  32. {
  33. $output = '';
  34.  
  35. foreach ($this->rootIds as $rootId) {
  36. $this->walkTree($this->nodes[$rootId], $output, $format);
  37. }
  38.  
  39. return $output;
  40. }
  41.  
  42. public function __toString()
  43. {
  44. $this->format(static::FORMAT_TEXT);
  45. }
  46.  
  47. protected function buildAdjacencyList($template)
  48. {
  49. $adjacencyList = [];
  50.  
  51. foreach ($template as $node) {
  52. if ($node['parentId'] !== null) {
  53. if (isset($adjacencyList[$node['parentId']])) {
  54. $adjacencyList[$node['parentId']][] = $node['id'];
  55. } else {
  56. $adjacencyList[$node['parentId']] = [$node['id']];
  57. }
  58. }
  59. }
  60.  
  61. return $adjacencyList;
  62. }
  63.  
  64. protected function getNodes($template)
  65. {
  66. $nodes = [];
  67.  
  68. foreach ($template as $node) {
  69. $nodes[$node['id']] = $node;
  70. }
  71.  
  72. return $nodes;
  73. }
  74.  
  75. protected function getRootIds($template)
  76. {
  77. $rootIds = [];
  78.  
  79. foreach ($template as $node) {
  80. if ($node['parentId'] === null) {
  81. $rootIds[] = $node['id'];
  82. }
  83. }
  84.  
  85. if ($rootIds !== []) {
  86. return $rootIds;
  87. } else {
  88. throw new Exception('Parent node do not exists.');
  89. }
  90. }
  91.  
  92. protected function walkTree($node, &$output, $format, $depth = 0)
  93. {
  94. switch ($format) {
  95. case Tree::FORMAT_TEXT:
  96. $output .= $this->formatNodeAsText($node['text'], $depth);
  97. break;
  98. case Tree::FORMAT_HTML:
  99. $output .= $this->formatNodeAsHtml($node['text'], $depth);
  100. break;
  101. default:
  102. $output .= $this->formatNodeAsText($node['text'], $depth);
  103. }
  104. $depth += 1;
  105.  
  106. if (isset($this->adjacencyList[$node['id']])) {
  107. foreach ($this->adjacencyList[$node['id']] as $childId) {
  108. $this->walkTree($this->nodes[$childId], $output, $format, $depth);
  109. }
  110. }
  111. }
  112.  
  113. protected function formatNodeAsText($nodeText, $depth)
  114. {
  115. return str_repeat(' ', $depth) . $nodeText . "\r\n";
  116. }
  117.  
  118. protected function formatNodeAsHtml($nodeText, $depth)
  119. {
  120. return '<p class="offset-' . $depth . '">' . $nodeText . '</p>';
  121. }
  122. }
  123.  
  124. $template = array(
  125. array("id" => 1, "parentId" => null, "text" => "Первая строка"),
  126. array("id" => 2, "parentId" => 3, "text" => "Вторая строка"),
  127. array("id" => 3, "parentId" => 1, "text" => "Третья строка"),
  128. array("id" => 4, "parentId" => 1, "text" => "Четвертая строка"),
  129.  
  130. array("id" => 5, "parentId" => null, "text" => "Пятая строка"),
  131. array("id" => 6, "parentId" => 5, "text" => "Шестая строка")
  132. );
  133.  
  134. $tree = new Tree($template);
  135. echo $tree->format(Tree::FORMAT_TEXT);
Success #stdin #stdout 0.02s 24448KB
stdin
Standard input is empty
stdout
Первая строка
    Третья строка
        Вторая строка
    Четвертая строка
Пятая строка
    Шестая строка