Przeglądaj źródła

feat: 新增 extension:sync 同步扩展包最新信息到扩展表,移除 crontab 命令

runphp 1 miesiąc temu
rodzic
commit
4558262fa1

+ 2 - 2
command.php

@@ -3,15 +3,15 @@
 declare(strict_types=1);
 
 use SixShop\System\Command\CoreExtensionConfigCommand;
-use SixShop\System\Command\CrontabCommand;
 use SixShop\System\Command\ExtensionManagementCommand;
 use SixShop\System\Command\ExtensionScaffoldMakeCommand;
+use SixShop\System\Command\ExtensionSyncCommand;
 use SixShop\System\Command\WorkerCommand;
 
 return [
     'core:config' => CoreExtensionConfigCommand::class,
     'extension:manage' => ExtensionManagementCommand::class,
     'extension:make' => ExtensionScaffoldMakeCommand::class,
-    'crontab' => CrontabCommand::class,
+    'extension:sync' => ExtensionSyncCommand::class,
     'system:worker' => WorkerCommand::class,
 ];

+ 0 - 68
src/Command/CrontabCommand.php

@@ -1,68 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace SixShop\System\Command;
-
-use SixShop\System\Event\CrontabWorkerStartEvent;
-use think\App;
-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\Event;
-use Workerman\Worker;
-
-class CrontabCommand extends Command
-{
-    public function configure(): void
-    {
-        $this->setName('crontab')
-            ->addArgument('action', Argument::OPTIONAL, 'action')
-            ->addOption('daemon', 'd', Option::VALUE_NONE, 'daemon mode')
-            ->addOption('grace', 'g', Option::VALUE_NONE, 'graceful shutdown')
-            ->setDescription('Crontab command');
-    }
-
-    protected function execute(Input $input, Output $output): void
-    {
-        $argv = [$input->getArgument('action')];
-        $daemon = $input->getOption('daemon');
-        if ($daemon) {
-            $argv[] = '-d';
-        }
-        $grace = $input->getOption('grace');
-        if ($grace) {
-            $argv[] = '-g';
-        }
-        $worker = new class ($argv, $this->app) extends Worker {
-            private static array $argv;
-
-            public function __construct(array $argv, private readonly App $app, ?string $socketName = null, array $socketContext = [])
-            {
-                parent::__construct($socketName, $socketContext);
-                self::$argv = $argv;
-                self::$pidFile = $app->getRootPath() . 'runtime/crontab.pid';
-                self::$logFile = $app->getRootPath() . 'runtime/log/' . date('Ymd') . '_crontab.log';
-                self::$statisticsFile = $app->getRootPath() . 'runtime/crontab_statistics.php';
-            }
-
-            public function setOnWorkerStart(callable $worker): void
-            {
-                $this->onWorkerStart = $worker;
-            }
-
-            public static function getArgv(): array
-            {
-                return self::$argv;
-            }
-        };
-
-        $worker->setOnWorkerStart(function (Worker $worker) {
-            $worker->name = 'crontab';
-            Event::trigger(CrontabWorkerStartEvent::class, $worker);
-        });
-        Worker::runAll();
-    }
-}

+ 27 - 0
src/Command/ExtensionSyncCommand.php

@@ -0,0 +1,27 @@
+<?php
+
+declare(strict_types=1);
+
+namespace SixShop\System\Command;
+
+use SixShop\System\ExtensionManager;
+use think\console\Command;
+
+class ExtensionSyncCommand extends Command
+{
+    protected function configure(): void
+    {
+        $this->setName('extension:sync')
+            ->setDescription('同步扩展包最新信息(名称、描述、版本、作者等)到扩展表');
+    }
+
+    protected function handle(): void
+    {
+        try {
+            $updated = $this->app->make(ExtensionManager::class)->syncInfo();
+            $this->output->writeln("扩展信息同步完成,共处理 {$updated} 个扩展");
+        } catch (\Throwable $exception) {
+            $this->output->writeln("<comment>扩展信息同步跳过:" . $exception->getMessage() . "</comment>");
+        }
+    }
+}

