要进行菜单控制,就需要用到刚才创建的那几个表中的menu表,左侧的导航按照我们的设计应该可以通过权限进行控制,写死的导航不能达到目的,可扩展行还不强,所以菜单控制必须要支持。
需要注意的是,如果你的后台框架中用到了自己的layout,你需要自己去指定,我们这个项目就是,有我们自己的layout,上面再添加admin组件的时候已经添加了:
'layout' => '@app/views/layouts/main_nifty',
然后我们操作菜单列表。添加菜单项,然后在打开layout文件,其实获取菜单的逻辑已经写好了,在MenuHelper中,添加命名空间mdm\admin\components\MenuHelper; 然后注销原来的导航,添加下面的代码,基本上就可以实现权限-用户-导航的控制了。
echo Nav::widget( [ "encodeLabels" => false, "options" => ["class" => "sidebar-menu"], "items" => MenuHelper::getAssignedMenu(Yii::$app->user->id), ] );
好了说完了,最后看一下这个页面:
二、yii-admin优化和重写
在使用的过程中,yii-admin实现的导航权限控制远不能满足我们的需求,并且,这种组件试的开发,每个操作是完全独立的,比如,检查权限,取菜单,取用户信息,每个操作都需要执行SQL来进行下面是正常的检查权限和得到菜单的sql执行过程。其实这个过程是极其费时的,当用户量比较多,菜单比较大,权限表中的数据非常多的时候是不能这样干的,使用我们自己的sql检测工具可以看到,这个过程执行了20条之多的sql语句:
在图中可以看出,权限检查涉及了14次的sql查询,菜单涉及了5次sql查询,如此多的sql 执行一旦上线事没有什么并发可言的。yii-admin这个组件提供了方便的权限控制,菜单控制,但是性能上面我们不敢苟同。查看源码你就知道,这个组件在我看来是一个解耦比较高的组件,每个成分之间可以单独的使用,这就需要每个操作必须要有自己独立的数据库来源,说白了就需要每次都执行sql去取到想要的值,中间很少使用连表查询这样的sql,其实10条sql做的功能,在耦合上网情况下,一条sql就搞定了。
像我这种人是不能忍受这么多不相关的sql执行的,所以我就在根源上面修改了yii-admin的权限检查部分,修改的方法是我自己想的,不一定对,也不一定适合所有的场景,下面就写出来与大家分享。
1、菜单的优化
我们通过查看菜单的生成过程大致会执行了5条以上的sql,这个还算可以,我没有做sql上的优化,原因是我们的菜单是要对应不同的角色和子父级关系,在原来的基础上我添加了一个type来区分是那种角色能看到这种菜单,一级哪种角色对应某一个菜单显示的层级关系。这样管理员,省代用户,客户都会呈现不同的菜单。即使配置相同的权限,不同层级的用户也会看到不同的菜单。
我们的优化是缓存菜单的生成数据,我们这个菜单是定制的,没有采用一开始配置的Nav::widget来呈现,而是我们自己循环层级关系,这样虽然麻烦,但是能很好的提取菜单中我们需要的没一个逻辑,比如:面包屑的自动生成,就可以每次提取菜单的label,再比如子页面,不同控制器下得左导航的高亮,下面是代码,php和html混写了,以后会慢慢的提取。
<ul> <?php $idx = ; $request_url = 'https://www.jb51.net/' . $mod_id . 'https://www.jb51.net/' . $con_id . 'https://www.jb51.net/' . $act_id . 'https://www.jb51.net/'; foreach ($menus_new['list'] as $label => $menu): ?> <?php if (empty($menu['label']) && empty($menu['url'][])) { continue; } ?> <?php if(!isset($menu['items'])):?> <li> <a href="<?php echo $menu['url'][] ?>"> <i></i> <span> <?php echo $menu['label'] ?> </span> </a> <b></b> </li> <?php else:?> <li> <a href="https://www.jb51.net/index.html"data-target="#multi-cols-<?php echo $idx ?>"class="dropdown-toggle"> <i></i> <span> <?php echo $menu['label'] ?> </span> <b></b> </a> <b></b> <ul> <?php foreach ($menu['items'] as $label => $menu): ?> <?php if (empty($menu) || !is_array($menu)) { continue; } if(!isset($menu['items'])):?> <li> <a href="<?php echo $menu['url'][] ?>"> <i></i> <?php echo $menu['label'] ?> </a> <b></b> </li> <?php else:?> <li> <a href="#"> <i></i> <?php echo $menu['label'] ?> <b></b> </a> <b></b> <ul> <?php foreach ($menu['items'] as $label => $url): ?> <?php if (empty($url) || !is_array($url)) { continue; } ?> <li> <a href="<?php echo $url['url'][] ?>"> <i></i> <?php echo $url['label'] ?> </a> <b></b> </li> <?php endforeach ?> </ul> </li> <?php endif?> <?php endforeach ?> </ul> </li> <?php endif?> <?php $idx++; ?> <?php endforeach ?> </ul>