Reputation: 583
I got entity called SupportMessage which contains messages from my support (ticket) system. I want to implement feature which allows users and support agents attach files to their posts.
I also got an entity called Files where all files from my project are listed: file ID, file name, user and uploading date.
When user writes a message in my support system, he can attach multiple files. I think using multiple=true
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.
When I send the form, I got an array of UploadedFile object, but not ArrayCollection, so everything fails:
Expected value of type "Doctrine\Common\Collections\Collection|array" for association field "AppBundle\Entity\SupportMessage#$attachments", got "Symfony\Component\HttpFoundation\File\UploadedFile" instead.
Controller:
/**
* @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->get('translator');
$breadcrumbs = $this->get('white_october_breadcrumbs');
$breadcrumbs->addRouteItem('app.name', 'homepage');
$breadcrumbs->addRouteItem('page_title.support', 'my_support_tickets');
$breadcrumbs->addItem($supportTicket->getTitle());
$supportMessage = new SupportMessage();
$supportMessage->setSupportTicket($supportTicket);
$supportMessage->setUser($this->getUser());
$form = $this->createForm(SupportMessageType::class, $supportMessage);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
foreach ($supportMessage->getAttachments() as $attachment) {
$fileName = $this->get('app.file_uploader')->upload($attachment);
$file = new File();
$file->setFilename($fileName);
$file->setUser($this->getUser());
//$supportMessage->addAttachment($file);
}
//dump($supportMessage);die;
$em = $this->getDoctrine()->getManager();
$em->persist($supportMessage);
$em->flush();
$this->addFlash('notice', $translator->trans('support.flash_message.sent'));
return $this->redirect($request->getUri());
}
return $this->render('support/view-ticket.html.twig', [
'title' => $supportTicket->getTitle(),
'supportTicket' => $supportTicket,
'form' => $form->createView()
]);
}
Service:
namespace AppBundle\Service;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class FileUploader
{
private $targetDir;
public function __construct($targetDir)
{
$this->targetDir = $targetDir;
}
public function upload(UploadedFile $file)
{
$fileName = md5(uniqid()).'.'.$file->guessExtension();
$file->move($this->targetDir, $fileName);
return $fileName;
}
}
SupportMessage entity:
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->postedAt = new \DateTime();
$this->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->id;
}
/**
* @return string
*/
public function getMessage(): ?string
{
return $this->message;
}
/**
* @param string $message
*/
public function setMessage(?string $message)
{
$this->message = $message;
}
/**
* @return \DateTime
*/
public function getPostedAt()
{
return $this->postedAt;
}
/**
* @return string
*/
public function getPostedAgo()
{
Carbon::setLocale('ru');
return Carbon::instance($this->postedAt)->diffForHumans();
}
/**
* @param \DateTime $postedAt
*/
public function setPostedAt($postedAt)
{
$this->postedAt = $postedAt;
}
/**
* @ORM\ManyToOne(targetEntity="User")
* @ORM\JoinColumn(nullable=false)
*
* @var User
*/
private $user;
/**
* @return User
*/
public function getUser()
{
return $this->user;
}
/**
* @param User $user
*/
public function setUser($user)
{
$this->user = $user;
}
/**
* @ORM\ManyToOne(targetEntity="SupportTicket", inversedBy="supportMessages")
*
* @var SupportTicket
*/
private $supportTicket;
/**
* @return SupportTicket
*/
public function getSupportTicket()
{
return $this->supportTicket;
}
/**
* @param SupportTicket $supportTicket
*/
public function setSupportTicket($supportTicket)
{
$this->supportTicket = $supportTicket;
}
/**
* @ORM\ManyToMany(targetEntity="File", inversedBy="supportMessages")
*
* @var File[]
*/
private $attachments;
/**
* @return File[]
*/
public function getAttachments()
{
return $this->attachments;
}
/**
* @param File[] $attachments
*/
public function setAttachments($attachments)
{
foreach ($attachments as $attachment) {
$this->attachments->add($attachment);
}
//dump($this->attachments);die;
}
/**
* @param File $attachment
*/
public function addAttachment($attachment)
{
$this->attachments->add($attachment);
}
}
File entity:
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->uploadedAt = new \DateTime();
$this->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->id;
}
/**
* @return string
*/
public function getFilename(): ?string
{
return $this->filename;
}
/**
* @param string $filename
*/
public function setFilename(?string $filename)
{
$this->filename = $filename;
}
/**
* @return User
*/
public function getUser()
{
return $this->user;
}
/**
* @param mixed $user
*/
public function setUser($user)
{
$this->user = $user;
}
/**
* @return \DateTime
*/
public function getUploadedAt()
{
return $this->uploadedAt;
}
/**
* @param \DateTime $uploadedAt
*/
public function setUploadedAt($uploadedAt)
{
$this->uploadedAt = $uploadedAt;
}
/**
* @ORM\ManyToMany(targetEntity="SupportMessage", mappedBy="attachments")
*
* @var Collection|SupportMessage[]
*/
private $supportMessages;
/**
* @return Collection|SupportMessage[]
*/
public function getSupportMessages()
{
return $this->supportMessages;
}
/**
* @param Collection|SupportMessage[] $supportMessages
*/
public function setSupportMessages($supportMessages)
{
$this->supportMessages = $supportMessages;
}
/**
* @param SupportMessage $supportMessage
*/
public function addSupportMessage($supportMessage)
{
$supportMessage->addAttachment($this);
$this->supportMessages->add($supportMessage);
}
}
Much thanks for any help in advance.
Upvotes: 0
Views: 864
Reputation: 583
Finally, my colleague found the problem. It was in my controller. I've attached UploadedFile
objects there, but in the fact I needed to attach my entity File
objects.
Fixed code snipped:
if ($form->isSubmitted() && $form->isValid()) {
$attachments = new ArrayCollection();
foreach ($supportMessage->getAttachments() as $attachment) {
$fileName = $this->get('app.file_uploader')->upload($attachment);
$file = new File();
$file->setFilename($fileName);
$file->setUser($this->getUser());
$attachments->add($file);
//$supportMessage->addAttachment($file);
}
$supportMessage->setAttachments($attachments);
// ... other code here ...
}
Upvotes: 0