Erreur EntityManager#remove()

Par alexwtrs, il y a 4 ans


Bonjour,

Je suis bloqué depuis plusieurs jours sur une même erreur. Je cherche à ce que l'utilisateur puisse supprimer des lignes SQL de deux tableaux différents. L'utilisateur peut supprimer les lignes du premier tableau mais pas du deuxième. En effet, il obtient l'erreur suivante lorsqu'il souhaite supprimer la ligne : EntityManager#remove() expects parameter 1 to be an entity object, NULL given.

Le code de mon controller est le suivant :

<?php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\HttpFoundation\Request; use App\Entity\SuiviFrais; use Doctrine\Persistence\ManagerRegistry; use App\Entity\ElementsForfaitises; use App\Entity\ElementsHorsForfait; class SuiviFraisController extends AbstractController { /** * @Route("/suivifrais", name="app_suivi_frais") */ public function show():Response { $elementsforfaitises = $this->getDoctrine()->getRepository(ElementsForfaitises::class)->findAll(); $elementshorsforfait = $this->getDoctrine()->getRepository(ElementsHorsForfait::class)->findAll(); return $this->render('suivi_frais/index.html.twig', [ 'ElementsForfaitises' => $elementsforfaitises, 'ElementsHorsForfait' => $elementshorsforfait ]); } /** * @Route("/suivifrais/delete/{ef}", name="app_suivi_frais_delete_ef") */ public function frais_forfaitises_delete($ef):Response { $em = $this->getDoctrine()->getManager(); $fef = $em->getRepository(ElementsForfaitises::class)->find($ef); $em->remove($fef); $em->flush(); return $this->redirectToRoute('app_suivi_frais'); } /** * @Route("/suivifrais/delete/{ehf}", name="app_suivi_frais_delete_ehf") */ public function frais_hors_forfait_delete($ehf):Response { $em = $this->getDoctrine()->getManager(); $fehf = $em->getRepository(ElementsHorsForfait::class)->find($ehf); $em->remove($fehf); $em->flush(); return $this->redirectToRoute('app_suivi_frais'); } }

Je cherche à ce que l'utilisateur puisse aussi bien supprimer les lignes SQL du premier tableau que celui du deuxième.

Merci par avance !

25 réponses

gillesr, il y a 4 ans

Bonjour,

Oui, pense à bien mettre ton constructeur et la déclaration de l'entity manager en haut de la classe et les annotations de la route juste au dessus de la méthode concernée.
Ensuite, tu utilises la même route pour tes deux actions, la deuxième n'est donc jamais prise en compte et c'est toujours la méthode frais_forfaitises_delete qui est appelée.

gillesr, il y a 4 ans

Bonjour,

Pour faire ça, il est conseillé d'injecter l'EntityManagerInterface.
Il faut donc déclarer l'entity manager et ajouter un constructeur comme ceci, après avoir importé la classe 'Doctrine\ORM\EntityManagerInterface' en haut de ton fichier :

private $em; public function __construct(EntityManagerInterface $em) { $this->em = $em; }

ou en php 8 (la déclaration en private se fait directement dans le constructeur)

public function __construct(private EntityManagerInterface $em){}

Ensuite, tu peux simplifier ta méthode comme ça :

public function frais_forfaitises_delete(ElementsForfaitises $ef):Response { $this->em->remove($ef); $this->em->flush(); return $this->redirectToRoute('app_suivi_frais'); }

Tu noteras que j'ai typé le paramètre de la méthode ($ef) ce qui permet de le supprimer directement car le paramConverter de symfony reconnait que c'est un objet de type ElementsForfaitises et va le chercher à partir de son id passé en paramètre.

Arbi, il y a 4 ans

il faut veifier si l'objet existe

$fehf = $em->getRepository(ElementsHorsForfait::class)->find($ehf);

si l'objet n'existe pas donc vous ne pouvez pas supprimer l'objet est NULL

alexwtrs, il y a 4 ans

