SolvedEasyAdminBundle Multiple file/images upload - OneupUploaderBundle

Is there any possibility to manage upload multiple files? Maybe this functionality could be added to documentation.

There are some case fg. Gallery/Images in gallery with One2Many relation when it will be nice to have one form for that in EasyAdmin with possibility to manage multiple files at once.

I think that this bundle OneupUploaderBundle is very nice to do this job. Maybe somebody use this bundle with EasyAdmin and can share with community how to start ?

OneupUploaderBundle integrate many external Javascript uploaders:
See examples here:
http://www.plupload.com/examples/
http://blueimp.github.io/jQuery-File-Upload/
http://fineuploader.com/demos.html

Maybe it can be added to roadmap fo EasyAdmin 2.0?

34 Answers

✔️Accepted Answer

I got this to work with VichUploaderBundle.

I wanted to have an entity to hold images for several other entities and this is what I did:

First of all I created the Image entity (it has a name field that I needed for this case which also works):

AppBundle\Entity\Image

<?php

namespace AppBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;

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

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(type="string", length=255)
     */
    private $image;

    /**
     * @var File
     *
     * @Vich\UploadableField(mapping="images", fileNameProperty="image")
     */
    private $imageFile;

    /**
     * @var \DateTime
     *
     * @ORM\Column(type="datetime", length=255)
     */
    private $updatedAt;


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

    /**
     * Set name
     *
     * @param string $name
     *
     * @return Image
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

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

    /**
     * @param File|null $image
     * @return Image
     */
    public function setImageFile(File $image = null)
    {
        $this->imageFile = $image;

        if ($image) {
            $this->updatedAt = new \DateTime('now');
        }

        return $this;
    }

    /**
     * @return File
     */
    public function getImageFile()
    {
        return $this->imageFile;
    }

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

        return $this;
    }

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

And its form type:

AppBundle\Form\ImageType

<?php

namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Vich\UploaderBundle\Form\Type\VichFileType;

class ImageType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name')
            ->add('imageFile', VichFileType::class)
        ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\Image'
        ));
    }
}

One of the owner entities:

AppBundle\Entity\Owner

<?php

namespace AppBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;

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

    /**
     * @var Image[]|ArrayCollection
     *
     * @ORM\ManyToMany(targetEntity="Image", cascade={"persist"})
     * @ORM\JoinTable(name="owner_images",
     *      joinColumns={@ORM\JoinColumn(name="owner_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="image_id", referencedColumnName="id", unique=true)}
     * )
     */
    private $images;


    /**
     * Owner constructor.
     */
    public function __construct()
    {
        $this->images = new ArrayCollection();
    }

    /**
     * Get images
     *
     * @return Image[]|ArrayCollection
     */
    public function getImages()
    {
        return $this->images;
    }
}

Then I configured the Vich mapping and easy admin config:

app/config/config.yml

parameters:
    app.path.images: /images/uploaded/

vich_uploader:
    db_driver: orm
    mappings:
        images:
            uri_prefix:         %app.path.images%
            upload_destination: %kernel.root_dir%/../web/%app.path.images%

easy_admin:
    entities:
        Owner:
            class: AppBundle\Entity\Owner
            form:
                fields: [{ property: 'images', type: 'collection', type_options: { entry_type: 'AppBundle\Form\ImageType' }}]
            list:
                fields: ['id','images']

Haven't had time to find a better solution but I hope this could help someone.

Other Answers:

@juaruipi I tried to follow above example to get OneToMany relation with images for rooms:
RoomImage that suppose to store images for class Room

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Symfony\Component\HttpFoundation\File\File;

/**
 * RoomImage
 *
 * @ORM\Table(name=room_images")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\RoomImageRepository")
 * @Vich\Uploadable
 */
class RoomImage
{

    /**
     * @var Room
     * @ORM\ManyToOne(targetEntity="Room", inversedBy="images")
     */
    private $room;

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="SEQUENCE")
     * @ORM\SequenceGenerator(sequenceName="room_images_id_seq", allocationSize=1, initialValue=1)
     */
    private $id;

    /**
     * @ORM\Column(name="image", type="string", length=255, nullable=true)
     * @var string
     */
    private $image;

    /**
     * @var File
     *
     * @Vich\UploadableField(mapping="room_images", fileNameProperty="image")
     */
    private $imageFile;

    /**
     * @var \DateTime
     *
     * @ORM\Column(type="datetime", length=255)
     */
    private $updatedAt;


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


    /**
     * Set room
     *
     * @param Room $room
     *
     * @return RoomImage
     */
    public function setRoom(Room $room = null)
    {
        $this->room = $room;

        return $this;
    }

    /**
     * Get room
     *
     * @return Room
     */
    public function getRoom()
    {
        return $this->room;
    }

    /**
     * @param File|null $image
     * @return Image
     */
    public function setImageFile(File $image = null)
    {
        $this->imageFile = $image;

        if ($image) {
            $this->updatedAt = new \DateTime('now');
        }

        return $this;
    }

    /**
     * @return File
     */
    public function getImageFile()
    {
        return $this->imageFile;
    }

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

        return $this;
    }

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

    public function __toString()
    {
        return (string)$this->image;
    }
}

class Room

<?php

namespace Agh\GeoEpomBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;


/**
 * Room
 *
 * @ORM\Table(name="rooms")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\RoomRepository")
 * @Gedmo\Loggable()
 */
class Room
{
    /**
     * @var RoomImage[]|ArrayCollection
     *
     * @ORM\OneToMany(targetEntity="RoomImage", mappedBy="room", cascade={"persist"})
     */
    private $images;

  // other functionality of the class

   /**
     * Get images
     *
     * @return RoomImages[]|ArrayCollection
     */
    public function getImages()
    {
        return $this->images;
    }

    /**
     * Add image
     *
     * @param RoomImage $image
     *
     * @return Room
     */
    public function addImage(RoomImage $image)
    {
        $image->setRoom($this);
        $this->images[] = $image;

        dump($image);

        return $this;
    }

    /**
     * Remove image
     *
     * @param RoomImage $image
     */
    public function removeImage(RoomImage $image)
    {
        $image->setRoom(null);
        $this->images->removeElement($image);
    }

I modified ImageType as I do not need name field

<?php

namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Vich\UploaderBundle\Form\Type\VichFileType;

class ImageType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
//            ->add('name')
            ->add('imageFile', VichFileType::class);
        dump($builder);
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\RoomImage'
        ));
    }
}

config file

parameters:
    app.path.room_images: /uploads/images/rooms

vich_uploader:
    db_driver: orm

    mappings:
        room_images:
            uri_prefix:         %app.path.room_images%
            upload_destination: %kernel.root_dir%/../web/uploads/images/rooms

I have it partially working. I have form in EasyAdmin, can select and add many files but the only info stored in RoomImage table is:

id room_id image updated_at
1 NULL image1.jpg 2017-01-17 13:15:15
2 NULL image2.jpg 2017-01-17 13:25:35

@mysiar Have you tried setting by_reference option to false for the images collection field?

easy_admin:
    entities:
        Owner:
            class: AppBundle\Entity\Room
            form:
                fields: [{ property: 'images', type: 'collection', type_options: { entry_type: 'AppBundle\Form\RoomImage', by_reference: false }}]

More Issues: