增加扩展机制定位文件;将common模块实现扩展模式;发布新版本;

This commit is contained in:
2023-09-25 17:07:38 +08:00
parent 3dcf336bbc
commit 184dae8185
65 changed files with 3093 additions and 2751 deletions

View File

@@ -1,146 +1,9 @@
<?php
namespace app\common\command;
use base\common\command\CurdBase;
use app\admin\service\curd\BuildCurdService;
use app\common\tools\PathTools;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
use think\Exception;
use think\facade\App;
class Curd extends Command
class Curd extends CurdBase
{
protected function configure()
{
$this->setName('curd')
->addOption('table', 't', Option::VALUE_REQUIRED, '主表名', null)
->addOption('controllerFilename', 'c', Option::VALUE_REQUIRED, '控制器文件名', null)
->addOption('modelFilename', 'm', Option::VALUE_REQUIRED, '主表模型文件名', null)
#
->addOption('force', 'f', Option::VALUE_NONE, '强制覆盖模式')
->addOption('delete', 'd', Option::VALUE_NONE, '删除模式')
->addOption('runtime', 'r', Option::VALUE_NONE, '临时生成')
->setDescription('一键curd命令服务');
}
protected function execute(Input $input, Output $output)
{
$table = $input->getOption('table');
$controllerFilename = $input->getOption('controllerFilename');
$modelFilename = $input->getOption('modelFilename');
$force = 0;
$delete = 0;
if ($input->hasOption('force')) {
$force = 1;
}
if ($input->hasOption('delete')) {
$delete = 1;
}
if (empty($table)) {
$output->error('请设置主表');
return false;
}
try {
$build = (new BuildCurdService())
->setTable($table)
->setForce($force);
if ($input->hasOption('runtime')) {
$runtime_path = App::getRuntimePath() . 'source/build/' . date('YmdHis') . '/';
dump($runtime_path);
PathTools::intiDir($runtime_path . 'a.temp');
$build->setRootDir($runtime_path);
}
$columns = $build->getTableColumns();
$relations = [];
foreach ($columns as $field => $column) {
if (isset($column['formType']) && $column['formType'] == 'relation') {
$define = $column['define'];
if (!isset($define['table'])) {
$output->error("关联字段{$field}没有设置关联表名称");
return false;
}
$relations[] = [
'table' => $define['table'],
'foreignKey' => $field,
'primaryKey' => $define['primaryKey'] ?? null,
'modelFilename' => $define['modelFilename'] ?? null,
'onlyFileds' => isset($define['onlyFileds']) ? explode("|", $define['onlyFileds']) : [],
'relationBindSelect' => $define['relationBindSelect'] ?? null,
];
}
}
!empty($controllerFilename) && $build = $build->setControllerFilename($controllerFilename);
!empty($modelFilename) && $build = $build->setModelFilename($modelFilename);
foreach ($relations as $relation) {
$build = $build->setRelation($relation['table'], $relation['foreignKey'], $relation['primaryKey'], $relation['modelFilename'], $relation['onlyFileds'], $relation['relationBindSelect']);
}
$build = $build->render();
$fileList = $build->getFileList();
if (!$delete) {
if ($force) {
$output->writeln(">>>>>>>>>>>>>>>");
foreach ($fileList as $key => $val) {
$output->writeln($key);
}
$output->writeln(">>>>>>>>>>>>>>>");
$ask_force_delete_result = $output->confirm($input,'确定强制生成上方所有文件? 如果文件存在会直接覆盖。');
if (!$ask_force_delete_result) {
throw new Exception("取消文件CURD生成操作");
}
}
$result = $build->create();
$output->info('自动生成CURD成功');
} else {
$output->writeln(">>>>>>>>>>>>>>>");
foreach ($fileList as $key => $val) {
$output->writeln($key);
}
$output->writeln(">>>>>>>>>>>>>>>");
$ask_force_delete_result = $output->confirm($input,'确定删除上方所有文件? ');
if (!$ask_force_delete_result) {
throw new Exception("取消删除文件操作");
}
$result = $build->delete();
$output->info('>>>>>>>>>>>>>>>');
$output->info('删除自动生成CURD文件成功');
}
$output->info('>>>>>>>>>>>>>>>');
foreach ($result as $vo) {
$output->info($vo);
}
} catch (\Exception $e) {
$output->error($e->getMessage());
return false;
}
}
}

