ServiceProvider.php 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. <?php
  2. namespace Dcat\Admin\Extend;
  3. use Dcat\Admin\Admin;
  4. use Dcat\Admin\Exception\RuntimeException;
  5. use Dcat\Admin\Support\ComposerProperty;
  6. use Illuminate\Support\Arr;
  7. use Illuminate\Support\Facades\Validator;
  8. use Illuminate\Support\ServiceProvider as LaravelServiceProvider;
  9. use Symfony\Component\Console\Output\NullOutput;
  10. abstract class ServiceProvider extends LaravelServiceProvider
  11. {
  12. /**
  13. * @var ComposerProperty
  14. */
  15. protected $composerProperty;
  16. /**
  17. * @var string
  18. */
  19. protected $name;
  20. /**
  21. * @var string
  22. */
  23. protected $path;
  24. /**
  25. * @var array
  26. */
  27. protected $js = [];
  28. /**
  29. * @var array
  30. */
  31. protected $css = [];
  32. /**
  33. * @var array
  34. */
  35. protected $menu = [];
  36. /**
  37. * @var array
  38. */
  39. protected $permission = [];
  40. /**
  41. * @var array
  42. */
  43. protected $menuValidationRules = [
  44. 'title' => 'required',
  45. 'path' => 'required',
  46. 'icon' => 'required',
  47. ];
  48. /**
  49. * @var array
  50. */
  51. protected $permissionValidationRules = [
  52. 'name' => 'required',
  53. 'slug' => 'required',
  54. 'path' => 'required',
  55. ];
  56. /**
  57. * @var \Symfony\Component\Console\Output\OutputInterface
  58. */
  59. public $output;
  60. public function __construct($app)
  61. {
  62. parent::__construct($app);
  63. $this->output = new NullOutput();
  64. }
  65. /**
  66. * {@inheritdoc}
  67. */
  68. public function boot()
  69. {
  70. if ($views = $this->getViewPath()) {
  71. $this->loadViewsFrom($views, $this->getName());
  72. }
  73. if ($lang = $this->getLangPath()) {
  74. $this->loadTranslationsFrom($lang, $this->getName());
  75. }
  76. if ($routes = $this->getRoutes()) {
  77. return $this->registerRoutes($routes);
  78. }
  79. $this->registerAssets();
  80. }
  81. /**
  82. * 获取扩展名称.
  83. *
  84. * @return string
  85. */
  86. final public function getName()
  87. {
  88. return $this->name ?: ($this->name = str_replace('/', '.', $this->composerProperty->name));
  89. }
  90. /**
  91. * 获取扩展包路径.
  92. *
  93. * @param string $path
  94. *
  95. * @return string
  96. *
  97. * @throws \ReflectionException
  98. */
  99. public function path(?string $path = null)
  100. {
  101. if (! $this->path) {
  102. $this->path = realpath(dirname((new \ReflectionClass(static::class))->getFileName()).'/..');
  103. if (! is_dir($this->path)) {
  104. throw new RuntimeException("The {$this->path} is not a directory.");
  105. }
  106. }
  107. $path = ltrim($path, '/');
  108. return $path ? $this->path.'/'.$path : $this->path;
  109. }
  110. /**
  111. * 判断扩展是否启用.
  112. *
  113. * @return bool
  114. */
  115. final public function enabled()
  116. {
  117. return Admin::extension()->enabled($this->getName());
  118. }
  119. /**
  120. * 判断扩展是否禁用.
  121. *
  122. * @return bool
  123. */
  124. final public function disabled()
  125. {
  126. return ! $this->enabled();
  127. }
  128. /**
  129. * 获取配置.
  130. *
  131. * @param string $key
  132. * @param null $default
  133. *
  134. * @return \Illuminate\Config\Repository|mixed
  135. */
  136. final public function config($key = null, $default = null)
  137. {
  138. return Admin::setting()->get($this->name);
  139. }
  140. /**
  141. * 导入扩展.
  142. */
  143. public function import()
  144. {
  145. $this->importMenus();
  146. $this->importPermissions();
  147. }
  148. /**
  149. * 卸载扩展.
  150. */
  151. public function uninstall()
  152. {
  153. }
  154. /**
  155. * 注册路由.
  156. *
  157. * @param $callback
  158. */
  159. public function registerRoutes($callback)
  160. {
  161. Admin::app()->routes(function ($router) use ($callback) {
  162. $attributes = array_merge(
  163. [
  164. 'prefix' => config('admin.route.prefix'),
  165. 'middleware' => config('admin.route.middleware'),
  166. ]
  167. );
  168. $router->group($attributes, $callback);
  169. });
  170. }
  171. /**
  172. * 获取静态资源路径.
  173. *
  174. * @return string
  175. */
  176. final public function getAssetPath()
  177. {
  178. return $this->path('resources/assets');
  179. }
  180. /**
  181. * 获取视图路径.
  182. *
  183. * @return string
  184. */
  185. final public function getViewPath()
  186. {
  187. return $this->path('resources/views');
  188. }
  189. /**
  190. * 获取语言包路径.
  191. *
  192. * @return string
  193. */
  194. final public function getLangPath()
  195. {
  196. return $this->path('resources/lang');
  197. }
  198. /**
  199. * 获取路由地址.
  200. *
  201. * @return string
  202. *
  203. * @throws \ReflectionException
  204. */
  205. final public function getRoutes()
  206. {
  207. $path = $this->path('src/Http/routes.php');
  208. return is_file($path) ? $path : null;
  209. }
  210. /**
  211. * 获取菜单.
  212. *
  213. * @return array
  214. */
  215. protected function menu()
  216. {
  217. return $this->menu;
  218. }
  219. /**
  220. * @return array
  221. */
  222. protected function permission()
  223. {
  224. return $this->permission;
  225. }
  226. /**
  227. * @param ComposerProperty $composerProperty
  228. *
  229. * @return $this
  230. */
  231. public function withComposerProperty(ComposerProperty $composerProperty)
  232. {
  233. $this->composerProperty = $composerProperty;
  234. return $this;
  235. }
  236. /**
  237. * 导入菜单.
  238. *
  239. * @throws \Exception
  240. */
  241. protected function importMenus()
  242. {
  243. if (! ($menu = $this->menu()) || ! $this->validateMenu($menu)) {
  244. return;
  245. }
  246. extract($menu);
  247. if ($this->checkMenu($path)) {
  248. $this->output->writeln("<warn>Menu [$path] already exists!</warn>");
  249. } else {
  250. $this->createMenu($title, $path, $icon);
  251. $this->output->writeln('<info>Import extension menu succeeded!</info>');
  252. }
  253. }
  254. /**
  255. * 导入权限.
  256. *
  257. * @throws \Exception
  258. */
  259. protected function importPermissions()
  260. {
  261. if (! $this->config('admin.permission.enable')) {
  262. return;
  263. }
  264. if (! ($permission = $this->permission()) || ! $this->validatePermission($permission)) {
  265. return;
  266. }
  267. extract($permission);
  268. if ($this->checkPermission($slug)) {
  269. $this->output->writeln("<warn>Permission [$slug] already exists!</warn>");
  270. } else {
  271. $this->createPermission($name, $slug, $path);
  272. $this->output->writeln('<info>Import extension permission succeeded!</info>');
  273. }
  274. }
  275. /**
  276. * 注册别名.
  277. */
  278. protected function registerAssets()
  279. {
  280. if ($this->js || $this->css) {
  281. Admin::asset()->alias($this->getName(), $this->js, $this->css);
  282. }
  283. }
  284. /**
  285. * 验证菜单.
  286. *
  287. * @param array $menu
  288. *
  289. * @throws \Exception
  290. *
  291. * @return bool
  292. */
  293. protected function validateMenu(array $menu)
  294. {
  295. /** @var \Illuminate\Validation\Validator $validator */
  296. $validator = Validator::make($menu, $this->menuValidationRules);
  297. if ($validator->passes()) {
  298. return true;
  299. }
  300. $message = "Invalid menu:\r\n".implode("\r\n", Arr::flatten($validator->errors()->messages()));
  301. $this->output->writeln("<error>{$message}</error>");
  302. }
  303. /**
  304. * @param $path
  305. *
  306. * @return bool
  307. */
  308. protected function checkMenu($path)
  309. {
  310. $menuModel = config('admin.database.menu_model');
  311. return $result = $menuModel::where('uri', $path)->exists();
  312. }
  313. /**
  314. * 验证权限.
  315. *
  316. * @param array $permission
  317. *
  318. * @throws \Exception
  319. *
  320. * @return bool
  321. */
  322. protected function validatePermission(array $permission)
  323. {
  324. /** @var \Illuminate\Validation\Validator $validator */
  325. $validator = Validator::make($permission, $this->permissionValidationRules);
  326. if ($validator->passes()) {
  327. return true;
  328. }
  329. $message = "Invalid permission:\r\n".implode("\r\n", Arr::flatten($validator->errors()->messages()));
  330. $this->output->writeln("<error>{$message}</error>");
  331. }
  332. /**
  333. * 创建菜单.
  334. *
  335. * @param string $title
  336. * @param string $uri
  337. * @param string $icon
  338. * @param int $parentId
  339. */
  340. protected function createMenu($title, $uri, $icon = 'fa-bars', $parentId = 0)
  341. {
  342. $menuModel = config('admin.database.menu_model');
  343. $lastOrder = $menuModel::max('order');
  344. $menuModel::create([
  345. 'parent_id' => $parentId,
  346. 'order' => $lastOrder + 1,
  347. 'title' => $title,
  348. 'icon' => $icon,
  349. 'uri' => $uri,
  350. ]);
  351. }
  352. /**
  353. * @param $slug
  354. *
  355. * @return bool
  356. */
  357. protected function checkPermission($slug)
  358. {
  359. $permissionModel = config('admin.database.permissions_model');
  360. return $permissionModel::where('slug', $slug)->exists();
  361. }
  362. /**
  363. * 创建权限.
  364. *
  365. * @param $name
  366. * @param $slug
  367. * @param $path
  368. */
  369. protected function createPermission($name, $slug, $path)
  370. {
  371. $permissionModel = config('admin.database.permissions_model');
  372. $permissionModel::create([
  373. 'name' => $name,
  374. 'slug' => $slug,
  375. 'http_path' => trim($path, '/'),
  376. ]);
  377. }
  378. }