ScaffoldController.php 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. <?php
  2. namespace Dcat\Admin\Http\Controllers;
  3. use Dcat\Admin\Admin;
  4. use Dcat\Admin\Http\Auth\Permission;
  5. use Dcat\Admin\Layout\Content;
  6. use Dcat\Admin\Scaffold\ControllerCreator;
  7. use Dcat\Admin\Scaffold\LangCreator;
  8. use Dcat\Admin\Scaffold\MigrationCreator;
  9. use Dcat\Admin\Scaffold\ModelCreator;
  10. use Dcat\Admin\Scaffold\RepositoryCreator;
  11. use Dcat\Admin\Support\Helper;
  12. use Illuminate\Http\Request;
  13. use Illuminate\Routing\Controller;
  14. use Illuminate\Support\Arr;
  15. use Illuminate\Support\Facades\Artisan;
  16. use Illuminate\Support\Facades\DB;
  17. use Illuminate\Support\Facades\URL;
  18. use Illuminate\Support\MessageBag;
  19. use Illuminate\Support\Str;
  20. class ScaffoldController extends Controller
  21. {
  22. public static $dbTypes = [
  23. 'string', 'integer', 'text', 'float', 'double', 'decimal', 'boolean', 'date', 'time',
  24. 'dateTime', 'timestamp', 'char', 'mediumText', 'longText', 'tinyInteger', 'smallInteger',
  25. 'mediumInteger', 'bigInteger', 'unsignedTinyInteger', 'unsignedSmallInteger', 'unsignedMediumInteger',
  26. 'unsignedInteger', 'unsignedBigInteger', 'enum', 'json', 'jsonb', 'dateTimeTz', 'timeTz',
  27. 'timestampTz', 'nullableTimestamps', 'binary', 'ipAddress', 'macAddress',
  28. ];
  29. public static $dataTypeMap = [
  30. 'int' => 'integer',
  31. 'int@unsigned' => 'unsignedInteger',
  32. 'tinyint' => 'tinyInteger',
  33. 'tinyint@unsigned' => 'unsignedTinyInteger',
  34. 'smallint' => 'smallInteger',
  35. 'smallint@unsigned' => 'unsignedSmallInteger',
  36. 'mediumint' => 'mediumInteger',
  37. 'mediumint@unsigned' => 'unsignedMediumInteger',
  38. 'bigint' => 'bigInteger',
  39. 'bigint@unsigned' => 'unsignedBigInteger',
  40. 'date' => 'date',
  41. 'time' => 'time',
  42. 'datetime' => 'dateTime',
  43. 'timestamp' => 'timestamp',
  44. 'enum' => 'enum',
  45. 'json' => 'json',
  46. 'binary' => 'binary',
  47. 'float' => 'float',
  48. 'double' => 'double',
  49. 'decimal' => 'decimal',
  50. 'varchar' => 'string',
  51. 'char' => 'char',
  52. 'text' => 'text',
  53. 'mediumtext' => 'mediumText',
  54. 'longtext' => 'longText',
  55. ];
  56. public function index(Content $content)
  57. {
  58. if (! config('app.debug')) {
  59. Permission::error();
  60. }
  61. if ($tableName = request('singular')) {
  62. return $this->singular($tableName);
  63. }
  64. Admin::requireAssets('select2');
  65. Admin::requireAssets('sortable');
  66. $dbTypes = static::$dbTypes;
  67. $dataTypeMap = static::$dataTypeMap;
  68. $action = URL::current();
  69. $tables = collect($this->getDatabaseColumns())->map(function ($v) {
  70. return array_keys($v);
  71. })->toArray();
  72. return $content
  73. ->title(trans('admin.scaffold.header'))
  74. ->description(' ')
  75. ->body(view(
  76. 'admin::helpers.scaffold',
  77. compact('dbTypes', 'action', 'tables', 'dataTypeMap')
  78. ));
  79. }
  80. protected function singular($tableName)
  81. {
  82. return [
  83. 'status' => 1,
  84. 'value' => Str::singular($tableName),
  85. ];
  86. }
  87. public function store(Request $request)
  88. {
  89. if (! config('app.debug')) {
  90. Permission::error();
  91. }
  92. $paths = [];
  93. $message = '';
  94. $creates = (array) $request->get('create');
  95. $table = Helper::slug($request->get('table_name'), '_');
  96. $controller = $request->get('controller_name');
  97. $model = $request->get('model_name');
  98. $repository = $request->get('repository_name');
  99. try {
  100. // 1. Create model.
  101. if (in_array('model', $creates)) {
  102. $modelCreator = new ModelCreator($table, $model);
  103. $paths['model'] = $modelCreator->create(
  104. $request->get('primary_key'),
  105. $request->get('timestamps') == 1,
  106. $request->get('soft_deletes') == 1
  107. );
  108. }
  109. // 2. Create controller.
  110. if (in_array('controller', $creates)) {
  111. $paths['controller'] = (new ControllerCreator($controller))
  112. ->create(in_array('repository', $creates) ? $repository : $model);
  113. }
  114. // 3. Create migration.
  115. if (in_array('migration', $creates)) {
  116. $migrationName = 'create_'.$table.'_table';
  117. $paths['migration'] = (new MigrationCreator(app('files')))->buildBluePrint(
  118. $request->get('fields'),
  119. $request->get('primary_key', 'id'),
  120. $request->get('timestamps') == 1,
  121. $request->get('soft_deletes') == 1
  122. )->create($migrationName, database_path('migrations'), $table);
  123. }
  124. if (in_array('lang', $creates)) {
  125. $paths['lang'] = (new LangCreator($request->get('fields')))
  126. ->create($controller, $request->get('translate_title'));
  127. }
  128. if (in_array('repository', $creates)) {
  129. $paths['repository'] = (new RepositoryCreator())
  130. ->create($model, $repository);
  131. }
  132. // Run migrate.
  133. if (in_array('migrate', $creates)) {
  134. Artisan::call('migrate');
  135. $message = Artisan::output();
  136. }
  137. // Make ide helper file.
  138. if (in_array('migrate', $creates) || in_array('controller', $creates)) {
  139. try {
  140. Artisan::call('admin:ide-helper', ['-c' => $controller]);
  141. $paths['ide-helper'] = 'dcat_admin_ide_helper.php';
  142. } catch (\Throwable $e) {
  143. }
  144. }
  145. } catch (\Exception $exception) {
  146. // Delete generated files if exception thrown.
  147. app('files')->delete($paths);
  148. return $this->backWithException($exception);
  149. }
  150. return $this->backWithSuccess($paths, $message);
  151. }
  152. /**
  153. * @return array
  154. */
  155. public function table()
  156. {
  157. $db = addslashes(\request('db'));
  158. $table = \request('tb');
  159. if (! $table || ! $db) {
  160. return ['status' => 1, 'list' => []];
  161. }
  162. $tables = collect($this->getDatabaseColumns($db, $table))
  163. ->filter(function ($v, $k) use ($db) {
  164. return $k == $db;
  165. })->map(function ($v) use ($table) {
  166. return Arr::get($v, $table);
  167. })
  168. ->filter()
  169. ->first();
  170. return ['status' => 1, 'list' => $tables];
  171. }
  172. /**
  173. * @return array
  174. */
  175. protected function getDatabaseColumns($db = null, $tb = null)
  176. {
  177. $databases = Arr::where(config('database.connections', []), function ($value) {
  178. $supports = ['mysql'];
  179. return in_array(strtolower(Arr::get($value, 'driver')), $supports);
  180. });
  181. $data = [];
  182. try {
  183. foreach ($databases as $connectName => $value) {
  184. if ($db && $db != $value['database']) {
  185. continue;
  186. }
  187. $sql = sprintf('SELECT * FROM information_schema.columns WHERE table_schema = "%s"', $value['database']);
  188. if ($tb) {
  189. $p = Arr::get($value, 'prefix');
  190. $sql .= " AND TABLE_NAME = '{$p}{$tb}'";
  191. }
  192. $sql .= " ORDER BY `ORDINAL_POSITION` ASC";
  193. $tmp = DB::connection($connectName)->select($sql);
  194. $collection = collect($tmp)->map(function ($v) use ($value) {
  195. if (! $p = Arr::get($value, 'prefix')) {
  196. return (array) $v;
  197. }
  198. $v = (array) $v;
  199. $v['TABLE_NAME'] = Str::replaceFirst($p, '', $v['TABLE_NAME']);
  200. return $v;
  201. });
  202. $data[$value['database']] = $collection->groupBy('TABLE_NAME')->map(function ($v) {
  203. return collect($v)->keyBy('COLUMN_NAME')->map(function ($v) {
  204. $v['COLUMN_TYPE'] = strtolower($v['COLUMN_TYPE']);
  205. $v['DATA_TYPE'] = strtolower($v['DATA_TYPE']);
  206. if (Str::contains($v['COLUMN_TYPE'], 'unsigned')) {
  207. $v['DATA_TYPE'] .= '@unsigned';
  208. }
  209. return [
  210. 'type' => $v['DATA_TYPE'],
  211. 'default' => $v['COLUMN_DEFAULT'],
  212. 'nullable' => $v['IS_NULLABLE'],
  213. 'key' => $v['COLUMN_KEY'],
  214. 'id' => $v['COLUMN_KEY'] === 'PRI',
  215. 'comment' => $v['COLUMN_COMMENT'],
  216. ];
  217. })->toArray();
  218. })->toArray();
  219. }
  220. } catch (\Throwable $e) {
  221. }
  222. return $data;
  223. }
  224. protected function backWithException(\Exception $exception)
  225. {
  226. $error = new MessageBag([
  227. 'title' => 'Error',
  228. 'message' => $exception->getMessage(),
  229. ]);
  230. return redirect()->refresh()->withInput()->with(compact('error'));
  231. }
  232. protected function backWithSuccess($paths, $message)
  233. {
  234. $messages = [];
  235. foreach ($paths as $name => $path) {
  236. $messages[] = ucfirst($name).": $path";
  237. }
  238. $messages[] = "<br />$message";
  239. $success = new MessageBag([
  240. 'title' => 'Success',
  241. 'message' => implode('<br />', $messages),
  242. ]);
  243. return redirect()->refresh()->with(compact('success'));
  244. }
  245. }