symfony2软删除核心是“标记+过滤”,需同时配置扩展、filter和实体注解;默认查询自动过滤已删除记录,查已删数据须禁用filter并清缓存,子实体需单独配置。

在 Symfony2 中实现软删除,核心不是“删”,而是“标记+过滤”。默认情况下,所有查询(find()、findBy()、DQL)都会自动跳过已软删除的记录。若想查出已删除或未删除的数据,关键在于控制过滤器状态和字段逻辑,而不是改写查询条件。
启用软删除的三要素必须齐备
只装扩展、只加注解、只配 filter 任意一项缺失,软删除都不生效:
- 在
config/packages/stof_doctrine_extensions.yaml中开启:softdeleteable: true - 在
config/packages/doctrine.yaml中注册并启用 filter:soft-deleteable: { class: Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter, enabled: true } - 实体类顶部添加注解:
@Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=true, hardDelete=false),且deletedAt字段必须是@ORM\Column(type="datetime", nullable=true)
查未删除数据:无需额外操作
这是默认行为,所有标准查询天然支持:
-
$em->find(Article::class, $id)—— 若deletedAt非空,返回null -
$repo->findBy(['status' => 'published'])—— 自动追加WHERE deletedAt IS NULL - DQL 查询如
SELECT a FROM App\Entity\Article a WHERE a.status = :status同样被自动过滤
查已删除数据:临时禁用 filter 并清缓存
不能靠 DQL 写 WHERE deletedAt IS NOT NULL —— filter 在 SQL 构建阶段就介入,该条件会被覆盖。正确做法是:
- 先禁用 filter:
$em->getFilters()->disable('soft-deleteable') - 再清除 EntityManager 缓存:
$em->clear(),否则可能返回旧的、带过滤的结果 - 执行查询:
$repo->findBy(['deletedAt' => $value])或 DQL +WHERE a.deletedAt IS NOT NULL - 如需恢复全局过滤,记得重新启用:
$em->getFilters()->enable('soft-deleteable')
子实体软删除要单独配置
父实体加了软删除,不会影响关联的子实体。例如 Article 有 @OneToMany 的 Comment:
-
Comment类也必须加@Gedmo\SoftDeleteable(...)注解 - 关联映射中避免
cascade={"remove"},改用cascade={"persist"} - 表单中移除子项时,
removeElement()不会自动设deletedAt,需在PreRemove事件或控制器中手动赋值
不复杂但容易忽略