Merci pour ta réponse et tes conseils gillesr.

Mon code doit donc ressembler à quelque chose comme cela ?

<?php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\HttpFoundation\Request; use App\Entity\SuiviFrais; use App\Entity\ElementsForfaitises; use App\Entity\ElementsHorsForfait; use Doctrine\Persistence\ManagerRegistry; use Doctrine\ORM\EntityManagerInterface; class SuiviFraisController extends AbstractController { /** * @Route("/suivifrais", name="app_suivi_frais") */ public function show():Response { $elementsforfaitises = $this->getDoctrine()->getRepository(ElementsForfaitises::class)->findAll(); $elementshorsforfait = $this->getDoctrine()->getRepository(ElementsHorsForfait::class)->findAll(); return $this->render('suivi_frais/index.html.twig', [ 'ElementsForfaitises' => $elementsforfaitises, 'ElementsHorsForfait' => $elementshorsforfait ]); } /** * @Route("/suivifrais/delete/{ef}", name="app_suivi_frais_delete_ef") */ private $em; public function __construct(EntityManagerInterface $em) { $this->em = $em; } public function frais_forfaitises_delete(ElementsForfaitises $ef):Response { $em->remove($fef); $em->flush(); return $this->redirectToRoute('app_suivi_frais'); } /** * @Route("/suivifrais/delete/{ehf}", name="app_suivi_frais_delete_ehf") */ public function frais_hors_forfait_delete(ElementsHorsForfait $ehf):Response { $em->remove($fehf); $em->flush(); return $this->redirectToRoute('app_suivi_frais'); } }
alexwtrs, il y a 4 ans

Arbi, l'objet existe pourtant. Cela fonctionne très bien pour la route du code "frais_forfaitisés_delete" mais pas pour la route "frais_hors_forfait_delete".

alexwtrs, il y a 4 ans

Bonjour,

Merci pour ces informations. J'ai corrigé ce qui n'allait pas mais j'obtiens l'erreur suivante : Argument 1 passed to App\Controller\SuiviFraisController::frais_forfaitises_delete() must be an instance of App\Entity\ElementsForfaitises, string given, called in C:\wamp64\www\bts\vendor\symfony\http-kernel\HttpKernel.php on line 152

Le nouveau code de mon controller est le suivant :

<?php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\HttpFoundation\Request; use App\Entity\SuiviFrais; use App\Entity\ElementsForfaitises; use App\Entity\ElementsHorsForfait; use Doctrine\Persistence\ManagerRegistry; use Doctrine\ORM\EntityManagerInterface; class SuiviFraisController extends AbstractController { private $em; public function __construct(EntityManagerInterface $em) { $this->em = $em; } /** * @Route("/suivifrais", name="app_suivi_frais") */ public function show():Response { $elementsforfaitises = $this->getDoctrine()->getRepository(ElementsForfaitises::class)->findAll(); $elementshorsforfait = $this->getDoctrine()->getRepository(ElementsHorsForfait::class)->findAll(); return $this->render('suivi_frais/index.html.twig', [ 'ElementsForfaitises' => $elementsforfaitises, 'ElementsHorsForfait' => $elementshorsforfait ]); } /** * @Route("/suivifrais/delete/{ef}", name="app_suivi_frais_delete_ef") */ public function frais_forfaitises_delete(ElementsForfaitises $ef):Response { $em->remove($fef); $em->flush(); return $this->redirectToRoute('app_suivi_frais'); } public function frais_hors_forfait_delete(ElementsHorsForfait $ehf):Response { $em->remove($fehf); $em->flush(); return $this->redirectToRoute('app_suivi_frais'); } }

Sais-tu d'où cela peut venir ?

Arbi, il y a 4 ans

est ce que vous avez crée un fichier ElementsForfaitisesRepository() ?

alexwtrs, il y a 4 ans

Bonjour Arbi,

Oui, il contient le code suivant :

