brgs
brgs

Reputation: 806

Symfony 2.4 multiple file upload

How can I upload multiple images using only one file widget? Currently I have disabled mapping for the images (otherwise it would try to map to the values of the object, but then it would complain in the view because it's an array), but I have no idea how to get them back into the service.images array. What would be the best solution to this?

Service class

/**
 * Service
 *
 * @ORM\Table(name="services")
 * @ORM\Entity
 * @Gedmo\TranslationEntity(class="xxx\SiteBundle\Entity\ServiceTranslation")
 */
class Service
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

    /**
     * @var string
     *
     * @ORM\Column(name="price", type="decimal", scale=2)
     */
    private $price;

    /**
     * @var string
     *
     * @Gedmo\Slug(fields={"name"})
     * @ORM\Column(name="slug", type="string", length=128)
     */
    private $slug;

    /**
     * @var string
     *
     * @Gedmo\Translatable
     * @ORM\Column(name="description", type="text")
     */
    private $description;

    /**
     * @ORM\OneToMany(
     *     targetEntity="xxx\SiteBundle\Entity\ServiceTranslation",
     *  mappedBy="object",
     *  cascade={"persist", "remove"}
     * )
     */
    private $translations;

    /**
     * @ORM\OneToMany(
     *      targetEntity="xxx\SiteBundle\Entity\Image", mappedBy="service",
     *      cascade={"persist", "remove"}
     * )
     */
    private $images;

    public function __construct()
    {
        $this->translations = new ArrayCollection();
        $this->images = new ArrayCollection();
    }

    // everything else

}

Image class:

    /**
     * Image class.
     *
     * @ORM\Table(name="images")
     * @ORM\Entity
     * @Gedmo\Uploadable(filenameGenerator="SHA1", allowOverwrite=true, appendNumber=true)
     */
    class Image
    {
        /**
         * @ORM\Id
         * @ORM\Column(type="integer")
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;

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

        /**
         * @ORM\Column(type="string", length=255, nullable=true)
         * @Gedmo\UploadableFilePath
         */
        private $path;

        /**
         * @var
         */
        private $file;

        /**
         * @ORM\ManyToOne(targetEntity="xxx\SiteBundle\Entity\Service", inversedBy="images")
         * @ORM\JoinColumn(name="service_id", referencedColumnName="id")
         *
         */
        private $service;

        // everything else
}

Service form type:

$builder
    ->add('translations', 'a2lix_translations_gedmo', array(
        'translatable_class' => 'xxx\SiteBundle\Entity\Service',
        'label'  => false,
        'fields' => array(
            'name' => array(),
            'price' => array(
                'locale_options' => array(
                    'lt' => array(
                        'display' => false,
                    ),
                ),
            ),
            'description' => array(),
        ),
    ))
    ->add('images', 'file', array(
        'data_class' => 'xxx\SiteBundle\Entity\Image',
        'required' => false,
        'attr' => array(
            'accept' => 'image/*',
            'multiple' => 'multiple',
        ),
        'mapped' => false,
    ))
;

Controller

if ($form->isValid()) {

    $uploadableManager = $this->get('stof_doctrine_extensions.uploadable.manager');

    foreach ($service->getImages() as $image) {
        $uploadableManager->markEntityToUpload(
            $image,
            $image->getFile()
        );
    }

    $em = $this->getDoctrine()->getManager();
    $em->persist($service);
    $em->flush();

Upvotes: 1

Views: 838

Answers (2)

Manuel
Manuel

Reputation: 443

One additional detail to save others some time: You should set the attribute multiple as a boolean value in the options of the file field instead of setting it manually as an 'attr':

->add('images', 'file', array(
    'data_class' => 'xxx\SiteBundle\Entity\Image',
    'required' => false,
    'attr' => array(
        'accept' => 'image/*'
    ),
    'multiple' => true,
    'mapped' => false,
))

This change ensures $files['images'] to be in array in any case, because when I select only 1 image, the object is returned without an array and I could not iterate over it with foreach.

Upvotes: 0

brgs
brgs

Reputation: 806

Alright, it seems I got it working.

$files = $request->files->get($form->getName());
foreach ($files['images'] as $imageData) {
    $image = new Image();

    $uploadableManager->markEntityToUpload(
        $image,
        $imageData
    );

    $em->persist($image);
}

Yeah, it doesn't look so good, but works..

Upvotes: 1

Related Questions