Symfony CollectionType,其中"allow_add"未将子实体添加到父实体

Hei*_*tor 2 forms collections symfony doctrine-orm

在Symfony 2.8上,我得到了以下实体:

联系:

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

    /**
     * @ORM\Column
     * @Assert\NotBlank
     */
    protected $name;

    /**
     * @ORM\OneToMany(targetEntity="EmailContact", mappedBy="contact", cascade={"persist"})
     * @Assert\Valid
     */
    protected $emails;

    // ...

    /**
     * Add emails
     *
     * @param \AppBundle\Entity\EmailContact $emails
     * @return Contact
     */
    public function addEmail(\AppBundle\Entity\EmailContact $emails)
    {
        $this->emails[] = $emails;
        $emails->setContact($this);  //this line added by me

        return $this;
    }

    // ...
Run Code Online (Sandbox Code Playgroud)

EmailContact:

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

    /**
     * @ORM\Column
     * @Assert\NotBlank
     */
    protected $email;

    /**
     * @ORM\ManyToOne(targetEntity="Contact", inversedBy="emails")
     * @ORM\JoinColumn(nullable=false)
     */
    protected $contact;

    // ...
Run Code Online (Sandbox Code Playgroud)

其余的方法由doctrine:generate:entities命令自动生成.

我的表格如下:

ContactType:

class ContactType extends AbstractType
{   
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', null, [
                'label' => 'contact.name',
            ])
            ->add('emails', CollectionType::class, [
                'label' => false,
                'entry_options' => array('label' => false),
                'entry_type' => EmailContactType::class,
                'allow_add' => true,
                'allow_delete' => true,
                'delete_empty' => true,
                'prototype' => true,
            ])
        ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => 'AppBundle\Entity\Contact'
        ]);
    }
Run Code Online (Sandbox Code Playgroud)

EmailContactType:

class EmailContactType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('email', EmailType::class, [
                'label' => 'emailContact.email',
            ])                
        ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => 'AppBundle\Entity\EmailContact'
        ]);
    }
Run Code Online (Sandbox Code Playgroud)

我使用javascript为请求添加额外的字段,并提交它.示例请求(来自Symfony Profiler):

[ 
name => test4,
emails => [ 
    0 => [ 
        email => t@t.t4
    ], 
    1 => [ 
        email => t@t.t5
    ] 
], 
_token => ...
]
Run Code Online (Sandbox Code Playgroud)

但是我收到以下错误:

An exception occurred while executing 'INSERT INTO email_contact ...

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'contact_id' cannot be null 
Run Code Online (Sandbox Code Playgroud)

调试,我看到addEmail上面的方法永远不会被调用.这里发生了什么?

Don*_*sto 6

您错过by_reference => false了表单集合定义

->add('emails', CollectionType::class, [
    'label' => false,
    'entry_options' => array('label' => false),
    'entry_type' => EmailContactType::class,
    'allow_add' => true,
    'allow_delete' => true,
    'delete_empty' => true,
    'prototype' => true,
    'by_reference' => false; // <--- you missed this
]);
Run Code Online (Sandbox Code Playgroud)

看看这里

修改后,您的代码应按预期运行.

此外,请记住,如果你setEmails()Contact类中有一个方法,框架最终会调用它,所以你需要(对于集合的每个元素)来设置联系(正如你正确地做的那样addEmails())