<?php namespace App\Repository; use App\Entity\ElementsForfaitises; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\ORM\OptimisticLockException; use Doctrine\ORM\ORMException; use Doctrine\Persistence\ManagerRegistry; /** * @method ElementsForfaitises|null find($id, $lockMode = null, $lockVersion = null) * @method ElementsForfaitises|null findOneBy(array $criteria, array $orderBy = null) * @method ElementsForfaitises[] findAll() * @method ElementsForfaitises[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) */ class ElementsForfaitisesRepository extends ServiceEntityRepository { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, ElementsForfaitises::class); } /** * @throws ORMException * @throws OptimisticLockException */ public function add(ElementsForfaitises $entity, bool $flush = true): void { $this->_em->persist($entity); if ($flush) { $this->_em->flush(); } } /** * @throws ORMException * @throws OptimisticLockException */ public function remove(ElementsForfaitises $entity, bool $flush = true): void { $this->_em->remove($entity); if ($flush) { $this->_em->flush(); } } // /** // * @return ElementsForfaitises[] Returns an array of ElementsForfaitises objects // */ /* public function findByExampleField($value) { return $this->createQueryBuilder('e') ->andWhere('e.exampleField = :val') ->setParameter('val', $value) ->orderBy('e.id', 'ASC') ->setMaxResults(10) ->getQuery() ->getResult() ; } */ /* public function findOneBySomeField($value): ?ElementsForfaitises { return $this->createQueryBuilder('e') ->andWhere('e.exampleField = :val') ->setParameter('val', $value) ->getQuery() ->getOneOrNullResult() ; } */ }
Arbi, il y a 4 ans

ok dans votre fonction ajout un dd pour verifier l'objet j'aime bien voir l'objet

public function frais_forfaitises_delete(ElementsForfaitises $ef):Response { dd($fef); $em->remove($fef); $em->flush(); return $this->redirectToRoute('app_suivi_frais'); }
gillesr, il y a 4 ans

Argument 1 passed to App\Controller\SuiviFraisController::frais_forfaitises_delete() must be an instance of App\Entity\ElementsForfaitises, string given, called in C:\wamp64\www\bts\vendor\symfony\http-kernel\HttpKernel.php on line 152

ça veut dire que ton controleur attend l'id d'un ElementsForfaitises et que tu lui passes une chaine à la place.
A quoi ressemble l'url que tu appelles ?

Elle devrat ressembler à un truc du genre http://urlDeTonSite/suivifrais/delete/3

Et ça doit supprimer l'entité dont l'id est 3

alexwtrs, il y a 4 ans

Arbi, j'ai ajouté dd($fef); mais j'obtiens toujours : Argument 1 passed to App\Controller\SuiviFraisController::frais_forfaitises_delete() must be an instance of App\Entity\ElementsForfaitises, string given, called in C:\wamp64\www\bts\vendor\symfony\http-kernel\HttpKernel.php on line 152.

gillesr, il y a 4 ans

Normalement tu n'as pas besoin de la méthode remove dans le repository (ni de la méthode add), que se passe-t-il si tu la supprimes ?

alexwtrs, il y a 4 ans

Loesque je supprime les méthodes add et remove du repository, je rencontre toujours l'erreur suivante : Argument 1 passed to App\Controller\SuiviFraisController::frais_forfaitises_delete() must be an instance of App\Entity\ElementsForfaitises, string given, called in C:\wamp64\www\bts\vendor\symfony\http-kernel\HttpKernel.php on line 152

gillesr, il y a 4 ans

Et comment tu génère ton lien ?

Arbi, il y a 4 ans

oui le problème dans le lien donc l'id n'est pas correcte dans l'url

alexwtrs, il y a 4 ans

Je génère mon lien grâce au code suivant dans mon twig : {{ path('app_suivi_frais_delete_ef', {'ef':suivi_frais.id}) }}.

alexwtrs, il y a 4 ans

Pourquoi pensez-vous que l'id n'est pas correct dans l'url ?

Arbi, il y a 4 ans

