Doctrine 3.7.0 的 postGenerateSchema 被调用两次,恢复单次生命周期
Doctrine ORM 3.7.0 曾对同一 schema 重复派发生成事件。3.7.1 修正收尾路径,应同时验证派发次数和监听器返回的最终 schema。
升级 Doctrine ORM 后,生成 schema 的监听器突然报“表已存在”,而同一次调用中监听器被执行两遍,可以先检查 postGenerateSchema 的派发次数。监听器创建辅助表时不是幂等操作,重复进入就会暴露这个问题。
Doctrine ORM 3.7.0 有同一个 Schema 被重复派发的案例,原组合在 3.6.8 没有这一行为。判断时应把调用次数对应到一次 getSchemaFromMetadata,避免把应用主动生成两次 schema 误认为框架重复派发。
3.7.0 的 schema 收尾流程保留了两段事件处理逻辑,同一对象先后进入它们。这里不属于开发模式故意重放回调,也不是监听器注册了两个实例。仅把监听器改成“发现表就返回”,可能遮住框架的重复事件,同时使其他副作用仍执行两次。
Doctrine ORM 3.7.1 包含收尾路径修补:只派发一次事件,并从事件参数中取得最终 schema 返回。后一点也重要,监听器如果通过事件参数替换了 schema,调用者应拿到替换后的对象。不能只以“辅助表没报错”作为唯一验收标准。
更新 ORM 依赖并查看锁定版本:
composer update doctrine/orm --with-all-dependencies
composer show doctrine/orm
使用临时测试监听器记录对象身份和次数:
public function postGenerateSchema(GenerateSchemaEventArgs $args): void
{
++$this->calls;
$this->schemaIds[] = spl_object_id($args->getSchema());
}
类中相应声明 calls 和 schemaIds,并保持项目现有事件参数的正确命名空间。对一组固定实体 metadata 只调用一次 schema 生成,再断言计数为一。随后恢复真实创建辅助表的监听器,确认 schema 含该表且没有重复创建。使用实验性 schema 路径的项目也应检查自己启用的路径,不以另一路径通过替代验收。
如果仍出现两次调用,要继续查看监听器是否被容器重复注册、应用是否调用生成器两遍。3.7.1 的修补只处理这个版本的重复收尾派发;它不会替应用消除所有重复订阅,也不保证任何监听器都应该自行幂等。执行 schema 验证时使用测试数据库或仅生成 schema 对象,不要为了检查次数直接修改生产结构。


