Kaynağa Gözat

feat(core): 使用 Composer 自动生成扩展列表

- 新增 $extensionComposerMap 属性,用于存储扩展的 Composer 信息
- 改进 initExtensionList 方法,通过 Composer 获取已安装的扩展信息
- 添加兼容性处理,保留旧的 $extensionNameList 属性
- 优化扩展激活过程,增加扩展 ID 的唯一性校验
runphp 7 ay önce
ebeveyn
işleme
98d55b666a
3 değiştirilmiş dosya ile 45 ekleme ve 30 silme
  1. 11 2
      src/Plugin.php
  2. 2 0
      src/Service/AutoloadService.php
  3. 32 28
      src/Service/CoreService.php

+ 11 - 2
src/Plugin.php

@@ -5,6 +5,7 @@ namespace SixShop\Core;
 
 use Composer\Composer;
 use Composer\EventDispatcher\EventSubscriberInterface;
+use Composer\InstalledVersions;
 use Composer\Installer\PackageEvent;
 use Composer\Installer\PackageEvents;
 use Composer\IO\IOInterface;
@@ -12,11 +13,11 @@ use Composer\Plugin\PluginInterface;
 
 class Plugin implements PluginInterface, EventSubscriberInterface
 {
-
+    public const EXTENSION_TYPE = 'sixshop-extension';
 
     public function activate(Composer $composer, IOInterface $io): void
     {
-        $installer = new ExtensionInstaller($io, $composer, 'sixshop-extension');
+        $installer = new ExtensionInstaller($io, $composer, self::EXTENSION_TYPE);
         $composer->getInstallationManager()->addInstaller($installer);
     }
 
@@ -39,6 +40,14 @@ class Plugin implements PluginInterface, EventSubscriberInterface
         if (!isset($extra['sixshop']['id']) || !isset($extra['sixshop']['class'])) {
             throw new \RuntimeException('Invalid sixshop extension configuration');
         }
+        $extensionId = $extra['sixshop']['id'];
+        $installedPackages = InstalledVersions::getInstalledPackagesByType(self::EXTENSION_TYPE);
+        foreach ($installedPackages as $installedPackage) {
+            $installedExtra = $installedPackage->getExtra();
+            if ($installedExtra['sixshop']['id'] === $extensionId) {
+                throw new \RuntimeException("Extension ID '{$extensionId}' already exists. Please use a unique ID for your extension.");
+            }
+        }
         return true;
     }
 

+ 2 - 0
src/Service/AutoloadService.php

@@ -3,6 +3,8 @@ declare(strict_types=1);
 
 namespace SixShop\Core\Service;
 
+use Composer\InstalledVersions;
+use Composer\Installer;
 use Composer\Json\JsonFile;
 use SixShop\Core\Helper;
 use think\App;

+ 32 - 28
src/Service/CoreService.php

@@ -3,7 +3,10 @@ declare(strict_types=1);
 
 namespace SixShop\Core\Service;
 
+use Composer\InstalledVersions;
+use Composer\Json\JsonFile;
 use SixShop\Core\Exception\ExceptionHandle;
+use SixShop\Core\Plugin;
 use SixShop\Core\Request;
 use think\event\HttpRun;
 use think\exception\Handle;
@@ -13,6 +16,9 @@ class CoreService extends Service
 {
     public static string $extensionPath;
 
+    public static array $extensionComposerMap = [];
+
+    /* @deprecated */
     public static array $extensionNameList = [];
 
     public function register(): void
@@ -23,6 +29,7 @@ class CoreService extends Service
             require $this->app->getRootPath() . 'vendor/autoload.php');
         self::$extensionPath = $this->app->getRootPath() . 'extension' . DIRECTORY_SEPARATOR;
         $this->initExtensionList();
+        $this->compatibleExtensNameList();
     }
 
     public function boot(): void
@@ -38,36 +45,33 @@ class CoreService extends Service
         });
     }
 
-    public function initExtensionList(): void
+    private function initExtensionList(): void
+    {
+        if (!empty(self::$extensionComposerMap)) {
+            return;
+        }
+        $extensionComposerFile = $this->app->getRootPath() . 'runtime/extension_' . InstalledVersions::getRootPackage()['reference'].'.php';
+        if (file_exists($extensionComposerFile)) {
+            self::$extensionComposerMap = require $extensionComposerFile;
+            return;
+        }
+        foreach (InstalledVersions::getInstalledPackagesByType(Plugin::EXTENSION_TYPE) as $item) {
+            $version = InstalledVersions::getInstallPath($item);
+            $installPath = InstalledVersions::getInstallPath($item);
+            $composerJson = new JsonFile($installPath . '/composer.json');
+            $composer = $composerJson->read();
+            self::$extensionComposerMap[$composer['extra']['sixshop']['id']] = $composer;
+        };
+        $header = '// This file is automatically generated at:' . date('Y-m-d H:i:s') . PHP_EOL . 'declare (strict_types = 1);' . PHP_EOL;
+        $content = '<?php ' . PHP_EOL . $header . "return " . var_export(self::$extensionComposerMap, true) . ';';
+        file_put_contents($extensionComposerFile, $content);
+    }
+
+    /* @deprecated */
+    private function compatibleExtensNameList(): void
     {
         if (empty(self::$extensionNameList)) {
-            $coreFile = $this->app->getRootPath() . 'runtime/module_name_list_core.php';
-            if (file_exists($coreFile)) {
-                self::$extensionNameList = require $coreFile;
-            } else {
-                $extensionInfoList = [];
-                $extensionDirs = array_diff(scandir(self::$extensionPath), ['.', '..']);
-                foreach ($extensionDirs as $item) {
-                    if (!is_dir(self::$extensionPath . $item)) {
-                        continue;
-                    }
-                    $infoFile = self::$extensionPath . $item . '/info.php';
-                    if (is_file($infoFile)) {
-                        $info = require $infoFile;
-                        $info['weight'] = $info['weight'] ?? 10000;
-                        if ($info['is_core'] ?? false) {
-                            self::$extensionNameList[] = $info['id'];
-                            $extensionInfoList[] = $info;
-                        }
-                    }
-                }
-                usort($extensionInfoList, function ($a, $b) {
-                    return $a['weight'] <=> $b['weight'];
-                });
-                $header = '// This file is automatically generated at:' . date('Y-m-d H:i:s') . PHP_EOL . 'declare (strict_types = 1);' . PHP_EOL;
-                $content = '<?php ' . PHP_EOL . $header . "return " . var_export(array_column($extensionInfoList, 'id'), true) . ';';
-                file_put_contents($coreFile, $content);
-            }
+            self::$extensionNameList = array_keys(self::$extensionComposerMap);
             $normalFile = $this->app->getRootPath() . 'runtime/module_name_list_normal.php';
             if (file_exists($normalFile)) {
                 self::$extensionNameList = array_merge(self::$extensionNameList, require $normalFile);