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 {
    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Attachment", mappedBy="mail", cascade={"persist", "remove"})
     */
    protected $attachments;

    ...

    public function addAttachment(\AppBundle\Entity\ttachment $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();
    }

person fishbone    schedule 15.12.2017    source источник
comment
Вы пробовали добавить способ ArrayCollection? Нравится: $ this- ›attachments-› add ($ attachment);   -  person Ollie in PGH    schedule 15.12.2017
comment
И вы создаете экземпляр $ attachments как новый ArrayCollection () в конструкторе?   -  person Ollie in PGH    schedule 15.12.2017
comment
Разве 'by_reference' => false не заставляет Symfony вызывать $this->attachments->add($attachmetn)? Да, я создал экземпляр $ attachments как новую коллекцию ArrayCollection в конструкторе. Извините, я пропустил это выше   -  person fishbone    schedule 15.12.2017
comment
У вас есть '$ this- ›attachments [] = $ attachment;' попробуйте использовать метод ArrayCollection '$ this- ›attachments-› add ($ attachment);' Я не думаю, что это вызывается автоматически, нет.   -  person Ollie in PGH    schedule 15.12.2017


Ответы (1)


Есть несколько способов сделать то, что вы хотите. Самым простым было бы указать пустые данные или новые объекты вложений в поле формы:

$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;
}
person Jannes Botis    schedule 22.12.2017