软删除需绑定softdeleteable行为且字段名大小写敏感,迁移须从clean main分支生成并分步处理破坏性操作。二者均依赖doctrine机制,但各有关键陷阱:软删查询默认过滤已删数据,恢复需设deletedat为null;迁移执行需加--no-interaction等参数保障生产安全。

软删除不是加个字段就能用,迁移也不是生成就跑——这两件事在 Symfony 里常因配置错位、时机不当或理解偏差导致数据丢失、查询漏删、部署卡死。核心在于:软删除靠行为扩展或手动逻辑控制读写语义,迁移靠版本化 PHP 文件管理结构演进,二者都依赖 Doctrine 的底层机制,但又各自有不可绕过的细节陷阱。
软删除必须绑定行为,不能只加字段
很多人以为在实体里加个 isDeleted 或 deletedAt 字段,再设为 null 就算软删了。其实 Doctrine 完全不识别这个字段,除非你显式启用并绑定 SoftDeleteable 行为。
- 推荐用
stof/doctrine-extensions-bundle(v1.9+ 支持 Symfony 6.2+ 和 Doctrine 3.x),安装后在config/packages/stof_doctrine_extensions.yaml中启用:softdeleteable: true - 实体中字段名必须与注解的
fieldName完全一致,大小写敏感。例如:#[Gedmo\SoftDeleteable(fieldName: 'deletedAt')]
对应字段声明:private ?\DateTimeImmutable $deletedAt = null; - 别用布尔型字段(如
isDeleted)——Gedmo 默认只认时间戳字段,且要求数据库列允许NULL;迁移前务必确认该列未设NOT NULL约束,否则doctrine:migrations:migrate会失败
查询默认过滤,查“已删”要主动绕过
启用 SoftDeleteable 后,所有标准 DQL 查询(包括 $repo->findAll()、findBy())自动跳过 deletedAt IS NOT NULL 的记录。这不是魔法,而是 Doctrine 在生成 SQL 时悄悄加了 WHERE deletedAt IS NULL 条件。
- 想查含软删数据?不能靠
where('u.deletedAt IS NULL OR u.deletedAt IS NULL')这种无效写法 - 正确方式有两种:
— 用 Repository 自定义方法,调用$this->createQueryBuilder()并显式放开条件
— 或临时禁用过滤器:$em->getFilters()->disable('soft_deleteable');(执行完记得重启用) - 恢复数据不是“撤销 delete”,而是把
$entity->setDeletedAt(null)后$em->flush()
迁移文件必须从 clean main 分支生成
多人协作时,在未 rebase 的 feature 分支上运行 doctrine:migrations:diff,极易生成错误迁移——它对比的是你本地数据库(可能落后)和当前分支实体,而非最新主干状态,结果常是“误增字段”或“漏删索引”。
- 标准流程:先
git checkout main && git pull,确认doctrine:schema:update --dump-sql无差异,再切回功能分支执行doctrine:migrations:diff --no-interaction - CI 流水线应加入校验:
git diff main -- migrations/非空则阻断构建,强制人工确认 - 破坏性操作(如 DROP COLUMN)绝不能放在单次迁移里。应拆成三步:
— 第一步:新增兼容字段 + 迁移数据
— 第二步:应用新逻辑,旧字段标记废弃
— 第三步:删旧字段。每步up()/down()都可逆、幂等
生产迁移必须人工审批 + 事务保护
线上执行 doctrine:migrations:migrate 不是一键到底的事。没加 --no-interaction 会卡在交互提示;没加 --allow-no-migration 会导致无新迁移时返回非零退出码,CI 部署直接中断;更危险的是,缺少事务保护或超时设置,大表 ALTER 可能锁库数分钟。
- 上线命令建议写成:
php bin/console doctrine:migrations:migrate --no-interaction --allow-no-migration --timeout=300 --env=prod - 执行前必查:
php bin/console doctrine:migrations:status --show-versions,确认目标版本未被跳过、无冲突标记 -
doctrine_migration_versions表是迁移状态唯一权威来源,严禁手动删改。若误删,可用doctrine:migrations:version --add手动注册已执行版本,但需严格核对 SQL 实际执行情况
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











