Symfony中如何保留被软删除实体在EntityType中的选中值?
解决方案
核心思路是让自定义的EntityField在编辑已有实体时,自动将当前关联的已软删除实体加入选项列表,新建实体时仅显示未删除的选项,完全基于Symfony表单原生机制实现。
调整EntityField的query_builder配置
修改configureOptions方法中的默认query_builder闭包,使其根据表单绑定的数据动态调整查询条件:
namespace App\Form\Fields; use App\Entity\File; use App\Entity\FileType; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\QueryBuilder; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\OptionsResolver; class EntityField extends AbstractType { public function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); // some additional configuration $resolver->setDefaults([ 'query_builder' => function (EntityRepository $er, $options): QueryBuilder { $qb = $er->createQueryBuilder('entity') ->andWhere('entity.deletedAt IS NULL'); // 编辑已有File实体时,保留当前关联的FileType(即使已软删除) if (isset($options['data']) && $options['data'] instanceof File) { $fileType = $options['data']->getFileType(); if ($fileType instanceof FileType) { $qb->orWhere('entity.id = :fileTypeId') ->setParameter('fileTypeId', $fileType->getId()); } } return $qb; }, ]); } public function getParent(): string { return EntityType::class; } }
原理说明
- 新建
File时,$options['data']为新实例或null,query_builder仅返回未软删除的FileType,满足“不可选择已删除类型”的需求; - 编辑已有
File时,若该File关联了已软删除的FileType,会通过OR条件将该FileType加入查询结果,确保选项列表中存在对应值,表单即可正确显示选中状态; - 该方案完全遵循Symfony表单规范,无需手动修改视图属性,避免了非标准实现的维护成本。
通用型扩展(可选)
如果你的EntityField是通用组件(并非仅用于File关联FileType),可以通过新增自定义选项适配更多场景:
- 在
configureOptions中新增可选参数:
$resolver->setOptional(['include_current_entity']); $resolver->setAllowedTypes('include_current_entity', ['callable']);
- 在
query_builder中调用该回调:
if (isset($options['include_current_entity']) && is_callable($options['include_current_entity'])) { $currentEntity = $options['include_current_entity']($options['data']); if ($currentEntity) { $qb->orWhere('entity.id = :currentId') ->setParameter('currentId', $currentEntity->getId()); } }
- 使用
EntityField时传入回调:
$builder->add('fileType', EntityField::class, [ 'include_current_entity' => function (File $file) { return $file->getFileType(); }, ]);
内容的提问来源于stack exchange,提问作者Andrey Yanduganov
相关产品推荐
相关产品推荐

