Routes par attributs
Ce tutoriel vous montre comment simplifier la création de routes. Vous allez ainsi utiliser le même système que les professionnels du Web qui utilisent Symfony.
Plutôt que d’ajouter toutes les routes dans la fonction traiterRequete de la classe
RouteurURL, on aimerait plutôt pouvoir définir chaque route au-dessus de l’action
qui doit être déclenchée par la route. Cela est possible en utilisant le mécanisme
d’attributs (qui vient de PHP) qui permet de configurer certaines méta-données au-dessus
de méthodes, de classes, etc.
L’objectif est d’arriver à quelque-chose comme l’exemple suivant :
class MonControleur extends ControleurGenerique
{
#[Route(path: '/exemple', name:'routeExemple', methods:["GET"])]
public static function monAction(): Response {
// ...
}
}
Ici, on définit une route nommée routeExemple, qui a pour chemin /exemple et qui est
seulement accessible via la méthode GET. L’action déclenchée par cette route est la
méthode placée sous l’attribut : monAction.
Pour faire fonctionner cela dans notre framework maison, il faut suivre quelques étapes.
-
On commence par rajouter un paquet
composer require symfony/config -
Puis on rajoute une classe
AttributeRouteControllerLoaderdanssrc/Lib:// src/Lib/AttributeRouteControllerLoader.php <?php namespace TheFeed\Lib; use Symfony\Component\Routing\Loader\AttributeClassLoader; use Symfony\Component\Routing\Route; class AttributeRouteControllerLoader extends AttributeClassLoader { /** * Configures the _controller default parameter of a given Route instance. */ protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, object $annot): void { $route->setDefault('_controller', $class->getName().'::'.$method->getName()); } }Cette classe va nous permettre de traiter un attribut définissant une route afin d’enregistrer ses informations dans la liste des routes (notamment le contrôleur et la méthode à appeler…).
-
Enfin, dans
RouteurURL.php, on remplace toute la création des routes danstraiterRequetepar :use Symfony\Component\Config\FileLocator; use Symfony\Component\Routing\Loader\AttributeDirectoryLoader; use TheFeed\Lib\AttributeRouteControllerLoader; $fileLocator = new FileLocator(__DIR__); $attrClassLoader = new AttributeRouteControllerLoader(); $routes = (new AttributeDirectoryLoader($fileLocator, $attrClassLoader))->load(__DIR__);Les trois lignes ajoutées permettent de :
- Initialiser un
FileLocatorqui permet de préciser dans quel répertoire chercher les classes avec des attributs. La valeur__DIR__représente le dossier courant (doncControleur). - Initialiser notre service
AttributeRouteControllerLoadercréé plus tôt, qui permet de créer une route à partir d’un attribut. - Enfin, on explore tous les contrôleurs à la recherche d’attributs qui définissent des routes et on ajoute les routes correspondantes dans la collection.
- Initialiser un
-
Les routes se créent maintenant avec la syntaxe simplifiée suivante :
use Symfony\Component\Routing\Attribute\Route; class ControleurPublication extends ControleurGenerique { #[Route(path: '/publications', name:'afficherListe', methods:["GET"])] public static function afficherListe(): Response { // ... } }On retrouve le
path, le nom de la route (pour les appels à$generateurURL->generate()) et les méthodes autorisées.Le tableau qui associait
_controllerà"\TheFeed\Controleur\ControleurUtilisateur::afficherListe"sera rajouté par la méthode ci-dessusAttributeRouteControllerLoader::configureRoute, qui elle-même sera appelée dans le mécanisme deAttributeDirectoryLoaderde Symfony.