View File

@@ -1,66 +1,9 @@
<?php
namespace app\common\command;
use base\common\command\NodeBase;
use app\admin\model\SystemNode;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
use app\admin\service\NodeService;
class Node extends Command
class Node extends NodeBase
{
protected function configure()
{
$this->setName('node')
->addOption('force', null, Option::VALUE_REQUIRED, '是否强制刷新', 0)
->setDescription('系统节点刷新服务');
}
protected function execute(Input $input, Output $output)
{
$force = $input->getOption('force');
$output->writeln("========正在刷新节点服务:=====" . date('Y-m-d H:i:s'));
$check = $this->refresh($force);
$check !== true && $output->writeln("节点刷新失败:" . $check);
$output->writeln("刷新完成:" . date('Y-m-d H:i:s'));
}
protected function refresh($force)
{
$nodeList = (new NodeService())->getNodelist();
if (empty($nodeList)) {
return true;
}
$model = new SystemNode();
try {
if ($force == 1) {
$updateNodeList = $model->whereIn('node', array_column($nodeList, 'node'))->select();
$formatNodeList = array_format_key($nodeList, 'node');
foreach ($updateNodeList as $vo) {
isset($formatNodeList[$vo['node']]) && $model->where('id', $vo['id'])->update([
'title' => $formatNodeList[$vo['node']]['title'],
'is_auth' => $formatNodeList[$vo['node']]['is_auth'],
]);
}
}
$existNodeList = $model->field('node,title,type,is_auth')->select();
foreach ($nodeList as $key => $vo) {
foreach ($existNodeList as $v) {
if ($vo['node'] == $v->node) {
unset($nodeList[$key]);
break;
}
}
}
$model->insertAll($nodeList);
} catch (\Exception $e) {
return $e->getMessage();
}
return true;
}
}
}

View File

@@ -1,52 +1,9 @@
<?php
namespace app\common\command;
use app\common\service\UploadService;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\facade\Filesystem;
use think\File;
use base\common\command\OssStaticBase;
class OssStatic extends Command
class OssStatic extends OssStaticBase
{
protected function configure()
{
$this->setName('OssStatic')
->setDescription('将静态资源上传到oss上');
}
protected function execute(Input $input, Output $output)
{
$output->writeln("========正在上传静态资源到OSS上========" . date('Y-m-d H:i:s'));
$list = Filesystem::disk('local_static')->listContents('/', true);
$upload_service = new UploadService();
$uploadPrefix = config('app.oss_static_prefix', 'oss_static_prefix');
foreach ($list as $file_item) {
if ($file_item['type'] != 'file') {
continue;
}
$file_path = $file_item['path'];
$file_path = Filesystem::disk('local_static')->path($file_path);
$file = new File($file_path, false);
$save_name = $file_item['path'];
try {
$model_file = $upload_service->save($file, $save_name, true, $uploadPrefix, true);
$output->info('文件上传成功:' . $save_name . '。上传地址:' . $model_file['url']);
} catch (\Throwable $th) {
$output->error('文件上传失败:' . $save_name . '。错误信息:' . $th->getMessage());
}
}
$output->writeln("========已完成静态资源上传到OSS上========" . date('Y-m-d H:i:s'));
}
}

View File

