Question

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();
Was it helpful?

Solution

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..

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top