Tree.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. <?php
  2. namespace app\common\command;
  3. class Tree
  4. {
  5. private static $formatTree;//用于树型数组完成递归格式的全局变量
  6. /**
  7. * @param $arr
  8. * @param int $root
  9. * @return array
  10. * @author: hhygyl
  11. * @name: DeepTree
  12. * @describe:格式化数据
  13. */
  14. public static function DeepTree($arr, $child = "children", $root = 0)
  15. {
  16. if (empty($arr)) return [];
  17. $OriginalList = $arr;
  18. $tree = [];//最终数组
  19. $refer = [];//存储主键与数组单元的引用关系
  20. //遍历
  21. foreach ($OriginalList as $k => $v) {
  22. if (!isset($v['id']) || !isset($v['pid']) || isset($v[$child])) {
  23. unset($OriginalList[$k]);
  24. continue;
  25. }
  26. $refer[$v['id']] =& $OriginalList[$k];//为每个数组成员建立引用关系
  27. }
  28. //遍历2
  29. foreach ($OriginalList as $k => $v) {
  30. if ($v['pid'] == $root) {//根分类直接添加引用到tree中
  31. $tree[] =& $OriginalList[$k];
  32. } else {
  33. if (isset($refer[$v['pid']])) {
  34. $parent =& $refer[$v['pid']];//获取父分类的引用
  35. $parent[$child][] =& $OriginalList[$k];//在父分类的children中再添加一个引用成员
  36. }
  37. }
  38. }
  39. return $tree;
  40. }
  41. /**
  42. * @param $menu
  43. * @param int $id
  44. * @param int $level
  45. * @return array
  46. * @author: hhygyl <hhygyl520@qq.com>
  47. * @name: menulist
  48. * @describe:菜单格式化
  49. */
  50. public static function menulist($menu, $id = 0, $level = 0)
  51. {
  52. static $menus = array();
  53. $size = count($menus) - 1;
  54. foreach ($menu as $value) {
  55. if ($value['pid'] == $id) {
  56. $value['level'] = $level + 1;
  57. if ($level == 0) {
  58. $value['str'] = str_repeat('', $value['level']);
  59. $menus[] = $value;
  60. } elseif ($level == 2) {
  61. $value['str'] = '&emsp;&emsp;&emsp;&emsp;' . '└ ';
  62. $menus[$size]['list'][] = $value;
  63. } elseif ($level == 3) {
  64. $value['str'] = '&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;' . '└ ';
  65. $menus[$size]['list'][] = $value;
  66. } else {
  67. $value['str'] = '&emsp;&emsp;' . '└ ';
  68. $menus[$size]['list'][] = $value;
  69. }
  70. self::menulist($menu, $value['id'], $value['level']);
  71. }
  72. }
  73. return $menus;
  74. }
  75. /**
  76. * @param $data
  77. * @param int $pid
  78. * @param StringService $field
  79. * @param StringService $pk
  80. * @param StringService $html
  81. * @param int $level
  82. * @param bool $clear
  83. * @return array
  84. * @author: hhygyl
  85. * @name: sortListTier
  86. * @describe: 选择树形结构
  87. */
  88. public static function sortListTier($data, $pid = 0, $field = 'pid', $pk = 'id', $html = '|----', $level = 0, $clear = true)
  89. {
  90. static $list = [];
  91. if ($clear) $list = [];
  92. foreach ($data as $k => $res) {
  93. if ($res[$field] == $pid) {
  94. $res['html'] = str_repeat($html, $level) . $res['title'];
  95. $res['level'] = $level;
  96. $list[] = $res;
  97. unset($data[$k]);
  98. self::sortListTier($data, $res[$pk], $field, $pk, $html, $level + 1, false);
  99. }
  100. }
  101. return $list;
  102. }
  103. /**
  104. * @param $data
  105. * @param string $title
  106. * @param int $pid
  107. * @param string $field
  108. * @param string $pk
  109. * @param string $html
  110. * @param int $level
  111. * @param bool $clear
  112. * @return array
  113. * @author: Hhy <jackhhy520@qq.com>
  114. * @describe:
  115. */
  116. public static function SortTree($data,$title='name',$pid=0,$field='pid',$pk = 'id', $html = '|----', $level = 0, $clear = true){
  117. static $list = [];
  118. if ($clear) $list = [];
  119. foreach ($data as $k => $res) {
  120. if ($res[$field] == $pid) {
  121. $res['html'] = str_repeat($html, $level) . $res[$title];
  122. $res['level'] = $level;
  123. $list[] = $res;
  124. unset($data[$k]);
  125. self::SortTree($data, $title,$res[$pk], $field, $pk, $html, $level + 1, false);
  126. }
  127. }
  128. return $list;
  129. }
  130. /**
  131. * @param $data
  132. * @param int $pid
  133. * @param string $field
  134. * @param string $pk
  135. * @param int $level
  136. * @return array
  137. * @author: Hhy <jackhhy520@qq.com>
  138. * @describe:
  139. */
  140. public static function addLevelTree($data, $pid = 0, $field = 'pid', $pk = 'id', $level = 0){
  141. if (empty($data)) return [];
  142. static $list = [];
  143. foreach ($data as $k => $res) {
  144. if ($res[$field] == $pid) {
  145. $res['level'] = $level;
  146. $list[] = $res;
  147. unset($data[$k]);
  148. self::addLevelTree($data, $res[$pk], $field, $pk, $level + 1);
  149. }
  150. }
  151. return $list;
  152. }
  153. /**
  154. * @param $list
  155. * @param StringService $pk
  156. * @param StringService $pid
  157. * @param StringService $child
  158. * @param int $root
  159. * @return array
  160. * @author: hhygyl
  161. * @name: listToTree
  162. * @describe:把返回的数据集转换成Tree
  163. */
  164. public static function listToTree($list, $pk = 'id', $pid = 'pid', $child = '_child', $root = 0)
  165. {
  166. // 创建Tree
  167. $tree = [];
  168. if (is_array($list)) {
  169. // 创建基于主键的数组引用
  170. $refer = array();
  171. foreach ($list as $key => $data) {
  172. $refer[$data[$pk]] =& $list[$key];
  173. }
  174. foreach ($list as $key => $data) {
  175. // 判断是否存在parent
  176. $parentId = $data[$pid];
  177. if ($root == $parentId) {
  178. $tree[] =& $list[$key];
  179. } else {
  180. if (isset($refer[$parentId])) {
  181. $parent =& $refer[$parentId];
  182. $parent['childs'][] = $data[$pk];
  183. $parent[$child][] =& $list[$key];
  184. }
  185. }
  186. }
  187. }
  188. return $tree;
  189. }
  190. /**
  191. * 将树子节点加层级成列表
  192. */
  193. protected static function _toFormatTree($tree, $level = 1)
  194. {
  195. foreach ($tree as $key => $value) {
  196. $temp = $value;
  197. if (isset($temp['_child'])) {
  198. $temp['_child'] = true;
  199. $temp['level'] = $level;
  200. } else {
  201. $temp['_child'] = false;
  202. $temp['level'] = $level;
  203. }
  204. array_push(self::$formatTree, $temp);
  205. if (isset($value['_child'])) {
  206. self::_toFormatTree($value['_child'], ($level + 1));
  207. }
  208. }
  209. }
  210. /**
  211. * @param $cat
  212. * @param $next_parentid
  213. * @param StringService $pid
  214. * @param StringService $empty
  215. * @return StringService
  216. * @author: hhygyl
  217. * @name: catEmptyDeal
  218. * @describe:
  219. */
  220. public static function catEmptyDeal($cat, $next_parentid, $pid = 'pid', $empty = " ")
  221. {
  222. $str = "";
  223. if ($cat[$pid]) {
  224. for ($i = 2; $i < $cat['level']; $i++) {
  225. $str .= $empty . "│";
  226. }
  227. if ($cat[$pid] != $next_parentid && !$cat['_child']) {
  228. $str .= $empty . "└─ ";
  229. } else {
  230. $str .= $empty . "├─ ";
  231. }
  232. }
  233. return $str;
  234. }
  235. /**
  236. * @param $list
  237. * @param StringService $title
  238. * @param StringService $pk
  239. * @param StringService $pid
  240. * @param int $root
  241. * @return array|bool
  242. * @author: hhygyl
  243. * @name: toFormatTree
  244. * @describe:转换成树
  245. */
  246. public static function toFormatTree($list, $title = 'title', $pk = 'id', $pid = 'pid', $root = 0)
  247. {
  248. if (empty($list)) {
  249. return false;
  250. }
  251. $list = self::listToTree($list, $pk, $pid, '_child', $root);
  252. //dump($list);
  253. self::$formatTree = $data = [];
  254. self::_toFormatTree($list);
  255. foreach (self::$formatTree as $key => $value) {
  256. $index = ($key + 1);
  257. $next_parentid = isset(self::$formatTree[$index][$pid]) ? self::$formatTree[$index][$pid] : '';
  258. $value['level_show'] = self::catEmptyDeal($value, $next_parentid);
  259. $value['title_show'] = $value['level_show'] . $value[$title];
  260. $data[] = $value;
  261. }
  262. return $data;
  263. }
  264. /**
  265. * @param $data
  266. * @param int $pid
  267. * @param StringService $field
  268. * @param StringService $pk
  269. * @param int $level
  270. * @return array
  271. * @author: hhygyl
  272. * @name: getChindNode
  273. * @describe:分级返回多维数组
  274. */
  275. public static function getChindNode($data, $pid = 0, $field = 'pid', $pk = 'id', $level = 1)
  276. {
  277. static $list = [];
  278. foreach ($data as $k => $res) {
  279. if ($res['pid'] == $pid) {
  280. $list[] = $res;
  281. unset($data[$k]);
  282. self::getChindNode($data, $res['id'], $field, $pk, $level + 1);
  283. }
  284. }
  285. return $list;
  286. }
  287. /**
  288. * @param $data
  289. * @param $pid
  290. * @param string $field
  291. * @param string $pk
  292. * @return array
  293. * @author: hhygyl <hhygyl520@qq.com>
  294. * @name: getChildrenPid
  295. * @describe:分级返回下级所有分类ID
  296. */
  297. public static function getChildrenPid($data, $pid, $field = 'pid', $pk = 'id')
  298. {
  299. static $pids = [];
  300. foreach ($data as $k => $res) {
  301. if ($res[$field] == $pid) {
  302. $pids[] = $res[$pk];
  303. self::getChildrenPid($data, $res[$pk], $field, $pk);
  304. }
  305. }
  306. return $pids;
  307. }
  308. /**
  309. * @param $list
  310. * @param string $id
  311. * @param string $pid
  312. * @param string $son
  313. * @return array|mixed
  314. * @author: LuckyHhy <jackhhy520@qq.com>
  315. * @name: arr2tree
  316. * @describe:一维数据数组生成数据树
  317. */
  318. public static function arr2tree($list, $id = 'id', $pid = 'pid', $son = 'sub')
  319. {
  320. list($tree, $map) = [[], []];
  321. foreach ($list as $item) $map[$item[$id]] = $item;
  322. foreach ($list as $item) if (isset($item[$pid]) && isset($map[$item[$pid]])) {
  323. $map[$item[$pid]][$son][] = &$map[$item[$id]];
  324. } else $tree[] = &$map[$item[$id]];
  325. unset($map);
  326. return $tree;
  327. }
  328. /**
  329. * 一维数据数组生成数据树
  330. * @param array $list 数据列表
  331. * @param string $id ID Key
  332. * @param string $pid 父ID Key
  333. * @param string $path
  334. * @param string $ppath
  335. * @return array
  336. * @author: LuckyHhy <jackhhy520@qq.com>
  337. * @name: arr2tree
  338. * @describe:一维数据数组生成数据树
  339. */
  340. public static function arr2table(array $list, $id = 'id', $pid = 'pid', $path = 'path', $ppath = '')
  341. {
  342. $tree = [];
  343. foreach (self::arr2tree($list, $id, $pid) as $attr) {
  344. $attr[$path] = "{$ppath}-{$attr[$id]}";
  345. $attr['sub'] = isset($attr['sub']) ? $attr['sub'] : [];
  346. $attr['spt'] = substr_count($ppath, '-');
  347. $attr['spl'] = str_repeat(" ├ ", $attr['spt']);
  348. $sub = $attr['sub'];
  349. unset($attr['sub']);
  350. $tree[] = $attr;
  351. if (!empty($sub)) $tree = array_merge($tree, self::arr2table($sub, $id, $pid, $path, $attr[$path]));
  352. }
  353. return $tree;
  354. }
  355. }