Archives Wild Code School
Symfony

13 - Symfony : Le param converter

Quête 16 sur 35

Objectifs

  • ✅ Comprendre le principe du param converter
  • ✅ Connaître des cas d'utilisation plus avancés

Pré-requis

​ Avoir terminé la quête

Quêtes liées
title-book
Introduction

User stories 📋

en tant que visiteur, je souhaite récupérer les données d'une série

en tant que visiteur, je souhaite récupérer la liste des séries

en tant que contributeur, je souhaite ajouter une série

In progress 🤸

en tant que visiteur, je souhaite afficher les séries par catégories

Doing 🏗️

mise en place du param converter

Done ✅

mise en place de la relation bidirectionnelle

en tant que visiteur, je souhaite visualiser la fiche d'une série

création de la méthode show dans le contrôleur CategoryController

Le param converter est une fonctionnalité très pratique de Symfony, qui te permet de convertir directement des paramètres passés à travers une route en objets.

Sommaire

Le principe du param converter

Soit une méthode show() avec un attribut de route, permettant de récupérer une série, par exemple :

php
#[Route('/program/{id}/', name: 'program_show')]
public function show(int $id, ProgramRepository $programRepository): Response
{
  $program = $programRepository->find($id);
  return $this->render('program/show.html.twig', ['program' => $program]);
}
  1. Tu récupères un identifiant unique de Program, l'id,
  2. Tu passes ce paramètre issu de ta route en paramètre à ta méthode du controller.
  3. La variable $id est utilisée pour récupérer le Program avec l'id correspondant, via la méthode find() de ProgramRepository.
Info

Pour rappel : la méthode find() est l'équivalent de findOneById().

Tu es donc passé d'un paramètre de route à un objet $program. C'est là que le param converter peut te faire gagner du temps et des lignes de code ! C'est très simple à utiliser, car ce mécanisme est activé par défaut dans Symfony.

👀 Regarde le code ci-dessous :

php
#[Route('/program/{id}/', name: 'program_show')]
public function show(Program $program): Response
{
  return $this->render('program.html.twig', ['program'=>$program]);
}

Et voilà ! Tu obtiens directement l'objet Program qui correspond à l'id saisi dans ta route. Que s'est-il passé ?

Tu vois que le paramètre de la méthode est directement $program. Ce qui est important ici, ce n'est pas son nom, mais son type : Program.

Tu as typé le paramètre pour lui dire que tu voulais un objet Program, mais tu as entré un integer correspondant à l'id.

Il y a donc eu une conversion automatique de ton paramètre ! Le param converter n'est donc rien de plus !

Si tu indiques que tu souhaites un objet de type Program, il va automatiquement effectuer la requête find() du premier exemple.

Attention

Attention, cependant ! Pour que cela fonctionne, il faut que ton paramètre (ici {id}) corresponde à une propriété de ton entité et qu'il s'agisse d'un champ unique (c’est le cas ici, puisque le champ id est une primary key) ! Il s'agit bien du nom de la propriété de l'entité et non pas du nom du champ en base de données (bien que parfois identique).

Info

Note : lorsque tu as besoin de faire appel à ta route depuis Twig, par exemple, il faut bien que tu utilises le paramètre "id", tel qu'il est défini dans l'attribut #[Route()], et non appeler ton paramètre "program". <a href="{{ path('program_show', {'id': 1 }) }}">...</a>

↗
Documentation officielle

Concentre-toi sur le début. Note également que l'attribut #[ParamConverter] peut être omis pour les cas les plus simples, comme ceux évoqués ci-dessus.

symfony.com
↗
Un peu de code

... qui démontre l'utilisation du param converter.

symfonycasts.com

Utilisation avancée

Dans certains cas, depuis une route, tu as besoin de récupérer des informations de plusieurs entités, mais tu ne peux pas avoir deux fois le même paramètre. Imaginons que l'on souhaite afficher la critique d'une série par exemple. Dans ce cas, la route #[Route("/program/{id}/comment/{id}")] ne serait pas valide.

Comment faire alors pour éviter les ambiguïtés ? Car le param converter doit distinguer le paramètre correspondant à la propriété id de l'entité Program, de celle correspondant à l’id de la présupposée entité Comment.

Il faut alors tout simplement utiliser des noms de paramètres différents, par exemple :

Solution 1 : Utiliser un nom de paramètre identique au nom de l'entité

php
#[Route("/program/{program}/comment/{comment}", name:"program_show_comment")]
public function showProgramComment(Program $program, Comment $comment): Response
{
  return $this->render('comment.html.twig', [
    'program' => $program,
    'comment' => $comment,
  ]);
}

Lorsque le param converter rencontre un paramètre portant le même nom que l'entité, il cherchera alors à utiliser l'id pour faire la conversion. Cela permet alors de lever l'ambiguïté.

Info

Au niveau de l'appel de la route (dans Twig par exemple), il faudra alors bien spécifier les paramètres 'program' et 'comment' et non pas 'id'. Ex: <a href="{{ path("program_show_comment", {"program": 1, "comment": 2 })}}">...</a>

