SystemCrudServices.php 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210
  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\exceptions\AdminException;
  17. use crmeb\services\crud\Controller;
  18. use crmeb\services\crud\Dao;
  19. use crmeb\services\crud\enum\FormTypeEnum;
  20. use crmeb\services\crud\enum\SearchEnum;
  21. use crmeb\services\crud\Make;
  22. use crmeb\services\crud\Model;
  23. use crmeb\services\crud\Route;
  24. use crmeb\services\crud\Service;
  25. use crmeb\services\crud\Validate;
  26. use crmeb\services\crud\ViewApi;
  27. use crmeb\services\crud\ViewPages;
  28. use crmeb\services\crud\ViewRouter;
  29. use crmeb\services\FileService;
  30. use Phinx\Db\Adapter\AdapterFactory;
  31. use think\facade\Db;
  32. use think\helper\Str;
  33. use think\migration\db\Column;
  34. use think\migration\db\Table;
  35. /**
  36. * Class SystemCrudServices
  37. * @author 等风来
  38. * @email 136327134@qq.com
  39. * @date 2023/4/6
  40. * @package app\services\system
  41. */
  42. class SystemCrudServices extends BaseServices
  43. {
  44. //不能生成的系统自带表
  45. const NOT_CRUD_TABANAME = [
  46. 'system_config', 'system_attachment', 'system_attachment_category', 'system_config_tab',
  47. 'system_admin', 'eb_system_city', 'system_log', 'system_menus', 'system_notice',
  48. 'system_notice_admin', 'system_notification', 'system_role', 'system_route',
  49. 'system_route_cate', 'system_storage', 'system_timer', 'system_user_level',
  50. 'system_crud', 'wechat_key', 'user_label_relation', 'user_brokerage_frozen',
  51. 'user_brokerage', 'store_product_cate', 'store_bargain_user_help', 'shipping_templates_region',
  52. 'shipping_templates_no_delivery', 'shipping_templates_free', 'other_order_status', 'lang_code',
  53. 'lang_country', 'app_version', 'user', 'wechat_user', 'template_message', 'store_order',
  54. 'other_order', 'store_order_cart_info', 'store_order_economize', 'store_order_invoice', 'store_order_refund',
  55. 'store_order_status', 'store_pink', 'agent_level', 'agent_level_task', 'agent_level_task_record',
  56. 'agreement', 'app_version', 'article', 'article_category', 'article_content', 'auxiliary', 'cache',
  57. 'capital_flow', 'category', 'diy', 'express', 'lang_type', 'live_anchor', 'live_goods', 'live_room',
  58. 'live_room_goods', 'luck_lottery', 'luck_lottery_record', 'luck_prize', 'member_card',
  59. 'member_card_batch', 'member_right', 'member_ship', 'message_system', 'other_order',
  60. 'other_order_status', 'out_account', 'out_interface', 'page_categroy', 'page_link', 'qrcode',
  61. 'shipping_templates', 'shipping_templates_free', 'shipping_templates_no_delivery',
  62. 'shipping_templates_region', 'sms_record', 'store_advance', 'store_bargain', 'store_bargain_user',
  63. 'store_bargain_user_help', 'store_cart', 'store_category', 'store_combination', 'store_coupon_issue',
  64. 'store_coupon_issue_user', 'store_coupon_product', 'store_coupon_user', 'store_integral',
  65. 'store_integral_order', 'store_integral_order_status', 'store_order', 'store_order_cart_info',
  66. 'store_order_economize', 'store_order_invoice', 'store_order_refund', 'store_order_status',
  67. 'store_pink', 'store_product', 'store_product_attr', 'store_product_attr_result',
  68. 'store_product_attr_value', 'store_product_cate', 'store_product_coupon', 'store_product_description',
  69. 'store_product_log', 'store_product_relation', 'store_service', 'store_service_feedback',
  70. 'store_product_reply', 'store_product_rule', 'store_product_virtual', 'store_seckill', 'store_seckill_time',
  71. 'store_service_log', 'store_service_record', 'store_service_speechcraft', 'store_visit',
  72. 'system_attachment', 'system_attachment_category', 'system_city', 'system_config',
  73. 'system_config_tab', 'system_file', 'system_file_info', 'system_group', 'system_group_data',
  74. 'system_log', 'system_notice', 'system_notice_admin', 'system_notification',
  75. 'system_role', 'system_route', 'system_route_cate', 'system_storage', 'system_store',
  76. 'system_store_staff', 'system_timer', 'system_user_level', 'template_message', 'upgrade_log',
  77. 'user', 'user_address', 'user_bill', 'user_brokerage', 'user_brokerage_frozen', 'user_cancel',
  78. 'user_enter', 'user_extract', 'user_friends', 'user_group', 'user_invoice', 'user_label',
  79. 'user_label_relation', 'user_level', 'user_money', 'user_notice', 'user_notice_see',
  80. 'user_recharge', 'user_search', 'user_sign', 'user_spread', 'user_visit', 'wechat_key',
  81. 'wechat_media', 'wechat_message', 'wechat_news_category', 'wechat_qrcode', 'wechat_qrcode_cate',
  82. 'wechat_qrcode_record', 'wechat_reply', 'wechat_user', 'system_crud_data', 'admins',
  83. ];
  84. //表字符集
  85. const TABLR_COLLATION = 'utf8mb4_general_ci';
  86. /**
  87. * SystemCrudServices constructor.
  88. * @param SystemCrudDao $dao
  89. */
  90. public function __construct(SystemCrudDao $dao)
  91. {
  92. $this->dao = $dao;
  93. }
  94. /**
  95. * @return array
  96. * @author 等风来
  97. * @email 136327134@qq.com
  98. * @date 2023/4/11
  99. */
  100. public function getList()
  101. {
  102. [$page, $limit] = $this->getPageValue();
  103. $list = $this->dao->selectList([], 'add_time,id,name,table_name,table_comment,table_collation', $page, $limit, 'id desc');
  104. $count = $this->dao->count();
  105. return compact('list', 'count');
  106. }
  107. /**
  108. * 数据库字段类型
  109. * @return \string[][]
  110. * @author 等风来
  111. * @email 136327134@qq.com
  112. * @date 2023/4/11
  113. */
  114. public function getTabelRule()
  115. {
  116. $rule = [
  117. 'varchar' => 'string',
  118. 'int' => 'integer',
  119. 'biginteger' => 'bigint',
  120. 'tinyint' => 'boolean',
  121. ];
  122. return [
  123. 'types' => [
  124. 'varchar',
  125. 'char',
  126. 'text',
  127. 'longtext',
  128. 'tinytext',
  129. 'enum',
  130. 'blob',
  131. 'binary',
  132. 'varbinary',
  133. 'datetime',
  134. 'timestamp',
  135. 'time',
  136. 'date',
  137. 'year',
  138. 'boolean',
  139. 'tinyint',
  140. 'int',
  141. 'decimal',
  142. 'float',
  143. 'json',
  144. ],
  145. 'form' => [
  146. [
  147. 'value' => FormTypeEnum::INPUT,
  148. 'label' => '输入框',
  149. 'field_type' => 'varchar',
  150. 'limit' => 255
  151. ],
  152. [
  153. 'value' => FormTypeEnum::NUMBER,
  154. 'label' => '数字输入框',
  155. 'field_type' => 'int',
  156. 'limit' => 11
  157. ],
  158. [
  159. 'value' => FormTypeEnum::TEXTAREA,
  160. 'label' => '多行文本框',
  161. 'field_type' => 'text',
  162. 'limit' => null
  163. ],
  164. [
  165. 'value' => FormTypeEnum::DATE_TIME,
  166. 'label' => '单选日期时间',
  167. 'field_type' => 'varchar',
  168. 'limit' => 200
  169. ],
  170. [
  171. 'value' => FormTypeEnum::DATE_TIME_RANGE,
  172. 'label' => '日期时间区间选择',
  173. 'field_type' => 'varchar',
  174. 'limit' => 200
  175. ],
  176. [
  177. 'value' => FormTypeEnum::CHECKBOX,
  178. 'label' => '多选框',
  179. 'field_type' => 'varchar',
  180. 'limit' => 200
  181. ],
  182. [
  183. 'value' => FormTypeEnum::RADIO,
  184. 'label' => '单选框',
  185. 'field_type' => 'int',
  186. 'limit' => 11
  187. ],
  188. [
  189. 'value' => FormTypeEnum::SWITCH,
  190. 'label' => '开关',
  191. 'field_type' => 'int',
  192. 'limit' => 11
  193. ],
  194. [
  195. 'value' => FormTypeEnum::SELECT,
  196. 'label' => '下拉框',
  197. 'field_type' => 'int',
  198. 'limit' => 11
  199. ],
  200. [
  201. 'value' => FormTypeEnum::FRAME_IMAGE_ONE,
  202. 'label' => '单图选择',
  203. 'field_type' => 'varchar',
  204. 'limit' => 200
  205. ],
  206. [
  207. 'value' => FormTypeEnum::FRAME_IMAGES,
  208. 'label' => '多图选择',
  209. 'field_type' => 'varchar',
  210. 'limit' => 200
  211. ],
  212. ],
  213. 'search_type' => [
  214. [
  215. 'value' => SearchEnum::SEARCH_TYPE_EQ,
  216. 'label' => '等于搜索',
  217. ],
  218. [
  219. 'value' => SearchEnum::SEARCH_TYPE_LTEQ,
  220. 'label' => '小于等于搜索',
  221. ],
  222. [
  223. 'value' => SearchEnum::SEARCH_TYPE_GTEQ,
  224. 'label' => '大于等于搜索',
  225. ],
  226. [
  227. 'value' => SearchEnum::SEARCH_TYPE_NEQ,
  228. 'label' => '不等于搜索',
  229. ],
  230. [
  231. 'value' => SearchEnum::SEARCH_TYPE_LIKE,
  232. 'label' => '模糊搜索',
  233. ],
  234. [
  235. 'value' => SearchEnum::SEARCH_TYPE_BETWEEN,
  236. 'label' => '用来时间区间搜索',
  237. ],
  238. ],
  239. 'default_type' => [
  240. [
  241. 'value' => '-1',
  242. 'label' => '无',
  243. 'disabled' => false,
  244. ],
  245. [
  246. 'value' => '1',
  247. 'label' => '自定义',
  248. 'disabled' => true,
  249. ],
  250. [
  251. 'value' => '2',
  252. 'label' => 'NULL',
  253. 'disabled' => false,
  254. ],
  255. [
  256. 'value' => '3',
  257. 'label' => 'CURRENT_TIMESTAMP',
  258. 'disabled' => false,
  259. ],
  260. ],
  261. 'rule' => $rule
  262. ];
  263. }
  264. /**
  265. * 改变数据库类型
  266. * @param string $type
  267. * @return string
  268. * @author 等风来
  269. * @email 136327134@qq.com
  270. * @date 2023/4/13
  271. */
  272. public function changeTabelRule(string $type)
  273. {
  274. if (!in_array($type, $this->getTabelRule()['types'])) {
  275. throw new AdminException(500044);
  276. }
  277. return $this->getTabelRule()['rule'][$type] ?? $type;
  278. }
  279. /**
  280. * @param string $tableName
  281. * @return mixed
  282. * @author 等风来
  283. * @email 136327134@qq.com
  284. * @date 2023/4/14
  285. */
  286. public function getTableInfo(string $tableName)
  287. {
  288. $sql = 'SELECT * FROM `information_schema`.`TABLES` WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?';
  289. $tableInfo = Db::query($sql, [config('database.connections.mysql.database'), $this->getTableName($tableName)]);
  290. return $tableInfo[0] ?? [];
  291. }
  292. /**
  293. * 获取表字段
  294. * @param string $tableName
  295. * @return mixed
  296. * @author 等风来
  297. * @email 136327134@qq.com
  298. * @date 2023/4/7
  299. */
  300. public function getColumnNamesList(string $tableName)
  301. {
  302. $sql = 'SELECT * FROM `information_schema`.`columns` WHERE TABLE_SCHEMA = ? AND table_name = ? ORDER BY ORDINAL_POSITION';
  303. $column = Db::query($sql, [config('database.connections.mysql.database'), $this->getTableName($tableName)]);
  304. $columns = [];
  305. foreach ($column as $item) {
  306. $column = [
  307. 'name' => $item['COLUMN_NAME'],
  308. 'type' => $item['DATA_TYPE'],
  309. 'dataType' => stripos($item['COLUMN_TYPE'], '(') !== false ? substr_replace($item['COLUMN_TYPE'], '', stripos($item['COLUMN_TYPE'], ')') + 1) : $item['COLUMN_TYPE'],
  310. 'default' => $item['COLUMN_DEFAULT'],
  311. 'null' => $item['IS_NULLABLE'] == 'YES',
  312. 'primaryKey' => $item['COLUMN_KEY'] == 'PRI',
  313. 'unsigned' => (bool)stripos($item['COLUMN_TYPE'], 'unsigned'),
  314. 'autoIncrement' => stripos($item['EXTRA'], 'auto_increment') !== false,
  315. 'comment' => $item['COLUMN_COMMENT'],
  316. 'limit' => $item['CHARACTER_MAXIMUM_LENGTH'] ?: $item['NUMERIC_PRECISION'],
  317. ];
  318. $columns[$item['COLUMN_NAME']] = $column;
  319. }
  320. return $columns;
  321. }
  322. /**
  323. * 获取当前数据库所有表名
  324. * @return mixed
  325. * @author 等风来
  326. * @email 136327134@qq.com
  327. * @date 2023/8/2
  328. */
  329. public function getTableAll()
  330. {
  331. $sql = "SELECT TABLE_NAME, TABLE_COMMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = ?";
  332. $tableAll = Db::query($sql, [config('database.connections.mysql.database')]);
  333. $data = [];
  334. foreach ($tableAll as $item) {
  335. $item['TABLE_NAME'] = str_replace(config('database.connections.mysql.prefix'), '', $item['TABLE_NAME']);
  336. // if (!in_array($item['TABLE_NAME'], self::NOT_CRUD_TABANAME)) {
  337. $data[] = [
  338. 'value' => $item['TABLE_NAME'],
  339. 'label' => $item['TABLE_COMMENT'] ?: $item['TABLE_NAME'],
  340. ];
  341. // }
  342. }
  343. return $data;
  344. }
  345. /**
  346. * @param array $data
  347. * @return array
  348. * @author 等风来
  349. * @email 136327134@qq.com
  350. * @date 2023/4/12
  351. */
  352. public function valueReplace(array $data)
  353. {
  354. $replace = ['phar://'];
  355. $newData = [];
  356. foreach ($data as $key => $item) {
  357. if (is_array($item)) {
  358. $item = $this->valueReplace($item);
  359. } else {
  360. $item = str_replace($replace, '', $item);
  361. }
  362. $newData[str_replace($replace, '', $key)] = $item;
  363. }
  364. return $newData;
  365. }
  366. /**
  367. * 更新表字段
  368. * @param string $tableName
  369. * @param string $field
  370. * @param string $changeFiled
  371. * @param string $type
  372. * @param string $limit
  373. * @param string $default
  374. * @param string $comment
  375. * @param array $options
  376. * @return mixed
  377. * @author 等风来
  378. * @email 136327134@qq.com
  379. * @date 2023/4/24
  380. */
  381. protected function updateAlter(string $tableName, string $field, string $changeFiled, string $prevFiled, string $type, $limit = '', string $default = '', string $comment = '', array $options = [])
  382. {
  383. $tableName = $this->getTableName($tableName);
  384. $comment = addslashes($comment);
  385. $field = addslashes($field);
  386. $changeFiled = addslashes($changeFiled);
  387. $prevFiled = addslashes($prevFiled);
  388. $type = addslashes($type);
  389. $default = addslashes($default);
  390. if ($prevFiled) {
  391. $after = "AFTER `$prevFiled`";
  392. } else {
  393. $after = "";
  394. }
  395. if (isset($options['default_type'])) {
  396. switch ($options['default_type']) {
  397. case '-1':
  398. $default = 'NULL';
  399. break;
  400. case '1'://自定义
  401. $default = "NOT NULL DEFAULT '$default'";
  402. break;
  403. case '2'://为null
  404. $default = 'NULL DEFAULT NULL';
  405. break;
  406. case '3'://时间
  407. $default = 'NULL DEFAULT CURRENT_TIMESTAMP';
  408. break;
  409. }
  410. }
  411. if (in_array(strtolower($type), ['text', 'longtext', 'tinytext'])) {
  412. $sql = "ALTER TABLE `$tableName` CHANGE `$field` `$changeFiled` $type CHARACTER SET utf8mb4 COLLATE " . self::TABLR_COLLATION . " NULL COMMENT '$comment' $after;";
  413. } else if (strtolower($type) == 'enum') {
  414. $enum = [];
  415. foreach ($options['options'] as $option) {
  416. $enum[] = "'$option'";
  417. }
  418. $enumStr = implode(',', $enum);
  419. $sql = "ALTER TABLE `$tableName` CHANGE `$field` `$changeFiled` $type($enumStr) $default COMMENT '$comment' $after;";
  420. } else {
  421. $sql = "ALTER TABLE `$tableName` CHANGE `$field` `$changeFiled` $type($limit) $default COMMENT '$comment' $after;";
  422. }
  423. return Db::execute($sql);
  424. }
  425. /**
  426. * 添加字段
  427. * @param string $tableName
  428. * @param string $field
  429. * @param string $prevFiled
  430. * @param string $type
  431. * @param string $limit
  432. * @param string $default
  433. * @param string $comment
  434. * @param array $options
  435. * @return mixed
  436. * @author 等风来
  437. * @email 136327134@qq.com
  438. * @date 2023/4/24
  439. */
  440. public function addAlter(string $tableName, string $field, string $prevFiled, string $type, $limit = '', string $default = '', string $comment = '', array $options = [])
  441. {
  442. $tableName = $this->getTableName($tableName);
  443. $comment = addslashes($comment);
  444. $field = addslashes($field);
  445. $prevFiled = addslashes($prevFiled);
  446. $type = addslashes($type);
  447. $default = addslashes($default);
  448. if ($prevFiled) {
  449. $after = "AFTER `$prevFiled`";
  450. } else {
  451. $after = "";
  452. }
  453. if (isset($options['default_type'])) {
  454. switch ($options['default_type']) {
  455. case '-1':
  456. $default = 'NULL';
  457. break;
  458. case '1'://自定义
  459. $default = "NOT NULL DEFAULT '$default'";
  460. break;
  461. case '2'://为null
  462. $default = 'NULL DEFAULT NULL';
  463. break;
  464. case '3'://时间
  465. $default = 'NULL DEFAULT CURRENT_TIMESTAMP';
  466. break;
  467. }
  468. }
  469. if (in_array(strtolower($type), ['text', 'longtext', 'tinytext'])) {
  470. $sql = "ALTER TABLE `$tableName` ADD `$field` $type NULL COMMENT '$comment' $after;";
  471. } else {
  472. $defaultSql = $default;
  473. //处理时间字段默认值
  474. if (in_array(strtolower($type), ['datetime', 'timestamp', 'time', 'date', 'year'])) {
  475. switch ($field) {
  476. case 'delete_time':
  477. $defaultSql = 'NULL DEFAULT NULL';
  478. break;
  479. case 'create_time':
  480. case 'update_time':
  481. $defaultSql = 'NOT NULL DEFAULT CURRENT_TIMESTAMP';
  482. break;
  483. }
  484. }
  485. //兼容枚举字段
  486. if (strtolower($type) == 'enum') {
  487. $enum = [];
  488. foreach ($options['options'] as $option) {
  489. $enum[] = "'$option'";
  490. }
  491. $enumStr = implode(',', $enum);
  492. $limitSql = $enumStr ? '(' . $enumStr . ')' : '';
  493. } else {
  494. $limitSql = $limit ? '(' . $limit . ')' : '';
  495. }
  496. $sql = "ALTER TABLE `$tableName` ADD `$field` $type$limitSql $defaultSql COMMENT '$comment' $after;";
  497. }
  498. return Db::execute($sql);
  499. }
  500. /**
  501. * 删除表字段
  502. * @param string $tableName
  503. * @param string $field
  504. * @return mixed
  505. * @author 等风来
  506. * @email 136327134@qq.com
  507. * @date 2023/4/24
  508. */
  509. protected function deleteAlter(string $tableName, string $field)
  510. {
  511. $tableName = $this->getTableName($tableName);
  512. $field = addslashes($field);
  513. $sql = "ALTER TABLE `$tableName` DROP `$field`";
  514. return Db::execute($sql);
  515. }
  516. /**
  517. * 修改表备注
  518. * @param string $tableName
  519. * @param string $common
  520. * @return mixed
  521. * @author 等风来
  522. * @email 136327134@qq.com
  523. * @date 2023/4/24
  524. */
  525. protected function updateFromCommon(string $tableName, string $common)
  526. {
  527. $tableName = $this->getTableName($tableName);
  528. $common = addslashes($common);
  529. $sql = "ALTER TABLE `$tableName` COMMENT = '$common';";
  530. return Db::execute($sql);
  531. }
  532. /**
  533. * 对比字段变动了更改
  534. * @param string $tableName
  535. * @param array $deleteField
  536. * @param array $tableField
  537. * @author 等风来
  538. * @email 136327134@qq.com
  539. * @date 2023/4/24
  540. */
  541. protected function diffAlter(string $tableName, array $deleteField, array $tableField)
  542. {
  543. $updateAlter = [];
  544. $addAlter = [];
  545. $columns = $this->getColumnNamesList($tableName);
  546. $fieldAll = array_column($columns, 'name');
  547. //对比数据库字段
  548. foreach ($tableField as $i => $item) {
  549. if ($item['primaryKey'] || $item['field'] == 'delete_time') {
  550. continue;
  551. }
  552. $prevFiled = $i ? ($tableField[$i - 1]['field'] ?? 'id') : 'id';
  553. //前台新增的字段进行添加
  554. if (!(isset($item['default_field']) &&
  555. isset($item['default_field_type']) &&
  556. isset($item['default_limit']) &&
  557. isset($item['default_comment']) &&
  558. isset($item['default_default']) &&
  559. isset($item['default_default_type']))
  560. ) {
  561. if (!in_array($item['field'], $fieldAll)) {
  562. $addAlter[] = [
  563. 'prev_filed' => $prevFiled,
  564. 'field' => $item['field'],
  565. 'limit' => $item['limit'],
  566. 'type' => $item['field_type'],
  567. 'comment' => $item['comment'],
  568. 'default' => $item['default'],
  569. 'default_type' => $item['default_type'],
  570. 'values' => $item['field_type'] == 'enum' ? $item['limit'] : [],
  571. ];
  572. }
  573. continue;
  574. } else {
  575. //从数据库中新增的字段,并没有记录在表中做兼容处理;
  576. //默认字段没有在数据库中,需要添加字段;
  577. if (!in_array($item['default_field'], $fieldAll)) {
  578. $addAlter[] = [
  579. 'prev_filed' => $prevFiled,
  580. 'field' => $item['field'],
  581. 'limit' => $item['limit'],
  582. 'type' => $item['field_type'],
  583. 'comment' => $item['comment'],
  584. 'default' => $item['default'],
  585. 'default_type' => $item['default_type'],
  586. 'values' => $item['field_type'] == 'enum' ? $item['limit'] : [],
  587. ];
  588. continue;
  589. }
  590. }
  591. if ($item['default_field'] != $item['field'] && in_array($item['field_type'], ['addTimestamps', 'addSoftDelete'])) {
  592. throw new AdminException($item['field'] . '字段不允许被更改');
  593. }
  594. //数据库表存在的,字段,并且被修改
  595. if (!in_array($item['field'], ['id', 'create_time', 'update_time'])) {
  596. $updateAlter[] = [
  597. 'default_field' => $item['default_field'],
  598. 'prev_filed' => $prevFiled,
  599. 'field' => $item['field'],
  600. 'limit' => $item['limit'],
  601. 'type' => $item['field_type'],
  602. 'comment' => $item['comment'],
  603. 'default' => $item['default'],
  604. 'default_type' => $item['default_type'],
  605. 'values' => $item['field_type'] == 'enum' ? $item['limit'] : [],
  606. ];
  607. }
  608. }
  609. //添加字段
  610. foreach ($addAlter as $item) {
  611. $this->addAlter($tableName, $item['field'], $item['prev_filed'], $item['type'], $item['limit'], $item['default'], $item['comment'], [
  612. 'options' => $item['values'],
  613. 'default_type' => $item['default_type'],
  614. ]);
  615. }
  616. //删除多余字段
  617. foreach ($deleteField as $item) {
  618. $this->deleteAlter($tableName, $item);
  619. }
  620. //更新数据库字段
  621. foreach ($updateAlter as $item) {
  622. $this->updateAlter($tableName, $item['default_field'], $item['field'], $item['prev_filed'], $item['type'], $item['limit'], $item['default'], $item['comment'], [
  623. 'options' => $item['values'],
  624. 'default_type' => $item['default_type'],
  625. ]);
  626. }
  627. }
  628. /**
  629. * 创建
  630. * @param array $data
  631. * @return mixed
  632. * @author 等风来
  633. * @email 136327134@qq.com
  634. * @date 2023/4/11
  635. */
  636. public function createCrud(int $id, array $data)
  637. {
  638. $tableName = $data['tableName'];
  639. $tableField = $this->valueReplace($data['tableField']);
  640. $filePath = $this->valueReplace($data['filePath']);
  641. $modelName = !empty($data['modelName']) ? $data['modelName'] : $tableName;
  642. $tableComment = !empty($data['tableComment']) ? $data['tableComment'] : $modelName;
  643. //检测是否为系统表
  644. if (in_array($tableName, self::NOT_CRUD_TABANAME)) {
  645. throw new AdminException(500041);
  646. }
  647. $data['softDelete'] = false;
  648. $tableInfo = null;
  649. //先检查表存在则
  650. if ($id) {
  651. $this->updateFromCommon($tableName, $tableComment);
  652. //读取数据库表
  653. $tableInfo = $this->getTableInfo($tableName);
  654. if ($tableInfo) {
  655. //对比字段进行更新/删除字段
  656. $this->diffAlter($tableName, $data['deleteField'], $tableField);
  657. }
  658. } else {
  659. if ($this->dao->count(['table_name' => $tableName])) {
  660. throw new AdminException('表已经被生成过,请在列表中进行修改');
  661. }
  662. }
  663. //创建数据库
  664. $tableCreateInfo = null;
  665. if ($tableField && (!$data['isTable'] || !$tableInfo)) {
  666. $tableCreateInfo = $this->makeDatebase($tableName, $tableComment, $tableField);
  667. if ($tableCreateInfo['softDelete']) {
  668. $data['softDelete'] = true;
  669. }
  670. }
  671. //获取主键
  672. foreach ($tableField as $value) {
  673. if ($value['primaryKey']) {
  674. $data['key'] = $value['field'];
  675. break;
  676. }
  677. }
  678. $routeName = 'crud/' . Str::snake($tableName);
  679. $uniqueAuth = Str::snake($tableName) . '-crud-list-index';
  680. //增加保存的绝对路径
  681. foreach ($filePath as $k => $i) {
  682. if (in_array($k, ['pages', 'router', 'api'])) {
  683. $filePath[$k] = Make::adminTemplatePath() . $i;
  684. } else {
  685. $filePath[$k] = app()->getRootPath() . $i;
  686. }
  687. }
  688. //创建菜单
  689. if (!$data['menuName']) {
  690. $data['menuName'] = $tableName;
  691. }
  692. $dataMenu = [
  693. 'pid' => $data['pid'],
  694. 'menu_name' => $data['menuName'],
  695. 'menu_path' => '/' . $routeName,
  696. 'auth_type' => 1,
  697. 'is_show' => 1,
  698. 'is_show_path' => 1,
  699. 'is_del' => 0,
  700. 'unique_auth' => $uniqueAuth,
  701. 'is_header' => $data['pid'] ? 0 : 1,
  702. ];
  703. $crudInfo = null;
  704. if ($id) {
  705. $crudInfo = $this->dao->get($id);
  706. }
  707. $res = $this->transaction(function () use ($tableComment, $tableCreateInfo, $crudInfo, $modelName, $filePath, $tableName, $routeName, $data, $dataMenu) {
  708. $routeService = app()->make(SystemRouteServices::class);
  709. $meunService = app()->make(SystemMenusServices::class);
  710. //修改菜单名称
  711. if ($crudInfo) {
  712. //菜单存在的时候进行修改
  713. if ($crudInfo->menu_id && $meunService->value(['id' => [$crudInfo->menu_id]], 'id')) {
  714. $meunService->update($crudInfo->menu_id, $dataMenu);
  715. $menuInfo = (object)['id' => $crudInfo->menu_id];
  716. } else {
  717. $menuInfo = $meunService->save($dataMenu);
  718. }
  719. //删除掉添加的路由权限
  720. if ($crudInfo->route_ids) {
  721. $routeService->deleteRoutes($crudInfo->route_ids);
  722. }
  723. //删除掉权限路由
  724. if ($crudInfo->menu_ids) {
  725. app()->make(SystemMenusServices::class)->deleteMenus($crudInfo->menu_ids);
  726. }
  727. } else {
  728. $menuInfo = $meunService->save($dataMenu);
  729. }
  730. //写入路由权限
  731. $cateId = app()->make(SystemRouteServices::class)->topCateId('adminapi', 'CRUD');
  732. $ruleData = [
  733. [
  734. 'path' => $routeName,
  735. 'method' => 'GET',
  736. 'name' => $modelName . '列表接口',
  737. 'app_name' => 'adminapi',
  738. 'cate_id' => $cateId,
  739. 'unique_auth' => '',
  740. 'add_time' => date('Y-m-d H:i:s')
  741. ],
  742. [
  743. 'path' => $routeName . '/create',
  744. 'method' => 'GET',
  745. 'name' => $modelName . '获取创建表单接口',
  746. 'app_name' => 'adminapi',
  747. 'cate_id' => $cateId,
  748. 'unique_auth' => Str::snake($tableName) . '-add',
  749. 'add_time' => date('Y-m-d H:i:s')
  750. ],
  751. [
  752. 'path' => $routeName,
  753. 'method' => 'POST',
  754. 'name' => $modelName . '保存接口',
  755. 'app_name' => 'adminapi',
  756. 'cate_id' => $cateId,
  757. 'unique_auth' => '',
  758. 'add_time' => date('Y-m-d H:i:s')
  759. ],
  760. [
  761. 'path' => $routeName . '/<id>/edit',
  762. 'method' => 'GET',
  763. 'name' => $modelName . '获取修改表单接口',
  764. 'app_name' => 'adminapi',
  765. 'cate_id' => $cateId,
  766. 'unique_auth' => '',
  767. 'add_time' => date('Y-m-d H:i:s')
  768. ],
  769. [
  770. 'path' => $routeName . '/<id>',
  771. 'method' => 'GET',
  772. 'name' => $modelName . '查看数据接口',
  773. 'app_name' => 'adminapi',
  774. 'cate_id' => $cateId,
  775. 'unique_auth' => '',
  776. 'add_time' => date('Y-m-d H:i:s')
  777. ],
  778. [
  779. 'path' => $routeName . '/<id>',
  780. 'method' => 'PUT',
  781. 'name' => $modelName . '修改接口',
  782. 'app_name' => 'adminapi',
  783. 'cate_id' => $cateId,
  784. 'unique_auth' => '',
  785. 'add_time' => date('Y-m-d H:i:s')
  786. ],
  787. [
  788. 'path' => $routeName . '/status/<id>',
  789. 'method' => 'PUT',
  790. 'name' => $modelName . '修改状态接口',
  791. 'app_name' => 'adminapi',
  792. 'cate_id' => $cateId,
  793. 'unique_auth' => '',
  794. 'add_time' => date('Y-m-d H:i:s')
  795. ],
  796. [
  797. 'path' => $routeName . '/<id>',
  798. 'method' => 'DELETE',
  799. 'name' => $modelName . '删除接口',
  800. 'app_name' => 'adminapi',
  801. 'cate_id' => $cateId,
  802. 'unique_auth' => '',
  803. 'add_time' => date('Y-m-d H:i:s')
  804. ],
  805. ];
  806. $routeList = $routeService->saveAll($ruleData);
  807. $routeIds = array_column($routeList->toArray(), 'id');
  808. //记录权限加入菜单表
  809. $menuData = [];
  810. foreach ($ruleData as $item) {
  811. $menuData[] = [
  812. 'pid' => $menuInfo->id ?: 0,
  813. 'methods' => $item['method'],
  814. 'api_url' => $item['path'],
  815. 'unique_auth' => $item['unique_auth'],
  816. 'menu_name' => $item['name'],
  817. 'is_del' => 0,
  818. 'auth_type' => 2,
  819. ];
  820. }
  821. $menus = app()->make(SystemMenusServices::class)->saveAll($menuData);
  822. $menuIds = array_column($menus->toArray(), 'id');
  823. //生成文件
  824. $make = $this->makeFile($tableName, $routeName, true, $data, $filePath);
  825. $makePath = [];
  826. foreach ($make as $key => $item) {
  827. $makePath[$key] = $item['path'];
  828. }
  829. if ($tableCreateInfo && isset($tableCreateInfo['table']) && $tableCreateInfo['table'] instanceof Table) {
  830. //创建数据库
  831. $tableCreateInfo['table']->create();
  832. }
  833. $crudDate = [
  834. 'pid' => $data['pid'],
  835. 'name' => $data['menuName'],
  836. 'model_name' => $data['modelName'],
  837. 'table_name' => $tableName,
  838. 'table_comment' => $tableComment,
  839. 'table_collation' => self::TABLR_COLLATION,
  840. 'field' => json_encode($data),//提交的数据
  841. 'menu_ids' => json_encode($menuIds),//生成的菜单id
  842. 'menu_id' => $menuInfo->id,//生成的菜单id
  843. 'make_path' => json_encode($makePath),
  844. 'route_ids' => json_encode($routeIds),
  845. ];
  846. if ($crudInfo) {
  847. $res = $this->dao->update($crudInfo->id, $crudDate);
  848. } else {
  849. $crudDate['add_time'] = time();
  850. //记录crud生成
  851. $res = $this->dao->save($crudDate);
  852. }
  853. return $res;
  854. });
  855. return $res->toArray();
  856. }
  857. /**
  858. * 获取数据库配置
  859. * @return array
  860. */
  861. protected function getDbConfig(): array
  862. {
  863. $default = app()->config->get('database.default');
  864. $config = app()->config->get("database.connections.{$default}");
  865. if (0 == $config['deploy']) {
  866. $dbConfig = [
  867. 'adapter' => $config['type'],
  868. 'host' => $config['hostname'],
  869. 'name' => $config['database'],
  870. 'user' => $config['username'],
  871. 'pass' => $config['password'],
  872. 'port' => $config['hostport'],
  873. 'charset' => $config['charset'],
  874. 'table_prefix' => $config['prefix'],
  875. ];
  876. } else {
  877. $dbConfig = [
  878. 'adapter' => explode(',', $config['type'])[0],
  879. 'host' => explode(',', $config['hostname'])[0],
  880. 'name' => explode(',', $config['database'])[0],
  881. 'user' => explode(',', $config['username'])[0],
  882. 'pass' => explode(',', $config['password'])[0],
  883. 'port' => explode(',', $config['hostport'])[0],
  884. 'charset' => explode(',', $config['charset'])[0],
  885. 'table_prefix' => explode(',', $config['prefix'])[0],
  886. ];
  887. }
  888. $table = app()->config->get('database.migration_table', 'migrations');
  889. $dbConfig['default_migration_table'] = $dbConfig['table_prefix'] . $table;
  890. return $dbConfig;
  891. }
  892. public function getAdapter()
  893. {
  894. $options = $this->getDbConfig();
  895. $adapter = AdapterFactory::instance()->getAdapter($options['adapter'], $options);
  896. if ($adapter->hasOption('table_prefix') || $adapter->hasOption('table_suffix')) {
  897. $adapter = AdapterFactory::instance()->getWrapper('prefix', $adapter);
  898. }
  899. return $adapter;
  900. }
  901. /**
  902. * 创建数据库
  903. * @param string $tableName
  904. * @param string $tableComment
  905. * @param array $tableField
  906. * @return array
  907. * @author 等风来
  908. * @email 136327134@qq.com
  909. * @date 2023/4/7
  910. */
  911. public function makeDatebase(string $tableName, string $tableComment, array $tableField = [], string $collation = self::TABLR_COLLATION)
  912. {
  913. $timestampsField = [];
  914. $softDelete = false;
  915. $timestamps = false;
  916. $indexField = [];
  917. //创建表
  918. $table = new Table($tableName, ['comment' => $tableComment, 'collation' => $collation], $this->getAdapter());
  919. //创建字段
  920. foreach ($tableField as $item) {
  921. if (isset($item['primaryKey']) && $item['primaryKey']) {
  922. continue;
  923. }
  924. $option = [];
  925. if (isset($item['limit'])) {
  926. $option['limit'] = (int)$item['limit'];
  927. }
  928. if (isset($item['default']) && isset($item['default_type'])) {
  929. switch ($item['default_type']) {
  930. case '1'://自定义
  931. $option['default'] = $item['default'];
  932. break;
  933. case '2'://为null
  934. $option['null'] = true;
  935. break;
  936. case '3'://时间
  937. $option['default'] = Db::raw('CURRENT_TIMESTAMP');
  938. break;
  939. }
  940. }
  941. //创建伪删除
  942. if ($item['field_type'] === 'addSoftDelete') {
  943. $table->addSoftDelete();
  944. $softDelete = true;
  945. } else if ($item['field_type'] == 'timestamp' &&
  946. ($item['field'] === 'create_time' || $item['field'] === 'update_time')) {
  947. $timestampsField[] = $item;
  948. } else {
  949. $option['comment'] = $item['comment'];
  950. $fieldType = $this->changeTabelRule($item['field_type']);
  951. if (in_array($fieldType, ['text', 'longtext', 'tinytext'])) {
  952. unset($option['limit']);
  953. }
  954. //判断字段类型
  955. if ($fieldType == 'boolean' && isset($option['default']) && $option['default'] === '') {
  956. unset($option['default']);
  957. }
  958. //兼容枚举字段
  959. if ($fieldType == 'enum') {
  960. unset($option['limit']);
  961. $option['values'] = $item['limit'];
  962. }
  963. $table->addColumn($item['field'], $this->changeTabelRule($item['field_type']), $option);
  964. }
  965. }
  966. //创建索引
  967. if (!empty($data['tableIndex'])) {
  968. $indexField = $data['tableIndex'];
  969. foreach ($data['tableIndex'] as $item) {
  970. $table->addIndex($item);
  971. }
  972. }
  973. //如果是成对出现的create_time和update_time就直接增加修改和添加时间
  974. if (count($timestampsField) == 2) {
  975. //创建修改和增加时间
  976. $table->addTimestamps();
  977. $timestamps = true;
  978. } else {
  979. //如果是一个数组,增加一列
  980. foreach ($timestampsField as $item) {
  981. $option['comment'] = $item['comment'];
  982. $table->addColumn($item['field'], $this->changeTabelRule($item['field_type']), $option);
  983. }
  984. }
  985. return compact('indexField', 'softDelete', 'timestamps', 'table');
  986. }
  987. /**
  988. * 创建文件返回文件路径和内容
  989. * @param string $tableName
  990. * @param string $routeName
  991. * @param bool $isMake
  992. * @param array $options
  993. * @param array $filePath
  994. * @param string $basePath
  995. * @return array[]
  996. * @author 等风来
  997. * @email 136327134@qq.com
  998. * @date 2023/4/7
  999. */
  1000. public function makeFile(string $tableName, string $routeName, bool $isMake = false, array $options = [], array $filePath = [], string $basePath = '')
  1001. {
  1002. $options['fromField'] = is_array($options['fromField']) ? $options['fromField'] : [];
  1003. $options['columnField'] = is_array($options['columnField']) ? $options['columnField'] : [];
  1004. //生成模型
  1005. $model = app()->make(Model::class);
  1006. $model->setFilePathName($filePath['model'] ?? '')->setbasePath($basePath)->handle($tableName, $options);
  1007. //生成dao
  1008. $dao = app()->make(Dao::class);
  1009. $dao->setFilePathName($filePath['dao'] ?? '')->setbasePath($basePath)->handle($tableName, [
  1010. 'usePath' => $model->getUsePath(),
  1011. 'modelName' => $options['modelName'] ?? '',
  1012. 'searchField' => $options['searchField'] ?? [],
  1013. ]);
  1014. //生成service
  1015. $service = app()->make(Service::class);
  1016. $service->setFilePathName($filePath['service'] ?? '')->setbasePath($basePath)->handle($tableName, [
  1017. 'field' => $options['fromField'],
  1018. 'columnField' => $options['columnField'],
  1019. 'key' => $options['key'],
  1020. 'usePath' => $dao->getUsePath(),
  1021. 'modelName' => $options['modelName'] ?? '',
  1022. 'hasOneField' => $options['hasOneField'] ?? [],
  1023. ]);
  1024. //生成验证器
  1025. $validate = app()->make(Validate::class);
  1026. $validate->setFilePathName($filePath['validate'] ?? '')->setbasePath($basePath)->handle($tableName, [
  1027. 'field' => $options['fromField'],
  1028. 'modelName' => $options['modelName'] ?? '',
  1029. ]);
  1030. //生成控制器
  1031. $controller = app()->make(Controller::class);
  1032. $controller->setFilePathName($filePath['controller'] ?? '')->setbasePath($basePath)->handle($tableName, [
  1033. 'usePath' => $service->getUsePath(),
  1034. 'modelName' => $options['modelName'] ?? '',
  1035. 'searchField' => $options['searchField'] ?? [],
  1036. 'columnField' => $options['columnField'] ?? [],
  1037. 'validateName' => '\\' . str_replace('/', '\\', $validate->getUsePath()) . 'Validate::class',
  1038. 'field' => array_column($options['fromField'], 'field'),
  1039. ]);
  1040. //生成路由
  1041. $route = app()->make(Route::class);
  1042. $route->setFilePathName($filePath['route'] ?? '')->setbasePath($basePath)->handle($tableName, [
  1043. 'menus' => $options['modelName'] ?? $options['menuName'],
  1044. 'route' => $routeName
  1045. ]);
  1046. //生成前台路由
  1047. $viewRouter = app()->make(ViewRouter::class);
  1048. $viewRouter->setFilePathName($filePath['router'] ?? '')->setbasePath($basePath)->handle($tableName, [
  1049. 'route' => $routeName,
  1050. 'menuName' => $options['menuName'],
  1051. 'modelName' => $options['modelName'] ?? $options['menuName'],
  1052. ]);
  1053. //生成前台接口
  1054. $viewApi = app()->make(ViewApi::class);
  1055. $viewApi->setFilePathName($filePath['api'] ?? '')->setbasePath($basePath)->handle($tableName, [
  1056. 'route' => $routeName,
  1057. ]);
  1058. //生成前台页面
  1059. $viewPages = app()->make(ViewPages::class);
  1060. $viewPages->setFilePathName($filePath['pages'] ?? '')->setbasePath($basePath)->handle($tableName, [
  1061. 'field' => $options['columnField'],
  1062. 'tableFields' => $options['tableField'] ?? [],
  1063. 'searchField' => $options['searchField'] ?? [],
  1064. 'route' => $routeName,
  1065. 'key' => $options['key'],
  1066. 'pathApiJs' => '@/' . str_replace('\\', '/', str_replace([Make::adminTemplatePath(), '.js'], '', $viewApi->getPath())),
  1067. ]);
  1068. //创建文件
  1069. if ($isMake) {
  1070. FileService::batchMakeFiles([$model, $validate, $dao, $service, $controller, $route, $viewApi, $viewPages, $viewRouter]);
  1071. }
  1072. return [
  1073. 'controller' => [
  1074. 'path' => $this->replace($controller->getPath()),
  1075. 'content' => $controller->getContent()
  1076. ],
  1077. 'model' => [
  1078. 'path' => $this->replace($model->getPath()),
  1079. 'content' => $model->getContent()
  1080. ],
  1081. 'dao' => [
  1082. 'path' => $this->replace($dao->getPath()),
  1083. 'content' => $dao->getContent()
  1084. ],
  1085. 'route' => [
  1086. 'path' => $this->replace($route->getPath()),
  1087. 'content' => $route->getContent()
  1088. ],
  1089. 'service' => [
  1090. 'path' => $this->replace($service->getPath()),
  1091. 'content' => $service->getContent()
  1092. ],
  1093. 'validate' => [
  1094. 'path' => $this->replace($validate->getPath()),
  1095. 'content' => $validate->getContent()
  1096. ],
  1097. 'router' => [
  1098. 'path' => $this->replace($viewRouter->getPath()),
  1099. 'content' => $viewRouter->getContent()
  1100. ],
  1101. 'api' => [
  1102. 'path' => $this->replace($viewApi->getPath()),
  1103. 'content' => $viewApi->getContent()
  1104. ],
  1105. 'pages' => [
  1106. 'path' => $this->replace($viewPages->getPath()),
  1107. 'content' => $viewPages->getContent()
  1108. ],
  1109. ];
  1110. }
  1111. protected function replace(string $path)
  1112. {
  1113. return str_replace([app()->getRootPath(), Make::adminTemplatePath()], '', $path);
  1114. }
  1115. /**
  1116. * @param string $tableName
  1117. * @param bool $fullName
  1118. * @return string
  1119. * @author 等风来
  1120. * @email 136327134@qq.com
  1121. * @date 2023/4/7
  1122. */
  1123. public function getTableName(string $tableName, bool $fullName = true)
  1124. {
  1125. $tablePrefix = config('database.connections.mysql.prefix');
  1126. $pattern = '/^' . $tablePrefix . '/i';
  1127. return ($fullName ? $tablePrefix : '') . (preg_replace($pattern, '', $tableName));
  1128. }
  1129. }