ne change pas votre url

la premiere faute si vous appeler entity manager dans constucteur il faut utulisé $this->em

apres vous ete entrain d'essayer de supprimer $em->remove($fef); le $fef n'est existe pas

mais essayer ça

/** * @Route("/suivifrais/delete/{ef}", name="app_suivi_frais_delete_ef") */ public function frais_forfaitises_delete($ef):Response { $fef = $this->getDoctrine()->getRepository(ElementsForfaitises::class)->findOneById($ef); $this->em->remove($fef); $this->em->flush(); return $this->redirectToRoute('app_suivi_frais'); }
alexwtrs, il y a 4 ans

Merci pour votre retour Arbi. Lorsque je supprime une requête de mon premier tableau, cela fonctionne. Mais lorsque je souhaite supprimer une requête de mon deuxième tableau j'obtiens l'erreur suivante : EntityManager#remove() expects parameter 1 to be an entity object, NULL given.

Avec le code suivant :

<?php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\HttpFoundation\Request; use App\Entity\SuiviFrais; use App\Entity\ElementsForfaitises; use App\Entity\ElementsHorsForfait; use Doctrine\Persistence\ManagerRegistry; use Doctrine\ORM\EntityManagerInterface; class SuiviFraisController extends AbstractController { private $em; public function __construct(EntityManagerInterface $em) { $this->em = $em; } /** * @Route("/suivifrais", name="app_suivi_frais") */ public function show():Response { $elementsforfaitises = $this->getDoctrine()->getRepository(ElementsForfaitises::class)->findAll(); $elementshorsforfait = $this->getDoctrine()->getRepository(ElementsHorsForfait::class)->findAll(); return $this->render('suivi_frais/index.html.twig', [ 'ElementsForfaitises' => $elementsforfaitises, 'ElementsHorsForfait' => $elementshorsforfait ]); } /** * @Route("/suivifrais/delete/{ef}", name="app_suivi_frais_delete_ef") */ public function frais_forfaitises_delete($ef):Response { $fef = $this->getDoctrine()->getRepository(ElementsForfaitises::class)->findOneById($ef); $this->em->remove($fef); $this->em->flush(); return $this->redirectToRoute('app_suivi_frais'); } public function frais_hors_forfait_delete($ehf):Response { $fehf = $this->getDoctrine()->getRepository(ElementsHorsForfait::class)->findOneById($ehf); $this->em->remove($fehf); $this->em->flush(); return $this->redirectToRoute('app_suivi_frais'); } }

Je pense qu'on se rapproche de la solution !

Arbi, il y a 4 ans

je pense il faut crée deux route diffirents pour la suppresion et deux url diffirent pour la suppresion

/** * @Route("/suivifrais/delete/{ef}", name="app_suivi_frais_delete_ef") */ public function frais_forfaitises_delete($ef):Response { $fef = $this->getDoctrine()->getRepository(ElementsForfaitises::class)->findOneById($ef); $this->em->remove($fef); $this->em->flush(); return $this->redirectToRoute('app_suivi_frais'); } /** * @Route("/suivifrais/hors/delete/{ef}", name="app_suivi_frais_hors_delete_ef") */ public function frais_hors_forfait_delete($ehf):Response { $fehf = $this->getDoctrine()->getRepository(ElementsHorsForfait::class)->findOneById($ehf); $this->em->remove($fehf); $this->em->flush(); return $this->redirectToRoute('app_suivi_frais'); }
et aussi dans le fichier twig

```
{{ path('app_suivi_frais_delete_ef', {'ef':suivi_frais.id}) }}
{{ path('app_suivi_frais_hors_delete_ef', {'ef':suivi_frais_hors.id}) }}

```

si vous avez deux objet diffirent dans la view il faut crée deux objet avec deux nom diffirent
alexwtrs, il y a 4 ans

Pour la route du 2e, j'ai essayé avec ce que tu m'as donné et j'obtiens : Could not resolve argument $ehf of "App\Controller\SuiviFraisController::frais_hors_forfait_delete()", maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"?

