Module.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | 海豚PHP框架 [ DolphinPHP ]
  4. // +----------------------------------------------------------------------
  5. // | 版权所有 2016~2017 河源市卓锐科技有限公司 [ http://www.zrthink.com ]
  6. // +----------------------------------------------------------------------
  7. // | 官方网站: http://dolphinphp.com
  8. // +----------------------------------------------------------------------
  9. // | 开源协议 ( http://www.apache.org/licenses/LICENSE-2.0 )
  10. // +----------------------------------------------------------------------
  11. namespace app\admin\model;
  12. use think\Model;
  13. use think\facade\Env;
  14. /**
  15. * 模块模型
  16. * @package app\admin\model
  17. */
  18. class Module extends Model
  19. {
  20. // 设置当前模型对应的完整数据表名称
  21. protected $table = '__ADMIN_MODULE__';
  22. // 自动写入时间戳
  23. protected $autoWriteTimestamp = true;
  24. /**
  25. * 获取所有模块的名称和标题
  26. * @author 蔡伟明 <314013107@qq.com>
  27. * @return mixed
  28. */
  29. public static function getModule()
  30. {
  31. $modules = cache('modules');
  32. if (!$modules) {
  33. $modules = self::where('status', '>=', 0)->order('id')->column('name,title');
  34. // 非开发模式,缓存数据
  35. if (config('develop_mode') == 0) {
  36. cache('modules', $modules);
  37. }
  38. }
  39. return $modules;
  40. }
  41. /**
  42. * 获取所有模块信息
  43. * @param string $keyword 查找关键词
  44. * @param string $status 查找状态
  45. * @author 蔡伟明 <314013107@qq.com>
  46. * @return array|bool
  47. */
  48. public function getAll($keyword = '', $status = '')
  49. {
  50. $result = cache('module_all');
  51. if (!$result) {
  52. $dirs = array_map('basename', glob(Env::get('app_path').'*', GLOB_ONLYDIR));
  53. if ($dirs === false || !file_exists(Env::get('app_path'))) {
  54. $this->error = '模块目录不可读或者不存在';
  55. return false;
  56. }
  57. // 不读取模块信息的目录
  58. $except_module = config('system.except_module');
  59. // 正常模块(包括已安装和未安装)
  60. $dirs = array_diff($dirs, $except_module);
  61. // 读取数据库模块表
  62. $modules = $this->order('sort asc,id desc')->column(true, 'name');
  63. // 读取未安装的模块
  64. foreach ($dirs as $module) {
  65. if (!isset($modules[$module])) {
  66. // 获取模块信息
  67. $info = self::getInfoFromFile($module);
  68. $modules[$module]['name'] = $module;
  69. // 模块模块信息缺失
  70. if (empty($info)) {
  71. $modules[$module]['status'] = '-2';
  72. continue;
  73. }
  74. // 模块模块信息不完整
  75. if (!$this->checkInfo($info)) {
  76. $modules[$module]['status'] = '-3';
  77. continue;
  78. }
  79. // 模块未安装
  80. $modules[$module] = $info;
  81. $modules[$module]['status'] = '-1'; // 模块未安装
  82. }
  83. }
  84. // 数量统计
  85. $total = [
  86. 'all' => count($modules), // 所有模块数量
  87. '-2' => 0, // 已损坏数量
  88. '-1' => 0, // 未安装数量
  89. '0' => 0, // 已禁用数量
  90. '1' => 0, // 已启用数量
  91. ];
  92. // 过滤查询结果和统计数量
  93. foreach ($modules as $key => $value) {
  94. // 统计数量
  95. if (in_array($value['status'], ['-2', '-3'])) {
  96. // 已损坏数量
  97. $total['-2']++;
  98. } else {
  99. $total[(string)$value['status']]++;
  100. }
  101. // 过滤查询
  102. if ($status != '') {
  103. if ($status == '-2') {
  104. // 过滤掉非已损坏的模块
  105. if (!in_array($value['status'], ['-2', '-3'])) {
  106. unset($modules[$key]);
  107. continue;
  108. }
  109. } else if ($value['status'] != $status) {
  110. unset($modules[$key]);
  111. continue;
  112. }
  113. }
  114. if ($keyword != '') {
  115. if (stristr($value['name'], $keyword) === false && (!isset($value['title']) || stristr($value['title'], $keyword) === false) && (!isset($value['author']) || stristr($value['author'], $keyword) === false)) {
  116. unset($modules[$key]);
  117. continue;
  118. }
  119. }
  120. }
  121. // 处理状态及模块按钮
  122. foreach ($modules as &$module) {
  123. // 系统核心模块
  124. if (isset($module['system_module']) && $module['system_module'] == '1') {
  125. $module['actions'] = '<button class="btn btn-sm btn-noborder btn-danger" type="button" disabled>不可操作</button>';
  126. $module['status_class'] = 'text-success';
  127. $module['status_info'] = '<i class="fa fa-check"></i> 已启用';
  128. $module['bg_color'] = 'success';
  129. continue;
  130. }
  131. switch ($module['status']) {
  132. case '-3': // 模块信息不完整
  133. $module['title'] = '模块信息不完整';
  134. $module['bg_color'] = 'danger';
  135. $module['status_class'] = 'text-danger';
  136. $module['status_info'] = '<i class="fa fa-times"></i> 已损坏';
  137. $module['actions'] = '<button class="btn btn-sm btn-noborder btn-danger" type="button" disabled>不可操作</button>';
  138. break;
  139. case '-2': // 模块信息缺失
  140. $module['title'] = '模块信息缺失';
  141. $module['bg_color'] = 'danger';
  142. $module['status_class'] = 'text-danger';
  143. $module['status_info'] = '<i class="fa fa-times"></i> 已损坏';
  144. $module['actions'] = '<button class="btn btn-sm btn-noborder btn-danger" type="button" disabled>不可操作</button>';
  145. break;
  146. case '-1': // 未安装
  147. $module['bg_color'] = 'info';
  148. $module['actions'] = '<a class="btn btn-sm btn-noborder btn-success" href="'.url('install', ['name' => $module['name']]).'">安装</a>';
  149. $module['status_class'] = 'text-info';
  150. $module['status_info'] = '<i class="fa fa-fw fa-th-large"></i> 未安装';
  151. break;
  152. case '0': // 禁用
  153. $module['bg_color'] = 'warning';
  154. $module['actions'] = '<a class="btn btn-sm btn-noborder btn-success ajax-get confirm" href="'.url('enable', ['ids' => $module['id']]).'">启用</a> ';
  155. $module['actions'] .= '<a class="btn btn-sm btn-noborder btn-primary" href="'.url('export', ['name' => $module['name']]).'">导出</a> ';
  156. $module['actions'] .= '<a class="btn btn-sm btn-noborder btn-danger" href="'.url('uninstall', ['name' => $module['name']]).'">卸载</a> ';
  157. $module['status_class'] = 'text-warning';
  158. $module['status_info'] = '<i class="fa fa-ban"></i> 已禁用';
  159. break;
  160. case '1': // 启用
  161. $module['bg_color'] = 'success';
  162. $module['actions'] = '<a class="btn btn-sm btn-noborder btn-info ajax-get confirm" href="'.url('update', ['name' => $module['name']]).'">更新</a> ';
  163. $module['actions'] .= '<a class="btn btn-sm btn-noborder btn-warning ajax-get confirm" href="'.url('disable', ['ids' => $module['id']]).'">禁用</a> ';
  164. $module['actions'] .= '<a class="btn btn-sm btn-noborder btn-primary" href="'.url('export', ['name' => $module['name']]).'">导出</a> ';
  165. $module['actions'] .= '<a class="btn btn-sm btn-noborder btn-danger" href="'.url('uninstall', ['name' => $module['name']]).'">卸载</a> ';
  166. $module['status_class'] = 'text-success';
  167. $module['status_info'] = '<i class="fa fa-check"></i> 已启用';
  168. break;
  169. default: // 未知
  170. $module['title'] = '未知';
  171. break;
  172. }
  173. }
  174. $result = ['total' => $total, 'modules' => $modules];
  175. // 非开发模式,缓存数据
  176. if (config('develop_mode') == 0) {
  177. cache('module_all', $result);
  178. }
  179. }
  180. return $result;
  181. }
  182. /**
  183. * 从文件获取模块信息
  184. * @param string $name 模块名称
  185. * @author 蔡伟明 <314013107@qq.com>
  186. * @return array|mixed
  187. */
  188. public static function getInfoFromFile($name = '')
  189. {
  190. $info = [];
  191. if ($name != '') {
  192. // 从配置文件获取
  193. if (is_file(Env::get('app_path'). $name . '/info.php')) {
  194. $info = include Env::get('app_path'). $name . '/info.php';
  195. }
  196. }
  197. return $info;
  198. }
  199. /**
  200. * 检查模块模块信息是否完整
  201. * @param string $info 模块模块信息
  202. * @author 蔡伟明 <314013107@qq.com>
  203. * @return bool
  204. */
  205. private function checkInfo($info = '')
  206. {
  207. $default_item = ['name','title','author','version'];
  208. foreach ($default_item as $item) {
  209. if (!isset($info[$item]) || $info[$item] == '') {
  210. return false;
  211. }
  212. }
  213. return true;
  214. }
  215. /**
  216. * 获取模型配置信息
  217. * @param string $name 模型名
  218. * @param string $item 指定返回的模块配置项
  219. * @author 蔡伟明 <314013107@qq.com>
  220. * @return mixed
  221. */
  222. public static function getConfig($name = '', $item = '')
  223. {
  224. $name = $name == '' ? request()->module() : $name;
  225. $config = cache('module_config_'.$name);
  226. if (!$config) {
  227. $config = self::where('name', $name)->value('config');
  228. if (!$config) {
  229. return [];
  230. }
  231. $config = json_decode($config, true);
  232. // 非开发模式,缓存数据
  233. if (config('develop_mode') == 0) {
  234. cache('module_config_'.$name, $config);
  235. }
  236. }
  237. if (!empty($item)) {
  238. $items = explode(',', $item);
  239. if (count($items) == 1) {
  240. return isset($config[$item]) ? $config[$item] : '';
  241. }
  242. $result = [];
  243. foreach ($items as $item) {
  244. $result[$item] = isset($config[$item]) ? $config[$item] : '';
  245. }
  246. return $result;
  247. }
  248. return $config;
  249. }
  250. /**
  251. * 获取模型配置信息
  252. * @param string $name 插件名.配置名
  253. * @param string $value 配置值
  254. * @author caiweiming <314013107@qq.com>
  255. * @return bool
  256. */
  257. public static function setConfig($name = '', $value = '')
  258. {
  259. $item = '';
  260. if (strpos($name, '.')) {
  261. list($name, $item) = explode('.', $name);
  262. }
  263. // 获取缓存
  264. $config = cache('module_config_'.$name);
  265. if (!$config) {
  266. $config = self::where('name', $name)->value('config');
  267. if (!$config) {
  268. return false;
  269. }
  270. $config = json_decode($config, true);
  271. }
  272. if ($item === '') {
  273. // 批量更新
  274. if (!is_array($value) || empty($value)) {
  275. // 值的格式错误,必须为数组
  276. return false;
  277. }
  278. $config = array_merge($config, $value);
  279. } else {
  280. // 更新单个值
  281. $config[$item] = $value;
  282. }
  283. if (false === self::where('name', $name)->setField('config', json_encode($config))) {
  284. return false;
  285. }
  286. // 非开发模式,缓存数据
  287. if (config('develop_mode') == 0) {
  288. cache('module_config_'.$name, $config);
  289. }
  290. return true;
  291. }
  292. /**
  293. * 从文件获取模块菜单
  294. * @param string $name 模块名称
  295. * @author 蔡伟明 <314013107@qq.com>
  296. * @return array|mixed
  297. */
  298. public static function getMenusFromFile($name = '')
  299. {
  300. $menus = [];
  301. if ($name != '' && is_file(Env::get('app_path'). $name . '/menus.php')) {
  302. // 从菜单文件获取
  303. $menus = include Env::get('app_path'). $name . '/menus.php';
  304. }
  305. return $menus;
  306. }
  307. }