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


Arbi
Réponse acceptée

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}

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.

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
Auteur

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
Auteur

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".

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.

alexwtrs
Auteur

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 ?

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

alexwtrs
Auteur

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()
        ;
    }
    */
}

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');
    }

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
Auteur

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.

alexwtrs
Auteur

Gillesr, mon url est la suivante : http://127.0.0.1:8000/suivifrais/delete/5.

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
Auteur

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

Et comment tu génère ton lien ?

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

alexwtrs
Auteur

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
Auteur

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

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
Auteur

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 !

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
Auteur

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
Auteur

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 %}
alexwtrs
Auteur

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 !