MenuHelper::getAssignedMenu(Yii::$app->user->id) * ]); * ~~~ * * To reformat returned, provide callback to method. * * ~~~ * $callback = function ($menu) { * $data = eval($menu['data']); * return [ * 'label' => $menu['name'], * 'url' => [$menu['route']], * 'options' => $data, * 'items' => $menu['children'] * ] * ] * } * * $items = MenuHelper::getAssignedMenu(Yii::$app->user->id, null, $callback); * ~~~ * * @author Misbahul D Munir * * @since 1.0 */ class MenuHelper { const CACHE_TAG = 'mdm.admin.menu'; /** * Use to get assigned menu of user. * * @param mixed $userId * @param int $root * @param \Closure $callback use to reformat output. * callback should have format like * * ~~~ * function ($menu) { * return [ * 'label' => $menu['name'], * 'url' => [$menu['route']], * 'options' => $data, * 'items' => $menu['children'] * ] * ] * } * ~~~ * @param bool $refresh * * @return array */ public static function getAssignedMenu($userId, $root = null, $callback = null, $refresh = false) { $config = Configs::instance(); /* @var $manager \yii\rbac\BaseManager */ $manager = Yii::$app->getAuthManager(); $menus = Menu::find()->asArray()->indexBy('id')->all(); $key = [__METHOD__, $userId, $manager->defaultRoles]; $cache = $config->cache; if ($refresh || $cache === null || ($assigned = $cache->get($key)) === false) { $routes = $filter1 = $filter2 = []; if ($userId !== null) { foreach ($manager->getPermissionsByUser($userId) as $name => $value) { if ($name[0] === '/') { if (substr($name, -2) === '/*') { $name = substr($name, 0, -1); } $routes[] = $name; } } } foreach ($manager->defaultRoles as $role) { foreach ($manager->getPermissionsByRole($role) as $name => $value) { if ($name[0] === '/') { if (substr($name, -2) === '/*') { $name = substr($name, 0, -1); } $routes[] = $name; } } } $routes = array_unique($routes); sort($routes); $prefix = '\\'; foreach ($routes as $route) { if (strpos($route, $prefix) !== 0) { if (substr($route, -1) === '/') { $prefix = $route; $filter1[] = $route.'%'; } else { $filter2[] = $route; } } } $assigned = []; $query = Menu::find()->select(['id'])->asArray(); if (count($filter2)) { $assigned = $query->where(['route' => $filter2])->column(); } if (count($filter1)) { $query->where('route like :filter'); foreach ($filter1 as $filter) { $assigned = array_merge($assigned, $query->params([':filter' => $filter])->column()); } } $assigned = static::requiredParent($assigned, $menus); if ($cache !== null) { $cache->set($key, $assigned, $config->cacheDuration, new TagDependency([ 'tags' => self::CACHE_TAG, ])); } } $key = [__METHOD__, $assigned, $root]; if ($refresh || $callback !== null || $cache === null || (($result = $cache->get($key)) === false)) { $result = static::normalizeMenu($assigned, $menus, $callback, $root); if ($cache !== null && $callback === null) { $cache->set($key, $result, $config->cacheDuration, new TagDependency([ 'tags' => self::CACHE_TAG, ])); } } return $result; } /** * 获取navs中第一个有url的nav. * * @param unknown $navs */ public static function getFirstMenu($navs) { foreach ($navs as $nav) { if (array_key_exists('url', $nav) && $nav['url'] != '#') { return $nav; } if (array_key_exists('items', $nav) && count($nav['items']) > 0) { $nav = static::getFirstMenu($nav['items']); if ($nav != null) { return $nav; } } } return; } public static function getSiblingsMenu($label, $navs) { foreach ($navs as $nav) { if($nav['label'] == $label) { return $navs; } if (array_key_exists('items', $nav) && count($nav['items']) > 0) { $n = self::getSiblingsMenu($label, $nav['items']); if (!empty($n)) { return $n; } } } return []; } public static function getRootMenu($nav) { if ($nav['parent'] == null) { return $nav; } $parent = Menu::find()->where(['id' => $nav['parent']])->one(); if ($parent['parent'] != null) { return static::getRootMenu($parent); } else { return $parent; } } /** * Ensure all item menu has parent. * * @param array $assigned * @param array $menus * * @return array */ private static function requiredParent($assigned, &$menus) { $l = count($assigned); for ($i = 0; $i < $l; ++$i) { $id = $assigned[$i]; $parent_id = $menus[$id]['parent']; if ($parent_id !== null && !in_array($parent_id, $assigned)) { $assigned[$l++] = $parent_id; } } return $assigned; } /** * Parse route. * * @param string $route * * @return mixed */ public static function parseRoute($route) { if (!empty($route)) { $url = []; $r = explode('&', $route); $url[0] = $r[0]; unset($r[0]); foreach ($r as $part) { $part = explode('=', $part); $url[$part[0]] = isset($part[1]) ? $part[1] : ''; } return $url; } return '#'; } /** * Normalize menu. * * @param array $assigned * @param array $menus * @param Closure $callback * @param int $parent * * @return array */ private static function normalizeMenu(&$assigned, &$menus, $callback, $parent = null) { $result = []; $order = []; foreach ($assigned as $id) { if(!isset($menus[$id])) { continue; } $menu = $menus[$id]; if ($menu['parent'] == $parent) { $menu['children'] = static::normalizeMenu($assigned, $menus, $callback, $id); if ($callback !== null) { $item = call_user_func($callback, $menu); } else { $item = [ 'label' => $menu['name'], 'url' => static::parseRoute($menu['route']), 'icon' => $menu['icon'] ]; if ($menu['children'] != []) { $item['items'] = $menu['children']; } } $result[] = $item; $order[] = $menu['order']; } } if ($result != []) { array_multisort($order, $result); } return $result; } /** * Use to invalidate cache. */ public static function invalidate() { if (Configs::instance()->cache !== null) { TagDependency::invalidate(Configs::instance()->cache, self::CACHE_TAG); } } }