在开发中我们经常会遇到:导航菜单、部门菜单、权限树、评论等功能。
这些功能都有共同的特点:
以导航菜单为例, 将导航菜单设置为动态的, 即从动态加载菜单数据。
CREATE TABLE `SuperUserMenus` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`pid` int(11) NOT NULL COMMENT '父级ID',
`order` int(11) NOT NULL DEFAULT '0' COMMENT '菜单排序',
`title` varchar(100) NOT NULL COMMENT '菜单标题',
`controller` varchar(100) DEFAULT NULL COMMENT '控制器名称',
`method` varchar(100) DEFAULT NULL COMMENT '方法名称',
`ishidden` int(1) NOT NULL DEFAULT '0' COMMENT '是否隐藏:0正常显示,1隐藏',
`status` int(1) NOT NULL DEFAULT '0' COMMENT '状态:0正常,1禁用',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8;
在这里用作分级的表示字段就是pid
,用作查找对应父ID
,一个菜单一方面自己可以具有父ID
,可以有一个父级菜单,另一方面可以用作父级,子级来定义该父级ID
,这样就可以设计无限级菜单,这样设计好处是可以父子级别菜单同表存储,便于遍历显示,但是存储在表中的数据只有对应逻辑,不好在数据库中维护及查看,需要写一下算法进行可视化遍历。
使用算法进行封装读取之后,使得父子关系一目了然,包含关系,如下显示:
array(8) {
[0] => array(9) {
["id"] => int(1)
["pid"] => int(0)
["order"] => int(0)
["title"] => string(18) "超级用户管理"
["controller"] => string(0) ""
["method"] => string(0) ""
["ishidden"] => int(0)
["status"] => int(0)
["children"] => array(1) {
[0] => array(8) {
["id"] => int(3)
["pid"] => int(1)
["order"] => int(0)
["title"] => string(18) "超级用户列表"
["controller"] => string(14) "admin"
["method"] => string(5) "index"
["ishidden"] => int(0)
["status"] => int(0)
}
}
}
}
在这里使用ThinkPHP5
这个框架来进行编写,虽然语言及框架不同,但是思路及使用算法函数都是一样的,首先将对应用户下菜单json
存储数组读取出并进行索引处理:
/**
* 动态菜单显示操作
* @return string
* @throws DataNotFoundException
* @throws ModelNotFoundException
* @throws DbException
*/
public function index()
{
$Super_id = 1;
$menus = false;
$role = Db::table('SuperUser')->where('Super_id', $Super_id)->select();
$role = $role[0];
if ($role) {
$role['rights'] = (isset($role['rights']) && $role['rights']) ? json_decode($role['rights'], true) : [];
}
if ($role['rights']) {
$menus = Db::query('select * from SuperUserMenus where id in(' . implode(',', $role['rights']) . ') and ishidden=0 and status=0');
$menus = $this->_array_column($menus, null, 'id');
$menus && $menus = $this->gettreeitems($menus);
}
return json_encode($menus);
}
之后将ID
作为二维数组中的唯一索引,这里使用array_column
函数,由于这个函数只支持PHP5.5+版本,低版本不支持,我将此函数放在此处:
/**
* PHP5.5+ array_column函数
* @param null $input
* @param null $columnKey
* @param null $indexKey
* @return array|bool|null
*/
public function _array_column($input = null, $columnKey = null, $indexKey = null)
{
// Using func_get_args() in order to check for proper number of
// parameters and trigger errors exactly as the built-in array_column()
// does in PHP 5.5.
$argc = func_num_args();
$params = func_get_args();
if ($argc < 2) {
trigger_error("array_column() expects at least 2 parameters, {$argc} given", E_USER_WARNING);
return null;
}
if (!is_array($params[0])) {
trigger_error(
'array_column() expects parameter 1 to be array, ' . gettype($params[0]) . ' given',
E_USER_WARNING
);
return null;
}
if (!is_int($params[1])
&& !is_float($params[1])
&& !is_string($params[1])
&& $params[1] !== null
&& !(is_object($params[1]) && method_exists($params[1], '__toString'))
) {
trigger_error('array_column(): The column key should be either a string or an integer', E_USER_WARNING);
return false;
}
if (isset($params[2])
&& !is_int($params[2])
&& !is_float($params[2])
&& !is_string($params[2])
&& !(is_object($params[2]) && method_exists($params[2], '__toString'))
) {
trigger_error('array_column(): The index key should be either a string or an integer', E_USER_WARNING);
return false;
}
$paramsInput = $params[0];
$paramsColumnKey = ($params[1] !== null) ? (string)$params[1] : null;
$paramsIndexKey = null;
if (isset($params[2])) {
if (is_float($params[2]) || is_int($params[2])) {
$paramsIndexKey = (int)$params[2];
} else {
$paramsIndexKey = (string)$params[2];
}
}
$resultArray = array();
foreach ($paramsInput as $row) {
$key = $value = null;
$keySet = $valueSet = false;
if ($paramsIndexKey !== null && array_key_exists($paramsIndexKey, $row)) {
$keySet = true;
$key = (string)$row[$paramsIndexKey];
}
if ($paramsColumnKey === null) {
$valueSet = true;
$value = $row;
} elseif (is_array($row) && array_key_exists($paramsColumnKey, $row)) {
$valueSet = true;
$value = $row[$paramsColumnKey];
}
if ($valueSet) {
if ($keySet) {
$resultArray[$key] = $value;
} else {
$resultArray[] = $value;
}
}
}
return $resultArray;
}
最后将数组进行树形分类,将同属于一个父级ID
的子元素归类至children
下:
/**
* 子节点分级显示
* @param $items
* @return array
*/
private function gettreeitems($items)
{
$tree = array();
foreach ($items as $item) {
if (isset($items[$item['pid']])) {
$items[$item['pid']]['children'][] = &$items[$item['id']];
} else {
$tree[] = &$items[$item['id']];
}
}
return $tree;
}
无限级菜单/权限树设计原理就是使用pid
来进行区分父子关系,就是将二维数组进行树形划分来实现。
本文链接:https://cloud.tencent.com/developer/article/1558560
本文采用CC BY-NC-SA 3.0 Unported协议进行许可,转载请保留此文章链接