J'ai aussi essayé en modifiant une partie de la route :

/** * @Route("/suivifrais/delete/{ehf}", name="app_suivi_frais_delete_ehf") */

et j'obtiens toujours : EntityManager#remove() expects parameter 1 to be an entity object, NULL given.

Mon twig contient :

{{ path('app_suivi_frais_delete_ef', {'ef':suivi_frais.id}) }} {{ path('app_suivi_frais_delete_ehf', {'ehf':suivi_frais.id}) }}
alexwtrs, il y a 4 ans

Voici le contenu de mon fichier twig :

{% extends 'base.html.twig' %} {% block title %}Galaxy Swiss Bourdin | Suivi de mes frais{% endblock %} {% block body %} <head> <meta charset='utf-8'> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> <link rel="stylesheet" href="/css/style.css"> </head> <body> <div class="container-fluid"> <div class="row"> {% include 'include/sidebar.html.twig' %} <div class="col-9"> <br><br><br> <h2>Suivi frais</h2> <br><br><br><h4>Éléments forfaitisés</h4> <div class="table-responsive-sm"> <table class="table table-hover"> <br><br><br><thead> <tr> <th>#</th> <th>Forfait étape</th> <th>Frais kilométrique</th> <th>Nuitée hôtel</th> <th>Repas restaurant</th> {% if is_granted('ROLE_VISITEUR') %} <th>Actions</th> {% endif %} </tr> </thead> <tbdody> {% for suivi_frais in ElementsForfaitises %} <tr> <td>{{ suivi_frais.id }}</td> <td>{{ suivi_frais.forfaitetape }}</td> <td>{{ suivi_frais.fraiskilometrique }}</td> <td>{{ suivi_frais.nuiteehotel }}</td> <td>{{ suivi_frais.repasrestaurant }}</td> {% if is_granted('ROLE_VISITEUR') %} <td><a href="{{ path('app_suivi_frais_delete_ef', {'ef':suivi_frais.id}) }}"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16"> <path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/> <path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/> </svg></a></td> {% endif %} </tr> {% endfor %} </tbdody> </table> </div> <br><br><br><h4>Éléments hors forfait</h4> <div class="table-responsive-sm"> <table class="table table-hover"> <br><br><br><thead> <tr> <th>#</th> <th>Date</th> <th>Libellé</th> <th>Montant</th> {% if is_granted('ROLE_VISITEUR') %} <th>Actions</th> {% endif %} </tr> </thead> <tbdody> {% for suivi_frais in ElementsHorsForfait %} <tr> <td>{{ suivi_frais.id }}</td> <td>{{ suivi_frais.date|date('m/Y') }}</td> <td>{{ suivi_frais.libelle }}</td> <td>{{ suivi_frais.montant }}</td> {% if is_granted('ROLE_VISITEUR') %} <td><a href="{{ path('app_suivi_frais_delete_ehf', {'ehf':suivi_frais.id}) }}"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16"> <path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/> <path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/> </svg></a></td> {% endif %} </tr> {% endfor %} </tbdody> </table> </div> </div> </div> </div> </div> </body> </style> {% endblock %}
Arbi, il y a 4 ans

j'aime bien voir votre fichier twig

il faut changer le route par exemple
un route comme ça

/** * @Route("/suivifrais/hors/delete/{ef}", name="app_suivi_frais_hors_delete_ef") */
 et l'autre
/** * @Route("/suivifrais/delete/{ef}", name="app_suivi_frais_delete_ef") */
 cette partie de route il faut que doit etre diffirent

 /suivifrais/delete/{ef}
 /suivifrais/hors/delete/{ef}
alexwtrs, il y a 4 ans

Bonjour Arbi,

Merci pour votre retour ! Ma fonctionne marche correctement. Il s'agissait en effet d'un problème de route. Elles ne peuvent pas être identiques.

A bientôt !