Symfony5自引用Person实体表单开启allow_add触发无限循环超时问题
问题根因
你触发无限循环的核心原因是PersonType表单类递归引用自身:你在PersonType的buildForm方法中,将myFamily集合字段的entry_type设为了PersonType::class,这会导致Symfony渲染表单时,每次渲染myFamily的条目都会再次实例化PersonType,而新的PersonType又会尝试渲染自身的myFamily字段,无限递归最终导致请求超时。
修复方案
步骤1:新建独立的家庭成员表单类型
创建一个仅包含家庭成员必要字段的表单类,不要引入myFamily集合字段,避免递归:
// src/Form/FamilyMemberType.php namespace App\Form; use App\Entity\Person; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Form\Extension\Core\Type\TextType; use App\Form\Type\GenderType; // 替换为你自己的GenderType实际路径 class FamilyMemberType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('name', TextType::class, ['attr' => ['class' => 'form_textfield']]) ->add('firstname') ->add('birthdayDate', TextType::class, ['attr' => ['class' => 'form_datetime']]) ->add('gender', GenderType::class); // 无需添加submit按钮和myFamily字段 } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => Person::class, ]); } }
步骤2:修改原PersonType的集合字段配置
将myFamily字段的entry_type替换为新的FamilyMemberType::class:
// src/Form/PersonType.php ->add('myFamily', CollectionType::class, [ 'entry_type' => FamilyMemberType::class, // 替换原来的PersonType::class 'mapped' => false, 'allow_add' => true, 'by_reference' => false, 'allow_delete' => true ]);
步骤3:修复实体关联配置错误
你当前Person实体的自关联配置中referencedColumnName值错误,Person实体的主键字段名为id,不是person__id,修正后配置如下:
/** * @ORM\ManyToMany(targetEntity="Person") * @ORM\JoinTable(name="family", * joinColumns={@ORM\JoinColumn(name="person_id", referencedColumnName="id")}, * inverseJoinColumns={@ORM\JoinColumn(name="family_member_id", referencedColumnName="id")} * ) */ private $myFamily;
同时记得给$myFamily属性初始化ArrayCollection,否则新增关联时会报错:
public function __construct() { $this->myFamily = new \Doctrine\Common\Collections\ArrayCollection(); }
步骤4:修复前端模板错误
你的Twig模板中新增按钮标签未闭合,且data-collection-holder-class需要对应集合字段的容器类,修改后参考:
{% extends 'base.html.twig' %} {% block title %}Hello PersonController!{% endblock %} {% block body %} {{ form_start(form) }} {{ form_row(form.name) }} {{ form_row(form.firstname) }} {{ form_row(form.birthdayDate) }} {{ form_row(form.gender) }} {# 给myFamily加专属容器,方便JS插入新字段 #} <div class="my-family-holder" data-prototype="{{ form_widget(form.myFamily.vars.prototype)|e('html_attr') }}"> {% for member in form.myFamily %} {{ form_row(member) }} {% endfor %} </div> <button type="button" class="add_item_link" data-collection-holder-class="my-family-holder">添加家庭成员</button> {{ form_row(form.submit) }} {{ form_end(form) }} {% endblock %}
修改后即可正常生成prototype,配合前端JS即可实现动态新增家庭成员字段的功能。
内容的提问来源于stack exchange,提问作者Arkandas
相关产品推荐
相关产品推荐

