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 :
Voici mon formulaire principal :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111 /** * 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 le formulaire embarqué pour chaque photo ajoutée à la volée via du javascript :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 <?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 template appelé dans mon controller :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 <?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', ]); } }
Code twig : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 {% 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 →</button> </div> <div class="float-left"> <button type="submit" class="btn btn-link">← 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é :
Code twig : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 <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 :
En cherchant, j'ai compris que mon formulaire est considéré comme invalide, car, dans mon controller, le code suivantAn 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.").
me donne false pour la première ligne.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 if($form->isSubmitted()) { \dump($form->isValid()); \dump($advert->getPhotos()); }
Cependant, je ne comprends pas pourquoi.
Quelqu'un aurait une idée?
Merci d'avance pour votre aide!
Partager