Symfony 5表单ChoiceType绑定NomenclatureDTO取idNom提交报错问题
问题原因分析
- 第一个
Notice: Trying to get property 'idNom' of non-object报错:choice_value回调在表单初始化、字段无默认值的场景下会接收到null参数,你直接访问$choice->idNom未做空值判断触发报错。你看到的dump输出仅捕获了处理有效选项的调用,空值场景的调用未被你抓取到,所以会出现看似矛盾的现象。 - 第二个
Typed property App\Entity\DTO\AvisDTO::$nomNatureAvisRendu must be int, App\Entity\DTO\NomenclatureDTO used报错:Symfony的ChoiceType默认会将选中的选项(也就是你传入的NomenclatureDTO对象)直接赋值给绑定的AvisDTO对应属性,但AvisDTO的nomNatureAvisRendu声明为int类型,类型不匹配触发报错。
解决方案
方案1:预处理选项数组(更简单,推荐)
直接将NomenclatureDTO数组转换为「显示文本=>id值」格式的选项数组,提交时直接返回int类型的id,无需额外回调或转换器:
// 在buildForm方法中先预处理选项 $natureAvisChoices = []; foreach ($options['dataPostAvis']->nomNatureAvisRendu as $dto) { $natureAvisChoices[$dto->libNom] = $dto->idNom; } $typeAvisChoices = []; foreach ($options['dataPostAvis']->nomTypeAvis as $dto) { $typeAvisChoices[$dto->libNom] = $dto->idNom; } // 字段配置简化为: ->add('nomNatureAvisRendu', ChoiceType::class, [ 'label' => "Nature de l'avis rendu", 'required' => false, 'choices' => $natureAvisChoices, ]) ->add('nomTypeAvis', ChoiceType::class, [ 'label' => "Type d'avis", 'required' => false, 'choices' => $typeAvisChoices, ])
方案2:添加数据转换器(适用于需要保留对象做额外逻辑的场景)
如果需要在表单逻辑中用到NomenclatureDTO的其他属性,可以给字段添加模型转换器,实现对象和int id的互转:
首先引入转换器接口:
use Symfony\Component\Form\DataTransformerInterface;
然后修改字段配置并追加转换器:
->add('nomNatureAvisRendu', ChoiceType::class, [ 'label' => "Nature de l'avis rendu", 'required' => false, 'choices' => $options['dataPostAvis']->nomNatureAvisRendu, 'choice_label' => fn(?NomenclatureDTO $choice) => $choice?->libNom, 'choice_value' => fn(?NomenclatureDTO $choice) => $choice?->idNom, ]) ->get('nomNatureAvisRendu') ->addModelTransformer(new class ($options['dataPostAvis']->nomNatureAvisRendu) implements DataTransformerInterface { public function __construct( private array $choices ) {} // 把AvisDTO中存储的int id转换为对应的NomenclatureDTO对象供表单渲染 public function transform(mixed $value): ?NomenclatureDTO { if (null === $value) return null; foreach ($this->choices as $dto) { if ($dto->idNom === $value) return $dto; } return null; } // 把表单提交的NomenclatureDTO对象转换为int id赋值给AvisDTO public function reverseTransform(mixed $value): int { return $value?->idNom ?? 0; } });
nomTypeAvis字段按照相同逻辑添加转换器即可。
额外修正
你的configureOptions中dataPostAvis的默认值配置错误,不应该设置为类名,建议调整为:
public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => AvisDTO::class, 'dataPostAvis' => null, ]); // 添加类型约束避免传参错误 $resolver->setAllowedTypes('dataPostAvis', DataAvisType::class); }
内容的提问来源于stack exchange,提问作者Zabon
相关产品推荐
相关产品推荐

