一个模块里有三个 Data Patch:先创建默认数据,再补关联关系,最后迁移旧配置。只把类名写成 Patch01、Patch02 并不能保证执行顺序,文件时间也不可靠。Magento 判断顺序看的是 patch 之间声明的依赖。

后执行的Patch明确返回它依赖的类

use Magento\Framework\Setup\Patch\DataPatchInterface;

class AssignDefaultGroup implements DataPatchInterface
{
    public static function getDependencies(): array
    {
        return [
            CreateDefaultGroup::class,
        ];
    }

    public function apply(): void
    {
        // CreateDefaultGroup 已完成后再写关联数据
    }

    public function getAliases(): array
    {
        return [];
    }
}

如果 Patch C 必须在 A、B 都完成之后执行,就同时返回两个类。依赖可以跨模块,但对方模块也应该在 module.xml 的 sequence 或 Composer 依赖中体现安装关系,避免代码根本未安装。

只给真正的数据依赖排序

两个 Patch 操作互不相关的表,就不必为了“看起来整齐”串成一条长链。依赖越多,循环依赖和后续重构越麻烦。判断标准很简单:前一个 Patch 没有执行,后一个是否必然失败或产生错误数据?只有答案为是,才写进 getDependencies()。

patch_list有记录后,改apply不会重新执行

SELECT patch_name
FROM patch_list
WHERE patch_name LIKE 'Vendor\\Module\\Setup\\Patch\\Data\\%';

Data Patch 成功后会记录类名。你后来修改 apply(),Magento 不会再次执行它。开发环境可以在确认数据可回滚后删除对应记录重测;生产环境不要随便删 patch_list,应该新增一个 Patch 来做后续变更。

如果只是给类改名,需要通过 getAliases() 返回旧类名,避免升级站点把同一份变更再跑一次。

在空库和升级库各跑一遍

空库测试能验证完整依赖排序,已有数据库升级测试能验证历史 patch 记录、类重命名和新增 patch 的组合。执行后除了看命令成功,还要核对业务表和 patch_list。Patch 的目标是可重复部署同一个结果,不是依赖某台服务器恰好按文件名顺序扫描。