本文針對 Yii2 + AdminLTE + rbac-admin 場景,系統分析 dmstr\widgets\Menu::isItemActive() 預設「全路由匹配」導致子路由不高亮、父選單不展開的問題,提供繼承覆寫的最佳實踐方案,確保升級安全。
['label'=>'角色管理', 'url'=>['role/index'], 'items'=>[['label'=>'新增', 'url'=>['role/create']]]]/role/create → 父項「角色管理」不高亮、子選單不自動展開。
// vendor/dmstr/yii2-adminlte-asset/Menu.php
protected function isItemActive($item)
{
if (isset($item['url']) && is_array($item['url']) && isset($item['url'][0])) {
$route = (array)$item['url'][0]; // ['role/index']
$current = (array)Yii::$app->controller->getRoute(); // ['role/create']
// 逐段嚴格比對:模塊、控制器、動作
if ($route[0] !== $current[0]) return false;
if (isset($route[1]) && $route[1] !== $current[1]) return false;
if (isset($route[2]) && $route[2] !== $current[2]) return false;
return true;
}
return false;
}
因 role/create 與 role/index 動作段不同,判定為非激活。
backend/components/Menu.phpdmstr\widgets\Menu<?php
namespace backend\components;
use dmstr\widgets\Menu as BaseMenu;
use Yii;
class Menu extends BaseMenu
{
protected function isItemActive($item)
{
if (!isset($item['url']) || !is_array($item['url']) || !isset($item['url'][0])) {
return false;
}
$menuRoute = (array)$item['url'][0]; // 選單配置路由
$currentRoute = (array)Yii::$app->controller->getRoute(); // 當前路由
// 僅比對前兩段:模塊、控制器
if ($menuRoute[0] !== $currentRoute[0]) return false; // 模塊不同
if (isset($menuRoute[1], $currentRoute[1]) && $menuRoute[1] !== $currentRoute[1]) {
return false; // 控制器不同
}
return true; // 同一控制器下所有 action 視為激活
}
}
<?php
use backend\components\Menu;
use mdm\admin\components\MenuHelper;
echo Menu::widget([
'options' => ['class' => 'sidebar-menu'],
'items' => MenuHelper::getAssignedMenu(Yii::$app->user->id),
]);
若「權限分配」屬於 permission/index,但需隸屬「角色管理」分組,可在回調中動態標記:
$callback = function ($menu) {
$route = Yii::$app->controller->getRoute();
$permissionRoutes = ['permission/index', 'permission/assign', 'permission/revoke'];
if (in_array($route, $permissionRoutes)) {
foreach ($menu as &$item) {
if (($item['url'][0] ?? '') === 'role/index') {
$item['active'] = true; // 強制激活父項
}
}
}
return $menu;
};
echo Menu::widget([
'items' => MenuHelper::getAssignedMenu(Yii::$app->user->id, null, $callback),
]);
/role/create、/role/update/1、/role/view/1 → 「角色管理」高亮、展開/permission/index → 「權限管理」高亮(或按上述邏輯歸屬角色管理)composer update 後無衝突(未修改 vendor 目錄)通過繼承覆寫單一受保護方法,將激活判定粒度從「動作級」放寬至「控制器級」,完美解決子路由高亮問題,代碼量極小、維護成本極低、升級零風險。