You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Shopware 6中正确实现插件的自动化更新?

如何在Shopware 6中正确实现插件的自动化更新?

针对你遇到的官方Migration和生命周期方法的局限性,可通过自定义版本跟踪机制 + 生命周期方法结合的方案解决,同时也可扩展官方Migration系统实现需求,以下是具体实现思路:

核心痛点回顾

  • Migration局限性:仅支持SQL操作,无法注入服务,无法处理文件系统、API调用等复杂逻辑
  • 生命周期方法局限性:plugin:refresh会直接标记插件为最新版本,导致无法按版本梯度执行更新脚本

可行解决方案

方案1:自定义版本跟踪 + 生命周期方法(推荐)

自己维护版本执行记录,结合插件的install和update方法,按版本梯度执行更新脚本,同时利用容器获取所需服务处理复杂操作。

步骤1:创建自定义版本跟踪表

在插件的install方法中,先创建用于记录已执行更新版本的表:

public function install(InstallContext $context): void
{
    parent::install($context);
    
    // 创建版本跟踪表
    $connection = $this->container->get(Connection::class);
    $connection->executeStatement('
        CREATE TABLE IF NOT EXISTS my_custom_plugin_version (
            id INT AUTO_INCREMENT PRIMARY KEY,
            version VARCHAR(255) NOT NULL UNIQUE,
            executed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
    ');
    
    // 执行版本检测与更新脚本
    $this->processVersionUpdates($context);
}

步骤2:实现版本检测与脚本执行逻辑

新增通用方法处理版本对比和脚本执行,同时兼容首次安装和版本升级场景:

private function processVersionUpdates(InstallContext $context): void
{
    $connection = $this->container->get(Connection::class);
    $currentPluginVersion = $this->getVersion();
    
    // 获取已执行的最高版本,首次安装则为空
    $lastExecutedVersion = $connection->fetchOne('SELECT MAX(version) FROM my_custom_plugin_version');
    
    // 定义所有版本梯度(按升级顺序排列)
    $versionList = [
        '1.0.0',
        '1.0.1',
        '1.0.2',
        // ... 中间版本
        '2.9.2',
        '2.9.3'
    ];
    
    // 确定需要执行的版本范围
    $startIndex = $lastExecutedVersion ? array_search($lastExecutedVersion, $versionList) + 1 : 0;
    $endIndex = array_search($currentPluginVersion, $versionList);
    
    // 依次执行每个版本的更新脚本
    for ($i = $startIndex; $i <= $endIndex; $i++) {
        $targetVersion = $versionList[$i];
        $this->runUpdateScriptForVersion($targetVersion, $context);
        
        // 记录已执行的版本
        $connection->executeStatement(
            'INSERT INTO my_custom_plugin_version (version) VALUES (?) ON DUPLICATE KEY UPDATE executed_at = CURRENT_TIMESTAMP',
            [$targetVersion]
        );
    }
}

private function runUpdateScriptForVersion(string $version, InstallContext $context): void
{
    switch ($version) {
        case '1.0.1':
            // 示例:创建目录 + 调用外部API
            $fileSystem = $this->container->get(FileSystem::class);
            $fileSystem->mkdir($this->getPath() . '/data');
            
            $externalApiService = $this->container->get(ExternalApiService::class);
            $externalApiService->syncInitialData();
            break;
        case '1.0.2':
            // 示例:添加数据库字段
            $connection = $this->container->get(Connection::class);
            $connection->executeStatement(
                'ALTER TABLE my_custom_entity ADD COLUMN `new_field` VARCHAR(255) NULL AFTER `existing_field`',
                [],
                [Connection::PARAM_STR]
            );
            break;
        case '2.9.3':
            // 示例:调用其他插件的服务
            $otherPluginService = $this->container->get('other.plugin.service.id');
            $otherPluginService->performAction();
            break;
        // 其他版本的更新逻辑
    }
}

步骤3:适配update方法

在插件的update方法中复用版本处理逻辑,支持从旧版本升级:

public function update(UpdateContext $context): void
{
    parent::update($context);
    $this->processVersionUpdates($context);
}

注意事项

  • 版本列表必须严格按升级顺序排列,确保脚本执行顺序正确
  • 所有更新脚本需保证幂等性(如使用IF NOT EXISTS、ON DUPLICATE KEY等),避免重复执行出错
  • 在uninstall方法中添加版本跟踪表的删除逻辑,清理残留数据

方案2:扩展官方Migration系统

若想保留官方Migration的版本跟踪机制,可自定义Migration运行器,允许注入服务:

  1. 创建自定义Migration类,继承官方Migration并添加容器注入逻辑
  2. 自定义MigrationRuntime的实现,将容器传递给Migration实例
  3. 在自定义Migration中即可使用服务处理复杂操作

此方案需对Shopware内核有一定了解,适合需要深度定制的场景。


内容的提问来源于stack exchange,提问作者Matheus Gontijo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 13:15:02