get('table'); $table = Util::filterAlphaNum($table); $form = Layui::buildForm($table, 'search'); $table_info = Util::getSchema($table, 'table'); $primary_key = $table_info['primary_key'][0] ?? null; return raw_view("table/view", [ 'form' => $form, 'table' => $table, 'primary_key' => $primary_key, ]); } /** * 查询表 * @param Request $request * @return Response * @throws BusinessException */ public function show(Request $request): Response { $table_name = $request->get('table_name',''); $limit = (int)$request->get('limit', 10); $page = (int)$request->get('page', 1); $offset = ($page - 1) * $limit; $database = config('database.connections')['plugin.admin.mysql']['database']; $field = $request->get('field', 'TABLE_NAME'); $field = Util::filterAlphaNum($field); $order = $request->get('order', 'asc'); $allow_column = ['TABLE_NAME', 'TABLE_COMMENT', 'ENGINE', 'TABLE_ROWS', 'CREATE_TIME', 'UPDATE_TIME', 'TABLE_COLLATION']; if (!in_array($field, $allow_column)) { $field = 'TABLE_NAME'; } $order = $order === 'asc' ? 'asc' : 'desc'; $total = Util::db()->select("SELECT count(*)total FROM information_schema.`TABLES` WHERE TABLE_SCHEMA='$database' AND TABLE_NAME like '%{$table_name}%'")[0]->total ?? 0; $tables = Util::db()->select("SELECT TABLE_NAME,TABLE_COMMENT,ENGINE,TABLE_ROWS,CREATE_TIME,UPDATE_TIME,TABLE_COLLATION FROM information_schema.`TABLES` WHERE TABLE_SCHEMA='$database' AND TABLE_NAME like '%{$table_name}%' order by $field $order limit $offset,$limit"); if ($tables) { $table_names = array_column($tables, 'TABLE_NAME'); $table_rows_count = []; foreach ($table_names as $table_name) { $table_rows_count[$table_name] = Util::db()->table($table_name)->count(); } foreach ($tables as $key => $table) { $tables[$key]->TABLE_ROWS = $table_rows_count[$table->TABLE_NAME] ?? $table->TABLE_ROWS; } } return json(['code' => 0, 'msg' => 'ok', 'count' => $total, 'data' => $tables]); } /** * 创建表 * @param Request $request * @return Response * @throws BusinessException|Throwable */ public function create(Request $request): Response { if ($request->method() === 'GET') { return raw_view("table/create", []); } $data = $request->post(); $table_name = Util::filterAlphaNum($data['table']); $table_comment = Util::pdoQuote($data['table_comment']); $columns = $data['columns']; $forms = $data['forms']; $keys = $data['keys']; $primary_key_count = 0; foreach ($columns as $index => $item) { $columns[$index]['field'] = trim($item['field']); if (!$item['field']) { unset($columns[$index]); continue; } $columns[$index]['primary_key'] = !empty($item['primary_key']); if ($columns[$index]['primary_key']) { $primary_key_count++; } $columns[$index]['auto_increment'] = !empty($item['auto_increment']); $columns[$index]['nullable'] = !empty($item['nullable']); if ($item['default'] === '') { $columns[$index]['default'] = null; } else if ($item['default'] === "''") { $columns[$index]['default'] = ''; } } if ($primary_key_count > 1) { throw new BusinessException('不支持复合主键'); } foreach ($forms as $index => $item) { if (!$item['field']) { unset($forms[$index]); continue; } $forms[$index]['form_show'] = !empty($item['form_show']); $forms[$index]['list_show'] = !empty($item['list_show']); $forms[$index]['enable_sort'] = !empty($item['enable_sort']); $forms[$index]['searchable'] = !empty($item['searchable']); } foreach ($keys as $index => $item) { if (!$item['name'] || !$item['columns']) { unset($keys[$index]); } } Util::schema()->create($table_name, function (Blueprint $table) use ($columns) { $type_method_map = Util::methodControlMap(); foreach ($columns as $column) { if (!isset($column['type'])) { throw new BusinessException("请为{$column['field']}选择类型"); } if (!isset($type_method_map[$column['type']])) { throw new BusinessException("不支持的类型{$column['type']}"); } $this->createColumn($column, $table); } $table->charset = 'utf8mb4'; $table->collation = 'utf8mb4_general_ci'; $table->engine = 'InnoDB'; }); Util::db()->statement("ALTER TABLE `$table_name` COMMENT $table_comment"); // 索引 Util::schema()->table($table_name, function (Blueprint $table) use ($keys) { foreach ($keys as $key) { $name = $key['name']; $columns = is_array($key['columns']) ? $key['columns'] : explode(',', $key['columns']); $type = $key['type']; if ($type == 'unique') { $table->unique($columns, $name); continue; } $table->index($columns, $name); } }); $form_schema_map = []; foreach ($forms as $item) { $form_schema_map[$item['field']] = $item; } $form_schema_map = json_encode($form_schema_map, JSON_UNESCAPED_UNICODE); $this->updateSchemaOption($table_name, $form_schema_map); return $this->json(0, 'ok'); } /** * 修改表 * @param Request $request * @return Response * @throws BusinessException|Throwable */ public function modify(Request $request): Response { if ($request->method() === 'GET') { return raw_view("table/modify", ['table' => $request->get('table')]); } $data = $request->post(); $old_table_name = Util::filterAlphaNum($data['old_table']); $table_name = Util::filterAlphaNum($data['table']); $table_comment = $data['table_comment']; $columns = $data['columns']; $forms = $data['forms']; $keys = $data['keys']; $primary_key = null; $auto_increment_column = null; $schema = Util::getSchema($old_table_name); $old_columns = $schema['columns']; $old_primary_key = $schema['table']['primary_key'][0] ?? null; $primary_key_count = $auto_increment_count = 0; foreach ($columns as $index => $item) { $columns[$index]['field'] = trim($item['field']); if (!$item['field']) { unset($columns[$index]); continue; } $field = $item['field']; $columns[$index]['auto_increment'] = !empty($item['auto_increment']); $columns[$index]['nullable'] = !empty($item['nullable']); $columns[$index]['primary_key'] = !empty($item['primary_key']); if ($columns[$index]['primary_key']) { $primary_key = $item['field']; $columns[$index]['nullable'] = false; $primary_key_count++; } if ($item['default'] === '') { $columns[$index]['default'] = null; } else if ($item['default'] === "''") { $columns[$index]['default'] = ''; } if ($columns[$index]['auto_increment']) { $auto_increment_count++; if (!isset($old_columns[$field]) || !$old_columns[$field]['auto_increment']) { $auto_increment_column = $columns[$index]; unset($auto_increment_column['old_field']); $columns[$index]['auto_increment'] = false; } } } if ($primary_key_count > 1) { throw new BusinessException('不支持复合主键'); } if ($auto_increment_count > 1) { throw new BusinessException('一个表只能有一个自增字段,并且必须为key'); } foreach ($forms as $index => $item) { if (!$item['field']) { unset($forms[$index]); continue; } $forms[$index]['form_show'] = !empty($item['form_show']); $forms[$index]['list_show'] = !empty($item['list_show']); $forms[$index]['enable_sort'] = !empty($item['enable_sort']); $forms[$index]['searchable'] = !empty($item['searchable']); } foreach ($keys as $index => $item) { if (!$item['name'] || !$item['columns']) { unset($keys[$index]); } } // 改表名 if ($table_name != $old_table_name) { Util::schema()->rename($old_table_name, $table_name); } $type_method_map = Util::methodControlMap(); foreach ($columns as $column) { if (!isset($type_method_map[$column['type']])) { throw new BusinessException("不支持的类型{$column['type']}"); } $field = $column['old_field'] ?? $column['field'] ; $old_column = $old_columns[$field] ?? []; // 类型更改 foreach ($old_column as $key => $value) { if (key_exists($key, $column) && ($column[$key] != $value || ($key === 'default' && $column[$key] !== $value))) { $this->modifyColumn($column, $table_name); break; } } } $table = Util::getSchema($table_name, 'table'); if ($table_comment !== $table['comment']) { $table_comment = Util::pdoQuote($table_comment); Util::db()->statement("ALTER TABLE `$table_name` COMMENT $table_comment"); } $old_columns = Util::getSchema($table_name, 'columns'); Util::schema()->table($table_name, function (Blueprint $table) use ($columns, $old_columns, $keys, $table_name) { foreach ($columns as $column) { $field = $column['field']; // 新字段 if (!isset($old_columns[$field])) { $this->createColumn($column, $table); } } // 更新索引名字 foreach ($keys as $key) { if (!empty($key['old_name']) && $key['old_name'] !== $key['name']) { $table->renameIndex($key['old_name'], $key['name']); } } }); // 找到删除的字段 $old_columns = Util::getSchema($table_name, 'columns'); $exists_column_names = array_column($columns, 'field', 'field'); $old_columns_names = array_column($old_columns, 'field'); $drop_column_names = array_diff($old_columns_names, $exists_column_names); $drop_column_names = Util::filterAlphaNum($drop_column_names); foreach ($drop_column_names as $drop_column_name) { Util::db()->statement("ALTER TABLE `$table_name` DROP COLUMN `$drop_column_name`"); } $old_keys = Util::getSchema($table_name, 'keys'); Util::schema()->table($table_name, function (Blueprint $table) use ($keys, $old_keys, $table_name) { foreach ($keys as $key) { $key_name = $key['name']; $old_key = $old_keys[$key_name] ?? []; // 如果索引有变动,则删除索引,重新建立索引 if ($old_key && ($key['type'] != $old_key['type'] || $key['columns'] != implode(',', $old_key['columns']))) { $old_key = []; unset($old_keys[$key_name]); echo "Drop Index $key_name\n"; $table->dropIndex($key_name); } // 重新建立索引 if (!$old_key) { $name = $key['name']; $columns = is_array($key['columns']) ? $key['columns'] : explode(',', $key['columns']); $type = $key['type']; if ($type == 'unique') { $table->unique($columns, $name); continue; } echo "Create Index $key_name\n"; $table->index($columns, $name); } } // 找到删除的索引 $exists_key_names = array_column($keys, 'name', 'name'); $old_keys_names = array_column($old_keys, 'name'); $drop_keys_names = array_diff($old_keys_names, $exists_key_names); foreach ($drop_keys_names as $name) { echo "Drop Index $name\n"; $table->dropIndex($name); } }); // 变更主键 if ($old_primary_key != $primary_key) { if ($old_primary_key) { Util::db()->statement("ALTER TABLE `$table_name` DROP PRIMARY KEY"); } if ($primary_key) { $primary_key = Util::filterAlphaNum($primary_key); Util::db()->statement("ALTER TABLE `$table_name` ADD PRIMARY KEY(`$primary_key`)"); } } // 一个表只能有一个 auto_increment 字段,并且是key,所以需要在最后设置 if ($auto_increment_column) { $this->modifyColumn($auto_increment_column, $table_name); } $form_schema_map = []; foreach ($forms as $item) { $form_schema_map[$item['field']] = $item; } $form_schema_map = json_encode($form_schema_map, JSON_UNESCAPED_UNICODE); $option_name = $this->updateSchemaOption($table_name, $form_schema_map); return $this->json(0,$option_name); } /** * 一键菜单 * @param Request $request * @return Response * @throws BusinessException|Throwable */ public function crud(Request $request): Response { $table_name = $request->input('table'); Util::checkTableName($table_name); $prefix = 'wa_'; $table_basename = strpos($table_name, $prefix) === 0 ? substr($table_name, strlen($prefix)) : $table_name; $inflector = InflectorFactory::create()->build(); $model_class = $inflector->classify($inflector->singularize($table_basename)); $base_path = '/plugin/admin/app'; if ($request->method() === 'GET') { return raw_view("table/crud", [ 'table' => $table_name, 'model' => "$base_path/model/$model_class.php", 'controller' => "$base_path/controller/{$model_class}Controller.php", ]); } $title = $request->post('title'); $pid = $request->post('pid', 0); $icon = $request->post('icon', ''); $controller_file = '/' . trim($request->post('controller', ''), '/'); $model_file = '/' . trim($request->post('model', ''), '/'); $overwrite = $request->post('overwrite'); if ($controller_file === '/' || $model_file === '/') { return $this->json(1, '控制器和model不能为空'); } $controller_info = pathinfo($controller_file); $model_info = pathinfo($model_file); $controller_path = Util::filterPath($controller_info['dirname'] ?? ''); $model_path = Util::filterPath($model_info['dirname'] ?? ''); $controller_file_name = Util::filterAlphaNum($controller_info['filename'] ?? ''); $model_file_name = Util::filterAlphaNum($model_info['filename'] ?? ''); if ($controller_info['extension'] !== 'php' || $model_info['extension'] !== 'php' ) { return $this->json(1, '控制器和model必须以.php为后缀'); } $pid = (int)$pid; if ($pid) { $parent_menu = Rule::find($pid); if (!$parent_menu) { return $this->json(1, '父菜单不存在'); } } if (!$overwrite) { if (is_file(base_path($controller_file))) { return $this->json(1, "$controller_file 已经存在"); } if (is_file(base_path($model_file))) { return $this->json(1, "$model_file 已经存在"); } } $explode = explode('/', trim($controller_path, '/')); $plugin = ''; if (strpos(strtolower($controller_file), '/controller/') === false) { return $this->json(2, '控制器必须在controller目录下'); } if ($explode[0] === 'plugin') { if (count($explode) < 4) { return $this->json(2, '控制器参数非法'); } $plugin = $explode[1]; if (strtolower($explode[2]) !== 'app') { return $this->json(2, '控制器必须在app目录'); } $app = strtolower($explode[3]) !== 'controller' ? $explode[3] : ''; } else { if (count($explode) < 2) { return $this->json(3, '控制器参数非法'); } if (strtolower($explode[0]) !== 'app') { return $this->json(3, '控制器必须在app目录'); } $app = strtolower($explode[1]) !== 'controller' ? $explode[1] : ''; } Util::pauseFileMonitor(); try { $model_class = $model_file_name; $model_namespace = str_replace('/', '\\', trim($model_path, '/')); // 创建model $this->createModel($model_class, $model_namespace, base_path($model_file), $table_name); $controller_suffix = $plugin ? config("plugin.$plugin.app.controller_suffix") : config('app.controller_suffix'); $controller_class = $controller_file_name; $controller_namespace = str_replace('/', '\\', trim($controller_path, '/')); // 创建controller $controller_url_name = $controller_suffix && substr($controller_class, -strlen($controller_suffix)) === $controller_suffix ? substr($controller_class, 0, -strlen($controller_suffix)) : $controller_class; $controller_url_name = str_replace('_', '-', $inflector->tableize($controller_url_name)); if ($plugin) { array_splice($explode, 0, 2); } array_shift($explode); if ($app) { array_shift($explode); } foreach ($explode as $index => $item) { if (strtolower($item) === 'controller') { unset($explode[$index]); } } $controller_base = implode('/', $explode); $controller_class_with_namespace = "$controller_namespace\\$controller_class"; $template_path = $controller_base ? "$controller_base/$controller_url_name" : $controller_url_name; $this->createController($controller_class, $controller_namespace, base_path($controller_file), $model_class, $model_namespace, $title, $template_path); // 创建模版 $template_file_path = ($plugin ? "/plugin/$plugin" : '') . '/app/' . ($app ? "$app/" : '') . 'view/' . $template_path; $model_class_with_namespace = "$model_namespace\\$model_class"; $primary_key = (new $model_class_with_namespace)->getKeyName(); $url_path_base = ($plugin ? "/app/$plugin/" : '/') . ($app ? "$app/" : '') . $template_path; $this->createTemplate(base_path($template_file_path), $table_name, $url_path_base, $primary_key, "$controller_namespace\\$controller_class"); } finally { Util::resumeFileMonitor(); } $menu = Rule::where('key', $controller_class_with_namespace)->first(); if (!$menu) { $menu = new Rule; } $menu->pid = $pid; $menu->key = $controller_class_with_namespace; $menu->title = $title; $menu->icon = $icon; $menu->href = "$url_path_base/index"; $menu->save(); $roles = admin('roles'); $rules = Role::whereIn('id', $roles)->pluck('rules'); $rule_ids = []; foreach ($rules as $rule_string) { if (!$rule_string) { continue; } $rule_ids = array_merge($rule_ids, explode(',', $rule_string)); } // 不是超级管理员,则需要给当前管理员这个菜单的权限 if (!in_array('*', $rule_ids) && $roles){ $role = Role::find(current($roles)); if ($role) { $role->rules .= ",{$menu->id}"; } $role->save(); } return $this->json(0); } /** * 创建model * @param $class * @param $namespace * @param $file * @param $table * @return void */ protected function createModel($class, $namespace, $file, $table) { $this->mkdir($file); $table_val = "'$table'"; $pk = 'id'; $properties = ''; $timestamps = ''; $incrementing = ''; $columns = []; try { $database = config('database.connections')['plugin.admin.mysql']['database']; //plugin.admin.mysql foreach (Util::db()->select("select COLUMN_NAME,DATA_TYPE,COLUMN_KEY,COLUMN_COMMENT from INFORMATION_SCHEMA.COLUMNS where table_name = '$table' and table_schema = '$database' order by ORDINAL_POSITION") as $item) { if ($item->COLUMN_KEY === 'PRI') { $pk = $item->COLUMN_NAME; $item->COLUMN_COMMENT .= "(主键)"; if (strpos(strtolower($item->DATA_TYPE), 'int') === false) { $incrementing = <<getType($item->DATA_TYPE); $properties .= " * @property $type \${$item->COLUMN_NAME} {$item->COLUMN_COMMENT}\n"; $columns[$item->COLUMN_NAME] = $item->COLUMN_NAME; } } catch (Throwable $e) {echo $e;} if (!isset($columns['created_at']) || !isset($columns['updated_at'])) { $timestamps = <<mkdir($file); $controller_content = <<model = new $model_class; } /** * 浏览 * @return Response */ public function index(): Response { return view('$template_path/index'); } /** * 插入 * @param Request \$request * @return Response * @throws BusinessException */ public function insert(Request \$request): Response { if (\$request->method() === 'POST') { return parent::insert(\$request); } return view('$template_path/insert'); } /** * 更新 * @param Request \$request * @return Response * @throws BusinessException */ public function update(Request \$request): Response { if (\$request->method() === 'POST') { return parent::update(\$request); } return view('$template_path/update'); } } EOF; file_put_contents($file, $controller_content); } /** * 创建控制器 * @param $template_file_path * @param $table * @param $template_path * @param $url_path_base * @param $primary_key * @param $controller_class_with_namespace * @return void */ protected function createTemplate($template_file_path, $table, $url_path_base, $primary_key, $controller_class_with_namespace) { $this->mkdir($template_file_path . '/index.html'); $code_base = Util::controllerToUrlPath($controller_class_with_namespace); $code_base = str_replace('/', '.', trim($code_base, '/')); $form = Layui::buildForm($table, 'search'); $html = $form->html(3); $html = $html ? <<
$html
EOF : ''; $html = str_replace("\n", "\n" . str_repeat(' ', 2), $html); $js = $form->js(3); $table_js = Layui::buildTable($table, 4); $template_content = << 浏览页面 $html
EOF; file_put_contents("$template_file_path/index.html", $template_content); $form = Layui::buildForm($table); $html = $form->html(5); $js = $form->js(3); $template_content = << 新增页面
$html
EOF; file_put_contents("$template_file_path/insert.html", $template_content); $form = Layui::buildForm($table, 'update'); $html = $form->html(5); $js = $form->js(6); $template_content = << 更新页面
$html
EOF; file_put_contents("$template_file_path/update.html", $template_content); } /** * 创建目录 * @param $file * @return void */ protected function mkdir($file) { $path = pathinfo($file, PATHINFO_DIRNAME); if (!is_dir($path)) { mkdir($path, 0777, true); } } /** * 查询记录 * @param Request $request * @return Response * @throws BusinessException */ public function select(Request $request): Response { $page = $request->get('page', 1); $field = $request->get('field'); $order = $request->get('order', 'asc'); $table = Util::filterAlphaNum($request->get('table', '')); $format = $request->get('format', 'normal'); $limit = $request->get('limit', $format === 'tree' ? 5000 : 10); $allow_column = Util::db()->select("desc `$table`"); if (!$allow_column) { return $this->json(2, '表不存在'); } $allow_column = array_column($allow_column, 'Field', 'Field'); if (!in_array($field, $allow_column)) { $field = current($allow_column); } $order = $order === 'asc' ? 'asc' : 'desc'; $paginator = Util::db()->table($table); foreach ($request->get() as $column => $value) { if ($value === '') { continue; } if (isset($allow_column[$column])) { if (is_array($value)) { if ($value[0] === 'like') { $paginator = $paginator->where($column, 'like', "%$value[1]%"); } elseif (in_array($value[0], ['>', '=', '<', '<>', 'not like'])) { $paginator = $paginator->where($column, $value[0], $value[1]); } else { if($value[0] !== '' || $value[1] !== '') { $paginator = $paginator->whereBetween($column, $value); } } } else { $paginator = $paginator->where($column, $value); } } } $paginator = $paginator->orderBy($field, $order)->paginate($limit, '*', 'page', $page); $items = $paginator->items(); if ($format == 'tree') { $items_map = []; foreach ($items as $item) { $items_map[$item->id] = (array)$item; } $formatted_items = []; foreach ($items_map as $index => $item) { if ($item['pid'] && isset($items_map[$item['pid']])) { $items_map[$item['pid']]['children'][] = &$items_map[$index]; } } foreach ($items_map as $item) { if (!$item['pid']) { $formatted_items[] = $item; } } $items = $formatted_items; } return json(['code' => 0, 'msg' => 'ok', 'count' => $paginator->total(), 'data' => $items]); } /** * 插入记录 * @param Request $request * @return Response * @throws BusinessException|Throwable */ public function insert(Request $request): Response { if ($request->method() === 'GET') { $table = $request->get('table'); $form = Layui::buildForm($table); return raw_view("table/insert", [ 'form' => $form, 'table' => $table ]); } $table = Util::filterAlphaNum($request->input('table', '')); $data = $request->post(); $allow_column = Util::db()->select("desc `$table`"); if (!$allow_column) { throw new BusinessException('表不存在', 2); } $columns = array_column($allow_column, 'Type', 'Field'); foreach ($data as $col => $item) { if (!isset($columns[$col])) { unset($data[$col]); continue; } // 非字符串类型传空则为null if ($item === '' && strpos(strtolower($columns[$col]), 'varchar') === false && strpos(strtolower($columns[$col]), 'text') === false) { $data[$col] = null; } if (is_array($item)) { $data[$col] = implode(',', $item); continue; } if ($col === 'password') { $data[$col] = Util::passwordHash($item); } } $datetime = date('Y-m-d H:i:s'); if (isset($columns['created_at']) && empty($data['created_at'])) { $data['created_at'] = $datetime; } if (isset($columns['updated_at']) && empty($data['updated_at'])) { $data['updated_at'] = $datetime; } $id = Util::db()->table($table)->insertGetId($data); return $this->json(0, $id); } /** * 更新记录 * @param Request $request * @return Response * @throws BusinessException|Throwable */ public function update(Request $request): Response { if ($request->method() === 'GET') { $table = $request->get('table'); $table_info = Util::getSchema($table, 'table'); $primary_key = $table_info['primary_key'][0] ?? null; $value = htmlspecialchars($request->get($primary_key, '')); $form = Layui::buildForm($table,'update'); return raw_view("table/update", [ 'primary_key' => $primary_key, 'value' => $value, 'form' => $form, 'table' => $table ]); } $table = Util::filterAlphaNum($request->post('table')); $table_info = Util::getSchema($table, 'table'); $primary_keys = $table_info['primary_key']; if (empty($primary_keys)) { return $this->json(1, '该表没有主键,无法执行更新操作'); } if (count($primary_keys) > 1) { return $this->json(1, '不支持复合主键更新'); } $primary_key = $primary_keys[0]; $value = $request->post($primary_key); $data = $request->post(); $allow_column = Util::db()->select("desc `$table`"); if (!$allow_column) { throw new BusinessException('表不存在', 2); } $columns = array_column($allow_column, 'Type', 'Field'); foreach ($data as $col => $item) { if (!isset($columns[$col])) { unset($data[$col]); continue; } // 非字符串类型传空则为null if ($item === '' && strpos(strtolower($columns[$col]), 'varchar') === false && strpos(strtolower($columns[$col]), 'text') === false) { $data[$col] = null; } if (is_array($item)) { $data[$col] = implode(',', $item); } if ($col === 'password') { // 密码为空,则不更新密码 if ($item == '') { unset($data[$col]); continue; } $data[$col] = Util::passwordHash($item); } } $datetime = date('Y-m-d H:i:s'); if (isset($columns['updated_at']) && empty($data['updated_at'])) { $data['updated_at'] = $datetime; } Util::db()->table($table)->where($primary_key, $value)->update($data); return $this->json(0); } /** * 删除记录 * @param Request $request * @return Response * @throws BusinessException */ public function delete(Request $request): Response { $table = $request->post('table'); $table_info = Util::getSchema($table, 'table'); $primary_keys = $table_info['primary_key']; if (empty($primary_keys)) { return $this->json(1, '该表没有主键,无法执行删除操作'); } if (count($primary_keys) > 1) { return $this->json(1, '不支持复合主键删除'); } $primary_key = $primary_keys[0]; $value = (array)$request->post($primary_key); Util::db()->table($table)->whereIn($primary_key, $value)->delete(); return $this->json(0); } /** * 删除表 * @param Request $request * @return Response */ public function drop(Request $request): Response { $tables = $request->post('tables'); if (!$tables) { return $this->json(0, 'not found'); } $prefix = 'wa_'; $table_not_allow_drop = ["{$prefix}admins", "{$prefix}users", "{$prefix}options", "{$prefix}roles", "{$prefix}rules", "{$prefix}admin_roles", "{$prefix}uploads"]; if ($found = array_intersect($tables, $table_not_allow_drop)) { return $this->json(400, implode(',', $found) . '不允许删除'); } foreach ($tables as $table) { Util::schema()->drop($table); // 删除schema Util::db()->table('wa_options')->where('name', "table_form_schema_$table")->delete(); } return $this->json(0, 'ok'); } /** * 表摘要 * @param Request $request * @return Response */ public function schema(Request $request): Response { $table = $request->get('table'); $data = Util::getSchema($table); return $this->json(0, 'ok', [ 'table' => $data['table'], 'columns' => array_values($data['columns']), 'forms' => array_values($data['forms']), 'keys' => array_values($data['keys']), ]); } /** * 创建字段 * @param $column * @param Blueprint $table * @return mixed */ protected function createColumn($column, Blueprint $table) { $method = $column['type']; $args = [$column['field']]; if (stripos($method, 'int') !== false) { // auto_increment 会自动成为主键 if ($column['auto_increment']) { $column['nullable'] = false; $column['default'] = null; $args[] = true; } } elseif (in_array($method, ['string', 'char']) || stripos($method, 'time') !== false) { if ($column['length']) { $args[] = $column['length']; } } elseif ($method === 'enum') { $args[] = array_map('trim', explode(',', $column['length'])); } elseif (in_array($method, ['float', 'decimal', 'double'])) { if ($column['length']) { $args = array_merge($args, array_map('trim', explode(',', $column['length']))); } } else { $column['auto_increment'] = false; } $column_def = call_user_func_array([$table, $method], $args); if (!empty($column['comment'])) { $column_def = $column_def->comment($column['comment']); } if (!$column['auto_increment'] && $column['primary_key']) { $column_def = $column_def->primary(true); } if ($column['auto_increment'] && !$column['primary_key']) { $column_def = $column_def->primary(false); } $column_def = $column_def->nullable($column['nullable']); if ($column['primary_key']) { $column_def = $column_def->nullable(false); } if ($method != 'text' && $column['default'] !== null) { $column_def->default($column['default']); } return $column_def; } /** * 更改字段 * @param $column * @param $table * @return mixed * @throws BusinessException */ protected function modifyColumn($column, $table) { $table = Util::filterAlphaNum($table); $method = Util::filterAlphaNum($column['type']); $field = Util::filterAlphaNum($column['field']); $old_field = Util::filterAlphaNum($column['old_field'] ?? null); $nullable = $column['nullable']; $default = $column['default'] !== null ? Util::pdoQuote($column['default']) : null; $comment = Util::pdoQuote($column['comment']); $auto_increment = $column['auto_increment']; $length = (int)$column['length']; if ($column['primary_key']) { $default = null; } if ($old_field && $old_field !== $field) { $sql = "ALTER TABLE `$table` CHANGE COLUMN `$old_field` `$field` "; } else { $sql = "ALTER TABLE `$table` MODIFY `$field` "; } if (stripos($method, 'integer') !== false) { $type = str_ireplace('integer', 'int', $method); if (stripos($method, 'unsigned') !== false) { $type = str_ireplace('unsigned', '', $type); $sql .= "$type "; $sql .= 'unsigned '; } else { $sql .= "$type "; } if ($auto_increment) { $column['nullable'] = false; $column['default'] = null; $sql .= 'AUTO_INCREMENT '; } } else { switch ($method) { case 'string': $length = $length ?: 255; $sql .= "varchar($length) "; break; case 'char': case 'time': $sql .= $length ? "$method($length) " : "$method "; break; case 'enum': $args = array_map('trim', explode(',', (string)$column['length'])); foreach ($args as $key => $value) { $args[$key] = Util::pdoQuote($value); } $sql .= 'enum(' . implode(',', $args) . ') '; break; case 'double': case 'float': case 'decimal': if (trim($column['length'])) { $args = array_map('intval', explode(',', $column['length'])); $args[1] = $args[1] ?? $args[0]; $sql .= "$method($args[0], $args[1]) "; break; } $sql .= "$method "; break; default : $sql .= "$method "; } } if (!$nullable) { $sql .= "NOT NULL "; } if ($method != 'text' && $default !== null) { $sql .= "DEFAULT $default "; } if ($comment !== null) { $sql .= "COMMENT $comment "; } echo "$sql\n"; Util::db()->statement($sql); } /** * 字段类型列表 * @param Request $request * @return Response */ public function types(Request $request): Response { $types = Util::methodControlMap(); return $this->json(0, 'ok', $types); } /** * 更新表的form schema信息 * @param $table_name * @param $data * @return string */ protected function updateSchemaOption($table_name, $data): string { $option_name = "table_form_schema_$table_name"; $option = Option::where('name', $option_name)->first(); if ($option) { Option::where('name', $option_name)->update(['value' => $data]); } else { Option::insert(['name' => $option_name, 'value' => $data]); } return $option_name; } /** * 字段类型到php类型映射 * @param string $type * @return string */ protected function getType(string $type): string { if (strpos($type, 'int') !== false) { return 'integer'; } switch ($type) { case 'varchar': case 'string': case 'text': case 'date': case 'time': case 'guid': case 'datetimetz': case 'datetime': case 'decimal': case 'enum': return 'string'; case 'boolean': return 'integer'; case 'float': return 'float'; default: return 'mixed'; } } }