Impossible retirer element image a patir formulaire annonce

Par Andre43, il y a 5 ans


Bonjour,
Je cherche a supprimer une image presente dans mon form annonce
ayant pour cela dans adtype mis ma collection images a allow_delete.
Mon javascript supprime bien le tag visé par le bouton supprimer.
Le dump me renvoie bien le tableau d'image avec le nb d'elements conservé mais a l'affichage de mon getAnnonce toutes les images sont presentes y compris en bdd et je n'ai aucun message d'erreur.
A l'inverse l'ajout d'image fonctionne tres bien
Je suis sur Symfony 5
Merci d'avance

Ad/Entity

<?php namespace App\Entity; use App\Entity\Image; use Cocur\Slugify\Slugify; use App\Repository\AdRepository; use Doctrine\ORM\Mapping as ORM; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\ArrayCollection; use Symfony\Component\Validator\Constraints as Assert; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; /** * @ORM\Entity(repositoryClass=AdRepository::class) * @ORM\HasLifecycleCallbacks() * @UniqueEntity( * fields = {"title"}, * message ="Une autre annonce à déjà ce titre merci de la modifier" * ) */ class Ad { /** * @ORM\Id() * @ORM\GeneratedValue() * @ORM\Column(type="integer") */ private $id; /** * title * * @ORM\Column(type="string", length=255) * *@Assert\Length( * min=10, * max=50, * minMessage="Le titre doit au minimum contenir {{ limit }} caractères", * maxMessage="Le titre ne peut contenir plus de {{ limit }} caractères" *) * @var string */ private $title; /** * @ORM\Column(type="string", length=255) */ private $slug; /** * @ORM\Column(type="float") * * @Assert\NotNull * @Assert\Regex( * pattern = "/(^[0-9]+)\W?([0-9]{0,2}$)/i", * match=true, * message ="Le prix ne peut contenir que des nombres") * */ private $price; /** * @ORM\Column(type="text") */ private $introduction; /** * @ORM\Column(type="text") */ private $content; /** * @ORM\Column(type="string", length=255) * * @Assert\Url( message="l'url {{ value }}saisi n'est pas correcte") */ private $coverImage; /** * @ORM\Column(type="integer") */ private $rooms; /** * @ORM\OneToMany(targetEntity=Image::class, mappedBy="ad", cascade={"persist"}) * * @Assert\Valid */ private $images; public function __construct() { $this->images = new ArrayCollection(); } /** * This function initialize a new slug in case is empty * * @return void * * @ORM\PrePersist * @ORM\PreUpdate */ public function initializeSlug() { if (empty($this->slug)) { $slugTitle = new Slugify(); $this->setSlug($slugTitle->slugify($this->title)); } } public function getId(): ?int { return $this->id; } public function getTitle(): ?string { return $this->title; } public function setTitle(string $title): self { $this->title = $title; return $this; } public function getSlug(): ?string { return $this->slug; } public function setSlug(string $slug): self { $this->slug = $slug; return $this; } public function getPrice(): ?float { return $this->price; } public function setPrice(float $price): self { $this->price = $price; return $this; } public function getIntroduction(): ?string { return $this->introduction; } public function setIntroduction(string $introduction): self { $this->introduction = $introduction; return $this; } public function getContent(): ?string { return $this->content; } public function setContent(string $content): self { $this->content = $content; return $this; } public function getCoverImage(): ?string { return $this->coverImage; } public function setCoverImage(string $coverImage): self { $this->coverImage = $coverImage; return $this; } public function getRooms(): ?int { return $this->rooms; } public function setRooms(int $rooms): self { $this->rooms = $rooms; return $this; } /** * @return Collection|Image[] */ public function getImages(): Collection { return $this->images; } public function addImage(Image $image): self { if (!$this->images->contains($image)) { $this->images[] = $image; $image->setAd($this); } return $this; } public function removeImage(Image $image): self { if ($this->images->contains($image)) { $this->images->removeElement($image); //set the owning side to null (unless already changed) if ($image->getAd() === $this) { $image->setAd(null); } } return $this; } /** * Set the value of images * * @return self */ public function setImages(?ArrayCollection $images) { $this->images = $images; } }

Image/Entity

<?php namespace App\Entity; use App\Repository\ImageRepository; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; /** * @ORM\Entity(repositoryClass=ImageRepository::class) */ class Image { /** * @ORM\Id() * @ORM\GeneratedValue() * @ORM\Column(type="integer") */ private $id; /** * @ORM\Column(type="string", length=255) * * @Assert\Url(message="Ceci n'est pas une url valide veuillez la modifier merci!") */ private $url; /** * @ORM\Column(type="string", length=255) * * @Assert\Length(min=10, minMessage="Le titre doit faire au moins {{ limit }} caractères") */ private $caption; /** * @ORM\ManyToOne(targetEntity=Ad::class, inversedBy="images") * @ORM\JoinColumn(nullable=false) */ private $ad; public function getId(): ?int { return $this->id; } public function getUrl(): ?string { return $this->url; } public function setUrl(string $url): self { $this->url = $url; return $this; } public function getCaption(): ?string { return $this->caption; } public function setCaption(string $caption): self { $this->caption = $caption; return $this; } public function getAd(): ?Ad { return $this->ad; } public function setAd(?Ad $ad): self { $this->ad = $ad; return $this; } }

Ma View Twig

{% extends 'base.html.twig' %} {% block title %}{{titre}}{% endblock %} {% form_theme form _self %} {% block body %} <h1 class="text-center mb-5 pb-5 border-bottom border-grey mx-auto">{{titre}}</h1> {{ form_start(form, {'attr':{'class':'form-group'}}) }} {{ form_widget(form) }} <div class="d-flex justify-content-end"> <input type="submit" class="btn btn-primary form-group" {% if button_label is defined %} value="{{ button_label }}" {% else %} value="Créer cette annonce" {% endif %} > </div> {{ form_end(form) }} {% endblock %} {% block _ad_images_widget %} <p>Utlisez ces champs pour rajouter des images</p> {{form_widget(form)}} <div class="form-group"> <button type="button" name="" id="btn-add" class="btn btn-primary "> Ajouter une image </button> </div> {% endblock %} {# suppression des labels des champs dans twig #} {# {cette suppression est commentée car réalisée dans les options du form} #} {# {% block _ad_images_entry_label %} {{form_label(form,null,{'label_attr':{'class':'d-none'}})}} {% endblock %} #} {% block _ad_images_entry_widget %} <div class="row"> <div class="col d-inline"> {{ form_errors(form.caption) }} {{ form_widget(form.caption) }} </div> <div class="col d-inline"> {{ form_errors(form.url) }} {{ form_widget(form.url) }} </div> <div class="col d-inline"> <button type='button' class="btn btn-danger btn-delete"> Supprimer </button> </div> </div> {% endblock %} {% block javascripts %} <script> $(document).ready(function(){ // Add an image when newImage addbutton is typed $(document).on('click','#btn-add',function(){ let tmpl = $('#ad_images').data('prototype').replace(/__name__/g,count); $('#ad_images').append(tmpl); }); // Delete the image choosed by the user when press delete button $(document).on('click','.btn-delete',function(e){ let result = confirm('Confirmez-vous la suppression de cette image ?'); if (result == true){ if ($(this).closest('fieldset.form-group').attr('id')){ $(this).closest('fieldset.form-group').remove(); } else { $('fieldset.form-group:last').remove(); } } }); function count(){ let count = $('#ad_images .row').length; for(let i=0;i<=count;i++){ if(!$('fieldset.form-group:nth-child('+i+')').attr('id')){ $('fieldset.form-group:nth-child('+i+')').attr('id', "block_"+i); } } } count(); }); </script> {% endblock %}

Ma Method dans le controller

/** * This method edit the choosen ad form to be modifyed * * @Route("/ad/edit/{slug}", name="edit_ad") * * @return Ad */ public function editAction(Request $request, Ad $ad, EntityManagerInterface $manager) { $form = $this->createForm(AdType::class, $ad); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { foreach ($ad->getImages() as $image) { $image->setAd($ad); $manager->persist($image); } $manager->persist($ad); $manager->flush(); $this->addFlash('success', "Les modifications de l'annonce ont bien été prises en compte"); return $this->redirectToRoute('get_ad', ["slug"=>$ad->getSlug()]); } return $this->render( "ad/forms_ad.html.twig", [ 'titre'=>'Modification de l\'annonce: '.$ad->getTitle(), 'button_label'=> "Modifier cette annonce", 'ad'=>$ad, 'form'=>$form->createView() ] ); }

Mon FormType Annonce

<?php namespace App\Form; use App\Entity\Ad; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\MoneyType; use Symfony\Component\Form\Extension\Core\Type\IntegerType; use Symfony\Component\Form\Extension\Core\Type\UrlType; class AdType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add( 'title', TextType::class, $this->getConfiguration("Titre de l'annonce", 'Saisissez votre titre') ) ->add( 'introduction', TextType::class, $this->getConfiguration("Brève présentation", 'Petite phrase d\'introduction') ) ->add( 'coverImage', UrlType::class, $this->getConfiguration("Image de couverture", 'Url de l\'image de couverture') ) ->add( 'content', TextType::class, $this->getConfiguration("Contenu de l'annonce", 'Saisissez un contenu complet pour l\'annonce') ) ->add( 'price', MoneyType::class, $this->getConfiguration("Prix de la location / nuit", 'Saisissez le prix par nuit') ) ->add( 'rooms', IntegerType::class, $this->getConfiguration("Nombre de chambres à proposer", 'De combien de chambres disposez-vous ?') ) ->add( 'images', CollectionType::class, [ 'label'=>"Images complémentaires", 'label_attr'=>["class"=>"font-weight-bold border-top my-4 border-grey"], 'entry_type'=> ImageType::class, 'entry_options'=>['label'=>false], 'allow_add'=> true, 'allow_delete' => true ] ) ; } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'data_class' => Ad::class, ]); } /** * This function returns the label and the placeholder for each field * * @param string $label * @param string $placeholder * @return array */ private function getConfiguration(string $label, string $placeholder, $required = true):array { return [ 'required'=>$required, 'label'=>$label, 'attr'=>[ 'placeholder'=>$placeholder ] ]; } }

