SystemCrudServices.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. <?php
  2. /**
  3. * +----------------------------------------------------------------------
  4. * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  5. * +----------------------------------------------------------------------
  6. * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
  7. * +----------------------------------------------------------------------
  8. * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  9. * +----------------------------------------------------------------------
  10. * | Author: CRMEB Team <admin@crmeb.com>
  11. * +----------------------------------------------------------------------
  12. */
  13. namespace app\services\system;
  14. use app\dao\system\SystemCrudDao;
  15. use app\services\BaseServices;
  16. use crmeb\services\crud\Controller;
  17. use crmeb\services\crud\Dao;
  18. use crmeb\services\crud\Model;
  19. use crmeb\services\crud\Route;
  20. use crmeb\services\crud\Service;
  21. use crmeb\services\crud\Validate;
  22. use crmeb\services\crud\ViewApi;
  23. use crmeb\services\crud\ViewPages;
  24. use crmeb\services\crud\ViewRouter;
  25. use think\exception\ValidateException;
  26. use think\facade\Db;
  27. use think\helper\Str;
  28. use think\migration\Migrator;
  29. use Phinx\Db\Adapter\MysqlAdapter;
  30. /**
  31. * Class SystemCrudServices
  32. * @author 等风来
  33. * @email 136327134@qq.com
  34. * @date 2023/4/6
  35. * @package app\services\system
  36. */
  37. class SystemCrudServices extends BaseServices
  38. {
  39. /**
  40. * SystemCrudServices constructor.
  41. * @param SystemCrudDao $dao
  42. */
  43. public function __construct(SystemCrudDao $dao)
  44. {
  45. $this->dao = $dao;
  46. }
  47. /**
  48. * @return array
  49. * @author 等风来
  50. * @email 136327134@qq.com
  51. * @date 2023/4/11
  52. */
  53. public function getList()
  54. {
  55. [$page, $limit] = $this->getPageValue();
  56. $list = $this->dao->selectList([], '*', $page, $limit, 'id desc');
  57. $count = $this->dao->count();
  58. return compact('list', 'count');
  59. }
  60. /**
  61. * 数据库字段类型
  62. * @return \string[][]
  63. * @author 等风来
  64. * @email 136327134@qq.com
  65. * @date 2023/4/11
  66. */
  67. public function getTabelRule()
  68. {
  69. return [
  70. 'types' => [
  71. 'string',
  72. 'char',
  73. 'text',
  74. 'integer',
  75. 'biginteger',
  76. 'float',
  77. 'decimal',
  78. 'datetime',
  79. 'timestamp',
  80. 'time',
  81. 'date',
  82. 'blob',
  83. 'binary',
  84. 'varbinary',
  85. 'boolean',
  86. 'uuid',
  87. // Geospatial data types
  88. 'geometry',
  89. 'point',
  90. 'linestring',
  91. 'polygon',
  92. ]
  93. ];
  94. }
  95. /**
  96. * 获取表字段
  97. * @param string $tableName
  98. * @return mixed
  99. * @author 等风来
  100. * @email 136327134@qq.com
  101. * @date 2023/4/7
  102. */
  103. public function getColumnNamesList(string $tableName)
  104. {
  105. $sql = 'SELECT * FROM `information_schema`.`columns` WHERE TABLE_SCHEMA = ? AND table_name = ? ORDER BY ORDINAL_POSITION';
  106. $column = Db::query($sql, [config('database.connections.mysql.database'), $this->getTableName($tableName)]);
  107. $columns = [];
  108. foreach ($column as $item) {
  109. $column = [
  110. 'name' => $item['COLUMN_NAME'],
  111. 'type' => $item['DATA_TYPE'],
  112. 'dataType' => stripos($item['COLUMN_TYPE'], '(') !== false ? substr_replace($item['COLUMN_TYPE'], '', stripos($item['COLUMN_TYPE'], ')') + 1) : $item['COLUMN_TYPE'],
  113. 'default' => $item['COLUMN_DEFAULT'],
  114. 'null' => $item['IS_NULLABLE'] == 'YES',
  115. 'primaryKey' => $item['COLUMN_KEY'] == 'PRI',
  116. 'unsigned' => (bool)stripos($item['COLUMN_TYPE'], 'unsigned'),
  117. 'autoIncrement' => stripos($item['EXTRA'], 'auto_increment') !== false,
  118. 'comment' => $item['COLUMN_COMMENT'],
  119. ];
  120. $columns[$item['COLUMN_NAME']] = $column;
  121. }
  122. return $columns;
  123. }
  124. /**
  125. * 创建
  126. * @param array $data
  127. * @return mixed
  128. * @author 等风来
  129. * @email 136327134@qq.com
  130. * @date 2023/4/11
  131. */
  132. public function createCrud(array $data)
  133. {
  134. $tableName = $data['tableName'];
  135. $tableComment = $data['tableComment'];
  136. $tableField = $data['tableField'];
  137. $filePath = $data['filePath'];
  138. //创建数据库
  139. if ($tableField) {
  140. $this->makeDatebase($tableName, $tableComment, $tableField);
  141. }
  142. //读取表结构
  143. $column = $this->getColumnNamesList($tableName);
  144. if (!$column) {
  145. throw new ValidateException('请先创建' . $tableName . '表');
  146. }
  147. $routeName = 'crud/' . Str::snake($tableName);
  148. $uniqueAuth = $routeName . '-index-list';
  149. $make = $this->makeFile($tableName, $routeName, true, $data, $filePath);
  150. $makePath = [];
  151. foreach ($make as $key => $item) {
  152. $makePath[$key] = $item['path'];
  153. }
  154. //创建菜单
  155. if (!$data['menuName']) {
  156. $data['menuName'] = $tableName;
  157. }
  158. $data = [
  159. 'pid' => $data['pid'],
  160. 'menu_name' => $data['menuName'],
  161. 'menu_path' => '',
  162. 'auth_type' => 1,
  163. 'is_show' => 1,
  164. 'is_del' => 0,
  165. 'unique_auth' => $uniqueAuth,
  166. 'is_header' => $data['pid'] ? 0 : 1,
  167. ];
  168. $menuInfo = app()->make(SystemMenusServices::class)->save($data);
  169. //写入路由权限
  170. $cateId = app()->make(SystemRouteServices::class)->topCateId('adminapi');
  171. $ruleData = [
  172. [
  173. 'path' => $routeName,
  174. 'method' => 'GET',
  175. 'name' => $data['menuName'] . '列表接口',
  176. 'app_name' => 'adminapi',
  177. 'cate_id' => $cateId,
  178. 'add_time' => date('Y-m-d H:i:s')
  179. ],
  180. [
  181. 'path' => $routeName . '/create',
  182. 'method' => 'GET',
  183. 'name' => $data['menuName'] . '获取创建表单接口',
  184. 'app_name' => 'adminapi',
  185. 'cate_id' => $cateId,
  186. 'add_time' => date('Y-m-d H:i:s')
  187. ],
  188. [
  189. 'path' => $routeName,
  190. 'method' => 'POST',
  191. 'name' => $data['menuName'] . '保存数据接口',
  192. 'app_name' => 'adminapi',
  193. 'cate_id' => $cateId,
  194. 'add_time' => date('Y-m-d H:i:s')
  195. ],
  196. [
  197. 'path' => $routeName . '/<id>/edit',
  198. 'method' => 'GET',
  199. 'name' => $data['menuName'] . '获取修改表单接口',
  200. 'app_name' => 'adminapi',
  201. 'cate_id' => $cateId,
  202. 'add_time' => date('Y-m-d H:i:s')
  203. ],
  204. [
  205. 'path' => $routeName . '/<id>',
  206. 'method' => 'PUT',
  207. 'name' => $data['menuName'] . '修改数据接口',
  208. 'app_name' => 'adminapi',
  209. 'cate_id' => $cateId,
  210. 'add_time' => date('Y-m-d H:i:s')
  211. ],
  212. [
  213. 'path' => $routeName . '/<id>',
  214. 'method' => 'DELETE',
  215. 'name' => $data['menuName'] . '删除数据接口',
  216. 'app_name' => 'adminapi',
  217. 'cate_id' => $cateId,
  218. 'add_time' => date('Y-m-d H:i:s')
  219. ],
  220. ];
  221. app()->make(SystemRouteServices::class)->saveAll($ruleData);
  222. //记录权限加入菜单表
  223. $menuData = [];
  224. foreach ($ruleData as $item) {
  225. $menuData[] = [
  226. 'pid' => $menuInfo->id,
  227. 'method' => $item['method'],
  228. 'api_url' => $item['path'],
  229. 'name' => $item['name'],
  230. 'is_del' => 0,
  231. ];
  232. }
  233. app()->make(SystemMenusServices::class)->saveAll($menuData);
  234. //记录crud生成
  235. $res = $this->dao->save([
  236. 'pid' => $data['pid'],
  237. 'name' => $data['menuName'],
  238. 'table_name' => $tableName,
  239. 'field' => json_encode($data),
  240. 'make_path' => json_encode($makePath),
  241. 'add_time' => time()
  242. ]);
  243. return $res->toArray();
  244. }
  245. /**
  246. * 创建数据库
  247. * @param string $tableName
  248. * @param string $tableComment
  249. * @param array $tableField
  250. * @author 等风来
  251. * @email 136327134@qq.com
  252. * @date 2023/4/7
  253. */
  254. public function makeDatebase(string $tableName, string $tableComment, array $tableField = [])
  255. {
  256. $migrator = app()->make(Migrator::class);
  257. //创建表
  258. $table = $migrator->table($tableName, $tableComment);
  259. //创建字段
  260. foreach ($tableField as $item) {
  261. $option = [];
  262. if (!isset($item['limit'])) {
  263. $option['limit'] = (int)$item['limit'];
  264. }
  265. if (!isset($item['default'])) {
  266. $option['default'] = $item['default'];
  267. }
  268. $option['comment'] = $item['comment'];
  269. $table->addColumn($item['field'], $item['type'], $option);
  270. }
  271. //创建修改和增加时间
  272. if (!empty($data['tableTime'])) {
  273. $table->addTimestamps();
  274. }
  275. //创建索引
  276. if (!empty($data['tableIndex'])) {
  277. foreach ($data['tableIndex'] as $item) {
  278. $table->addIndex($item);
  279. }
  280. }
  281. //创建伪删除
  282. if (!empty($data['tableDelete'])) {
  283. $table->addSoftDelete();
  284. }
  285. //执行创建
  286. $table->create();
  287. }
  288. /**
  289. * 创建文件返回文件路径和内容
  290. * @param string $tableName
  291. * @param string $routeName
  292. * @param bool $isMake
  293. * @param array $options
  294. * @param array $filePath
  295. * @return array[]
  296. * @author 等风来
  297. * @email 136327134@qq.com
  298. * @date 2023/4/7
  299. */
  300. public function makeFile(string $tableName, string $routeName, bool $isMake = false, array $options = [], array $filePath = [])
  301. {
  302. //生成控制器
  303. $controller = app()->make(Controller::class);
  304. [$controllerContent, $controllerPath] = $controller->setFilePathName($filePath['controller'] ?? '')->isMake($isMake)->handle($tableName, '/');
  305. //生成模型
  306. $model = app()->make(Model::class);
  307. [$modelContent, $modelPath] = $model->setFilePathName($filePath['model'] ?? '')->isMake($isMake)->handle($tableName, '/');
  308. //生成dao
  309. $dao = app()->make(Dao::class);
  310. [$daoContent, $daoPath] = $dao->setFilePathName($filePath['dao'] ?? '')->isMake($isMake)->handle($tableName, '/');
  311. //生成路由
  312. $route = app()->make(Route::class);
  313. [$routeContent, $routePath] = $route->setFilePathName($filePath['route'] ?? '')->isMake($isMake)->handle($tableName, '/', [
  314. 'menus' => $options['menuName'],
  315. 'route' => $routeName
  316. ]);
  317. //生成service
  318. $service = app()->make(Service::class);
  319. [$serviceContent, $servicePath] = $service->setFilePathName($filePath['service'] ?? '')->isMake($isMake)->handle($tableName, '/', [
  320. 'field' => $options['fromField']
  321. ]);
  322. //生成验证器
  323. $validate = app()->make(Validate::class);
  324. [$validateContent, $validatePath] = $validate->setFilePathName($filePath['validate'] ?? '')->isMake($isMake)->handle($tableName, '/');
  325. //生成前台路由
  326. $viewRouter = app()->make(ViewRouter::class);
  327. [$routerContent, $routerPath] = $viewRouter->setFilePathName($filePath['router'] ?? '')->isMake($isMake)->handle($tableName, '/', [
  328. 'route' => $routeName,
  329. ]);
  330. //生成前台接口
  331. $viewApi = app()->make(ViewApi::class);
  332. [$apiContent, $apiPath] = $viewApi->setFilePathName($filePath['api'] ?? '')->isMake($isMake)->handle($tableName, '/', [
  333. 'route' => $routeName,
  334. ]);
  335. //生成前台页面
  336. $viewPages = app()->make(ViewPages::class);
  337. [$pagesContent, $pagesPath] = $viewPages->setFilePathName($filePath['pages'] ?? '')->isMake($isMake)->handle($tableName, '/', [
  338. 'field' => $options['columnField']
  339. ]);
  340. return [
  341. 'controller' => [
  342. 'path' => $controllerContent,
  343. 'content' => $controllerPath
  344. ],
  345. 'model' => [
  346. 'path' => $modelPath,
  347. 'content' => $modelContent
  348. ],
  349. 'dao' => [
  350. 'path' => $daoPath,
  351. 'content' => $daoContent
  352. ],
  353. 'route' => [
  354. 'path' => $routePath,
  355. 'content' => $routeContent
  356. ],
  357. 'service' => [
  358. 'path' => $servicePath,
  359. 'content' => $serviceContent
  360. ],
  361. 'validate' => [
  362. 'path' => $validatePath,
  363. 'content' => $validateContent
  364. ],
  365. 'router' => [
  366. 'path' => $routerPath,
  367. 'content' => $routerContent
  368. ],
  369. 'api' => [
  370. 'path' => $apiPath,
  371. 'content' => $apiContent
  372. ],
  373. 'pages' => [
  374. 'path' => $pagesPath,
  375. 'content' => $pagesContent
  376. ],
  377. ];
  378. }
  379. /**
  380. * @param string $tableName
  381. * @param bool $fullName
  382. * @return string
  383. * @author 等风来
  384. * @email 136327134@qq.com
  385. * @date 2023/4/7
  386. */
  387. public function getTableName(string $tableName, bool $fullName = true)
  388. {
  389. $tablePrefix = config('database.connections.mysql.prefix');
  390. $pattern = '/^' . $tablePrefix . '/i';
  391. return ($fullName ? $tablePrefix : '') . (preg_replace($pattern, '', $tableName));
  392. }
  393. }