Bonjour,

Dans un projet Symfony, je tente d'uploader plusieurs photos depuis un formulaire en utilisant vichUloaderBundle et LiipBundle.

Voici la fonction dans mon controller permettant d'afficher et de traiter le formulaire :

    /**
     * Creating and updating advert photos
     *
     *  @Route("/media/advert_photos/create/{id}", name="media.advert_photos.create")
     * 
     * @param Advert $advert
     * @param Request $request
     * @param EntityManagerInterface $manager
     * 
     * @return Response
     */
    public function photosForm(Advert $advert, Request $request, EntityManagerInterface $manager): Response 
    {

        $recordedPhotos = $advert->getPhotos();
        $numberRecordedPhotos = count($recordedPhotos);

        $editMode = false;
        $current_menu = 'add_advert';

        if ($numberRecordedPhotos > 0) 
        {

            $editMode = true;
            $current_menu = 'dashbord';

        }

        $form = $this->createForm(PhotosAdvertType::class, $advert);

        $form->handleRequest($request);

        if($form->isSubmitted())
        {

            \dump($form->isValid());
            \dump($advert->getPhotos());

        }

        if($form->isSubmitted() && $form->isValid()) 
        {

            $photos = $advert->getPhotos();
            $numberPhotos = $photos->count();

            $checkedMain = 0;

            if ($numberPhotos > 0) 
            {

                foreach ($photos as $photo) 
                {

                    $photo->setAdvert($advert);

                    if ($photo->getMainPhoto()) 
                    {

                        $checkedMain++;

                    }
                }

            }

            if ($numberPhotos > 0 && $checkedMain == 0) 
            {

                $error = new FormError("At least one photo must be checked as the main: it will be displayed in the list of adverts.");
                $form->addError($error);

            }
            elseif ($checkedMain > 1) 
            {

                $error = new FormError("There can only be one photo checked as the main.");
                $form->addError($error);

            }

            $manager->persist($advert);
            $manager->flush();   

            if ($editMode) 
            {

                $this->addFlash('success', 'The photos have been successfully updated.');

            }
            else
            {

                $this->addFlash('success', 'Photos have successfully been added to your advert.');

            }           

            return $this->redirectToRoute('advert.periods.create', array('id' => $advert->getId()));
        }        

        return $this->render('advert/photosCreation.html.twig', [
                                                                    'form' => $form->createView(),
                                                                    'recordedPhotos' => $recordedPhotos,
                                                                    'bodyId' =>  'photosCreation',
                                                                    'editMode' => $editMode,
                                                                    'current_menu' => $current_menu
                                                                ]
                            )
        ;

    }

Voici mon formulaire principal :

<?php

namespace App\Form\advert;

use App\Entity\advert\Advert;
use App\Form\media\PhotoType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\Valid;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;

class PhotosAdvertType extends AbstractType
{

    public function buildForm(FormBuilderInterface $builder, array $options)
    {

        $builder
            ->add('photos', CollectionType::class, array(
                                                            'entry_type' => PhotoType::class,  
                                                            'prototype' => true,
                                                            'allow_add' => true,
                                                            'allow_delete' => true,
                                                            'by_reference' => false,
                                                            'required' => false,
                                                            'constraints' => array(new Valid()),
                                                            'label' => false
                                                        )
                 )
            ->add('deletedPhotos', HiddenType::class, array('mapped' => false))
        ;

    }

    public function configureOptions(OptionsResolver $resolver)
    {

        $resolver->setDefaults(
                                [
                                    'data_class' => Advert::class, 
                                    'translation_domain' => 'forms'
                                ]
                              )
        ;

    }

}

Voici le formulaire embarqué pour chaque photo ajoutée à la volée via du javascript :

<?php

namespace App\Form\media;

use App\Entity\media\Photo;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\File;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;

class PhotoType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('file', FileType::class, array( 
                                                        'label' => false, 
                                                        'required' => true, 
                                                        'constraints' => array(new File(),),
                                                     )
                      )
        ;

        if(! $options['profilePhoto'])
        {

            $builder->add('mainPhoto', CheckboxType::class);

        }

        $builder->add('name', HiddenType::class);

    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Photo::class,
            'profilePhoto' => false,
            'translation_domain' => 'forms',
        ]);
    }
}

