IdeHelperCommand.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. <?php
  2. namespace Dcat\Admin\Console;
  3. use Dcat\Admin\Form;
  4. use Dcat\Admin\Grid;
  5. use Dcat\Admin\Show;
  6. use Illuminate\Console\Command;
  7. use Illuminate\Support\Arr;
  8. use Illuminate\Support\Collection;
  9. use Illuminate\Support\Facades\DB;
  10. use Illuminate\Support\Facades\File;
  11. /**
  12. * Class IdeHelperCommand.
  13. *
  14. * @authr jqh <841324345@qq.com>
  15. */
  16. class IdeHelperCommand extends Command
  17. {
  18. /**
  19. * The name and signature of the console command.
  20. *
  21. * @var string
  22. */
  23. protected $signature = 'admin:ide-helper {--c|controller= : Controller class. } ';
  24. /**
  25. * The console command description.
  26. *
  27. * @var string
  28. */
  29. protected $description = 'Create the ide-helper file';
  30. /**
  31. * @var array
  32. */
  33. protected $patterns = [
  34. 'grid' => '/(?:grid)->([\w0-9_]+)(?:\(|;|->|\s)/i',
  35. 'show' => '/show->([\w0-9_]+)(?:\(|;|->|\s)/i',
  36. 'grid-column' => '/@method[\s]+\$this[\s]+([\w0-9_]+)/i',
  37. 'form-field' => '/@method[\s]+[\\\\\w0-9_]+[\s]+([\w0-9_]+)/i',
  38. 'grid-filter' => '/@method[\s]+[\\\\\w0-9_]+[\s]+([\w0-9_]+)/i',
  39. ];
  40. /**
  41. * @var array
  42. */
  43. protected $templates = [
  44. 'grid' => [
  45. 'method' => '* @method Grid\Column|Collection %s(string $label = null)',
  46. 'property' => '* @property Grid\Column|Collection %s',
  47. ],
  48. 'show' => [
  49. 'method' => '* @method Show\Field|Collection %s(string $label = null)',
  50. 'property' => '* @property Show\Field|Collection %s',
  51. ],
  52. 'form' => '* @method %s %s(...$params)',
  53. 'grid-column' => '* @method $this %s(...$params)',
  54. 'grid-filter' => '* @method %s %s(...$params)',
  55. 'show-column' => '* @method $this %s(...$params)',
  56. ];
  57. protected $path = 'dcat_admin_ide_helper.php';
  58. /**
  59. * Execute the console command.
  60. */
  61. public function handle()
  62. {
  63. if (! config('app.debug')) {
  64. $this->error('Permission deny!');
  65. return;
  66. }
  67. if (is_file($bootstrap = admin_path('bootstrap.php'))) {
  68. require $bootstrap;
  69. }
  70. $builders = $this->getBuilderMethods();
  71. // Get all fields.
  72. $fields = $this->getFieldsFromControllerFiles($builders)
  73. ->merge($this->getFieldsFromDatabase($builders))
  74. ->unique();
  75. $this->write($fields);
  76. $path = basename($this->path);
  77. $this->info("The helper file [$path] created successfully.");
  78. }
  79. /**
  80. * @param array $reject
  81. *
  82. * @return Collection
  83. */
  84. protected function getFieldsFromDatabase(array $reject = [])
  85. {
  86. $databases = Arr::where(config('database.connections', []), function ($value) {
  87. $supports = ['mysql'];
  88. return in_array(strtolower(Arr::get($value, 'driver')), $supports);
  89. });
  90. $exceptTables = [
  91. 'migrations',
  92. 'phinxlog',
  93. ];
  94. $data = collect();
  95. try {
  96. foreach ($databases as $connectName => $value) {
  97. $sql = sprintf('SELECT * FROM information_schema.columns WHERE table_schema = "%s"', $value['database']);
  98. $each = collect(DB::connection($connectName)->select($sql))
  99. ->map(function ($v) use ($exceptTables, &$reject) {
  100. $v = (array) $v;
  101. if (in_array($v['TABLE_NAME'], $exceptTables) || in_array($v['COLUMN_NAME'], $reject)) {
  102. return;
  103. }
  104. return $v['COLUMN_NAME'];
  105. })
  106. ->filter();
  107. $data = $data->merge($each);
  108. }
  109. } catch (\Throwable $e) {
  110. }
  111. return $data->unique();
  112. }
  113. /**
  114. * @param array $reject
  115. *
  116. * @return Collection
  117. */
  118. protected function getFieldsFromControllerFiles(array $reject = [])
  119. {
  120. $option = $this->option('controller');
  121. return $this->getAllControllers()
  122. ->merge(explode(',', $option))
  123. ->map(function ($controller) use (&$reject) {
  124. if (! $controller || ! $content = $this->getClassContent($controller)) {
  125. return [];
  126. }
  127. preg_match_all($this->patterns['grid'], $content, $grid);
  128. preg_match_all($this->patterns['show'], $content, $show);
  129. $grid = $grid[1];
  130. $show = $show[1];
  131. return collect(array_merge($grid, $show))->reject(function ($name) use (&$reject) {
  132. return in_array($name, $reject);
  133. });
  134. })
  135. ->flatten()
  136. ->unique()
  137. ->filter();
  138. }
  139. /**
  140. * @param Collection $fields
  141. */
  142. protected function write(Collection $fields)
  143. {
  144. $content = str_replace(
  145. [
  146. '{grid}',
  147. '{show}',
  148. '{form}',
  149. '{grid-column}',
  150. '{grid-filter}',
  151. '{show-column}',
  152. ],
  153. [
  154. $this->generate('grid', $fields),
  155. $this->generate('show', $fields),
  156. $this->generateFormFields(),
  157. $this->generateGridColumns(),
  158. $this->generateGridFilters(),
  159. $this->generateShowFields(),
  160. ],
  161. File::get($this->getStub())
  162. );
  163. File::put(base_path($this->path), $content);
  164. }
  165. /**
  166. * @param string $type
  167. * @param Collection $fields
  168. *
  169. * @return string
  170. */
  171. public function generate(string $type, Collection $fields)
  172. {
  173. $methods = $properties = [];
  174. $space = str_repeat(' ', 5);
  175. $fields->each(function ($name) use ($type, &$methods, &$properties, $space) {
  176. $properties[] = $space.sprintf($this->templates[$type]['property'], $name);
  177. $methods[] = $space.sprintf($this->templates[$type]['method'], $name);
  178. });
  179. return trim(implode("\r\n", array_merge($properties, [$space.'*'], $methods)));
  180. }
  181. /**
  182. * @return string
  183. */
  184. protected function generateGridFilters()
  185. {
  186. $content = $this->getClassContent(Grid\Filter::class);
  187. preg_match_all($this->patterns['grid-filter'], $content, $fields);
  188. $reject = $fields[1];
  189. $fields = collect(Grid\Filter::extensions())->reject(function ($value, $key) use (&$reject) {
  190. return in_array($key, $reject);
  191. });
  192. $space = str_repeat(' ', 5);
  193. return trim(
  194. $fields
  195. ->map(function ($value, $key) use (&$space) {
  196. return $space.sprintf($this->templates['grid-filter'], '\\'.$value, $key);
  197. })
  198. ->implode("\r\n")
  199. );
  200. }
  201. /**
  202. * @return string
  203. */
  204. protected function generateShowFields()
  205. {
  206. $extensions = collect(Show\Field::extensions());
  207. $space = str_repeat(' ', 5);
  208. return trim(
  209. $extensions
  210. ->map(function ($value, $key) use (&$space) {
  211. return $space.sprintf($this->templates['show-column'], $key);
  212. })
  213. ->implode("\r\n")
  214. );
  215. }
  216. /**
  217. * @return string
  218. */
  219. protected function generateFormFields()
  220. {
  221. $content = $this->getClassContent(Form::class);
  222. preg_match_all($this->patterns['form-field'], $content, $fields);
  223. $reject = $fields[1];
  224. $fields = collect(Form::extensions())->reject(function ($value, $key) use (&$reject) {
  225. return in_array($key, $reject);
  226. });
  227. $space = str_repeat(' ', 5);
  228. return trim(
  229. $fields
  230. ->map(function ($value, $key) use (&$space) {
  231. return $space.sprintf($this->templates['form'], '\\'.$value, $key);
  232. })
  233. ->implode("\r\n")
  234. );
  235. }
  236. /**
  237. * @return string
  238. */
  239. protected function generateGridColumns()
  240. {
  241. $content = $this->getClassContent(Grid\Column::class);
  242. preg_match_all($this->patterns['grid-column'], $content, $column);
  243. $reject = $column[1];
  244. $columns = collect(array_keys(Grid\Column::extensions()))->reject(function ($displayer) use (&$reject) {
  245. return in_array($displayer, $reject);
  246. });
  247. $space = str_repeat(' ', 5);
  248. return trim(
  249. $columns
  250. ->map(function ($value) use (&$space) {
  251. return $space.sprintf($this->templates['grid-column'], $value);
  252. })
  253. ->implode("\r\n")
  254. );
  255. }
  256. /**
  257. * @return array
  258. */
  259. protected function getBuilderMethods()
  260. {
  261. $grid = new \ReflectionClass(Grid::class);
  262. $grids = collect($grid->getMethods())
  263. ->pluck('name')
  264. ->merge(collect($grid->getProperties())->pluck('name'))
  265. ->all();
  266. $show = new \ReflectionClass(Show::class);
  267. return collect($show->getMethods())
  268. ->pluck('name')
  269. ->merge(collect($show->getProperties())->pluck('name'))
  270. ->merge($grids)
  271. ->unique()
  272. ->all();
  273. }
  274. /**
  275. * @return string
  276. */
  277. protected function getStub()
  278. {
  279. return __DIR__.'/stubs/ide-helper.stub';
  280. }
  281. /**
  282. * Get all registered controllers.
  283. *
  284. * @return Collection
  285. */
  286. public function getAllControllers()
  287. {
  288. return collect(\Route::getRoutes())->map(function ($route) {
  289. try {
  290. $action = $route->getActionName();
  291. if ($action == 'Closure') {
  292. return;
  293. }
  294. return explode('@', $action)[0];
  295. } catch (\Exception $e) {
  296. }
  297. })->filter();
  298. }
  299. public function getClassContent($class)
  300. {
  301. if ($file = $this->getFileNameByClass($class)) {
  302. return File::get($file);
  303. }
  304. }
  305. /**
  306. * @param string $class
  307. *
  308. * @return string
  309. */
  310. public function getFileNameByClass($class)
  311. {
  312. if (! class_exists($class)) {
  313. return;
  314. }
  315. return (new \ReflectionClass($class))->getFileName();
  316. }
  317. }