title: Symfony 3: FileType multiple and Many-to-Many database relation
body: <p>I got entity called <strong>SupportMessage</strong> which contains messages from my support (ticket) system. I want to implement feature which allows users and support agents attach files to their posts.</p>
  
  <p>I also got an entity called <strong>Files</strong> where all files from my project are listed: file ID, file name, user and uploading date.</p>
  
  <p>When user writes a message in my support system, he can attach multiple files. I think using <code>multiple=true</code> is more elegant way than creating CollectionType of FileType buttons, but I don't really know how to implement this feature and make it works. Didn't find any information in official docs and Google about this case.</p>
  
  <p>When I send the form, I got an array of UploadedFile object, but not ArrayCollection, so everything fails:</p>
  
  <blockquote>
    <p>Expected value of type "Doctrine\Common\Collections\Collection|array" for association field "AppBundle\Entity\SupportMessage#$attachments", got "Symfony\Component\HttpFoundation\File\UploadedFile" instead.</p>
  </blockquote>
  
  <p>Controller:</p>
  
  <pre><code>/**
   * @Security("is_granted('ALLOWED_TO_VIEW_SUPPORT_TICKET', supportTicket)")
   * @Route("/support/ticket-{supportTicket}", name="view_ticket")
   *
   * @param Request       $request
   * @param SupportTicket $supportTicket
   * @return Response
   */
  public function viewTicket(Request $request, SupportTicket $supportTicket)
  {
      $translator  = $this-&gt;get('translator');
      $breadcrumbs = $this-&gt;get('white_october_breadcrumbs');
  
      $breadcrumbs-&gt;addRouteItem('app.name', 'homepage');
      $breadcrumbs-&gt;addRouteItem('page_title.support', 'my_support_tickets');
      $breadcrumbs-&gt;addItem($supportTicket-&gt;getTitle());
  
      $supportMessage = new SupportMessage();
      $supportMessage-&gt;setSupportTicket($supportTicket);
      $supportMessage-&gt;setUser($this-&gt;getUser());
  
      $form = $this-&gt;createForm(SupportMessageType::class, $supportMessage);
      $form-&gt;handleRequest($request);
  
      if ($form-&gt;isSubmitted() &amp;&amp; $form-&gt;isValid()) {
          foreach ($supportMessage-&gt;getAttachments() as $attachment) {
              $fileName = $this-&gt;get('app.file_uploader')-&gt;upload($attachment);
  
              $file = new File();
              $file-&gt;setFilename($fileName);
              $file-&gt;setUser($this-&gt;getUser());
  
              //$supportMessage-&gt;addAttachment($file);
          }
  
          //dump($supportMessage);die;
  
          $em = $this-&gt;getDoctrine()-&gt;getManager();
          $em-&gt;persist($supportMessage);
          $em-&gt;flush();
  
          $this-&gt;addFlash('notice', $translator-&gt;trans('support.flash_message.sent'));
  
          return $this-&gt;redirect($request-&gt;getUri());
      }
  
      return $this-&gt;render('support/view-ticket.html.twig', [
          'title'         =&gt; $supportTicket-&gt;getTitle(),
          'supportTicket' =&gt; $supportTicket,
          'form'          =&gt; $form-&gt;createView()
      ]);
  }
  </code></pre>
  
  <p>Service:</p>
  
  <pre><code>namespace AppBundle\Service;
  
  use Symfony\Component\HttpFoundation\File\UploadedFile;
  
  class FileUploader
  {
      private $targetDir;
  
      public function __construct($targetDir)
      {
          $this-&gt;targetDir = $targetDir;
      }
  
      public function upload(UploadedFile $file)
      {
          $fileName = md5(uniqid()).'.'.$file-&gt;guessExtension();
  
          $file-&gt;move($this-&gt;targetDir, $fileName);
  
          return $fileName;
      }
  }
  </code></pre>
  
  <p>SupportMessage entity:</p>
  
  <pre><code>namespace AppBundle\Entity;
  
  use Carbon\Carbon;
  use Doctrine\Common\Collections\ArrayCollection;
  use Doctrine\Common\Collections\Collection;
  use Doctrine\ORM\Mapping as ORM;
  use Symfony\Component\Validator\Constraints as Assert;
  
  /**
   * @ORM\Entity
   */
  class SupportMessage
  {
      public function __construct()
      {
          $this-&gt;postedAt = new \DateTime();
          $this-&gt;attachments = new ArrayCollection();
      }
  
      /**
       * @ORM\Id
       * @ORM\GeneratedValue(strategy="AUTO")
       * @ORM\Column(type="integer")
       *
       * @var int
       */
      private $id;
  
      /**
       * @ORM\Column(type="text")
       *
       * @Assert\NotBlank
       * @Assert\Length(max=65535)
       *
       * @var string
       */
      private $message;
  
      /**
       * @ORM\Column(type="datetime")
       *
       * @var \DateTime
       */
      private $postedAt;
  
      /**
       * @return int
       */
      public function getId(): ?int
      {
          return $this-&gt;id;
      }
  
      /**
       * @return string
       */
      public function getMessage(): ?string
      {
          return $this-&gt;message;
      }
  
      /**
       * @param string $message
       */
      public function setMessage(?string $message)
      {
          $this-&gt;message = $message;
      }
  
      /**
       * @return \DateTime
       */
      public function getPostedAt()
      {
          return $this-&gt;postedAt;
      }
  
      /**
       * @return string
       */
      public function getPostedAgo()
      {
          Carbon::setLocale('ru');
  
          return Carbon::instance($this-&gt;postedAt)-&gt;diffForHumans();
      }
  
      /**
       * @param \DateTime $postedAt
       */
      public function setPostedAt($postedAt)
      {
          $this-&gt;postedAt = $postedAt;
      }
  
      /**
       * @ORM\ManyToOne(targetEntity="User")
       * @ORM\JoinColumn(nullable=false)
       *
       * @var User
       */
      private $user;
  
      /**
       * @return User
       */
      public function getUser()
      {
          return $this-&gt;user;
      }
  
      /**
       * @param User $user
       */
      public function setUser($user)
      {
          $this-&gt;user = $user;
      }
  
      /**
       * @ORM\ManyToOne(targetEntity="SupportTicket", inversedBy="supportMessages")
       *
       * @var SupportTicket
       */
      private $supportTicket;
  
      /**
       * @return SupportTicket
       */
      public function getSupportTicket()
      {
          return $this-&gt;supportTicket;
      }
  
      /**
       * @param SupportTicket $supportTicket
       */
      public function setSupportTicket($supportTicket)
      {
          $this-&gt;supportTicket = $supportTicket;
      }
  
      /**
       * @ORM\ManyToMany(targetEntity="File", inversedBy="supportMessages")
       *
       * @var File[]
       */
      private $attachments;
  
      /**
       * @return File[]
       */
      public function getAttachments()
      {
          return $this-&gt;attachments;
      }
  
      /**
       * @param File[] $attachments
       */
      public function setAttachments($attachments)
      {
          foreach ($attachments as $attachment) {
              $this-&gt;attachments-&gt;add($attachment);
          }
  
          //dump($this-&gt;attachments);die;
      }
  
      /**
       * @param File $attachment
       */
      public function addAttachment($attachment)
      {
          $this-&gt;attachments-&gt;add($attachment);
      }
  }
  </code></pre>
  
  <p>File entity:</p>
  
  <pre><code>namespace AppBundle\Entity;
  
  use Doctrine\Common\Collections\ArrayCollection;
  use Doctrine\Common\Collections\Collection;
  use Doctrine\ORM\Mapping as ORM;
  use Symfony\Component\Validator\Constraints as Assert;
  
  /**
   * @ORM\Entity
   */
  class File
  {
      public function __construct()
      {
          $this-&gt;uploadedAt = new \DateTime();
          $this-&gt;supportMessages = new ArrayCollection();
      }
  
      /**
       * @ORM\Id
       * @ORM\GeneratedValue(strategy="AUTO")
       * @ORM\Column(type="integer")
       *
       * @var int
       */
      private $id;
  
      /**
       * @ORM\Column(type="string")
       *
       * @Assert\File
       *
       * @var string
       */
      private $filename;
  
      /**
       * @ORM\Column(type="string")
       *
       * @var User
       */
      private $user;
  
      /**
       * @ORM\Column(type="datetime")
       *
       * @var \DateTime
       */
      private $uploadedAt;
  
      /**
       * @return int
       */
      public function getId(): ?int
      {
          return $this-&gt;id;
      }
  
      /**
       * @return string
       */
      public function getFilename(): ?string
      {
          return $this-&gt;filename;
      }
  
      /**
       * @param string $filename
       */
      public function setFilename(?string $filename)
      {
          $this-&gt;filename = $filename;
      }
  
      /**
       * @return User
       */
      public function getUser()
      {
          return $this-&gt;user;
      }
  
      /**
       * @param mixed $user
       */
      public function setUser($user)
      {
          $this-&gt;user = $user;
      }
  
      /**
       * @return \DateTime
       */
      public function getUploadedAt()
      {
          return $this-&gt;uploadedAt;
      }
  
      /**
       * @param \DateTime $uploadedAt
       */
      public function setUploadedAt($uploadedAt)
      {
          $this-&gt;uploadedAt = $uploadedAt;
      }
  
      /**
       * @ORM\ManyToMany(targetEntity="SupportMessage", mappedBy="attachments")
       *
       * @var Collection|SupportMessage[]
       */
      private $supportMessages;
  
      /**
       * @return Collection|SupportMessage[]
       */
      public function getSupportMessages()
      {
          return $this-&gt;supportMessages;
      }
  
      /**
       * @param Collection|SupportMessage[] $supportMessages
       */
      public function setSupportMessages($supportMessages)
      {
          $this-&gt;supportMessages = $supportMessages;
      }
  
      /**
       * @param SupportMessage $supportMessage
       */
      public function addSupportMessage($supportMessage)
      {
          $supportMessage-&gt;addAttachment($this);
  
          $this-&gt;supportMessages-&gt;add($supportMessage);
      }
  }
  </code></pre>
  
  <p>Much thanks for any help in advance.</p>