feat: 发布智能体版

This commit is contained in:
augushong
2026-03-26 20:22:34 +08:00
parent 7ee9e102a5
commit 8cc08bcb8c
138 changed files with 7964 additions and 660 deletions

View File

@@ -0,0 +1,326 @@
<?php
namespace base\common\service;
use Exception;
use Throwable;
abstract class ErrorHandlerBase
{
/**
* 错误码注册表
*/
protected array $errorCodes = [
// 通用错误 (ERR_GEN_XXX)
'ERR_GEN_UNKNOWN' => '未知错误',
'ERR_GEN_INVALID_PARAM' => '参数错误',
'ERR_GEN_MISSING_PARAM' => '缺少必需参数',
'ERR_GEN_OPERATION_FAILED' => '操作失败',
'ERR_GEN_PERMISSION_DENIED' => '权限不足',
'ERR_GEN_NOT_FOUND' => '资源不存在',
'ERR_GEN_TIMEOUT' => '操作超时',
// 数据库错误 (ERR_DB_XXX)
'ERR_DB_CONNECTION' => '数据库连接失败',
'ERR_DB_QUERY' => '数据库查询失败',
'ERR_DB_INSERT' => '数据插入失败',
'ERR_DB_UPDATE' => '数据更新失败',
'ERR_DB_DELETE' => '数据删除失败',
'ERR_DB_TRANSACTION' => '数据库事务执行失败',
'ERR_DB_SCHEME_MISMATCH' => '数据库结构与期望不符',
// 文件系统错误 (ERR_FS_XXX)
'ERR_FS_NOT_FOUND' => '文件不存在',
'ERR_FS_READ_FAILED' => '文件读取失败',
'ERR_FS_WRITE_FAILED' => '文件写入失败',
'ERR_FS_DELETE_FAILED' => '文件删除失败',
'ERR_FS_PERMISSION' => '文件权限不足',
// 网络错误 (ERR_NET_XXX)
'ERR_NET_CONNECTION' => '网络连接失败',
'ERR_NET_TIMEOUT' => '网络请求超时',
'ERR_NET_RESPONSE' => '网络响应错误',
// 配置错误 (ERR_CFG_XXX)
'ERR_CFG_MISSING' => '配置缺失',
'ERR_CFG_INVALID' => '配置无效',
];
/**
* 修复建议注册表
*/
protected array $suggestions = [
// 通用错误修复建议
'ERR_GEN_UNKNOWN' => '未知错误,请稍后重试或联系管理员',
'ERR_GEN_INVALID_PARAM' => '请检查传入的参数是否符合要求',
'ERR_GEN_MISSING_PARAM' => '请确保所有必需参数都已提供',
'ERR_GEN_OPERATION_FAILED' => '请稍后重试,如果问题持续存在请联系管理员',
'ERR_GEN_PERMISSION_DENIED' => '请检查您是否有执行此操作的权限',
'ERR_GEN_NOT_FOUND' => '请确认请求的资源ID是否正确',
'ERR_GEN_TIMEOUT' => '请检查网络连接或稍后重试',
// 数据库错误修复建议
'ERR_DB_CONNECTION' => '请检查数据库连接配置和网络连接',
'ERR_DB_QUERY' => '请检查SQL语句语法和数据库表结构',
'ERR_DB_INSERT' => '请检查数据是否符合表结构和约束条件',
'ERR_DB_UPDATE' => '请确保要更新的数据存在且符合约束条件',
'ERR_DB_DELETE' => '请确保要删除的数据存在',
'ERR_DB_TRANSACTION' => '请检查事务中的操作是否都执行成功',
'ERR_DB_SCHEME_MISMATCH' => '请运行数据库迁移命令: php think migrate:run',
// 文件系统错误修复建议
'ERR_FS_NOT_FOUND' => '请检查文件路径是否正确',
'ERR_FS_READ_FAILED' => '请检查文件是否存在且有读取权限',
'ERR_FS_WRITE_FAILED' => '请检查目录是否存在且有写入权限',
'ERR_FS_DELETE_FAILED' => '请检查文件是否存在且有删除权限',
'ERR_FS_PERMISSION' => '请检查文件或目录的权限设置',
// 网络错误修复建议
'ERR_NET_CONNECTION' => '请检查网络连接和目标服务器状态',
'ERR_NET_TIMEOUT' => '请检查网络连接或增加超时时间',
'ERR_NET_RESPONSE' => '请检查请求参数和服务器响应',
// 配置错误修复建议
'ERR_CFG_MISSING' => '请在配置文件中添加缺失的配置项',
'ERR_CFG_INVALID' => '请检查配置项的值是否符合要求',
];
/**
* 获取结构化错误信息
*
* @param string $errorCode 错误码
* @param string|null $errorMessage 错误消息(覆盖默认错误消息)
* @param array $context 上下文信息
* @return array 结构化错误信息
*/
public function getError(string $errorCode, ?string $errorMessage = null, array $context = []): array
{
$defaultMessage = $this->errorCodes[$errorCode] ?? $this->errorCodes['ERR_GEN_UNKNOWN'];
$actualMessage = $errorMessage ?? $defaultMessage;
$error = [
'success' => false,
'error_code' => $errorCode,
'error_message' => $actualMessage,
];
// 添加文件和行信息(如果存在)
if (isset($context['file'])) {
$error['file'] = $context['file'];
}
if (isset($context['line'])) {
$error['line'] = $context['line'];
}
// 添加修复建议
$suggestion = $this->suggestions[$errorCode] ?? $this->suggestions['ERR_GEN_UNKNOWN'];
$error['suggestion'] = $suggestion;
// 添加额外的上下文信息
if (!empty($context)) {
$error['context'] = $context;
}
return $error;
}
/**
* 从异常生成结构化错误信息
*
* @param Throwable $exception 异常对象
* @param string|null $customErrorCode 自定义错误码
* @return array 结构化错误信息
*/
public function getErrorForException(Throwable $exception, ?string $customErrorCode = null): array
{
// 尝试从异常消息推断错误码
$errorCode = $customErrorCode ?? $this->inferErrorCodeFromException($exception);
$error = [
'success' => false,
'error_code' => $errorCode,
'error_message' => $exception->getMessage(),
];
// 添加文件和行信息
if ($exception->getFile()) {
$error['file'] = $exception->getFile();
}
if ($exception->getLine()) {
$error['line'] = $exception->getLine();
}
// 添加修复建议
$suggestion = $this->suggestions[$errorCode] ?? $this->suggestions['ERR_GEN_UNKNOWN'];
$error['suggestion'] = $suggestion;
// 添加异常类型
$error['exception_type'] = get_class($exception);
// 添加堆栈跟踪(在开发模式下)
if ($this->isDebugMode()) {
$error['trace'] = $this->formatTrace($exception);
}
return $error;
}
/**
* 从异常推断错误码
*
* @param Throwable $exception 异常对象
* @return string 错误码
*/
protected function inferErrorCodeFromException(Throwable $exception): string
{
$message = $exception->getMessage();
$class = get_class($exception);
// 根据异常类型推断
if (strpos($class, 'Db') !== false || strpos($class, 'Query') !== false) {
if (strpos($message, 'connection') !== false || strpos($message, 'connect') !== false) {
return 'ERR_DB_CONNECTION';
}
if (strpos($message, 'SQLSTATE') !== false) {
return 'ERR_DB_QUERY';
}
return 'ERR_DB_OPERATION_FAILED';
}
if (strpos($class, 'File') !== false || strpos($class, 'Stream') !== false) {
if (strpos($message, 'No such file') !== false || strpos($message, 'not found') !== false) {
return 'ERR_FS_NOT_FOUND';
}
if (strpos($message, 'permission') !== false) {
return 'ERR_FS_PERMISSION';
}
return 'ERR_FS_READ_FAILED';
}
if (strpos($class, 'Network') !== false || strpos($class, 'Curl') !== false) {
if (strpos($message, 'timeout') !== false) {
return 'ERR_NET_TIMEOUT';
}
return 'ERR_NET_CONNECTION';
}
// 根据消息内容推断
if (strpos($message, 'permission') !== false || strpos($message, 'denied') !== false) {
return 'ERR_GEN_PERMISSION_DENIED';
}
if (strpos($message, 'not found') !== false || strpos($message, '不存在') !== false) {
return 'ERR_GEN_NOT_FOUND';
}
if (strpos($message, 'timeout') !== false) {
return 'ERR_GEN_TIMEOUT';
}
return 'ERR_GEN_UNKNOWN';
}
/**
* 格式化堆栈跟踪
*
* @param Throwable $exception 异常对象
* @return array 格式化的堆栈跟踪
*/
protected function formatTrace(Throwable $exception): array
{
$trace = [];
foreach ($exception->getTrace() as $index => $frame) {
$traceItem = [
'index' => $index,
];
if (isset($frame['file'])) {
$traceItem['file'] = $frame['file'];
}
if (isset($frame['line'])) {
$traceItem['line'] = $frame['line'];
}
if (isset($frame['function'])) {
$traceItem['function'] = $frame['function'];
}
if (isset($frame['class'])) {
$traceItem['class'] = $frame['class'];
}
if (isset($frame['type'])) {
$traceItem['type'] = $frame['type'];
}
$trace[] = $traceItem;
}
return $trace;
}
/**
* 检查是否为调试模式
*
* @return bool
*/
protected function isDebugMode(): bool
{
try {
$app = \think\facade\App::instance();
return (bool)($app->config->get('app.app_debug') ?? false);
} catch (\Exception $e) {
return false;
}
}
/**
* 输出错误作为JSON
*
* @param array $error 错误信息
* @return string JSON格式的错误信息
*/
public function outputError(array $error): string
{
$options = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
return json_encode($error, $options);
}
/**
* 注册自定义错误码
*
* @param string $errorCode 错误码
* @param string $errorMessage 错误消息
* @param string|null $suggestion 修复建议
* @return void
*/
public function registerErrorCode(string $errorCode, string $errorMessage, ?string $suggestion = null): void
{
$this->errorCodes[$errorCode] = $errorMessage;
if ($suggestion !== null) {
$this->suggestions[$errorCode] = $suggestion;
}
}
/**
* 批量注册错误码
*
* @param array $errors 错误码数组,格式:['ERR_XXX' => ['message' => '...', 'suggestion' => '...']]
* @return void
*/
public function registerErrorCodes(array $errors): void
{
foreach ($errors as $errorCode => $config) {
$this->errorCodes[$errorCode] = $config['message'] ?? '未知错误';
if (isset($config['suggestion'])) {
$this->suggestions[$errorCode] = $config['suggestion'];
}
}
}
/**
* 获取所有已注册的错误码
*
* @return array 错误码数组
*/
public function getRegisteredErrorCodes(): array
{
return $this->errorCodes;
}
}