@@ -4,130 +4,8 @@ declare(strict_types=1);
namespace app\common\command;
use GuzzleHttp\Client;
use GuzzleHttp\Promise\Utils;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use think\facade\Cache;
use think\facade\Log;
use base\common\command\TimerBase;
class Timer extends Command
class Timer extends TimerBase
{
protected function configure()
{
// 指令配置
$this->setName('timer')
->addOption('temp', null, Option::VALUE_NONE)
->addOption('quit', null, Option::VALUE_NONE)
->setDescription('内置秒级定时器');
}
protected function execute(Input $input, Output $output)
{
// 指令输出
$output->writeln('start timer');
$site_domain = sysconfig('site', 'site_domain');
if (empty($site_domain)) {
$output->writeln('请前往后台设置站点域名site_domain配置项');
return;
}
$output->writeln('站点域名:'.$site_domain);
$client = new Client([
'base_uri' => $site_domain,
'verify' => false,
]);
while (true) {
try {
$config_list = include __DIR__ . '/timer/config.php';
$list_promises = [];
foreach ($config_list as $config_item) {
$config_item = static::initConfigItem($config_item);
$name = $config_item['name'];
if ($name == 'http_demo' && !env('adminsystem.is_demo', false)) {
continue;
}
$cache_key = 'timer_' . $name;
$cache_tag = 'system_timer';
$last_exec_time = Cache::get($cache_key, 0);
if ($last_exec_time >= time() - $config_item['frequency']) {
continue;
}
Cache::tag($cache_tag)->set($cache_key, time());
$type = $config_item['type'];
switch ($type) {
case 'site':
$output->writeln(date('Y-m-d H:i:s') . ': build site request async:' . $config_item['target']);
$list_promises[$config_item['name']] = $client->getAsync($config_item['target']);
break;
default:
$output->writeln(date('Y-m-d H:i:s') . 'unsupport type:' . $type);
break;
}
}
if (empty($list_promises)) {
if(!$input->hasOption('quit')){
$output->writeln(date('Y-m-d H:i:s') . ' no request');
}
} else {
$results = Utils::unwrap($list_promises);
$output->writeln(date('Y-m-d H:i:s') . ': request all finished');
}
} catch (\Throwable $th) {
// throw $th;
$output->writeln('error:' . $th->getMessage());
Log::error($th->getMessage());
}
if ($input->hasOption('temp')) {
break;
}
sleep(1);
}
}
private static function initConfigItem($config)
{
$default = [
'name' => 'http_demo',
'type' => 'site',
'target' => '',
'frequency' => 600
];
$data = array_merge($default, $config);
if ($data['frequency'] < 0) {
$data['frequency'] = 0;
}
return $data;
}
}

View File

@@ -4,49 +4,8 @@ declare(strict_types=1);
namespace app\common\command\admin;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use think\facade\App;
use base\common\command\admin\ClearBase;
class Clear extends Command
class Clear extends ClearBase
{
protected function configure()
{
// 指令配置
$this->setName('admin:clear')
->setDescription('删除开发临时生成目录');
}
protected function execute(Input $input, Output $output)
{
// 指令输出
$output->writeln('删除测试目录');
$command_line = '';
$dir = App::getRootPath() . '/runtime/source/';
if (!is_dir($dir)) {
$output->writeln('删除成功');
return;
}
if (strpos(strtolower(PHP_OS), 'win') === 0) {
$command_line = implode(' ', ['rd', '/s', '/q', str_replace('/', '\\', $dir)]);
} else {
$command_line = implode(' ', ['rm', '-rf', $dir]);
}
$output->info('删除目录:' . $command_line);
$output->info('run command: ' . $command_line);
exec($command_line);
$output->info('删除成功');
}
}

View File

@@ -4,47 +4,8 @@ declare(strict_types=1);
namespace app\common\command\admin;
use app\admin\model\SystemAdmin;
use app\common\constants\AdminConstant;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use base\common\command\admin\ResetPasswordBase;
class ResetPassword extends Command
class ResetPassword extends ResetPasswordBase
{
protected function configure()
{
// 指令配置
$this->setName('admin:reset:password')
->addOption('password','p', Option::VALUE_OPTIONAL)
->setDescription('重置超管密码');
}
protected function execute(Input $input, Output $output)
{
// 指令输出
$output->writeln('admin:reset:password');
$model_admin = SystemAdmin::find(AdminConstant::SUPER_ADMIN_ID);
if (empty($model_admin)) {
$output->writeln('管理员不存在');
return false;
}
$password = $input->getOption('password');
if(is_null($password)){
$password = uniqid();
}
$model_admin->save([
'password' => password($password)
]);
$output->writeln('密码修改为:' . $password);
}
}

