SaiOrm.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. <?php
  2. namespace plugin\saiadmin\command;
  3. use Symfony\Component\Console\Command\Command;
  4. use Symfony\Component\Console\Input\InputInterface;
  5. use Symfony\Component\Console\Output\OutputInterface;
  6. use Symfony\Component\Console\Style\SymfonyStyle;
  7. use Symfony\Component\Console\Question\ChoiceQuestion;
  8. /**
  9. * SaiAdmin ORM 切换命令
  10. * 用于切换 saiadmin 插件的 ORM 实现 (think / eloquent)
  11. */
  12. class SaiOrm extends Command
  13. {
  14. protected static $defaultName = 'sai:orm';
  15. protected static $defaultDescription = '切换 SaiAdmin 使用的 ORM';
  16. /**
  17. * ORM 源文件目录
  18. */
  19. protected string $ormSourcePath;
  20. /**
  21. * 目标插件目录
  22. */
  23. protected string $pluginAppPath;
  24. /**
  25. * ORM 选项配置
  26. */
  27. protected array $ormOptions = [
  28. 'think' => '1. ThinkORM (TopThink)',
  29. 'eloquent' => '2. Eloquent ORM (Laravel)',
  30. 'exit' => '3. 退出,什么也不做',
  31. ];
  32. protected function configure(): void
  33. {
  34. $this->setName('sai:orm')
  35. ->setDescription('切换 SaiAdmin 使用的 ORM');
  36. }
  37. protected function execute(InputInterface $input, OutputInterface $output): int
  38. {
  39. $io = new SymfonyStyle($input, $output);
  40. $io->title('SaiAdmin ORM 切换工具');
  41. $io->text('此命令只切换 saiadmin 框架核心使用的 ORM, 不影响其他模块功能, 多种 ORM 可以同时使用!');
  42. $io->newLine();
  43. // 创建选择问题(编号从1开始)
  44. $helper = $this->getHelper('question');
  45. $choices = [
  46. 1 => '1. ThinkORM (TopThink)',
  47. 2 => '2. Eloquent ORM (Laravel)',
  48. 3 => '3. 退出,什么也不做',
  49. ];
  50. $question = new ChoiceQuestion(
  51. '请选择要使用的 ORM 框架:',
  52. $choices,
  53. 1 // 默认选中第一个
  54. );
  55. $question->setErrorMessage('选项 %s 无效');
  56. // 获取用户选择
  57. $selected = $helper->ask($input, $output, $question);
  58. // 根据选择的文本反查 key
  59. $selectedKey = array_search($selected, $choices);
  60. // 如果选择退出
  61. if ($selectedKey == 3) {
  62. $io->newLine();
  63. $io->info('已退出,什么也没做。');
  64. return Command::SUCCESS;
  65. }
  66. // 映射选项到 ORM 类型
  67. $ormMap = [1 => 'think', 2 => 'eloquent'];
  68. $orm = $ormMap[$selectedKey];
  69. $io->newLine();
  70. $io->section("您选择了: {$selected}");
  71. // 确认操作
  72. if (!$io->confirm('确定要切换吗?这将覆盖 saiadmin 核心代码文件', true)) {
  73. $io->warning('操作已取消');
  74. return Command::SUCCESS;
  75. }
  76. // 设置路径
  77. $this->ormSourcePath = BASE_PATH . '/vendor/saithink/saiadmin/src/orm/' . $orm . '/app';
  78. $this->pluginAppPath = BASE_PATH . '/plugin/saiadmin/app';
  79. // 检查源目录是否存在
  80. if (!is_dir($this->ormSourcePath)) {
  81. $io->error("ORM 源目录不存在: {$this->ormSourcePath}");
  82. return Command::FAILURE;
  83. }
  84. $io->section('开始复制文件...');
  85. try {
  86. $copiedFiles = $this->copyDirectory($this->ormSourcePath, $this->pluginAppPath, $io);
  87. $io->newLine();
  88. $io->success([
  89. "ORM 切换成功!",
  90. "已切换到: {$selected}",
  91. "复制文件数: {$copiedFiles}"
  92. ]);
  93. $io->note([
  94. '请重启 webman 服务使更改生效',
  95. '命令: php webman restart 或 php windows.php'
  96. ]);
  97. return Command::SUCCESS;
  98. } catch (\Exception $e) {
  99. $io->error("切换失败: " . $e->getMessage());
  100. return Command::FAILURE;
  101. }
  102. }
  103. /**
  104. * 递归复制目录
  105. * @param string $source 源目录
  106. * @param string $dest 目标目录
  107. * @param SymfonyStyle $io 输出接口
  108. * @return int 复制的文件数量
  109. */
  110. protected function copyDirectory(string $source, string $dest, SymfonyStyle $io): int
  111. {
  112. $count = 0;
  113. if (!is_dir($dest)) {
  114. mkdir($dest, 0755, true);
  115. }
  116. $iterator = new \RecursiveIteratorIterator(
  117. new \RecursiveDirectoryIterator($source, \RecursiveDirectoryIterator::SKIP_DOTS),
  118. \RecursiveIteratorIterator::SELF_FIRST
  119. );
  120. // 先计算文件总数用于进度条
  121. $files = [];
  122. foreach ($iterator as $item) {
  123. if (!$item->isDir()) {
  124. $files[] = $item;
  125. }
  126. }
  127. // 创建进度条
  128. $io->progressStart(count($files));
  129. // 重新遍历并复制
  130. $iterator = new \RecursiveIteratorIterator(
  131. new \RecursiveDirectoryIterator($source, \RecursiveDirectoryIterator::SKIP_DOTS),
  132. \RecursiveIteratorIterator::SELF_FIRST
  133. );
  134. foreach ($iterator as $item) {
  135. $destPath = $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName();
  136. if ($item->isDir()) {
  137. if (!is_dir($destPath)) {
  138. mkdir($destPath, 0755, true);
  139. }
  140. } else {
  141. copy($item->getPathname(), $destPath);
  142. $count++;
  143. $io->progressAdvance();
  144. }
  145. }
  146. $io->progressFinish();
  147. return $count;
  148. }
  149. }