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

Symfony 6 POST_SUBMIT事件动态FormType数据注入失败问题

Symfony 6 动态嵌套表单预设值为空修复方案

问题原因

原有逻辑将用户子表单的添加逻辑绑定在house字段的POST_SUBMIT事件上,触发时机不符合表单数据流转规则:

  • POST_SUBMIT事件触发时,父表单已经完成所有请求数据与模型数据的绑定流程
  • 此时动态添加子表单传入的$testUser预设对象,不会参与数据映射,会被请求中对应字段的空提交值覆盖,最终子表单字段始终为空
  • 原有逻辑仅处理了提交场景,没有覆盖初始页面加载时的字段渲染逻辑,且模板未输出动态生成的用户字段

修复实现

1. 调整主表单事件逻辑

替换原有单事件监听的写法,同时覆盖初始加载、表单提交两个场景的数据填充,修改后的TestType代码如下:

class TestType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('house', ChoiceType::class, [
                'choices' => [
                    'first'  => 1,
                    'second' => 2,
                ],
            ]);

        // 提交前处理:在数据绑定前注入预设值、添加子表单
        $builder->addEventListener(FormEvents::PRE_SUBMIT, [$this, 'onPreSubmit']);
        // 初始加载处理:页面首次打开时根据已有数据渲染字段
        $builder->addEventListener(FormEvents::POST_SET_DATA, [$this, 'appendUserField']);
    }

    public function onPreSubmit(FormEvent $event)
    {
        $submitData = $event->getData();
        $form = $event->getForm();
        $house = $submitData['house'] ?? null;

        if (!$house) {
            return;
        }

        // 生成对应house选项的预设用户数据
        $defaultUser = (int)$house === 1
            ? ['name' => 'roger', 'age' => 65]
            : ['name' => 'billy', 'age' => 22];
        // 合并用户提交值和预设值,用户未修改时直接用预设内容
        $submitData['user'] = array_merge($defaultUser, $submitData['user'] ?? []);
        $event->setData($submitData);

        // 提前添加user字段,保证后续数据绑定流程能识别该字段
        $this->appendUserField($event);
    }

    public function appendUserField(FormEvent $event)
    {
        $form = $event->getForm();
        $data = $event->getData();

        // 避免重复添加字段报错
        if ($form->has('user')) {
            return;
        }

        $house = null;
        // 适配不同事件的数据源格式
        if ($data instanceof Test) {
            $house = $data->getHouse();
        } elseif (is_array($data)) {
            $house = $data['house'] ?? null;
        }

        if (!$house) {
            return;
        }

        // 生成预设用户实体
        $defaultUserEntity = (int)$house === 1
            ? (new TestUser())->setName('roger')->setAge(65)
            : (new TestUser())->setName('billy')->setAge(22);
        // 编辑场景优先使用已存在的用户数据
        if ($data instanceof Test && $data->getUser()) {
            $defaultUserEntity = $data->getUser();
        }

        $form->add('user', TestUserType::class, [
            'data' => $defaultUserEntity,
            'auto_initialize' => false,
        ]);
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => Test::class,
        ]);
    }
}

2. 补全模板字段渲染

原有模板仅渲染了提交按钮,没有输出动态生成的用户子表单字段,需要补充对应渲染逻辑:

{{ form_start(formtest) }}
    {{ form_row(formtest.house) }}
    {# 动态判断user字段是否生成,存在则渲染 #}
    {% if formtest.user is defined %}
        <div class="user-block">
            <h5>关联用户信息</h5>
            {{ form_row(formtest.user.name) }}
            {{ form_row(formtest.user.age) }}
        </div>
    {% endif %}
    <p>
        <button class="btn btn-primary" type="submit">test go</button>
    </p>
{{ form_end(formtest) }}

核心规则

  • 动态添加带默认值的表单字段,不能绑定在POST_SUBMIT事件,该阶段表单数据映射已经完成,新加入的字段不会自动填充默认值
  • 依赖其他字段值动态生成的表单,必须同时处理首次页面加载和表单提交两个流程,否则会出现刷新、回显时值丢失的问题
  • PRE_SUBMIT阶段如果要给动态字段传默认值,需要先把默认值合并到提交数据包中,否则表单会以空提交值覆盖传入的实体默认值

内容的提问来源于stack exchange,提问作者arno

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 10:06:37