Mon Form Image

<?php namespace App\Form; use App\Entity\Image; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Form\Extension\Core\Type\UrlType; use Symfony\Component\Form\Extension\Core\Type\TextType; class ImageType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add( 'url', UrlType::class, [ 'attr'=>["placeholder"=>"Url de l'image"] ] ) ->add( 'caption', TextType::class, [ 'attr'=>["placeholder"=>"Nom de l'image"] ] ) ; } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'data_class' => Image::class, ]); } }

1 réponse

Andre43, il y a 5 ans

J'ai réecris ma méthode edit du controlleur
J'initialise un tableau qui reprends les images présentes en bdd
Je compare ce tableau a ma request
Je supprime de ma bdd les images n'appartenant pas a ma request
Je valide les images de ma request
C'est plus lourd mais efficace.

/** * This method edit the choosen ad form to be modifyed * * @Route("/ad/edit/{slug}", name="edit_ad") * * @return Ad */ public function editAction(Request $request, Ad $ad, EntityManagerInterface $manager) { //Tableau qui reprend les images présentes en bdd $originalImages = new ArrayCollection(); foreach ($ad->getImages() as $image) { $originalImages->add($image); } $form = $this->createForm(AdType::class, $ad); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { //Comparaison et suppression des images de ma request non présentes en bdd foreach ($originalImages as $image) { if (false === $ad->getImages()->contains($image)) { $ad->removeImage($image); $manager->remove($image); $manager->flush(); } } //Validation des images de ma request foreach ($ad->getImages() as $image) { $image->setAd($ad); $manager->persist($image); } $manager->persist($ad); $manager->flush(); $this->addFlash('success', "Les modifications de l'annonce ont bien été prises en compte"); return $this->redirectToRoute('get_ad', ["slug"=>$ad->getSlug()]); } return $this->render( "ad/forms_ad.html.twig", [ 'titre'=>'Modification de l\'annonce: '.$ad->getTitle(), 'button_label'=> "Modifier cette annonce", 'form'=>$form->createView() ] ); }