View File

@@ -4,309 +4,8 @@ declare(strict_types=1);
namespace app\common\command\admin;
use app\common\tools\PathTools;
use CzProject\GitPhp\Git;
use League\Flysystem\Filesystem;
use League\Flysystem\Local\LocalFilesystemAdapter;
use League\Flysystem\StorageAttributes;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
use think\facade\App;
use think\facade\Env;
use base\common\command\admin\UpdateBase;
class Update extends Command
class Update extends UpdateBase
{
public const REPO = 'https://gitee.com/ulthon/ulthon_admin.git';
protected function configure()
{
// 指令配置
$this->setName('admin:update')
->addOption('reinstall', null, Option::VALUE_NONE, '重装版本')
->setDescription('the admin:update command');
}
protected function execute(Input $input, Output $output)
{
// 指令输出
$output->writeln('admin:update');
$this->cleanWorkpaceDir();
$current_version = Version::VERSION;
$current_version_dir = App::getRuntimePath() . '/update/' . $current_version;
$last_version_dir = App::getRuntimePath() . '/update/last';
$version_file_regx = "/\bconst VERSION\s*=\s*'[\d\.a-z]+'/";
$output->writeln('获取最新代码');
$last_version_git = new Git();
$last_version_repo = $last_version_git->cloneRepository(self::REPO, $last_version_dir);
$tags = $last_version_repo->getTags();
$update_level = Env::get('adminsystem.update_level', 'production');
if ($update_level == 'production') {
$tags = array_filter($tags, function ($value) {
if (strpos($value, '-')) {
return false;
}
return true;
});
}
usort($tags, function ($a, $b) {
return version_compare($a, $b);
});
$last_version = $tags[count($tags) - 1];
if ($last_version == $current_version) {
$output->writeln('当前版本为最新版本');
$this->cleanWorkpaceDir();
if ($input->hasOption('reinstall')) {
$output->writeln('重装代码');
} else {
return;
}
}
// 将最新代码切换到最新版本,因为最新的提交可能没有发布版本
$output->writeln('切换最新代码的最新版本');
$last_version_repo->checkout($last_version);
$current_version_git = new Git();
$output->writeln('获取当前版本代码');
$current_version_repo = $current_version_git->cloneRepository(self::REPO, $current_version_dir);
$output->writeln('切换版本' . $current_version);
$current_version_repo->checkout($current_version);
// 获取当前版本需要跳过的文件
$current_version_update_config = include $current_version_dir . '/config/update.php';
// 获取当前版本要替换的文件
$current_version_filesystem = new Filesystem(new LocalFilesystemAdapter($current_version_dir));
$current_version_list_files = $current_version_filesystem->listContents('/', Filesystem::LIST_DEEP)
->filter(function (StorageAttributes $attributes) use ($current_version_update_config) {
if ($attributes->isDir()) {
return false;
}
$path = $attributes->path();
$skip_files = $current_version_update_config['skip_files'] ?? [];
if (in_array($path, $skip_files)) {
return false;
}
$skip_dir = $current_version_update_config['skip_dir'] ?? [];
$skip_dir[] = '.git';
foreach ($skip_dir as $dir) {
if (str_starts_with($path, $dir)) {
return false;
}
}
return true;
})
->map(fn (StorageAttributes $attributes) => $attributes->path())
->toArray();
// 对比现在的代码,检查是否有定制修改
$output->writeln('对比源码是否被定制');
$now_dir = App::getRootPath();
/**
* @var array<bool|string>
*/
$changed_files = [];
foreach ($current_version_list_files as $file_path) {
$now_file_path = $now_dir . '/' . $file_path;
$current_version_file_path = $current_version_dir . '/' . $file_path;
$compare_result = PathTools::compareFiles($now_file_path, $current_version_file_path, true);
if (!$compare_result || is_string($compare_result)) {
$changed_files[$file_path] = $compare_result;
}
}
// 有定制修改则退出
if (!empty($changed_files)) {
$output->warning('无法自动更新,以下文件被定制,请还原或手动升级:');
foreach ($changed_files as $file_path => $compare_result) {
$output->warning($file_path);
if (is_string($compare_result)) {
$output->writeln($compare_result);
}
}
$file_count = count($changed_files);
$ask_result = $output->ask($input, "发现{$file_count}个文件被修改,如果您认为以上文件可以被覆盖或为检测错误,可以强制覆盖。\n是否强制继续更新?(y/n)");
if (!$ask_result) {
return;
}
}
// 获取最新版本需要跳过的文件
$last_version_skip_config = include $last_version_dir . '/config/update.php';
// 获取最新版本要替换的文件
$last_version_filesystem = new Filesystem(new LocalFilesystemAdapter($last_version_dir));
$last_version_list_files = $last_version_filesystem->listContents('/', Filesystem::LIST_DEEP)
->filter(function (StorageAttributes $attributes) use ($last_version_skip_config) {
if ($attributes->isDir()) {
return false;
}
$path = $attributes->path();
$skip_files = $last_version_skip_config['skip_files'] ?? [];
if (in_array($path, $skip_files)) {
return false;
}
$skip_dir = $last_version_skip_config['skip_dir'] ?? [];
$skip_dir[] = '.git';
foreach ($skip_dir as $dir) {
if (str_starts_with($path, $dir)) {
return false;
}
}
return true;
})
->map(fn (StorageAttributes $attributes) => $attributes->path())
->toArray();
$delete_files = array_diff($current_version_list_files, $last_version_list_files);
foreach ($delete_files as $file_path) {
$now_file_path = $now_dir . '/' . $file_path;
unlink($now_file_path);
}
foreach ($last_version_list_files as $file_path) {
$now_file_path = $now_dir . '/' . $file_path;
$last_file_path = $last_version_dir . '/' . $file_path;
$file_content = file_get_contents($last_file_path);
PathTools::intiDir($now_file_path);
file_put_contents($now_file_path, $file_content);
}
// 处理append的文件
$last_version_list_skip_files = $last_version_filesystem->listContents('/', Filesystem::LIST_DEEP)
->filter(function (StorageAttributes $attributes) use ($last_version_skip_config) {
if ($attributes->isDir()) {
return false;
}
$path = $attributes->path();
if (str_starts_with($path, '.git')) {
return false;
}
$skip_files = $last_version_skip_config['skip_files'] ?? [];
if (in_array($path, $skip_files)) {
return true;
}
$skip_dir = $last_version_skip_config['skip_dir'] ?? [];
foreach ($skip_dir as $dir) {
if (str_starts_with($path, $dir)) {
return true;
}
}
return true;
})
->map(fn (StorageAttributes $attributes) => $attributes->path())
->toArray();
$last_version_list_append_files = [];
foreach ($last_version_list_skip_files as $file_path) {
if (in_array($file_path, $last_version_skip_config['append_files'])) {
$last_version_list_append_files[] = $file_path;
continue;
}
foreach ($last_version_skip_config['append_dir'] as $dir) {
if (str_starts_with($file_path, $dir)) {
$last_version_list_append_files[] = $file_path;
continue;
}
}
}
foreach ($last_version_list_append_files as $file_path) {
$now_file_path = $now_dir . '/' . $file_path;
$last_file_path = $last_version_dir . '/' . $file_path;
if (file_exists($now_file_path)) {
continue;
}
$file_content = file_get_contents($last_file_path);
PathTools::intiDir($now_file_path);
file_put_contents($now_file_path, $file_content);
}
// 检测now的composer依赖和最新的composer依赖
$last_composer_json = file_get_contents($last_version_dir . '/composer.json');
$output->writeln($last_composer_json);
$output->writeln('请参考以上最新composer文件调整您的依赖');
// 分析出最新需要的但now没有的
// 为用户整理出要手动调整的composer命令
$this->cleanWorkpaceDir();
$output->writeln('更新完成');
// 更新完成
if (!empty(Version::UPDATE_TIPS)) {
foreach (Version::UPDATE_TIPS as $content) {
$output->writeln($content);
}
$output->writeln('删除对应文件之后,可以通过以下命令重新安装');
$output->writeln('php think admin:update --resinstall');
}
}
protected function cleanWorkpaceDir()
{
$dir = App::getRuntimePath() . '/update/';
$this->output->writeln('清理目录 ' . $dir);
PathTools::removeDir($dir);
}
}

