Récupérer et afficher un élément de la base de données
Si nous souhaitons réaliser la page d'une catégorie par exemple, la première problématique va être la suivante : comment récupérer la bonne catégorie ?
Première piste - Injecter la requête dans le contrôleur
Symfony possède une classe Request que nous pouvons type-hinter dans n'importe quel contrôleur. Une fois que nous disposons d'une instance de la classe Request, nous pouvons accéder à diverses informations concernant la requête effectuée.
Par exemple, ici, nous aimerions récupérer un paramètre GET id :
#[Route('/category', name: "category_item")]
public function item(Request $request): Response
{
$id = $request->query->getInt('id');
return $this->render('category/item.html.twig', [
'id' => $id
]);
}
On utilise la propriété query, qui contient tous les paramètres GET de la requête.
Dans l'objet Request, on peut récupérer plein d'autres informations
On pourrait donc, une fois qu'on a récupéré l'ID de la catégorie qu'on souhaite afficher, injecter notre CategoryRepository dans notre contrôleur afin de récupérer l'entité en question :
#[Route('/category', name: "category_item")]
public function item(Request $request, CategoryRepository $repo): Response
{
$id = $request->query->getInt('id');
$category = $repo->find($id);
return $this->render('category/item.html.twig', [
'category' => $category
]);
}
Bien que cette solution soit valide techniquement, elle ne sera pas convenable. En effet, nous aimerions par exemple disposer d'URL mieux formées, type /category/56 au lieu de /category?id=56.
Déclarer un paramètre d'URL
Pour ce faire, nous allons commencer par modifier l'URL de notre route, dans l'annotation, pour lui ajouter un paramètre d'URL :
#[Route('/category/{id}', name: "category_item")]
public function item(CategoryRepository $repo, int $id = 0): Response
{
$category = $repo->find($id);
return $this->render('category/item.html.twig', [
'category' => $category
]);
}
Ici, nous avons ajouté dans l'annotation de route un paramètre d'URL : id.
Mais nous voyons que tout paramètre d'URL peut être mappé en tant que paramètre de notre contrôleur. Nous avons également ajouté un paramètre à notre méthode, de type int.
Nous n'avons donc plus besoin de l'objet Request pour récupérer notre ID passé en paramètre d'URL, et nous pouvons directement utiliser notre repository pour récupérer la catégorie.
Symfony nous permet donc de déclarer un paramètre d'URL et de le récupérer directement en paramètre du contrôleur. Pour notre exemple, c'est un peu mieux mais pas encore convenable. Par exemple, on ne gère pas les erreurs 404 en cas de catégorie non trouvée.
Symfony nous donne la possibilité de faire encore plus simple et plus efficace.
Solution - L'EntityValueResolver
En réalité, avec Symfony, il est possible de déclarer notre route, y intégrer un paramètre d'URL comme id, puis de type-hinter directement le type de l'entité attendue pour que l'objet correspondant soit injecté dans notre contrôleur :
#[Route('/category/{id}', name: "category_item")]
public function item(Category $category): Response
{
return $this->render('category/item.html.twig', [
'category' => $category
]);
}
Ici, que se passe-t-il concrètement ?
- Symfony est capable, avec le routeur, d'identifier le paramètre d'URL
id - A la lecture du type-hint
Category, il comprend que nous souhaitons récupérer un élément de la base de données (Categoryest une entité Doctrine...) - Il exécute donc l'EntityValueResolver, qui permet de récupérer un élément de la base de données à partir d'un paramètre d'URL
- Notre paramètre d'URL s'appelle
id: Doctrine va donc chercher uneCategoryqui a cetid(note : on aurait également pu passer un paramètre dont le nom correspond à un autre champ deCategory, c'est comme ça que ça fonctionne) - Si un enregistrement est trouvé, alors il est injecté dans le contrôleur
- Sinon, une erreur 404 est générée
Nous avons donc considérablement réduit la quantité de code nécessaire pour récupérer notre catégorie, rendu notre contrôleur plus clair, notre URL plus lisible, et nous générons à présent une erreur 404 lorsque l'enregistrement n'est pas trouvé, ce qui est plus rigoureux que le comportement précédent qui pouvait transmettre une catégorie null à notre template.
L'EntityValueResolver permet de récupérer un élément automatiquement à partir d'un paramètre d'URL, et de l'injecter automatiquement dans le contrôleur
Bien sûr, si la logique de récupération de l'élément est plus complexe, il n'est pas nécessaire d'utiliser l'EntityValueResolver. On peut tout à fait déclarer un paramètre d'URL, puis utiliser un Repository pour récupérer un enregistrement selon une certaine logique