ExtensionMakeCommand.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. <?php
  2. namespace Dcat\Admin\Console;
  3. use Dcat\Admin\Support\Helper;
  4. use Illuminate\Console\Command;
  5. use Illuminate\Filesystem\Filesystem;
  6. use Illuminate\Support\Str;
  7. class ExtensionMakeCommand extends Command
  8. {
  9. /**
  10. * The console command name.
  11. *
  12. * @var string
  13. */
  14. protected $signature = 'admin:ext-make
  15. {name : The name of the extension. Eg: author-name/extension-name}
  16. {--namespace= : The namespace of the extension.}
  17. {--theme}
  18. ';
  19. /**
  20. * The console command description.
  21. *
  22. * @var string
  23. */
  24. protected $description = 'Build a dcat-admin extension';
  25. /**
  26. * @var string
  27. */
  28. protected $basePath = '';
  29. /**
  30. * @var Filesystem
  31. */
  32. protected $filesystem;
  33. /**
  34. * @var string
  35. */
  36. protected $namespace;
  37. /**
  38. * @var string
  39. */
  40. protected $className;
  41. /**
  42. * @var string
  43. */
  44. protected $extensionName;
  45. /**
  46. * @var string
  47. */
  48. protected $package;
  49. /**
  50. * @var string
  51. */
  52. protected $extensionDir;
  53. /**
  54. * @var array
  55. */
  56. protected $dirs = [
  57. 'updates',
  58. 'resources/assets/css',
  59. 'resources/assets/js',
  60. 'resources/views',
  61. 'resources/lang',
  62. 'src/Models',
  63. 'src/Http/Controllers',
  64. 'src/Http/Middleware',
  65. ];
  66. protected $themeDirs = [
  67. 'updates',
  68. 'resources/assets/css',
  69. 'resources/views',
  70. 'src',
  71. ];
  72. /**
  73. * Execute the console command.
  74. *
  75. * @return void
  76. */
  77. public function handle(Filesystem $filesystem)
  78. {
  79. $this->filesystem = $filesystem;
  80. $this->extensionDir = admin_extension_path();
  81. if (! file_exists($this->extensionDir)) {
  82. $this->makeDir();
  83. }
  84. $this->package = str_replace('.', '/', $this->argument('name'));
  85. $this->extensionName = str_replace('/', '.', $this->package);
  86. $this->basePath = rtrim($this->extensionDir, '/').'/'.ltrim($this->package, '/');
  87. if (is_dir($this->basePath)) {
  88. return $this->error(sprintf('The extension [%s] already exists!', $this->package));
  89. }
  90. InputExtensionName :
  91. if (! Helper::validateExtensionName($this->package)) {
  92. $this->package = $this->ask("[$this->package] is not a valid package name, please input a name like (<vendor>/<name>)");
  93. goto InputExtensionName;
  94. }
  95. $this->makeDirs();
  96. $this->makeFiles();
  97. $this->info("The extension scaffolding generated successfully. \r\n");
  98. $this->showTree();
  99. }
  100. /**
  101. * Show extension scaffolding with tree structure.
  102. */
  103. protected function showTree()
  104. {
  105. if ($this->option('theme')) {
  106. $tree = <<<TREE
  107. {$this->extensionPath()}
  108. ├── README.md
  109. ├── composer.json
  110. ├── version.php
  111. ├── updates
  112. ├── resources
  113. │ ├── lang
  114. │ ├── assets
  115. │ │ └── css
  116. │ │ └── index.css
  117. │   └── views
  118. └── src
  119. ├── {$this->className}ServiceProvider.php
  120. └── Setting.php
  121. TREE;
  122. } else {
  123. $tree = <<<TREE
  124. {$this->extensionPath()}
  125. ├── README.md
  126. ├── composer.json
  127. ├── version.php
  128. ├── updates
  129. ├── resources
  130. │ ├── lang
  131. │ ├── assets
  132. │ │ ├── css
  133. │ │ │ └── index.css
  134. │ │ └── js
  135. │ │ └── index.js
  136. │   └── views
  137. │   └── index.blade.php
  138. └── src
  139. ├── {$this->className}ServiceProvider.php
  140. ├── Setting.php
  141. ├── Models
  142. └── Http
  143. ├── routes.php
  144. ├── Middleware
  145. └── Controllers
  146. └── {$this->className}Controller.php
  147. TREE;
  148. }
  149. $this->info($tree);
  150. }
  151. /**
  152. * Make extension files.
  153. */
  154. protected function makeFiles()
  155. {
  156. $this->namespace = $this->getRootNameSpace();
  157. $this->className = $this->getClassName();
  158. // copy files
  159. $this->copyFiles();
  160. // make composer.json
  161. $composerContents = str_replace(
  162. ['{package}', '{alias}', '{namespace}', '{className}'],
  163. [$this->package, '', str_replace('\\', '\\\\', $this->namespace).'\\\\', $this->className],
  164. file_get_contents(__DIR__.'/stubs/extension/composer.json.stub')
  165. );
  166. $this->putFile('composer.json', $composerContents);
  167. // make composer.json
  168. $settingContents = str_replace(
  169. ['{namespace}'],
  170. [$this->namespace],
  171. file_get_contents(__DIR__.'/stubs/extension/setting.stub')
  172. );
  173. $this->putFile('src/Setting.php', $settingContents);
  174. $basePackage = Helper::slug(basename($this->package));
  175. // make class
  176. $classContents = str_replace(
  177. ['{namespace}', '{className}', '{title}', '{path}', '{basePackage}', '{property}', '{registerTheme}'],
  178. [
  179. $this->namespace,
  180. $this->className,
  181. Str::title($this->className),
  182. $basePackage,
  183. $basePackage,
  184. $this->makeProviderContent(),
  185. $this->makeRegisterThemeContent(),
  186. ],
  187. file_get_contents(__DIR__.'/stubs/extension/extension.stub')
  188. );
  189. $this->putFile("src/{$this->className}ServiceProvider.php", $classContents);
  190. if (! $this->option('theme')) {
  191. // make controller
  192. $controllerContent = str_replace(
  193. ['{namespace}', '{className}', '{name}'],
  194. [$this->namespace, $this->className, $this->extensionName],
  195. file_get_contents(__DIR__.'/stubs/extension/controller.stub')
  196. );
  197. $this->putFile("src/Http/Controllers/{$this->className}Controller.php", $controllerContent);
  198. $viewContents = str_replace(
  199. ['{name}'],
  200. [$this->extensionName],
  201. file_get_contents(__DIR__.'/stubs/extension/view.stub')
  202. );
  203. $this->putFile('resources/views/index.blade.php', $viewContents);
  204. // make routes
  205. $routesContent = str_replace(
  206. ['{namespace}', '{className}', '{path}'],
  207. [$this->namespace, $this->className, $basePackage],
  208. file_get_contents(__DIR__.'/stubs/extension/routes.stub')
  209. );
  210. $this->putFile('src/Http/routes.php', $routesContent);
  211. }
  212. }
  213. protected function makeProviderContent()
  214. {
  215. if (! $this->option('theme')) {
  216. return <<<'TEXT'
  217. protected $js = [
  218. 'js/index.js',
  219. ];
  220. TEXT;
  221. }
  222. return <<<'TEXT'
  223. protected $type = self::TYPE_THEME;
  224. TEXT;
  225. }
  226. protected function makeRegisterThemeContent()
  227. {
  228. if (! $this->option('theme')) {
  229. return;
  230. }
  231. return <<<'TEXT'
  232. Admin::baseCss($this->formatAssetFiles($this->css));
  233. TEXT;
  234. }
  235. protected function copyFiles()
  236. {
  237. $files = [
  238. $view = __DIR__.'/stubs/extension/view.stub' => 'resources/views/index.blade.php',
  239. $js = __DIR__.'/stubs/extension/js.stub' => 'resources/assets/js/index.js',
  240. __DIR__.'/stubs/extension/css.stub' => 'resources/assets/css/index.css',
  241. __DIR__.'/stubs/extension/.gitignore.stub' => '.gitignore',
  242. __DIR__.'/stubs/extension/README.md.stub' => 'README.md',
  243. __DIR__.'/stubs/extension/version.stub' => 'version.php',
  244. ];
  245. if ($this->option('theme')) {
  246. unset($files[$view], $files[$js]);
  247. }
  248. $this->copy($files);
  249. }
  250. /**
  251. * Get root namespace for this package.
  252. *
  253. * @return array|null|string
  254. */
  255. protected function getRootNameSpace()
  256. {
  257. [$vendor, $name] = explode('/', $this->package);
  258. $default = str_replace(['-'], '', Str::title($vendor).'\\'.Str::title($name));
  259. if (! $namespace = $this->option('namespace')) {
  260. $namespace = $this->ask('Root namespace', $default);
  261. }
  262. return $namespace === 'default' ? $default : $namespace;
  263. }
  264. /**
  265. * Get extension class name.
  266. *
  267. * @return string
  268. */
  269. protected function getClassName()
  270. {
  271. return ucfirst(Str::camel(basename($this->package)));
  272. }
  273. /**
  274. * Create package dirs.
  275. */
  276. protected function makeDirs()
  277. {
  278. $this->makeDir($this->option('theme') ? $this->themeDirs : $this->dirs);
  279. }
  280. /**
  281. * Extension path.
  282. *
  283. * @param string $path
  284. *
  285. * @return string
  286. */
  287. protected function extensionPath($path = '')
  288. {
  289. $path = rtrim($path, '/');
  290. if (empty($path)) {
  291. return rtrim($this->basePath, '/');
  292. }
  293. return rtrim($this->basePath, '/').'/'.ltrim($path, '/');
  294. }
  295. /**
  296. * Put contents to file.
  297. *
  298. * @param string $to
  299. * @param string $content
  300. */
  301. protected function putFile($to, $content)
  302. {
  303. $to = $this->extensionPath($to);
  304. $this->filesystem->put($to, $content);
  305. }
  306. /**
  307. * Copy files to extension path.
  308. *
  309. * @param string|array $from
  310. * @param string|null $to
  311. */
  312. protected function copy($from, $to = null)
  313. {
  314. if (is_array($from) && is_null($to)) {
  315. foreach ($from as $key => $value) {
  316. $this->copy($key, $value);
  317. }
  318. return;
  319. }
  320. if (! file_exists($from)) {
  321. return;
  322. }
  323. $to = $this->extensionPath($to);
  324. $this->filesystem->copy($from, $to);
  325. }
  326. /**
  327. * Make new directory.
  328. *
  329. * @param array|string $paths
  330. */
  331. protected function makeDir($paths = '')
  332. {
  333. foreach ((array) $paths as $path) {
  334. $path = $this->extensionPath($path);
  335. $this->filesystem->makeDirectory($path, 0755, true, true);
  336. }
  337. }
  338. }