Symfony CollectionType:合并新条目

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Symfony CollectionType:合并新条目相关的知识,希望对你有一定的参考价值。

我的symfony形式代表一个实体Mail,它与另一个叫做Attachment的实体有一对多的关系。因此,MailType形式包含一个CollectionType字段用于嵌入其AttachmentType形式:

$builder
    ->add('attachments', CollectionType::class, [
        'entry_type' => AttachmentType::class,
        'allow_add' => true,
        'allow_delete' => false,
        'by_reference' => false,
    ]);

我的视图只会向Symfony后端发送新附件。因此,在将表单数据存储到数据库中时,我只想添加邮件的新附件,而不要触及任何现有附件。

不幸的是,Symfony / Doctrine表现不同:如果n附件包含在表单数据中,那么n首先存在的附件会被这些新附件覆盖:

existing attachments (in DB): [old1, old2, old3]
new attachments (contained by HTTP request): [new1, new2]
desired result in DB: [old1, old2, old3, new1, new2]
actual result in DB: [new1, new2, old3]

我怎样才能做到这一点?我认为by_reference => false将导致调用addAttachment方法,所以我也期望这可以开箱即用。

我的Mail实体代码:

class Mail {
    /**
     * @ORMOneToMany(targetEntity="AppBundleEntityAttachment", mappedBy="mail", cascade={"persist", "remove"})
     */
    protected $attachments;

    ...

    public function addAttachment(AppBundleEntity	tachment $attachment) {
        $attachment->setMail($this);
        $this->attachments[] = $attachment;
        return $this;
    }
}

我的控制器代码处理表单:

    // $mail = find mail in database
    $form = $this->createForm(MailType::class, $mail);
    $form->handleRequest($request);

    if ($form->isValid()) {
        $mail = $form->getData();
        $em = $this->getDoctrine()->getManager();
        $em->persist($mail);
        $em->flush();
    }
答案

有几种方法可以做你想要的。最简单的方法是在表单字段中提供空数据或新附件实体:

$builder
        ->add('attachments', CollectionType::class, [
            'entry_type' => AttachmentType::class,
            'allow_add' => true,
            'allow_delete' => true,
            'by_reference' => false,
            'data' => [new Attachment()] // or add more or []
        ]);

然后在你的邮件实体中:

public function addAttachment(Attachment $attachment) {
    $attachment->setMail($this);
    $this->attachments[] = $attachment;
    return $this;
}

public function removeAttachment(Attachment $attachment) {
    return $this;
}

如果您正在使用removeAttachment来实现其他功能,并且您实际上要删除附件,则可以利用表单字段的property_path设置:

'property_path' => 'appendAttachments'

并创建addAppendAttachment和removeAppendAttachment:

public function addAppendAttachment(Attachment $attachment) {
    $attachment->setMail($this);
    $this->attachments[] = $attachment;
    return $this;
}

public function removeAppendAttachment(Attachment $attachment) {
    return $this;
}

以上是关于Symfony CollectionType:合并新条目的主要内容,如果未能解决你的问题,请参考以下文章

Symfony5 handleRequest 更新原始 collectionType 对象

Symfony 表单 - 在 CollectionType 中的子条目类型中访问实体

Symfony 4.4如何使用collectionType从0个字段开始

Symfony 4 表单 CollectionType:仅使新行需要 FileType 元素

Select2 与 collectionType - Symfony2

Symfony2.8 表单 CollectionType 字段 manyTo many