如何用实体类字段填充表单下拉框并显示去重值
解决Symfony表单下拉框显示实体去重字段的报错问题
看起来你遇到的问题根源很明确:你用了EntityType但查询只返回了字符串类型的type字段,而EntityType组件默认期望返回的是实体对象。当Symfony尝试对这些字符串调用spl_object_hash()函数时,自然就会抛出那个错误——因为这个函数只接受对象作为参数。
下面给你两种针对性的解决方案,根据你的实际需求选择:
方案一:改用ChoiceType(推荐,如果你只需要提交type字符串值)
如果你的表单字段typeOfPosition对应的是字符串类型的属性,直接用ChoiceType更合适,不需要绑定实体对象。你可以从数据库查询去重的type列表,转换成下拉框的选项:
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Doctrine\ORM\EntityRepository; $builder ->add('typeOfPosition', ChoiceType::class, [ 'label' => 'Type of Position: ', 'choices' => function(EntityRepository $er) { // 查询去重的type字段,返回 scalar 结果 $typeResults = $er->createQueryBuilder('c') ->select('DISTINCT c.type') ->getQuery() ->getScalarResult(); // 把结果转换成下拉框需要的键值对数组(键和值都是type) return array_column($typeResults, 'type', 'type'); }, ]);
方案二:继续用EntityType(如果需要绑定Choices实体)
如果你必须绑定Choices实体对象,那要调整查询,确保返回的是实体实例,同时保证type字段唯一:
方法A:用groupBy(适用于大多数数据库)
通过分组type字段来确保返回的实体对应的type都是唯一的:
$builder ->add('typeOfPosition', EntityType::class, [ 'class' => Choices::class, 'label' => 'Type of Position: ', 'choice_label' => 'type', // 指定下拉框显示的是type字段 'query_builder' => function(EntityRepository $er) { return $er->createQueryBuilder('c') ->groupBy('c.type'); // 按type分组,确保唯一 }, ]);
方法B:用DISTINCT ON(仅适用于PostgreSQL)
如果你用的是PostgreSQL,可以用DISTINCT ON语法,返回每个type对应的第一个实体:
$builder ->add('typeOfPosition', EntityType::class, [ 'class' => Choices::class, 'label' => 'Type of Position: ', 'choice_label' => 'type', 'query_builder' => function(EntityRepository $er) { return $er->createQueryBuilder('c') ->select('DISTINCT ON (c.type) c') ->orderBy('c.type'); }, ]);
补充说明
- 为什么之前的方案失败?因为
EntityType的query_builder必须返回实体对象集合,而你之前的select('DISTINCT c.type')返回的是字符串数组,不是Choices实例,导致Symfony处理时出错。 - 如果选择
ChoiceType,要确保你的实体属性typeOfPosition是字符串类型,这样表单提交后才能正确映射。
内容的提问来源于stack exchange,提问作者Olnac
相关产品推荐
相关产品推荐

