【问题标题】:Form with self-referencing data (Symfony 5)带有自引用数据的表单(Symfony 5)
【发布时间】:2022-01-09 01:32:10
【问题描述】:

我正在使用 Symfony 5 做一个应用程序,但有一个问题我无法找到解决方案,我不知道。

我想制作一个实体“人”的形式。 一个人可以在他的家庭中添加其他人。

因此,在我的实体中,我对 Person 进行了多对多自引用。

class Person
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=50)
     */
    private $name;

    /**
     * @ORM\Column(type="string", length=50)
     */
    private $firstname;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $birthdaydate;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $gender;

    /** 
     * @ManyToMany(targetEntity="Person")
     * @JoinTable(name="family",
     *      joinColumns={@JoinColumn(name="person__id", referencedColumnName="person__id")},
     *      inverseJoinColumns={@JoinColumn(name="family_id", referencedColumnName="person__id")}
     *      )
     */
    private $myFamily;

现在,我想制作一个表单,在其中我可以在一个人中添加新的人。 我做了一个 CollectionType,就像 symfony 说的那样,但是当我想将它打印到页面时,由于无限循环,我得到了超时。

这是导致问题的“allow_add”。

我需要“allow_add”返回的原型变量在前面添加新字段。

class PersonType 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)
            ->add('submit', SubmitType::class)
            ->add('myFamily', CollectionType::class, array('entry_type' => PersonType::class, 'mapped' => false, 'allow_add' => true, 'by_reference' => false, 'allow_delete' => true));
    }

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

这是我的表格,但没什么有趣的,我会在解决这个问题时添加必要的js。

{% 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) }}
{{ form_row(form.myFamily) }}
    <button type="button" class="add_item_link" data-collection-holder-class="tags">Add a tag</but
    {{ form_end(form) }}
{% endblock %}

提前感谢大家。

【问题讨论】:

    标签: php forms symfony doctrine


    【解决方案1】:

    存在无限循环,因为 myFamily 属性引用了一个 Person 实体,该实体本身引用了一个 myFamily 属性...

    为简单起见,管理一个人的家庭的一种方法是创建一个单独的家庭实体。 从 Person 的角度来看,与家庭建立 ManyToOne 关系似乎更加连贯。 之后,您可以使用 PersonFormType 中的 EntityType:class 添加 Person 的族。

    这里是 EntityType 的文档:https://symfony.com/doc/current/reference/forms/types/entity.html

    【讨论】:

    • 不需要创建另一个实体。但是,在您的集合类型中使用相同的 PersonType 是一个问题。您可以使用其他类型或仅使用组来拥有不带 myFamily 的 PersonType 集合。
    • @Parian,如果我要创建一个新实体“Family”,我想单击添加按钮,然后获取 Family 实体的形式。但是不可能用 EntityType 来做到这一点,对吧?还有 Dylan Kas,你能把“群组”的文档链接给我吗,我没明白你在说什么
    • @Arkandas,是的,你是对的 EntityType 只是一个选择相关实体的字段。如果您想结合个人表格和家庭表格,您可以使用嵌入式表格:symfony.com/doc/current/form/embedded.html。另一种方法是创建一个适合您的表单的模型类(您将使用 data_class 选项将其绑定)并使用它将数据传输到正确的实体
    • 是的,这就是为什么我首先做了一个收集类。但是对于一个实体,只有一种形式,它不起作用哈哈。我没有看到 data_class 选项,我稍后会看,但我不认为我会使用它。谢谢两位的回答,对我帮助很大。
    【解决方案2】:

    Dylan Kas 的回答很好,只要加个新的表格就好了。

    人物表格

    class PersonType 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)
                ->add('submit', SubmitType::class)
                ->add('myFamily', CollectionType::class, array('entry_type' => ChildType::class, 'by_reference' => false, 'allow_add' => true, 'allow_delete' => true));
        }
    
        public function configureOptions(OptionsResolver $resolver): void
        {
            $resolver->setDefaults([
                'data_class' => Person::class,
            ]);
        }
    }
    

    myFamily 引用的孩子:

    class ChildType 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)
                ->add('submit', SubmitType::class);
        }
    
        public function configureOptions(OptionsResolver $resolver): void
        {
            $resolver->setDefaults([
                'data_class' => Person::class,
            ]);
        }
    }
    

    还有观点:

    {% block body %}
        {{ form_start(form) }}
        {{ form_row(form.name) }}
        {{ form_row(form.firstname) }}
        {{ form_row(form.birthdayDate) }}
        {{ form_row(form.gender) }}
        <button type="button" class="add_item_link" data-collection-holder-class="myFamily">Add a tag</button>
        <ul class="myFamily" data-index="{{ form.myFamily|length > 0 ? form.myFamily|last.vars.name + 1 : 0 }}" data-prototype="{{ form_widget(form.myFamily.vars.prototype)|e('html_attr') }}"></ul>
        {{ form_end(form) }}
    {% endblock %}
    

    与js关联

    const addFormToCollection = (e) => {
      const collectionHolder = document.querySelector(
        "." + e.currentTarget.dataset.collectionHolderClass
      );
    
      const item = document.createElement("li");
    
      item.innerHTML = collectionHolder.dataset.prototype.replace(
        /__name__/g,
        collectionHolder.dataset.index
      );
    
      collectionHolder.appendChild(item);
    
      collectionHolder.dataset.index++;
    };
    
    document
      .querySelectorAll(".add_item_link")
      .forEach((btn) => btn.addEventListener("click", addFormToCollection));
    

    它仍然需要一些工作,也许我可以让子表单扩展人表单。前线也需要一些工作。但是下一个面临这个问题的人将在这里找到解决方案。

    我仍然在问自己,如果我需要一个包含自身相同形式的表单,包括自身相同的表单等,我该怎么办...... 该表单将是可递归的。

    【讨论】:

      猜你喜欢
      • 2016-10-07
      • 2020-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-05
      • 2016-04-25
      相关资源
      最近更新 更多