Symfony 4 загрузка нескольких файлов TransformationFailedException

У меня есть приложение React с Symfony 4 на сервере, которое генерирует вышеуказанное исключение.

Я попытался подписаться на эта почта (на французском).

В профилировщике Symfony, Form, я вижу оба файла, каждый со своей ошибкой. Отрывок следующий:

This value is not valid.    0   Caused by:

ConstraintViolation {#993 ▼
 root: Form {#792 ▶}
 path: "children[attachments].children[0]"
 value: UploadedFile {#36 ▼
   -test: false
   -originalName: "alfa-romeo-4C-1.jpg"
   -mimeType: "image/jpeg"
   -error: 0
   path: "/Applications/MAMP/tmp/php"
   filename: "php0vUzd5"
   basename: "php0vUzd5"
   pathname: "/Applications/MAMP/tmp/php/php0vUzd5"
   ....
 }
}

TransformationFailedException {#1029 ▼
  #message: "Compound forms expect an array or NULL on submission."
  ....

Спасибо за любую помощь.

В React я использую formData со следующим кодом:

let formData = new FormData();
formData.append('message[message]', this.props.message_form.values.message.message);
formData.append('message[ad]', this.props.match.params.ad_id);
// insert files in formData, if any
if (this.state.selectedFile.length > 0) {
    const file_length = this.state.selectedFile.length;
    for (let i = 0; i < file_length; i++) {
        formData.append('message[attachments][]', this.state.selectedFile[i]);
    }    
}

Кажется, данные отправлены правильно. Проверка дампа $ _FILES дает что-то вроде следующего, что согласуется с тем, что я вижу здесь.

["message"]=> array(5) { 
["name"]=> array(1) { 
    ["attachments"]=> array(2) { 
        [0]=> string(19) "alfa-romeo-4C-1.jpg" 
        [1]=> string(19) "alfa-romeo-4C-3.jpg" } } 
["type"]=> array(1) { 
    ["attachments"]=> array(2) { 
        [0]=> string(10) "image/jpeg" 
        [1]=> string(10) "image/jpeg" } } 
["tmp_name"]=> array(1) { 
    ["attachments"]=> array(2) { 
        [0]=> string(36) "/Applications/MAMP/tmp/php/phppPLE3Z" 
        [1]=> string(36) "/Applications/MAMP/tmp/php/phpAF1yQZ" } } 
["error"]=> array(1) { 
    ["attachments"]=> array(2) { 
        [0]=> int(0) 
        [1]=> int(0) } } 
["size"]=> array(1) { 
    ["attachments"]=> array(2) { 
        [0]=> int(41024) 
        [1]=> int(76577) } } 
} } 

Сущность сообщения:

class Message{
... other properties
/**
 * @ORM\OneToMany(targetEntity = "App\Entity\Attachment", mappedBy = "message",cascade = "all", orphanRemoval=true)
 * @Assert\Valid()
 * @Assert\NotNull()
 */
private $attachments;

public function __construct()
{
    $this->attachments = new ArrayCollection();
}
... other methods
/**
 * @return Collection|Attachment[]
 */
public function getAttachments(): Collection
{
    return $this->attachments;
}

public function addAttachment(Attachment $attachment): self
{
    if (!$this->attachments->contains($attachment)) {
        $this->attachments[] = $attachment;
        $attachment->setMessage($this);
    }

    return $this;
}

public function removeAttachment(Attachment $attachment): self
{
    if ($this->attachments->contains($attachment)) {
        $this->attachments->removeElement($attachment);
        // set the owning side to null (unless already changed)
        if ($attachment->getMessage() === $this) {
            $attachment->setMessage(null);
        }
    }

    return $this;
}

Вложение:

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

/**
 * @ORM\ManyToOne(targetEntity = "App\Entity\Message", inversedBy = "attachments")
 * @ORM\JoinColumn(nullable=false)
 * @Assert\NotNull()
 */
private $message;

/**
 * @ORM\Column(type = "string", length=255, nullable=true)
 * @Assert\File(mimeTypes = { "image/jpeg" })
 * @Assert\NotNull()
 */
private $path;

/**
 * Constructor
 *
 * @param Message $message
 */
public function __construct(Message $message = null)
{
    $this->message = $message;
}

public function getId()
{
    return $this->id;
}

public function getMessage(): ?Message
{
    return $this->message;
}

public function setMessage(?Message $message): self
{
    $this->message = $message;

    return $this;
}

public function getPath()
{
    return $this->path;
}

public function setPath($path)
{
    $this->path = $path;

    return $this;
}
}

Тип сообщения:

$builder
    ->add('message', TextType::class)
    ->add('ad', EntityType::class, array(
            'class' => Ad::class,
         ))
    ->add('attachments', CollectionType::class,array(
            'entry_type' => AttachmentType::class,
            'allow_add' => true,
            'allow_delete' => true,
            'by_reference' => false,
         ));

AttachmentType:

$builder
    ->add('path', FileType::class, array(
        'multiple' => true,
        ))
    ->add('message', TextType::class, array('label' => 'file'));

И, наконец, MessageController:

 private function insertMessage ($request) {
    $message = new Message();

    $form = $this->createForm('App\Form\MessageType', $message);

    // get message object and place it as form message content
    $data = $request->request->all();
    $text = $data['message']['message'];
    $message->setMessage($text);

    // get/set ad object
    $new_ad = new Ad();
    $ad = $this->ad_repo->findOneById($data['message']['ad']);
    if ($ad instanceof $new_ad) {
        $message->setAd($ad);
    }

    //set sender
    isset($this->user) ? 
        $message->setSender($this->user) :
        false;

    // get/set receiver
    $receiver_id = $ad->getUser();
    $receiver = $this->userManager->findUserBy(array('id'=>$receiver_id));
    $message->setReceiver($receiver);

    $form->handleRequest($request); // that's where the exception is thrown
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
0
244
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

У меня было несколько проблем:

На стороне клиента формат массива должен быть:

    let formData = new FormData();
    formData.append('message[message]', this.props.message_form.values.message.message);
    formData.append('message[ad]', this.props.match.params.ad_id);

    // insert files in formData, if any
    if (this.state.selectedFile.length > 0) {
        const file_length = this.state.selectedFile.length;
        for (let i = 0; i < file_length; i++) {
            const unique = `message[attachments][${i}][path]`;
            formData.append(unique, this.state.selectedFile[i]);
        }    
    }

AttachmentType должен выглядеть так:

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Validator\Constraints\File;
.....
        $builder
        ->add('path', FileType::class, array(
            'constraints' => array(
                new File(),
            ),
        ));

Другие вопросы по теме