+ 75 - 9
src/ExtensionManager.php

@@ -5,6 +5,7 @@ declare(strict_types=1);
 namespace SixShop\System;
 
 use Composer\InstalledVersions;
+use Composer\Json\JsonFile;
 use RuntimeException;
 use SixShop\Core\Contracts\ExtensionInterface;
 use SixShop\Core\Service\CoreService;
@@ -310,17 +311,82 @@ class ExtensionManager extends Service
 
     public function refresh(string $id): void
     {
-        // 获取当前版本更新版本信息
-        $currentVersion = '0.0.0';
-        if (isset(CoreService::$extensionComposerMap[$id])) {
-            $packageName = CoreService::$extensionComposerMap[$id]['name'];
-            $currentVersion = InstalledVersions::getPrettyVersion($packageName);
+        // 刷新单个扩展最新信息(含版本)
+        $packageName = CoreService::getExtensionComposerMap()[$id]['name'] ?? null;
+        if (!is_string($packageName) || $packageName === '') {
+            return;
+        }
+        $this->upsertExtensionInfo($id, $packageName);
+    }
+
+    /**
+     * 同步所有已安装扩展的最新信息(名称、描述、版本、作者等)到扩展表
+     *
+     * @return int 同步的扩展数量
+     */
+    public function syncInfo(): int
+    {
+        $updated = 0;
+        foreach (CoreService::getExtensionComposerMap() as $extensionID => $composer) {
+            $packageName = $composer['name'] ?? null;
+            if (!is_string($packageName) || $packageName === '') {
+                continue;
+            }
+            if ($this->upsertExtensionInfo($extensionID, $packageName)) {
+                $updated++;
+            }
+        }
+        return $updated;
+    }
 
+    private function upsertExtensionInfo(string $extensionID, string $packageName): bool
+    {
+        $data = $this->buildSyncData($extensionID, $packageName);
+        $extension = ExtensionModel::where(['id' => $extensionID])->findOrEmpty();
+        if ($extension->isEmpty()) {
+            $data['status'] = !empty($data['is_core']) ? 3 : 1; // 核心扩展默认启用,其余默认未安装
+            $extension->save($data);
+            return true;
+        }
+        unset($data['id']);
+        $extension->save($data);
+        return true;
+    }
+
+    /**
+     * 从包目录组装扩展最新信息,版本取 InstalledVersions::getPrettyVersion
+     */
+    private function buildSyncData(string $extensionID, string $packageName): array
+    {
+        $info = [];
+        $installPath = InstalledVersions::getInstallPath($packageName);
+        if ($installPath !== null && is_file($installPath . '/info.php')) {
+            $info = include $installPath . '/info.php';
+            if (!is_array($info)) {
+                $info = [];
+            }
+        } elseif ($installPath !== null && is_file($installPath . '/composer.json')) {
+            $composer = (new JsonFile($installPath . '/composer.json'))->read();
+            $info = [
+                'id' => $extensionID,
+                'name' => $composer['name'] ?? $extensionID,
+                'description' => $composer['description'] ?? '',
+            ];
         }
-        ExtensionModel::where([
-            ['id', '=', $id],
-            ['version', '<>', $currentVersion],
-        ])->update(['version' => $currentVersion]);
+        return [
+            'id' => $extensionID,
+            'name' => $info['name'] ?? $extensionID,
+            'is_core' => (int)($info['is_core'] ?? 0),
+            'category' => $info['category'] ?? '',
+            'description' => $info['description'] ?? '',
+            'version' => InstalledVersions::getPrettyVersion($packageName) ?? ($info['version'] ?? '1.0.0'),
+            'core_version' => $info['core_version'] ?? '^1.0',
+            'author' => $info['author'] ?? '未知',
+            'email' => $info['email'] ?? '',
+            'website' => $info['website'] ?? '',
+            'image' => $info['image'] ?? '',
+            'license' => $info['license'] ?? '',
+        ];
     }