You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 13:30:01