IdeHelperCommand.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  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 = 'Make 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. * @return Collection
  82. */
  83. protected function getFieldsFromDatabase(array $reject = [])
  84. {
  85. $databases = Arr::where(config('database.connections', []), function ($value) {
  86. $supports = ['mysql'];
  87. return in_array(strtolower(Arr::get($value, 'driver')), $supports);
  88. });
  89. $exceptTables = [
  90. 'migrations',
  91. 'phinxlog',
  92. ];
  93. $data = collect();
  94. try {
  95. foreach ($databases as $connectName => $value) {
  96. $sql = sprintf('SELECT * FROM information_schema.columns WHERE table_schema = "%s"', $value['database']);
  97. $each = collect(DB::connection($connectName)->select($sql))
  98. ->map(function ($v) use ($value, $exceptTables, &$reject) {
  99. $v = (array)$v;
  100. if (in_array($v['TABLE_NAME'], $exceptTables) || in_array($v['COLUMN_NAME'], $reject)) {
  101. return;
  102. }
  103. return $v['COLUMN_NAME'];
  104. })
  105. ->filter();
  106. $data = $data->merge($each);
  107. }
  108. } catch (\Throwable $e) {
  109. }
  110. return $data->unique();
  111. }
  112. /**
  113. * @param array $reject
  114. * @return Collection
  115. */
  116. protected function getFieldsFromControllerFiles(array $reject = [])
  117. {
  118. $option = $this->option('controller');
  119. return $this->getAllControllers()
  120. ->merge(explode(',', $option))
  121. ->map(function ($controller) use (&$reject) {
  122. if (!$controller || !$content = $this->getClassContent($controller)) {
  123. return [];
  124. }
  125. preg_match_all($this->patterns['grid'], $content, $grid);
  126. preg_match_all($this->patterns['show'], $content, $show);
  127. $grid = $grid[1];
  128. $show = $show[1];
  129. return collect(array_merge($grid, $show))->reject(function ($name) use (&$reject) {
  130. return in_array($name, $reject);
  131. });
  132. })
  133. ->flatten()
  134. ->unique()
  135. ->filter();
  136. }
  137. /**
  138. * @param Collection $fields
  139. */
  140. protected function write(Collection $fields)
  141. {
  142. $content = str_replace(
  143. [
  144. '{grid}',
  145. '{show}',
  146. '{form}',
  147. '{grid-column}',
  148. '{grid-filter}',
  149. '{show-column}',
  150. ],
  151. [
  152. $this->generate('grid', $fields),
  153. $this->generate('show', $fields),
  154. $this->generateFormFields(),
  155. $this->generateGridColumns(),
  156. $this->generateGridFilters(),
  157. $this->generateShowFields(),
  158. ],
  159. File::get($this->getStub())
  160. );
  161. File::put(app_path($this->path), $content);
  162. }
  163. /**
  164. * @param string $type
  165. * @param Collection $fields
  166. * @return string
  167. */
  168. public function generate(string $type, Collection $fields)
  169. {
  170. $methods = $properties = [];
  171. $space = str_repeat(' ', 5);
  172. $fields->each(function ($name) use ($type, &$methods, &$properties, $space) {
  173. $properties[] = $space.sprintf($this->templates[$type]['property'], $name);
  174. $methods[] = $space.sprintf($this->templates[$type]['method'], $name);
  175. });
  176. return trim(join("\r\n", array_merge($properties, [$space.'*'], $methods)));
  177. }
  178. /**
  179. * @return string
  180. */
  181. protected function generateGridFilters()
  182. {
  183. $content = $this->getClassContent(Grid\Filter::class);
  184. preg_match_all($this->patterns['grid-filter'], $content, $fields);
  185. $reject = $fields[1];
  186. $fields = collect(Grid\Filter::getExtensions())->reject(function ($value, $key) use (&$reject) {
  187. return in_array($key, $reject);
  188. });
  189. $space = str_repeat(' ', 5);
  190. return trim(
  191. $fields
  192. ->map(function ($value, $key) use (&$space) {
  193. return $space.sprintf($this->templates['grid-filter'], '\\'.$value, $key);
  194. })
  195. ->join("\r\n")
  196. );
  197. }
  198. /**
  199. * @return string
  200. */
  201. protected function generateShowFields()
  202. {
  203. $extensions = collect(Show\Field::getExtensions());
  204. $space = str_repeat(' ', 5);
  205. return trim(
  206. $extensions
  207. ->map(function ($value, $key) use (&$space) {
  208. return $space.sprintf($this->templates['show-column'], $key);
  209. })
  210. ->join("\r\n")
  211. );
  212. }
  213. /**
  214. * @return string
  215. */
  216. protected function generateFormFields()
  217. {
  218. $content = $this->getClassContent(Form::class);
  219. preg_match_all($this->patterns['form-field'], $content, $fields);
  220. $reject = $fields[1];
  221. $fields = collect(Form::getExtensions())->reject(function ($value, $key) use (&$reject) {
  222. return in_array($key, $reject);
  223. });
  224. $space = str_repeat(' ', 5);
  225. return trim(
  226. $fields
  227. ->map(function ($value, $key) use (&$space) {
  228. return $space.sprintf($this->templates['form'], '\\'.$value, $key);
  229. })
  230. ->join("\r\n")
  231. );
  232. }
  233. /**
  234. * @return string
  235. */
  236. protected function generateGridColumns()
  237. {
  238. $content = $this->getClassContent(Grid\Column::class);
  239. preg_match_all($this->patterns['grid-column'], $content, $column);
  240. $reject = $column[1];
  241. $columns = collect(array_keys(Grid\Column::getExtensions()))->reject(function ($displayer) use (&$reject) {
  242. return in_array($displayer, $reject);
  243. });
  244. $space = str_repeat(' ', 5);
  245. return trim(
  246. $columns
  247. ->map(function ($value) use (&$space) {
  248. return $space.sprintf($this->templates['grid-column'], $value);
  249. })
  250. ->join("\r\n")
  251. );
  252. }
  253. /**
  254. * @return array
  255. */
  256. protected function getBuilderMethods()
  257. {
  258. $grid = new \ReflectionClass(Grid::class);
  259. $grids = collect($grid->getMethods())
  260. ->pluck('name')
  261. ->merge(collect($grid->getProperties())->pluck('name'))
  262. ->all();
  263. $show = new \ReflectionClass(Show::class);
  264. return collect($show->getMethods())
  265. ->pluck('name')
  266. ->merge(collect($show->getProperties())->pluck('name'))
  267. ->merge($grids)
  268. ->unique()
  269. ->all();
  270. }
  271. /**
  272. * @return string
  273. */
  274. protected function getStub()
  275. {
  276. return __DIR__.'/stubs/ide-helper.stub';
  277. }
  278. /**
  279. * Get all registered controllers.
  280. *
  281. * @return Collection
  282. */
  283. public function getAllControllers()
  284. {
  285. return collect(\Route::getRoutes())->map(function ($route) {
  286. try {
  287. $action = $route->getActionName();
  288. if ($action == 'Closure') {
  289. return null;
  290. }
  291. return explode('@', $action)[0];
  292. } catch (\Exception $e) {
  293. }
  294. })->filter();
  295. }
  296. public function getClassContent($class)
  297. {
  298. if ($file = $this->getFileNameByClass($class)) {
  299. return File::get($file);
  300. }
  301. }
  302. /**
  303. * @param $class
  304. * @return string
  305. */
  306. public function getFileNameByClass($class)
  307. {
  308. if (!class_exists($class)) {
  309. return null;
  310. }
  311. return (new \ReflectionClass($class))->getFileName();
  312. }
  313. }