朱纯树博客
VPS测评推荐网站
cloudacead cloudacead

PHP 无限级菜单/权限树设计与实现

在开发中我们经常会遇到:导航菜单、部门菜单、权限树、评论等功能。
这些功能都有共同的特点:

  1. 有父子关系
  2. 可无限递归

以导航菜单为例, 将导航菜单设置为动态的, 即从动态加载菜单数据。

数据库设计

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
 */
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 

最后将数组进行树形分类,将同属于一个父级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来进行区分父子关系,就是将二维数组进行树形划分来实现。

-End-

文章来源于互联网:PHP 无限级菜单/权限树设计与实现

赞(0) 打赏
未经允许不得转载:VPS测评推荐网站 - 朱纯树博客 » PHP 无限级菜单/权限树设计与实现

评论 19

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. #30

    Your means of describing everything in this paragraph is actually good,
    every one be able to effortlessly understand it,
    Thanks a lot.

  2. #29

    Fine way of telling, and fastidious post to obtain information regarding my presentation subject, which i am going to present in college.

  3. #28

    I feel this is one of the most significant info for me.
    And i’m glad studying your article. However should observation on few basic things, The website style is ideal, the
    articles is in reality nice : D. Excellent process, cheers

  4. #27

    Appreciation to my father who informed me concerning this website, this webpage is actually
    awesome.

    tinyurl.com1周前 (08-03)回复