Voici le template appelé dans mon controller :

{% extends 'base.html.twig' %}

{% block title %}
    Roadtripr - Management of your vehicle photos
{% endblock %}

{% block body %}

<div class="container pb-5">
  <div class="row">
    <div class="col">
    <h1>Add a vehicule</h1>
    {{ include('_messages.html.twig') }}
    </div>
  </div>

  <div class="row justify-content-center">
    <div class="col-md-8 order-2">

        <h2>Photos of your vehicule</h2>
        <p>Please add as many pictures as you want here. Don't forget to specify which one you want to be seen in the search results.</p>
        {{ form_start(form) }}

            <ul class= "photos" data-prototype= " {{ form_widget ( form.photos.vars.prototype )| e ( 'html_attr' ) }} " >

                {% set i = 0 %}

                  {% if editMode %}                

                    {% for photo in form.photos %}

                        {{ include('advert/_photoCreation.html.twig') }}

                        {% set i = i + 1 %}

                    {% endfor %}

                  {% endif %}

            </ul>

            {{ form_row(form.deletedPhotos) }}

            <div class="text-left">

                <a href="#" class="btn btn-secondary" id="add_photo_link">Add a photo</a>

            </div>

            <div class="text-right">
              <button type="submit" class="btn btn-primary">Next &#8594;</button>
            </div>
            <div class="float-left">
              <button type="submit" class="btn btn-link">&#8592; Previous</button>
            </div>
            {{ form_end(form) }}
          </div>
          <div class="col-md-4 order-1">
          <ul class="timeline">
              <li class="timeline-down">
                <h5 class="mb-1">Step 1</h5>
                <p>Describe your vehicule</p>
              </li>
              <li class="timeline-down">
                <h5 class="mb-1">Step 2</h5>
                <p>Technical informations of your vehicule</p>
                </li>
              <li class="timeline-active">
                <h5 class="mb-1">Step 3</h5>
                <p>Photos of your vehicule</p>
              </li>
            </ul>
          </div>
        </div>
      </div>

    </div>

    {% block javascripts %}

        {{ parent() }}

        {{ encore_entry_script_tags('photosCreation') }}

    {% endblock %}

{% endblock %}

Et enfin, voici le template imbriqué :

<li id="li_photo_{{ recordedPhotos[i].id }}"> 

    <div style='display: none'>

        {{ form_row(photo.file) }}

    </div>

    <img id="photo_{{ recordedPhotos[i].id }}"  src="{{ vich_uploader_asset(recordedPhotos[i], 'file') | imagine_filter('thumb') }}" 
         width="100" alt="Photo{{ recordedPhotos[i].id }}">

    {{ form_row ( photo.mainPhoto ) }}
    {{ form_row ( photo.name ) }}

    <a href="{{ path('media.photo.delete', {id: recordedPhotos[i].id}) }}" class="btn btn-danger"  data-link-type="photoRemoving" 
       data-creation="no-dynamically" data-redirection="{{ path('media.advert_photos.create', {id: recordedPhotos[i].advert.id}) }}">

       Remove this photo

    </a>

</li>

Lorsque je soumets le formulaire contenant plusieurs photos, j'obtiens le message d'erreur suivant :

An exception has been thrown during the rendering of a template ("Parameter "path" for route "liip_imagine_filter" must match ".+" ("" given) to generate a corresponding URL.").

En cherchant, j'ai compris que mon formulaire est considéré comme invalide, car, dans mon controller, le code suivant :

        if($form->isSubmitted())
        {

            \dump($form->isValid());
            \dump($advert->getPhotos());

        }

me donne false pour la première ligne.

Cependant, je ne comprends pas pourquoi.

Quelqu'un aurait une idée?

Merci d'avance pour votre aide!

3 réponses


dubitoph
Auteur

Problème résolu

Bonjour, pourrais-tu donner l'origine du problème STP ? Et la solution ? J'ai le même problème. Merci

dubitoph
Auteur

Désolé, je ne sais plus du tout de quoi il s'agissait.