1

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

2
  • I think, the problem is only in uploadFile function. :( Commented Aug 4, 2017 at 16:18
  • Looks like no one knows how to do that. Ok Commented Aug 5, 2017 at 9:21

1 Answer 1

1

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);
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.