Tree.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. <?php
  2. namespace mall;
  3. /**
  4. * 树
  5. *
  6. * 0是根结点
  7. */
  8. class Tree
  9. {
  10. var $data = array();
  11. var $child = array(-1 => array());
  12. var $layer = array(0 => 0);
  13. var $parent = array();
  14. var $value_field = '';
  15. /**
  16. * 构造函数
  17. *
  18. * @param mix $value
  19. */
  20. function construct($value = 'root')
  21. {
  22. $this->Tree($value);
  23. }
  24. function Tree($value = 'root')
  25. {
  26. $this->setNode(0, -1, $value);
  27. }
  28. /**
  29. * 构造树
  30. *
  31. * @param array $nodes 结点数组
  32. * @param string $id_field
  33. * @param string $parent_field
  34. * @param string $value_field
  35. */
  36. function setTree($nodes, $id_field, $parent_field, $value_field)
  37. {
  38. $this->value_field = $value_field;
  39. foreach ($nodes as $node)
  40. {
  41. $this->setNode($node[$id_field], $node[$parent_field], $node);
  42. }
  43. $this->setLayer();
  44. }
  45. /**
  46. * 取得options
  47. *
  48. * @param int $layer
  49. * @param int $root
  50. * @param string $space
  51. * @return array (id=>value)
  52. */
  53. function getOptions($layer = 0, $root = 0, $except = NULL, $space = '&nbsp;&nbsp;')
  54. {
  55. $options = array();
  56. $childs = $this->getChilds($root, $except);
  57. foreach ($childs as $id)
  58. {
  59. if ($id > 0 && ($layer <= 0 || $this->getLayer($id) <= $layer))
  60. {
  61. $options[$id] = $this->getLayer($id, $space) . htmlspecialchars($this->getValue($id));
  62. }
  63. }
  64. return $options;
  65. }
  66. /**
  67. * 设置结点
  68. *
  69. * @param mix $id
  70. * @param mix $parent
  71. * @param mix $value
  72. */
  73. function setNode($id, $parent, $value)
  74. {
  75. $parent = $parent ? $parent : 0;
  76. $this->data[$id] = $value;
  77. if (!isset($this->child[$id]))
  78. {
  79. $this->child[$id] = array();
  80. }
  81. if (isset($this->child[$parent]))
  82. {
  83. $this->child[$parent][] = $id;
  84. }
  85. else
  86. {
  87. $this->child[$parent] = array($id);
  88. }
  89. $this->parent[$id] = $parent;
  90. }
  91. /**
  92. * 计算layer
  93. */
  94. function setLayer($root = 0)
  95. {
  96. foreach ($this->child[$root] as $id)
  97. {
  98. $this->layer[$id] = $this->layer[$this->parent[$id]] + 1;
  99. if ($this->child[$id]) $this->setLayer($id);
  100. }
  101. }
  102. /**
  103. * 先根遍历,不包括root
  104. *
  105. * @param array $tree
  106. * @param mix $root
  107. * @param mix $except 除外的结点,用于编辑结点时,上级不能选择自身及子结点
  108. */
  109. function getList(&$tree, $root = 0, $except = NULL)
  110. {
  111. foreach ($this->child[$root] as $id)
  112. {
  113. if ($id == $except)
  114. {
  115. continue;
  116. }
  117. $tree[] = $id;
  118. if ($this->child[$id]) $this->getList($tree, $id, $except);
  119. }
  120. }
  121. function getValue($id)
  122. {
  123. return $this->data[$id][$this->value_field];
  124. }
  125. function getLayer($id, $space = false)
  126. {
  127. return $space ? str_repeat($space, $this->layer[$id]) : $this->layer[$id];
  128. }
  129. function getParent($id)
  130. {
  131. return $this->parent[$id];
  132. }
  133. /**
  134. * 取得祖先,不包括自身
  135. *
  136. * @param mix $id
  137. * @return array
  138. */
  139. function getParents($id)
  140. {
  141. while ($this->parent[$id] != -1)
  142. {
  143. $id = $parent[$this->layer[$id]] = $this->parent[$id];
  144. }
  145. ksort($parent);
  146. reset($parent);
  147. return $parent;
  148. }
  149. function getChild($id)
  150. {
  151. return $this->child[$id];
  152. }
  153. /**
  154. * 取得子孙,包括自身,先根遍历
  155. *
  156. * @param int $id
  157. * @return array
  158. */
  159. function getChilds($id = 0, $except = NULL)
  160. {
  161. $child = array($id);
  162. $this->getList($child, $id, $except);
  163. unset($child[0]);
  164. return $child;
  165. }
  166. /**
  167. * 先根遍历,数组格式
  168. * array(
  169. * array('id' => '', 'value' => '', children => array(
  170. * array('id' => '', 'value' => '', children => array()),
  171. * ))
  172. * )
  173. */
  174. function getArrayList($root = 0 , $layer = NULL)
  175. {
  176. $data = array();
  177. foreach ($this->child[$root] as $id)
  178. {
  179. if($layer && $this->layer[$this->parent[$id]] > $layer-1)
  180. {
  181. continue;
  182. }
  183. $data[] = array('id' => $id, 'value' => $this->getValue($id), 'children' => $this->child[$id] ? $this->getArrayList($id , $layer) : array());
  184. }
  185. return $data;
  186. }
  187. /**
  188. * 取得csv格式数据
  189. *
  190. * @param int $root
  191. * @param mix $ext_field 辅助字段
  192. * @return array(
  193. * array('辅助字段名','主字段名'), //如无辅助字段则无此元素
  194. * array('辅助字段值','一级分类'), //如无辅助字段则无辅助字段值
  195. * array('辅助字段值','一级分类'),
  196. * array('辅助字段值','', '二级分类'),
  197. * array('辅助字段值','', '', '三级分类'),
  198. * )
  199. */
  200. function getCSVData($root = 0, $ext_field = array())
  201. {
  202. $data = array();
  203. $main = $this->value_field; //用于显示树分级结果的字段
  204. $extra =array(); //辅助的字段
  205. if (!empty($ext_field))
  206. {
  207. if (is_array($ext_field))
  208. {
  209. $extra = $ext_field;
  210. }
  211. elseif (is_string($ext_field))
  212. {
  213. $extra = array($ext_field);
  214. }
  215. }
  216. $childs = $this->getChilds($root);
  217. array_values($extra) && $data[0] = array_values($extra);
  218. $main && $data[0] && array_push($data[0], $main);
  219. foreach ($childs as $id)
  220. {
  221. $row = array();
  222. $value = $this->data[$id];
  223. foreach ($extra as $field)
  224. {
  225. $row[] = $value[$field];
  226. }
  227. for ($i = 1; $i < $this->getLayer($id); $i++)
  228. {
  229. $row[] = '';
  230. }
  231. if ($main)
  232. {
  233. $row[] = $value[$main];
  234. }
  235. else
  236. {
  237. $row[] = $value;
  238. }
  239. $data[] = $row;
  240. }
  241. return $data;
  242. }
  243. }
  244. ?>