现有如下表结构可以构造多级分类
CREATE TABLE `navs` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT ,
`name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '名称' ,
`created_at` int(11) UNSIGNED NULL DEFAULT NULL ,
`pid` int(11) UNSIGNED NULL DEFAULT 0 COMMENT '父ID支持二级分类' ,
`deep` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 COMMENT '区域深度'
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
COMMENT='分类表'
;
需要在列表中获取所有记录按照层级依附的顺序排列。考虑到分类元素记录个数有限,可以全部遍历出来,这个时候需要适当格式化。
//获取全部记录
function all() {
$sql = '';
if ($_GET['pid']) {
$sql.=' WHERE pid='.intval($_GET['pid']);
}
$rows = DB::fetch_all("SELECT * FROM " . DB::table('navs').$sql);
return $rows;
}
//格式化记录
function allSelect($pid=0) {
$rows = all();
$rows = formatTreeToArray($rows,$pid);
return $rows;
}
通过先将集合转换为树结构,然后将树结构转换为列表 可以得到有序相邻的集合
//格式化树结构成列表信息
function formatTreeToArray($data,$pid=0) {
if ($pid>0) {
$row = C::t('navs')->fetch($pid);
if (!$row){
return [];
}
//取相对深度
$deep = $row['deep'] - $data[0]['deep'];
} else {
//从根节点开始算深度
$deep = $data[0]['deep'];
}
$list = [];
foreach ($data as $k => &$v) {
$pre_str = '';
if ($v['deep']>=2) {
for ($i=0; $i < $v['deep']-1; $i++) {
$pre_str.="——";
}
$pre_str.="|";
}
$v['format_name'] = $pre_str.$v['name'];
$list[$v['id']] = $v;
unset($v);
}
//转换成树结构
$list = generateTree($list);
//找到特定的那一分支
if ($pid>0) {
$target_data = [];
findTargetTree($list,$pid,$target_data);
$list = [$target_data];
}
//递归元素 转换成数组并列
$data = [];
treeToArr($list,$data);
return $data;
}
//将数据库记录集返回的数组转换成树结构
function generateTree($items){
$tree = array();
foreach($items as $item){
if(isset($items[$item['pid']])){
$items[$item['pid']]['son'][] = &$items[$item['id']];
}else{
$tree[] = &$items[$item['id']];
}
}
return $tree;
}
//递归将树转换为列表 保证能够使得子元素能够与上层元素相邻
function treeToArr($items,&$data) {
foreach ($items as $k => $v) {
$son = $v['son'];
unset($v['son']);
$data[] = $v;
if ($son) {
treeToArr($son,$data);
}
}
}
//找到指定父节点的旁支
function findTargetTree($data,$pid,&$targetdata) {
foreach ($data as $k => $v) {
if ($v['id']==$pid) {
$targetdata = $v;
} else {
findTargetTree($v['son'],$pid,$targetdata);
}
}
}