Menu.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. <?php
  2. namespace app\common\library;
  3. use app\admin\model\AuthRule;
  4. use fast\Tree;
  5. use think\addons\Service;
  6. use think\Db;
  7. use think\Exception;
  8. use think\exception\PDOException;
  9. class Menu
  10. {
  11. /**
  12. * 创建菜单
  13. * @param array $menu
  14. * @param mixed $parent 父类的name或pid
  15. */
  16. public static function create($menu = [], $parent = 0)
  17. {
  18. $old = [];
  19. self::menuUpdate($menu, $old, $parent);
  20. //菜单刷新处理
  21. $info = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1];
  22. preg_match('/addons\\\\([a-z0-9]+)\\\\/i', $info['class'], $matches);
  23. if ($matches && isset($matches[1])) {
  24. Menu::refresh($matches[1], $menu);
  25. }
  26. }
  27. /**
  28. * 删除菜单
  29. * @param string $name 规则name
  30. * @return boolean
  31. */
  32. public static function delete($name)
  33. {
  34. $ids = self::getAuthRuleIdsByName($name);
  35. if (!$ids) {
  36. return false;
  37. }
  38. AuthRule::destroy($ids);
  39. return true;
  40. }
  41. /**
  42. * 启用菜单
  43. * @param string $name
  44. * @return boolean
  45. */
  46. public static function enable($name)
  47. {
  48. $ids = self::getAuthRuleIdsByName($name);
  49. if (!$ids) {
  50. return false;
  51. }
  52. AuthRule::where('id', 'in', $ids)->update(['status' => 'normal']);
  53. return true;
  54. }
  55. /**
  56. * 禁用菜单
  57. * @param string $name
  58. * @return boolean
  59. */
  60. public static function disable($name)
  61. {
  62. $ids = self::getAuthRuleIdsByName($name);
  63. if (!$ids) {
  64. return false;
  65. }
  66. AuthRule::where('id', 'in', $ids)->update(['status' => 'hidden']);
  67. return true;
  68. }
  69. /**
  70. * 升级菜单
  71. * @param string $name 插件名称
  72. * @param array $menu 新菜单
  73. * @return bool
  74. */
  75. public static function upgrade($name, $menu)
  76. {
  77. $ids = self::getAuthRuleIdsByName($name);
  78. $old = AuthRule::where('id', 'in', $ids)->select();
  79. $old = collection($old)->toArray();
  80. $old = array_column($old, null, 'name');
  81. Db::startTrans();
  82. try {
  83. self::menuUpdate($menu, $old);
  84. $ids = [];
  85. foreach ($old as $index => $item) {
  86. if (!isset($item['keep'])) {
  87. $ids[] = $item['id'];
  88. }
  89. }
  90. if ($ids) {
  91. //旧版本的菜单需要做删除处理
  92. $config = Service::config($name);
  93. $menus = $config['menus'] ?? [];
  94. $where = ['id' => ['in', $ids]];
  95. if ($menus) {
  96. //必须是旧版本中的菜单,可排除用户自主创建的菜单
  97. $where['name'] = ['in', $menus];
  98. }
  99. AuthRule::where($where)->delete();
  100. }
  101. Db::commit();
  102. } catch (PDOException $e) {
  103. Db::rollback();
  104. return false;
  105. }
  106. Menu::refresh($name, $menu);
  107. return true;
  108. }
  109. /**
  110. * 刷新插件菜单配置缓存
  111. * @param string $name
  112. * @param array $menu
  113. */
  114. public static function refresh($name, $menu = [])
  115. {
  116. if (!$menu) {
  117. // $menu为空时表示首次安装,首次安装需刷新插件菜单标识缓存
  118. $menuIds = Menu::getAuthRuleIdsByName($name);
  119. $menus = Db::name("auth_rule")->where('id', 'in', $menuIds)->column('name');
  120. } else {
  121. // 刷新新的菜单缓存
  122. $getMenus = function ($menu) use (&$getMenus) {
  123. $result = [];
  124. foreach ($menu as $index => $item) {
  125. $result[] = $item['name'];
  126. $result = array_merge($result, isset($item['sublist']) && is_array($item['sublist']) ? $getMenus($item['sublist']) : []);
  127. }
  128. return $result;
  129. };
  130. $menus = $getMenus($menu);
  131. }
  132. //刷新新的插件核心菜单缓存
  133. Service::config($name, ['menus' => $menus]);
  134. }
  135. /**
  136. * 导出指定名称的菜单规则
  137. * @param string $name
  138. * @return array
  139. */
  140. public static function export($name)
  141. {
  142. $ids = self::getAuthRuleIdsByName($name);
  143. if (!$ids) {
  144. return [];
  145. }
  146. $menuList = [];
  147. $menu = AuthRule::getByName($name);
  148. if ($menu) {
  149. $ruleList = collection(AuthRule::where('id', 'in', $ids)->select())->toArray();
  150. $menuList = Tree::instance()->init($ruleList)->getTreeArray($menu['id']);
  151. }
  152. return $menuList;
  153. }
  154. /**
  155. * 菜单升级
  156. * @param array $newMenu
  157. * @param array $oldMenu
  158. * @param int $parent
  159. * @throws Exception
  160. */
  161. private static function menuUpdate($newMenu, &$oldMenu, $parent = 0)
  162. {
  163. if (!is_numeric($parent)) {
  164. $parentRule = AuthRule::getByName($parent);
  165. $pid = $parentRule ? $parentRule['id'] : 0;
  166. } else {
  167. $pid = $parent;
  168. }
  169. $allow = array_flip(['file', 'name', 'title', 'url', 'icon', 'condition', 'remark', 'ismenu', 'menutype', 'extend', 'weigh', 'status']);
  170. foreach ($newMenu as $k => $v) {
  171. $hasChild = isset($v['sublist']) && $v['sublist'];
  172. $data = array_intersect_key($v, $allow);
  173. $data['ismenu'] = $data['ismenu'] ?? ($hasChild ? 1 : 0);
  174. $data['icon'] = $data['icon'] ?? ($hasChild ? 'fa fa-list' : 'fa fa-circle-o');
  175. $data['pid'] = $pid;
  176. $data['status'] = $data['status'] ?? 'normal';
  177. if (!isset($oldMenu[$data['name']])) {
  178. $menu = AuthRule::create($data);
  179. } else {
  180. $menu = $oldMenu[$data['name']];
  181. //更新旧菜单
  182. AuthRule::update($data, ['id' => $menu['id']]);
  183. $oldMenu[$data['name']]['keep'] = true;
  184. }
  185. if ($hasChild) {
  186. self::menuUpdate($v['sublist'], $oldMenu, $menu['id']);
  187. }
  188. }
  189. }
  190. /**
  191. * 根据名称获取规则IDS
  192. * @param string $name
  193. * @return array
  194. */
  195. public static function getAuthRuleIdsByName($name)
  196. {
  197. $ids = [];
  198. $menu = AuthRule::getByName($name);
  199. if ($menu) {
  200. // 必须将结果集转换为数组
  201. $ruleList = collection(AuthRule::order('weigh', 'desc')->field('id,pid,name')->select())->toArray();
  202. // 构造菜单数据
  203. $ids = Tree::instance()->init($ruleList)->getChildrenIds($menu['id'], true);
  204. }
  205. return $ids;
  206. }
  207. }