buildadmin/extend/ba/Tree.php

145 lines
4.5 KiB
PHP
Raw Normal View History

2022-03-08 08:31:49 +00:00
<?php
namespace ba;
/**
2022-10-28 17:03:35 +00:00
*
2022-03-08 08:31:49 +00:00
*/
class Tree
{
/**
* 实例
* @var ?Tree
2022-03-08 08:31:49 +00:00
*/
protected static ?Tree $instance = null;
2022-03-08 08:31:49 +00:00
/**
* 生成树型结构所需修饰符号
* @var array
*/
public static array $icon = array('│', '├', '└');
2022-03-08 08:31:49 +00:00
2022-10-28 17:03:35 +00:00
/**
* 子级数据(树枝)
* @var array
*/
protected array $children = [];
2022-03-20 20:11:23 +00:00
2022-03-08 08:31:49 +00:00
/**
* 初始化
* @access public
* @return Tree
*/
public static function instance(): Tree
{
if (is_null(self::$instance)) {
self::$instance = new static();
}
return self::$instance;
}
/**
2022-10-28 17:03:35 +00:00
* 将数组某个字段渲染为树状,需自备children children可通过$this->assembleChild()方法组装
2022-03-08 08:31:49 +00:00
* @param array $arr 要改为树状的数组
* @param string $field '树枝'字段
* @param int $level 递归数组层次,无需手动维护
* @param bool $superiorEnd 递归上一级树枝是否结束,无需手动维护
2022-03-08 08:31:49 +00:00
* @return array
*/
2022-10-28 17:03:35 +00:00
public static function getTreeArray(array $arr, string $field = 'name', int $level = 0, bool $superiorEnd = false): array
2022-03-08 08:31:49 +00:00
{
$level++;
$number = 1;
$total = count($arr);
foreach ($arr as $key => $item) {
$prefix = ($number == $total) ? self::$icon[2] : self::$icon[1];
if ($level == 2) {
2022-08-23 16:27:21 +00:00
$arr[$key][$field] = str_pad('', 4) . $prefix . $item[$field];
2022-05-05 05:44:23 +00:00
} elseif ($level >= 3) {
2022-08-23 16:27:21 +00:00
$arr[$key][$field] = str_pad('', 4) . ($superiorEnd ? '' : self::$icon[0]) . str_pad('', ($level - 2) * 4) . $prefix . $item[$field];
2022-03-08 08:31:49 +00:00
}
2022-03-24 22:53:39 +00:00
if (isset($item['children']) && $item['children']) {
2022-03-08 08:31:49 +00:00
$arr[$key]['children'] = self::getTreeArray($item['children'], $field, $level, $number == $total);
}
$number++;
}
return $arr;
}
/**
2022-10-28 17:03:35 +00:00
* 递归合并树状数组根据children多维变二维方便渲染
* @param array $data 要合并的数组 ['id' => 1, 'pid' => 0, 'title' => '标题1', 'children' => ['id' => 2, 'pid' => 1, 'title' => ' └标题1-1']]
* @return array [['id' => 1, 'pid' => 0, 'title' => '标题1'], ['id' => 2, 'pid' => 1, 'title' => ' └标题1-1']]
2022-03-08 08:31:49 +00:00
*/
2022-10-28 17:03:35 +00:00
public static function assembleTree(array $data): array
2022-03-08 08:31:49 +00:00
{
$arr = [];
foreach ($data as $v) {
$children = $v['children'] ?? [];
unset($v['children']);
$arr[] = $v;
if ($children) {
$arr = array_merge($arr, self::assembleTree($children));
}
}
return $arr;
}
2022-03-20 20:11:23 +00:00
/**
2022-10-28 17:03:35 +00:00
* 递归的根据指定字段组装 children 数组
2022-03-20 20:31:31 +00:00
* @param array $data 数据源 例如:[['id' => 1, 'pid' => 0, title => '标题1'], ['id' => 2, 'pid' => 1, title => '标题1-1']]
2022-03-20 20:11:23 +00:00
* @param string $pid 存储上级id的字段
2022-10-28 17:03:35 +00:00
* @param string $pk 主键字段
2022-03-20 20:31:31 +00:00
* @return array ['id' => 1, 'pid' => 0, 'title' => '标题1', 'children' => ['id' => 2, 'pid' => 1, 'title' => '标题1-1']]
2022-03-20 20:11:23 +00:00
*/
2022-10-28 17:03:35 +00:00
public function assembleChild(array $data, string $pid = 'pid', string $pk = 'id'): array
2022-03-20 20:11:23 +00:00
{
2022-10-28 17:03:35 +00:00
if (!$data) return [];
2022-03-20 20:11:23 +00:00
$pks = [];
$topLevelData = []; // 顶级数据
$this->children = []; // 置空子级数据
2022-03-20 20:11:23 +00:00
foreach ($data as $item) {
2022-10-28 17:03:35 +00:00
$pks[] = $item[$pk];
// 以pid组成children
$this->children[$item[$pid]][] = $item;
2022-03-20 20:11:23 +00:00
}
2022-10-28 17:03:35 +00:00
// 上级不存在的就是顶级,只获取它们的 children
foreach ($data as $item) {
if (!in_array($item[$pid], $pks)) {
$topLevelData[] = $item;
}
}
if (count($this->children) > 0) {
2022-10-28 17:03:35 +00:00
foreach ($topLevelData as $key => $item) {
$topLevelData[$key]['children'] = $this->getChildren($this->children[$item[$pk]] ?? [], $pk);
2022-10-28 17:03:35 +00:00
}
return $topLevelData;
2022-03-20 20:11:23 +00:00
} else {
return $data;
}
}
2022-10-28 17:03:35 +00:00
/**
* 获取 children 数组
* 辅助 assembleChild 组装 children
* @param array $data
* @param string $pk
* @return array
*/
protected function getChildren(array $data, string $pk = 'id'): array
2022-03-20 20:11:23 +00:00
{
2022-10-28 17:03:35 +00:00
if (!$data) return [];
2022-03-20 20:11:23 +00:00
foreach ($data as $key => $item) {
if (array_key_exists($item[$pk], $this->children)) {
$data[$key]['children'] = $this->getChildren($this->children[$item[$pk]], $pk);
2022-03-20 20:11:23 +00:00
}
}
return $data;
}
2022-03-08 08:31:49 +00:00
}