MenuService.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. <?php
  2. /**
  3. * Author: lf
  4. * Blog: https://blog.feehi.com
  5. * Email: job@feehi.com
  6. * Created at: 2020-01-22 10:38
  7. */
  8. namespace common\services;
  9. use Yii;
  10. use backend\models\search\MenuSearch;
  11. use common\helpers\FileDependencyHelper;
  12. use common\models\Menu;
  13. use yii\base\Exception;
  14. use yii\caching\FileDependency;
  15. use yii\helpers\ArrayHelper;
  16. class MenuService extends Service implements MenuServiceInterface
  17. {
  18. public function getSearchModel(array $options=[])
  19. {
  20. return new MenuSearch();
  21. }
  22. public function getModel($id, array $options = [])
  23. {
  24. return Menu::findOne($id);
  25. }
  26. public function newModel(array $options = [])
  27. {
  28. $menu = new Menu();
  29. $menu->type = Menu::TYPE_BACKEND;
  30. if( isset($options['type'] ) && $options['type']=== Menu::TYPE_FRONTEND){
  31. $menu->type = Menu::TYPE_FRONTEND;
  32. }
  33. $menu->loadDefaultValues();
  34. return $menu;
  35. }
  36. public function getList(array $query = [], array $options = [])
  37. {
  38. if (!isset($options["type"]) || !in_array($options['type'], [Menu::TYPE_BACKEND, Menu::TYPE_FRONTEND])){
  39. throw new Exception("Menu search must set options['type']");
  40. }
  41. $searchModel = $this->getSearchModel();
  42. $options['dataSource'] = $this->getLevelMenusWithPrefixLevelCharacters($options['type']);
  43. $dataProvider = $searchModel->search($query, $options);
  44. return [
  45. 'dataProvider' => $dataProvider,
  46. 'searchModel' => $searchModel,
  47. ];
  48. }
  49. /**
  50. * get authorized backend menus by admin user id
  51. *
  52. * @param $userId
  53. * @return array|mixed|\yii\db\ActiveRecord[]
  54. * @throws \yii\base\InvalidConfigException
  55. */
  56. public function getAuthorizedBackendMenusByUserId($userId)
  57. {
  58. $menus = $this->getMenus(Menu::TYPE_BACKEND, Menu::DISPLAY_YES);
  59. $permissions = Yii::$app->getAuthManager()->getPermissionsByUser($userId);
  60. $permissions = array_keys($permissions);
  61. if (in_array(Yii::$app->getUser()->getId(), Yii::$app->getBehavior('access')->superAdminUserIds)) {
  62. return $menus;//config user ids own all permissions
  63. }
  64. $tempMenus = [];
  65. foreach ($menus as $menu) {
  66. /** @var Menu $menu */
  67. $url = $menu->url;
  68. $temp = @json_decode($menu->url, true);
  69. if ($temp !== null) {//menu url store json format
  70. $url = $temp[0];
  71. }
  72. if (strpos($url, '/') !== 0) $url = '/' . $url;//ensure url must start with '/'
  73. $url = $url . ':GET';
  74. if (in_array($url, $permissions)) {
  75. $menu = $menu->getAncestors($menu->id) + [$menu];
  76. $tempMenus = array_merge($tempMenus, $menu);
  77. }
  78. }
  79. $existMenuIds = [];
  80. $hasPermissionMenus = [];
  81. foreach ($tempMenus as $v) {
  82. /** @var Menu $v */
  83. if( in_array($v->id, $existMenuIds) ) {
  84. continue;
  85. }
  86. $hasPermissionMenus[] = $v;
  87. $existMenuIds[] = $v->id;
  88. }
  89. ArrayHelper::multisort($hasPermissionMenus, 'sort', SORT_ASC);
  90. return $hasPermissionMenus;
  91. }
  92. /**
  93. * set menu name with prefix level characters
  94. *
  95. * @param int $menuType
  96. * @return array
  97. */
  98. public function getLevelMenusWithPrefixLevelCharacters($menuType = Menu::TYPE_BACKEND)
  99. {
  100. $model = $this->newModel(['type' => $menuType]);
  101. $menus = $model->getDescendants(0);
  102. foreach ($menus as $k => $menu) {
  103. /** @var Menu $menu */
  104. if (isset($menus[$k + 1]['level']) && $menus[$k + 1]['level'] == $menu['level']) {
  105. $name = ' ├' . $menu['name'];
  106. } else {
  107. $name = ' └' . $menu['name'];
  108. }
  109. if (end($menus)->id == $menu->id) {
  110. $sign = ' └';
  111. } else {
  112. $sign = ' │';
  113. }
  114. $menu->prefix_level_name = str_repeat($sign, $menu['level'] - 1) . $name;
  115. }
  116. return ArrayHelper::index($menus, 'id');
  117. }
  118. /**
  119. * get menus from cache, if cache not exist then get from storage and set to cache
  120. *
  121. * @param $menuType
  122. * @param $isDisplay
  123. * @return array|mixed|\yii\db\ActiveRecord[]
  124. * @throws \yii\base\InvalidConfigException
  125. */
  126. public function getMenus($menuType=null, $isDisplay=null){
  127. $cacheKey = "menu_" . (string)$menuType . "_" . (string)$isDisplay;
  128. $cache = Yii::$app->getCache();
  129. $menus = $cache->get($cacheKey);
  130. if( $menus === false || !is_array($menus) ){
  131. $cacheDependencyObject = Yii::createObject([
  132. 'class' => FileDependencyHelper::className(),
  133. 'fileName' => Menu::MENU_CACHE_DEPENDENCY_FILE,
  134. ]);
  135. $dependency = [
  136. 'class' => FileDependency::className(),
  137. 'fileName' => $cacheDependencyObject->createFileIfNotExists(),
  138. ];
  139. $menus = $this->getMenusFromStorage($menuType, $isDisplay);
  140. if ( $cache->set($cacheKey, $menus, 60*60, Yii::createObject($dependency)) === false ){
  141. Yii::error(__METHOD__ . " save menu cache error");
  142. }
  143. }
  144. return $menus;
  145. }
  146. /**
  147. * get menus from storage
  148. *
  149. * @param $menuType
  150. * @param $isDisplay
  151. * @return array|\yii\db\ActiveRecord[]
  152. */
  153. public function getMenusFromStorage($menuType=null, $isDisplay=null){
  154. return Menu::getMenus($menuType, $isDisplay);
  155. }
  156. }