1
votes

I'm trying to follow this tutorial https://symfony.com/doc/current/controller/upload_file.html and it's nice and works, but I need to upload multiple files.

Right now I have 2 related tables Products and ProductImages. I know how to upload multiple files in controller, but I want it in doctrine, I think it's more clean and professional.

So I tried a lot of combinations with foreach but've always got an error:

Expected argument of type "Web\BaseBundle\Entity\ProductImages", "Symfony\Component\HttpFoundation\File\UploadedFile" given

My entities:

Products:

class Product
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    ///

    /**
     * @ORM\OneToMany(targetEntity="Web\BaseBundle\Entity\ProductImages", mappedBy="product", cascade={"persist", "remove"})
     * @ORM\OrderBy({"id" = "ASC"})
     *
     */
    private $images;

    public function __toString(): string
    {
        return $this->getTitle();
    }
    /**
     * Constructor
     */
    public function __construct()
    {
        $this->images = new \Doctrine\Common\Collections\ArrayCollection();
    }

    ////

    /**
     * Add image
     *
     * @param \Web\BaseBundle\Entity\ProductImages $image
     *
     * @return Product
     */
    public function addImage(\Web\BaseBundle\Entity\ProductImages $image)
    {
        $this->images[] = $image;

        return $this;
    }

    /**
     * Remove image
     *
     * @param \Web\BaseBundle\Entity\ProductImages $image
     */
    public function removeImage(\Web\BaseBundle\Entity\ProductImages $image)
    {
        $this->images->removeElement($image);
    }

    /**
     * Get images
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getImages()
    {
        return $this->images;
    }
}

ProductImages:

class ProductImages
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     *
     * @ORM\Column(name="image", type="string", length=255, nullable=true)
     * @Assert\NotBlank(message="Please, upload the product brochure as a PDF file.")
     * @Assert\File(mimeTypes={ "image/jpeg", "image/jpg", "image/png" })
     */
    private $image;


    ///


    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    ///

    /**
     * Set image
     *
     * @param string $image
     *
     * @return ProductImages
     */
    public function setImage($image)
    {
        $this->image = $image;

        return $this;
    }

    /**
     * Get image
     *
     * @return string
     */
    public function getImage()
    {
        return $this->image;
    }

}

FileUploader:

class FileUploader
{
    private $targetDir;

    public function __construct($targetDir)
    {
        $this->targetDir = $targetDir;
    }

    public function upload(UploadedFile $file)
    {
        $fileName = md5(uniqid()).'.'.$file->guessExtension();

        $file->move($this->getTargetDir(), $fileName);

        return $fileName;
    }

    public function getTargetDir()
    {
        return $this->targetDir;
    }
}

FileUploadListener:

class FileUploadListener
{
    private $uploader;

    public function __construct(FileUploader $uploader)
    {
        $this->uploader = $uploader;
    }

    public function prePersist(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        $this->uploadFile($entity);
    }

    public function preUpdate(PreUpdateEventArgs $args)
    {
        $entity = $args->getEntity();

        $this->uploadFile($entity);
    }

    private function uploadFile($entity)
    {

        //Tried a lot of combinations with foreach, but not working :(        

        if (!$entity instanceof Product) {
            return;
        }

        $file = $entity->getImages();

        // only upload new files
        if (!$file instanceof UploadedFile) {
            return;
        }

        $fileName = $this->uploader->upload($file);
        $entity->setImages($fileName);
    }
}

Could someone help me with this? Thanks

1
I think, the problem is only in uploadFile function. :( - user3703456
Looks like no one knows how to do that. Ok - user3703456

1 Answers

1
votes

Fixed by myself...

Declared temp. variable for files in Product entity

private $files;

public function __construct()
{
    $this->files = new \Doctrine\Common\Collections\ArrayCollection();
}

public function setFiles($files)
{
    $this->files = $files;

    return $this;
}

public function getFiles()
{
    return $this->files;
}

Updated uploadFile function:

private function uploadFile($entity)
{
    if (!$entity instanceof Product) {
        return;
    }

    $files = $entity->getFiles();

    foreach ($files as $file) {
        if (!$file instanceof UploadedFile) {
            return;
        }
        $fileName = $this->uploader->upload($file);
        $productImage = new ProductImages();
        $productImage->setImage($fileName);
        $productImage->setProduct($entity);
        $entity->addImage($productImage);
    }
}