ServiceProvider.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  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\ServiceProvider as LaravelServiceProvider;
  8. use Symfony\Component\Console\Output\NullOutput;
  9. abstract class ServiceProvider extends LaravelServiceProvider
  10. {
  11. const TYPE_THEME = 'theme';
  12. /**
  13. * @var ComposerProperty
  14. */
  15. public $composerProperty;
  16. /**
  17. * @var string
  18. */
  19. protected $name;
  20. /**
  21. * @var string
  22. */
  23. protected $packageName;
  24. /**
  25. * @var string
  26. */
  27. protected $type;
  28. /**
  29. * @var string
  30. */
  31. protected $path;
  32. /**
  33. * @var array
  34. */
  35. protected $js = [];
  36. /**
  37. * @var array
  38. */
  39. protected $css = [];
  40. /**
  41. * @var \Symfony\Component\Console\Output\OutputInterface
  42. */
  43. public $output;
  44. /**
  45. * @var array
  46. */
  47. protected $config;
  48. /**
  49. * @var array
  50. */
  51. protected $middleware = [];
  52. /**
  53. * @var array
  54. */
  55. protected $exceptRoutes = [];
  56. public function __construct($app)
  57. {
  58. parent::__construct($app);
  59. $this->output = new NullOutput();
  60. }
  61. /**
  62. * {@inheritdoc}
  63. */
  64. final public function boot()
  65. {
  66. $this->autoRegister();
  67. if ($this->disabled()) {
  68. return;
  69. }
  70. $this->init();
  71. }
  72. /**
  73. * 初始化操作.
  74. *
  75. * @return void
  76. */
  77. public function init()
  78. {
  79. if ($views = $this->getViewPath()) {
  80. $this->loadViewsFrom($views, $this->getName());
  81. }
  82. if ($lang = $this->getLangPath()) {
  83. $this->loadTranslationsFrom($lang, $this->getName());
  84. }
  85. if ($routes = $this->getRoutes()) {
  86. $this->registerRoutes($routes);
  87. }
  88. if ($this->middleware) {
  89. $this->addMiddleware();
  90. }
  91. if ($this->exceptRoutes) {
  92. $this->addExceptRoutes();
  93. }
  94. $this->aliasAssets();
  95. }
  96. /**
  97. * 自动注册扩展.
  98. */
  99. protected function autoRegister()
  100. {
  101. if (! $this->getName()) {
  102. return;
  103. }
  104. Admin::extension()->addExtension($this);
  105. }
  106. /**
  107. * 获取扩展名称.
  108. *
  109. * @return string|void
  110. */
  111. final public function getName()
  112. {
  113. return $this->name ?: ($this->name = str_replace('/', '.', $this->getPackageName()));
  114. }
  115. /**
  116. * 获取包名.
  117. *
  118. * @return string|void
  119. */
  120. final public function getPackageName()
  121. {
  122. if (! $this->packageName) {
  123. if (! $this->composerProperty) {
  124. return;
  125. }
  126. $this->packageName = $this->composerProperty->name;
  127. }
  128. return $this->packageName;
  129. }
  130. /**
  131. * 获取插件类型.
  132. *
  133. * @return string
  134. */
  135. public function getType()
  136. {
  137. return $this->type;
  138. }
  139. /**
  140. * 获取当前已安装版本.
  141. *
  142. * @return string
  143. */
  144. final public function getVersion()
  145. {
  146. return Admin::extension()->versionManager()->getCurrentVersion($this);
  147. }
  148. /**
  149. * 获取当前最新版本.
  150. *
  151. * @return string
  152. */
  153. final public function getLatestVersion()
  154. {
  155. return Admin::extension()->versionManager()->getFileVersions($this);
  156. }
  157. /**
  158. * 获取当前本地最新版本.
  159. *
  160. * @return string
  161. */
  162. final public function getLocalLatestVersion()
  163. {
  164. return last(
  165. array_keys(Admin::extension()->versionManager()->getFileVersions($this))
  166. );
  167. }
  168. /**
  169. * 获取扩展包路径.
  170. *
  171. * @param string $path
  172. *
  173. * @return string
  174. *
  175. * @throws \ReflectionException
  176. */
  177. public function path(?string $path = null)
  178. {
  179. if (! $this->path) {
  180. $this->path = realpath(dirname((new \ReflectionClass(static::class))->getFileName()).'/..');
  181. if (! is_dir($this->path)) {
  182. throw new RuntimeException("The {$this->path} is not a directory.");
  183. }
  184. }
  185. $path = ltrim($path, '/');
  186. return $path ? $this->path.'/'.$path : $this->path;
  187. }
  188. /**
  189. * 判断扩展是否启用.
  190. *
  191. * @return bool
  192. */
  193. final public function enabled()
  194. {
  195. return Admin::extension()->enabled($this->getName());
  196. }
  197. /**
  198. * 判断扩展是否禁用.
  199. *
  200. * @return bool
  201. */
  202. final public function disabled()
  203. {
  204. return ! $this->enabled();
  205. }
  206. /**
  207. * 获取或保存配置.
  208. *
  209. * @param string $key
  210. * @param null $default
  211. *
  212. * @return mixed
  213. */
  214. final public function config($key = null, $default = null)
  215. {
  216. if ($this->config === null) {
  217. $this->initConfig();
  218. }
  219. if (is_array($key)) {
  220. $this->saveConfig($key);
  221. return;
  222. }
  223. if ($key === null) {
  224. return $this->config;
  225. }
  226. return Arr::get($this->config, $key, $default);
  227. }
  228. /**
  229. * 保存配置.
  230. *
  231. * @param array $config
  232. */
  233. public function saveConfig(array $config)
  234. {
  235. $this->config = array_merge($this->config, $config);
  236. Admin::setting()->save([$this->getConfigKey() => $this->serializeConfig($this->config)]);
  237. }
  238. /**
  239. * 初始化配置.
  240. */
  241. protected function initConfig()
  242. {
  243. $this->config = Admin::setting()->get($this->getConfigKey());
  244. $this->config = $this->config ? $this->unserializeConfig($this->config) : [];
  245. }
  246. /**
  247. * 更新扩展.
  248. */
  249. public function update()
  250. {
  251. }
  252. /**
  253. * 卸载扩展.
  254. */
  255. public function uninstall()
  256. {
  257. }
  258. /**
  259. * 发布静态资源.
  260. */
  261. public function publishable()
  262. {
  263. if ($assets = $this->getAssetPath()) {
  264. $this->publishes([
  265. $assets => $this->getPublishsPath(),
  266. ], $this->getName());
  267. }
  268. }
  269. /**
  270. * 获取资源发布路径.
  271. *
  272. * @return string
  273. */
  274. protected function getPublishsPath()
  275. {
  276. return public_path(
  277. Admin::asset()->getRealPath('@extension/'.str_replace('.', '/', $this->getName()))
  278. );
  279. }
  280. /**
  281. * 注册路由.
  282. *
  283. * @param $callback
  284. */
  285. public function registerRoutes($callback)
  286. {
  287. Admin::app()->routes(function ($router) use ($callback) {
  288. $router->group([
  289. 'prefix' => config('admin.route.prefix'),
  290. 'middleware' => config('admin.route.middleware'),
  291. ], $callback);
  292. });
  293. }
  294. /**
  295. * 注册中间件.
  296. */
  297. protected function addMiddleware()
  298. {
  299. $middleware = (array) config('admin.route.middleware');
  300. $before = $this->middleware['before'] ?? [];
  301. $middle = $this->middleware['middle'] ?? [];
  302. $after = $this->middleware['after'] ?? [];
  303. $this->mixMiddleware($middle);
  304. config([
  305. 'admin.route.middleware' => array_merge((array) $before, $middleware, (array) $after),
  306. ]);
  307. }
  308. protected function mixMiddleware(array $middle)
  309. {
  310. Admin::mixMiddlewareGroup($middle);
  311. }
  312. /**
  313. * 配置需要跳过权限认证和登录认证的路由.
  314. */
  315. protected function addExceptRoutes()
  316. {
  317. if (! empty($this->exceptRoutes['permission'])) {
  318. Admin::context()->addMany('permission.except', (array) $this->exceptRoutes['permission']);
  319. }
  320. if (! empty($this->exceptRoutes['auth'])) {
  321. Admin::context()->addMany('auth.except', (array) $this->exceptRoutes['auth']);
  322. }
  323. }
  324. /**
  325. * 获取静态资源路径.
  326. *
  327. * @return string
  328. */
  329. final public function getAssetPath()
  330. {
  331. return $this->path('resources/assets');
  332. }
  333. /**
  334. * 获取视图路径.
  335. *
  336. * @return string
  337. */
  338. final public function getViewPath()
  339. {
  340. return $this->path('resources/views');
  341. }
  342. /**
  343. * 获取语言包路径.
  344. *
  345. * @return string
  346. */
  347. final public function getLangPath()
  348. {
  349. return $this->path('resources/lang');
  350. }
  351. /**
  352. * 获取路由地址.
  353. *
  354. * @return string
  355. *
  356. * @throws \ReflectionException
  357. */
  358. final public function getRoutes()
  359. {
  360. $path = $this->path('src/Http/routes.php');
  361. return is_file($path) ? $path : null;
  362. }
  363. /**
  364. * @param ComposerProperty $composerProperty
  365. *
  366. * @return $this
  367. */
  368. public function withComposerProperty(ComposerProperty $composerProperty)
  369. {
  370. $this->composerProperty = $composerProperty;
  371. return $this;
  372. }
  373. /**
  374. * 获取或保存配置.
  375. *
  376. * @param string $key
  377. * @param string $value
  378. *
  379. * @return mixed
  380. */
  381. public static function setting($key = null, $value = null)
  382. {
  383. $extension = static::instance();
  384. if ($extension && $extension instanceof ServiceProvider) {
  385. return $extension->config($key, $value);
  386. }
  387. }
  388. /**
  389. * 翻译.
  390. *
  391. * @param string $key
  392. * @param array $replace
  393. * @param null $locale
  394. *
  395. * @return array|string|null
  396. */
  397. public static function trans($key, $replace = [], $locale = null)
  398. {
  399. return trans(static::instance()->getName().'::'.$key, $replace, $locale);
  400. }
  401. /**
  402. * 获取自身实例.
  403. *
  404. * @return $this
  405. */
  406. public static function instance()
  407. {
  408. return app(static::class);
  409. }
  410. /**
  411. * 注册别名.
  412. */
  413. protected function aliasAssets()
  414. {
  415. $asset = Admin::asset();
  416. // 注册静态资源路径别名
  417. $asset->alias($this->getName().'.path', '@extension/'.$this->getPackageName());
  418. if ($this->js || $this->css) {
  419. $asset->alias($this->getName(), [
  420. 'js' => $this->formatAssetFiles($this->js),
  421. 'css' => $this->formatAssetFiles($this->css),
  422. ]);
  423. }
  424. }
  425. /**
  426. * @param string|array $files
  427. *
  428. * @return mixed
  429. */
  430. protected function formatAssetFiles($files)
  431. {
  432. if (is_array($files)) {
  433. return array_map([$this, 'formatAssetFiles'], $files);
  434. }
  435. return '@'.$this->getName().'.path/'.trim($files, '/');
  436. }
  437. /**
  438. * 配置key.
  439. *
  440. * @return mixed
  441. */
  442. protected function getConfigKey()
  443. {
  444. return str_replace('.', ':', $this->getName());
  445. }
  446. /**
  447. * @param $config
  448. *
  449. * @return false|string
  450. */
  451. protected function serializeConfig($config)
  452. {
  453. return json_encode($config);
  454. }
  455. /**
  456. * @param $config
  457. *
  458. * @return array
  459. */
  460. protected function unserializeConfig($config)
  461. {
  462. return json_decode($config, true);
  463. }
  464. }