Solution 2 : Mapper manuellement le paramètre à la propriété de l'entité

php
#[Route("/program/{program_id}/comment/{comment_id}", name:"program_show_comment")]
public function showProgramComment(Program $program, Comment $comment): Response
{
  return $this->render('comment.html.twig', [
    'program' => $program,
    'comment' => $comment,
  ]);
}

❌ ne fonctionne pas

Ici les paramètres ont un nom différent de l'entité. Ça ne peut pas fonctionner, puisque l'entité Program ne contient pas de propriété $program_id et Comment de propriété $comment_id. Il faut alors ajouter un attribut devant les paramètres cette fois (oui c'est possible 😎) #[MapEntity()] qui va permettre d'indiquer correctement le lien entre paramètres et propriétés d'entité. Attention à bien ajouter le use Symfony\Bridge\Doctrine\Attribute\MapEntity; en début de fichier.

On obtient alors :

php
#[Route('/program/{program_id}/comment/{comment_id}', name: 'program_show_comment')]
public function showProgramComment(
    #[MapEntity(mapping: ['program_id' => 'id'])] Program $program, 
    #[MapEntity(mapping: ['comment_id' => 'id'])] Comment $comment
): Response {
  return $this->render('comment.html.twig', [
    'program' => $program,
    'comment' => $comment,
  ]);
}

✅ correct

👀 Dans l'exemple ci-dessus, on indique que le paramètre program_id doit être considéré comme correspondant à la propriété $id de l'entité Program et que le paramètre comment_id doit être considéré comme correspondant à la propriété $id de l'entité Comment.

Info

Au niveau de l'appel de la route (dans Twig par exemple), il faudra alors bien spécifier les paramètres 'program_id' et 'comment_id' et non pas 'id'. Ex: <a href="{{ path("program_show_comment", {"program_id": 1, "comment_id": 2 })}}">...</a>

Il existe de nombreuses autres options que tu peux découvrir dans la documentation pour faire des choses encore plus complexes, mais cela dépasse le cadre de cette quête.

Date converter

Le terme de param converter est souvent utilisé pour les Doctrine converters, c'est-à-dire transformer un paramètre de route en entité Doctrine. Cependant, ils peuvent servir à d'autres conversions paramètre > objet. Un exemple concret est le Date Converter qui transforme un paramètre au format "date" automatiquement en un objet Datetime.

php
#[Route('/wild/historic/{start}')]
public function historic (\DateTime $start): Response
{
  // si {start} est au format 'YYYY-mm-dd', $start est converti en un objet \DateTime
  // par exemple : /wild/historic/2025-09-18
}

Ici, si {start} est au format date par défaut (YYYY-mm-dd, mais des options supplémentaires permettent d'ajuster ce comportement), alors le Date Converter fait son travail et la chaîne de caractères est convertie automatiquement en objet \Datetime, car le paramètre $start de la fonction historic() est typé en ce sens.

Info

Remarque : il est également possible de développer ses propres custom converters pour des usages plus avancés.

↗
DateTime Converter

plus d'infos sur les autres types de converters.

symfony.com
↗
Les bonnes pratiques d'utilisation

en fonction des cas.

symfony.com
↗
Suite et fin de la documentation officielle

listant toutes les options plus ou moins complexes des param converters.

symfony.com

💪 Challenge

Utilise un param converter

Pour ton projet Wild Séries, reprends ta classe ProgramController.

  1. Modifie la méthode show()(route = "program_show") pour récupérer l'objet Program directement depuis les paramètres de la méthode grâce au param converter (modifie le typage de ton paramètre).
  2. Modifie la méthode showSeason()(route = "program_season_show") pour récupérer les objets Program et Season directement depuis les paramètres de la méthode grâce au param converter (modifie le typage de tes paramètres).
  3. Crée une méthode showEpisode(Program $program, Season $season, Episode $episode)
    • La route de cette méthode sera donc de la forme /program/{programId}/season/{seasonId}/episode/{episodeId} et le nom de la route sera program_episode_show
    • Récupère les objets Program, Season et Episode directement depuis les paramètres de la méthode grâce au param converter
    • Cette méthode retournera une nouvelle vue : templates/program/episode_show.html.twig. Cette vue affichera :
      • le nom de la série
      • le numéro de la saison
      • le numéro et le titre de l'épisode
      • le résumé de l'épisode
  4. Sur la page de détail d'une saison, ajoute un lien sur chaque épisode afin de pouvoir accéder à sa fiche.

Critères de validation

  • Dans ProgramController, la méthode show() permet de récupérer l'objet program via le param converter, à partir de l’id en paramètre de la route
  • Dans ProgramController, la méthode showSeason() permet de récupérer les objets program et season via le param converter, à partir de l’id en paramètre de la route
  • Dans ProgramController, la méthode showEpisode() permet de récupérer les objets program, season et episode via le param converter, à partir de l’id en paramètre de la route
  • La méthode showEpisode() rend une vue affichant le nom de la série, la saison, ainsi que les informations de l'épisode.
  • Le code est disponible sur un repository GitHub, avec une branche correspondant à cette quête.