View File

@@ -4,69 +4,8 @@ declare(strict_types=1);
namespace app\common\command\admin;
use think\App as ThinkApp;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
use base\common\command\admin\VersionBase;
class Version extends Command
class Version extends VersionBase
{
public const VERSION = 'v2.0.45';
public const LAYUI_VERSION = '2.8.16';
public const COMMENT = [
'实现view的扩展架构',
'调整think-view依赖',
'发布新版本',
];
public const UPDATE_TIPS = [
'本次更新调整了composer依赖请根据实际情况调整',
'可以删除app下admin的view目录了',
'删除 think-view',
'引入 topthink/think-template-view',
];
protected function configure()
{
// 指令配置
$this->setName('admin:version')
->addOption('push-tag', null, Option::VALUE_NONE, '使用git命令生成tag并推送')
->setDescription('查看当前ulthon_admin的版本号');
}
protected function execute(Input $input, Output $output)
{
// 指令输出
$output->info('当前版本号为:' . $this::VERSION);
$output->info('当前Layui版本号为' . $this::LAYUI_VERSION);
$output->info('当前ThinkPHP版本号为' . ThinkApp::VERSION);
$output->writeln('当前的修改说明:');
$output->writeln('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');
foreach ($this::COMMENT as $comment) {
$output->info($comment);
}
$output->writeln('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<');
$output->highlight('代码托管地址https://gitee.com/ulthon/ulthon_admin');
$output->highlight('开发文档地址http://doc.ulthon.com/home/read/ulthon_admin/home.html');
$is_push_tag = $input->hasOption('push-tag');
if ($is_push_tag) {
$output->writeln('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');
$version = $this::VERSION;
$comment = implode(';', $this::COMMENT);
$output->info('生成标签:' . $version);
$output->info('标签描述:' . $comment);
exec("git tag -a $version -m \"$comment\"");
$output->info('推送到远程仓库');
exec('git push --tags');
}
}
}