View File

@@ -111,4 +111,198 @@ class MenuServiceBase
return $menuData;
}
/**
* 创建菜单
*
* @param array $data 菜单数据
* @return int 返回新创建的菜单ID
* @throws \Exception
*/
public function create(array $data): int
{
$menu = Db::name('system_menu');
// 准备数据
$insertData = [
'pid' => $data['parent_id'] ?? 0,
'title' => $data['title'] ?? '',
'icon' => $data['icon'] ?? '',
'href' => $data['path'] ?? '',
'auth_node' => $data['node'] ?? '',
'sort' => $data['sort'] ?? 100,
'status' => 1,
'target' => '_self',
'remark' => $data['remark'] ?? '',
'create_time' => time(),
'update_time' => time(),
'delete_time' => 0,
];
// 验证必填字段
if (empty($insertData['title'])) {
throw new \Exception('菜单标题不能为空');
}
// 验证父菜单是否存在
if ($insertData['pid'] > 0) {
$parentMenu = Db::name('system_menu')
->where('id', $insertData['pid'])
->where('delete_time', 0)
->find();
if (empty($parentMenu)) {
throw new \Exception("父菜单ID {$insertData['pid']} 不存在");
}
}
// 插入数据
$menuId = $menu->insertGetId($insertData);
if (!$menuId) {
throw new \Exception('菜单创建失败');
}
return (int)$menuId;
}
/**
* 更新菜单
*
* @param int $menuId 菜单ID
* @param array $data 更新数据
* @return bool 是否更新成功
* @throws \Exception
*/
public function update(int $menuId, array $data): bool
{
// 验证菜单是否存在
$menu = Db::name('system_menu')
->where('id', $menuId)
->where('delete_time', 0)
->find();
if (empty($menu)) {
throw new \Exception("菜单ID {$menuId} 不存在");
}
// 准备更新数据
$updateData = [
'update_time' => time(),
];
if (isset($data['title'])) {
$updateData['title'] = $data['title'];
}
if (isset($data['parent_id'])) {
$updateData['pid'] = $data['parent_id'];
}
if (isset($data['icon'])) {
$updateData['icon'] = $data['icon'];
}
if (isset($data['path'])) {
$updateData['href'] = $data['path'];
}
if (isset($data['node'])) {
$updateData['auth_node'] = $data['node'];
}
if (isset($data['sort'])) {
$updateData['sort'] = $data['sort'];
}
if (isset($data['status'])) {
$updateData['status'] = $data['status'];
}
if (isset($data['remark'])) {
$updateData['remark'] = $data['remark'];
}
if (isset($data['target'])) {
$updateData['target'] = $data['target'];
}
// 验证必填字段
if (empty($menu['title']) && empty($updateData['title'])) {
throw new \Exception('菜单标题不能为空');
}
// 验证父菜单是否存在(如果修改了父菜单)
if (isset($updateData['pid']) && $updateData['pid'] > 0) {
// 不能将自己设置为父菜单
if ($updateData['pid'] == $menuId) {
throw new \Exception('不能将自己设置为父菜单');
}
$parentMenu = Db::name('system_menu')
->where('id', $updateData['pid'])
->where('delete_time', 0)
->find();
if (empty($parentMenu)) {
throw new \Exception("父菜单ID {$updateData['pid']} 不存在");
}
}
// 更新数据
$result = Db::name('system_menu')
->where('id', $menuId)
->update($updateData);
return $result !== false;
}
/**
* 删除菜单
*
* @param int $menuId 菜单ID
* @return bool 是否删除成功
* @throws \Exception
*/
public function delete(int $menuId): bool
{
// 验证菜单是否存在
$menu = Db::name('system_menu')
->where('id', $menuId)
->where('delete_time', 0)
->find();
if (empty($menu)) {
throw new \Exception("菜单ID {$menuId} 不存在");
}
// 检查是否有子菜单
$hasChildren = Db::name('system_menu')
->where('pid', $menuId)
->where('delete_time', 0)
->count();
if ($hasChildren > 0) {
throw new \Exception('该菜单下存在子菜单,请先删除子菜单');
}
// 软删除
$result = Db::name('system_menu')
->where('id', $menuId)
->update([
'delete_time' => time(),
'update_time' => time(),
]);
return $result !== false;
}
/**
* 获取菜单详情
*
* @param int $menuId 菜单ID
* @return array|null 菜单数据
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getMenu(int $menuId): ?array
{
$menu = Db::name('system_menu')
->where('id', $menuId)
->where('delete_time', 0)
->find();
return $menu ? $menu : null;
}
}

View File

@@ -46,6 +46,8 @@ class SchemeToDbService
$fullTableName = $prefix . $tableName;
}
$sql = $this->buildCreateTableSql($fullTableName, $tableAttr, $ref);
// 检查表是否存在
$tableExists = $this->checkTableExists($connection, $fullTableName);
$backupTableName = null;
@@ -66,7 +68,6 @@ class SchemeToDbService
}
// 2. 建表
$sql = $this->buildCreateTableSql($fullTableName, $tableAttr, $ref);
Db::connect($connection)->execute($sql);
// 3. 恢复数据
@@ -121,88 +122,159 @@ class SchemeToDbService
$schemeIndexes = $this->buildSchemeIndexSignature($ref);
$dbIndexes = $this->buildDbIndexSignature($dbKeysRows);
$diffs = [];
$missingFields = [];
$extraFields = [];
$changedFields = [];
foreach ($schemeColumns as $field => $sig) {
if (!isset($dbColumns[$field])) {
$diffs[] = "缺少字段:{$field}";
$missingFields[] = $field;
continue;
}
$row = $dbColumns[$field];
$fieldChanges = [];
$dbType = $this->normalizeDbType((string)$row['Type']);
$schemeType = $this->normalizeDbType($sig['type']);
if ($dbType !== $schemeType) {
$diffs[] = "字段类型不一致:{$field} DB={$dbType} Scheme={$schemeType}";
$fieldChanges['type'] = ['db' => $dbType, 'scheme' => $schemeType];
}
$dbNull = (string)$row['Null'];
$schemeNull = $sig['null'];
if ($dbNull !== $schemeNull) {
$diffs[] = "字段可空不一致:{$field} DB={$dbNull} Scheme={$schemeNull}";
$fieldChanges['null'] = ['db' => $dbNull, 'scheme' => $schemeNull];
}
$dbDefault = $row['Default'];
$schemeDefault = $sig['default'];
if (!$this->defaultEquals($dbDefault, $schemeDefault)) {
$dbStr = is_null($dbDefault) ? 'NULL' : (string)$dbDefault;
$schemeStr = is_null($schemeDefault) ? 'NULL' : (string)$schemeDefault;
$diffs[] = "字段默认值不一致:{$field} DB={$dbStr} Scheme={$schemeStr}";
$fieldChanges['default'] = [
'db' => $this->stringifyDefault($dbDefault),
'scheme' => $this->stringifyDefault($schemeDefault),
];
}
$dbExtra = (string)$row['Extra'];
$schemeExtra = $sig['extra'];
if ($dbExtra !== $schemeExtra) {
$diffs[] = "字段 Extra 不一致:{$field} DB={$dbExtra} Scheme={$schemeExtra}";
$fieldChanges['extra'] = ['db' => $dbExtra, 'scheme' => $schemeExtra];
}
$dbPrimary = (string)$row['Key'] === 'PRI';
if ($dbPrimary !== $sig['primary']) {
$diffs[] = "字段主键不一致:{$field} DB=" . ($dbPrimary ? 'PRI' : '') . " Scheme=" . ($sig['primary'] ? 'PRI' : '');
$fieldChanges['primary'] = [
'db' => $dbPrimary ? 'PRI' : '',
'scheme' => $sig['primary'] ? 'PRI' : '',
];
}
$dbComment = (string)$row['Comment'];
$schemeComment = $sig['comment'];
if ($this->parseComment($dbComment) !== $this->parseComment($schemeComment)) {
$diffs[] = "字段注释不一致:{$field} DB={$dbComment} Scheme={$schemeComment}";
$fieldChanges['comment'] = ['db' => $dbComment, 'scheme' => $schemeComment];
}
if (!empty($fieldChanges)) {
$changedFields[$field] = $fieldChanges;
}
}
foreach ($dbColumns as $field => $row) {
if (!isset($schemeColumns[$field])) {
$diffs[] = "多余字段:{$field}";
$extraFields[] = $field;
}
}
$missingIndexes = [];
$extraIndexes = [];
$changedIndexes = [];
foreach ($schemeIndexes as $name => $idx) {
if (!isset($dbIndexes[$name])) {
$diffs[] = "缺少索引:{$name}";
$missingIndexes[] = $name;
continue;
}
$dbIdx = $dbIndexes[$name];
$idxChanges = [];
if ($dbIdx['type'] !== $idx['type']) {
$diffs[] = "索引类型不一致:{$name} DB={$dbIdx['type']} Scheme={$idx['type']}";
$idxChanges['type'] = ['db' => $dbIdx['type'], 'scheme' => $idx['type']];
}
if ($dbIdx['columns'] !== $idx['columns']) {
$diffs[] = "索引字段不一致:{$name} DB=" . implode(',', $dbIdx['columns']) . " Scheme=" . implode(',', $idx['columns']);
$idxChanges['columns'] = [
'db' => implode(',', $dbIdx['columns']),
'scheme' => implode(',', $idx['columns']),
];
}
if (!empty($idxChanges)) {
$changedIndexes[$name] = $idxChanges;
}
}
foreach ($dbIndexes as $name => $idx) {
if (!isset($schemeIndexes[$name])) {
$diffs[] = "多余索引:{$name}";
$extraIndexes[] = $name;
}
}
$tableCommentDiff = $this->diffTableComment($connection, $fullTableName, $tableAttr->comment);
if ($tableCommentDiff !== null) {
$diffs[] = $tableCommentDiff;
$hasDiff = !empty($missingFields) || !empty($extraFields) || !empty($changedFields) || !empty($missingIndexes) || !empty($extraIndexes) || !empty($changedIndexes) || $tableCommentDiff !== null;
if (!$hasDiff) {
return [];
}
return $diffs;
$lines = [];
$lines[] = '差异汇总:'
. '字段缺失=' . count($missingFields)
. ',字段多余=' . count($extraFields)
. ',字段修改=' . count($changedFields)
. ';索引缺失=' . count($missingIndexes)
. ',索引多余=' . count($extraIndexes)
. ',索引修改=' . count($changedIndexes)
. ';表注释=' . ($tableCommentDiff !== null ? '不一致' : '一致');
if (!empty($missingFields)) {
$lines[] = '字段缺失(' . count($missingFields) . '' . implode(',', $missingFields);
}
if (!empty($extraFields)) {
$lines[] = '字段多余(' . count($extraFields) . '' . implode(',', $extraFields);
}
if (!empty($changedFields)) {
$lines[] = '字段修改(' . count($changedFields) . '' . implode(',', array_keys($changedFields));
foreach ($changedFields as $field => $changes) {
$lines[] = '字段 ' . $field . '';
foreach ($changes as $k => $v) {
$lines[] = ' - ' . $k . 'DB=' . $v['db'] . ' Scheme=' . $v['scheme'];
}
}
}
if (!empty($missingIndexes)) {
$lines[] = '索引缺失(' . count($missingIndexes) . '' . implode(',', $missingIndexes);
}
if (!empty($extraIndexes)) {
$lines[] = '索引多余(' . count($extraIndexes) . '' . implode(',', $extraIndexes);
}
if (!empty($changedIndexes)) {
$lines[] = '索引修改(' . count($changedIndexes) . '' . implode(',', array_keys($changedIndexes));
foreach ($changedIndexes as $name => $changes) {
$lines[] = '索引 ' . $name . '';
foreach ($changes as $k => $v) {
$lines[] = ' - ' . $k . 'DB=' . $v['db'] . ' Scheme=' . $v['scheme'];
}
}
}
if ($tableCommentDiff !== null) {
$lines[] = $tableCommentDiff;
}
return $lines;
}
public function getColumnsForCurd(string $className, array $onlyFields = []): array
@@ -227,6 +299,7 @@ class SchemeToDbService
/** @var Field $field */
$field = $fieldAttrs[0]->newInstance();
$this->validateSchemeField($field, $ref->getName(), $fieldName);
$columns[$fieldName] = [
'type' => $this->buildMysqlTypeFromSchemeField($field),
@@ -283,6 +356,7 @@ class SchemeToDbService
/** @var Field $field */
$field = $fieldAttrs[0]->newInstance();
$fieldName = $prop->getName();
$this->validateSchemeField($field, $ref->getName(), $fieldName);
$line = "`$fieldName` {$field->type}";
@@ -364,6 +438,20 @@ class SchemeToDbService
return "CREATE TABLE `$tableName` (\n $body\n) ENGINE={$tableAttr->engine} DEFAULT CHARSET={$tableAttr->charset}$comment";
}
protected function validateSchemeField(Field $field, string $className, string $fieldName): void
{
$type = strtolower(trim($field->type));
$length = $field->length;
if ($length !== null && $length < 1) {
throw new \InvalidArgumentException("Scheme 字段定义非法:{$className}::\${$fieldName} length 必须 >= 1当前={$length}");
}
if ($type === 'char' && $length !== null && $length > 255) {
throw new \InvalidArgumentException("Scheme 字段定义非法:{$className}::\${$fieldName} type=char 的 length 超出范围,允许 1-255当前={$length}");
}
}
protected function restoreData(string $connection, $newTable, $oldTable, array $properties)
{
$fields = [];
@@ -431,6 +519,7 @@ class SchemeToDbService
$fieldName = $prop->getName();
/** @var Field $field */
$field = $fieldAttrs[0]->newInstance();
$this->validateSchemeField($field, $ref->getName(), $fieldName);
$sig[$fieldName] = [
'type' => $this->buildMysqlTypeFromSchemeField($field),
@@ -614,6 +703,23 @@ class SchemeToDbService
return (string)$dbDefault === (string)$schemeDefault;
}
protected function stringifyDefault($value): string
{
if (is_null($value)) {
return 'NULL';
}
if (is_bool($value)) {
return $value ? '1' : '0';
}
if (is_int($value) || is_float($value)) {
return (string)$value;
}
return (string)$value;
}
protected function diffTableComment(string $connection, string $tableName, string $schemeComment): ?string
{
$type = strtolower((string)Config::get('database.connections.' . $connection . '.type', ''));

View File

@@ -1,6 +1,6 @@
<?php
namespace base\common\service;
namespace base\common\service\tools;
use think\console\Input;
use think\console\Output;
@@ -9,7 +9,7 @@ use think\facade\Env;
use think\facade\Config;
use think\Exception;
class ToolsDbServiceBase
class DbServiceBase
{
protected $connection = 'main';