Formulaire non valide

Par dubitoph, il y a 6 ans


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, il y a 6 ans

Problème résolu

parisaqua, il y a 6 ans

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

dubitoph, il y a 6 ans

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