View File

@@ -4,220 +4,8 @@ declare(strict_types=1);
namespace app\common\command\curd;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use think\facade\App;
use think\facade\Db;
use think\facade\View;
use base\common\command\curd\MigrateBase;
class Migrate extends Command
class Migrate extends MigrateBase
{
protected $table;
protected $database;
protected $tablePrefix;
protected function configure()
{
// 指令配置
$this->setName('curd:migrate')
->addOption('table', 't', Option::VALUE_REQUIRED, '主表名')
->addOption('tableName', '', Option::VALUE_OPTIONAL, '要生成的表名')
->addOption('fileName', '', Option::VALUE_OPTIONAL, '要生成的文件名')
->addOption('force', 'f', Option::VALUE_NONE, '强制生成')
->setDescription('the curd:migrate command');
}
protected function execute(Input $input, Output $output)
{
// 指令输出
$output->writeln('curd:migrate');
$table = $input->getOption('table');
$file_name = $input->getOption('fileName');
$table_name = $input->getOption('tableName');
$force = $input->getOption('force');
if (empty($table)) {
$output->error('请输入表名');
return;
}
if (empty($table_name)) {
$table_name = $table;
}
if (empty($file_name)) {
$file_name = $table_name;
}
$this->table = $table;
$this->database = config('database.connections.mysql.database');
$this->tablePrefix = config('database.connections.mysql.prefix');
$table_info_sql = "select * from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='{$this->database}' and TABLE_NAME='{$this->tablePrefix}{$this->table}'";
$table_info = Db::query($table_info_sql);
if (empty($table_info)) {
$output->error('表不存在');
return;
}
$dist_file_path = App::getRootPath() . '/database/migrations/' . date('YmdHis') . '_' . $file_name . '.php';
$patt_path = App::getRootPath() . '/database/migrations/*' . $file_name . '.php';
$patt_files = glob($patt_path);
$is_extis = false;
foreach ($patt_files as $patt_file) {
$patt = '/.*database\/migrations\/\d+_' . $file_name . '.php$/';
$preg_result = preg_match($patt, $patt_file);
if ($preg_result) {
$is_extis = true;
}
}
if ($is_extis) {
$output->error('文件已存在:' . $patt_files[0]);
if (!$force) {
$confirm_force = $output->confirm($input, '确定要覆盖文件吗?', false);
if (!$confirm_force) {
return;
}
}
$output->highlight('执行覆盖操作');
$dist_file_path = $patt_files[0];
}
$columns = Db::query("SHOW FULL COLUMNS FROM {$this->tablePrefix}{$this->table}");
$data['class_name'] = \think\helper\Str::studly($file_name);
$table_columns = [];
$table_keys = [];
$table_keys_text = [];
$table_keys_uni = [];
foreach ($columns as $column) {
if ($column['Field'] == 'id') {
continue;
}
$column_item = [];
$column_item['options'] = [];
$column_item['field'] = $column['Field'];
$column_item['type'] = '';
$type = $column['Type'];
if (strpos($type, '(') !== false) {
// 带有长度
$type_info = explode('(', $type);
$column_item['type'] = $type_info[0];
$length = substr($type_info[1], 0, strpos($type_info[1], ')'));
if (strpos($length, ',') !== false) {
$length_info = explode(',', $length);
$column_item['options']['precision'] = $length_info[0];
$column_item['options']['scale'] = $length_info[1];
} else {
$column_item['options']['limit'] = $length;
}
if (strpos($type, 'unsigned') !== false) {
// 无符号
$column_item['options']['signed'] = 0;
}
} else {
$column_item['type'] = $type;
}
$column_item['options']['null'] = $column['Null'] == 'YES' ? 1 : 0;
if ($column['Default'] !== null) {
$column_item['options']['default'] = $column['Default'];
}
$column_item['options']['comment'] = $column['Comment'];
$key = $column['Key'];
if (!empty($key)) {
if ($key == 'MUL') {
if ($type == 'text' || $type == 'longtext') {
$table_keys_text[] = $column['Field'];
} else {
$table_keys[] = $column['Field'];
}
} elseif ($key == 'UNI') {
$table_keys_uni[] = $column['Field'];
}
}
$table_columns[] = $column_item;
}
$type_map = [
'bigint' => 'biginteger',
'int' => 'integer',
'varchar' => 'string',
'smallint' => 'integer',
'tinyint' => 'integer',
'longtext' => 'text',
];
foreach ($table_columns as &$column_item_set) {
if (isset($type_map[$column_item_set['type']])) {
$column_item_set['type'] = $type_map[$column_item_set['type']];
}
foreach ($column_item_set['options'] as $key => $option) {
if(is_array($option)) {
$column_item_set['options'][$key] = "[".implode(',', $option)."]";
} else {
$column_item_set['options'][$key] = "'{$option}'";
}
}
}
$data['table_info'] = $table_info[0];
$data['table'] = $table_name;
$data['table_columns'] = $table_columns;
$data['table_keys'] = $table_keys;
$data['table_keys_uni'] = $table_keys_uni;
$data['table_keys_text'] = $table_keys_text;
$migrate_content = View::fetch(__DIR__ . '/migrate.tpl', $data);
file_put_contents(__DIR__ . '/migrate_output.php', "<?php\n\n" . $migrate_content);
file_put_contents($dist_file_path, "<?php\n\n" . $migrate_content);
}
}