Astuce Le routage dans Symfony

Cet article est une synthèse de la documentation officielle : Routing.

Généralités

Qu'est-ce qu'une route ?

C'est une configuration qui décrit comment trouver le contrôleur à exécuter pour un chemin (ou un ensemble de chemins) donné.

Pour cela, elle va décrire précisément :

  • le ou les chemins concerné(s)
  • le contrôleur cible
  • le contexte pour lequel cela doit matcher (telle IP, telle méthode HTTP, ...)

Elle peut être de différents types, Symfony gérant nativement annotation, yaml, xml et php.

Est-il possible d'avoir une route par langue pour un même contrôleur ? (ex: /about-us et /a-propos-de-nous)

Oui, en indiquant un tableau associatif pour path :

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

/**
 * @Route({
 *     "en": "/about-us",
 *     "nl": "/over-ons"
 * }, name="about_us")
 */
public function about(): Response
{
    // ...
}

Regex

Pour indiquer une regex décrivant le format attendu pour l'un des paramètres de la route, deux syntaxes sont possibles :

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

/**
 * @Route("/blog/{page}", name="blog_list", requirements={"page"="\d+"})
 */
public function list(int $page): Response
{
    // ...
}

/**
 * @Route("/blog/{slug<[a-z-]+>}", name="blog_show")
 */
public function show(string $slug): Response
{
    // ...
}

Explications :

  • La première route utilise la liste des requirements pour définir la regex du paramètre page.
  • La seconde utilise la notation abrégée indiquant la regex directement au niveau du paramètre.

Valeurs par défaut

Même chose, deux possibilités :

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

/**
 * @Route("/blog/{page}", name="blog_list", requirements={"page"="\d+"}, defaults={"page"="homepage"})
 */
public function list(int $page): Response
{
    // ...
}

/**
 * @Route("/blog/{slug<[a-z-]+>?homepage}", name="blog_show")
 */
public function show(string $slug): Response
{
    // ...
}

Notes :

  • Pour laseconde notation, s'il n'y a pas de regex, on indique la valeur par défaut juste après le paramètre (ie. "/blog/{slug?homepage}").
  • Si on ne mets rien après le ?, alors le paramètre devient optionnel

Générer des URL

La génération est fournie via la méthode generate() du service UrlGeneratorInterface.

Elle peut générer plusieurs choses selon le paramètre $referenceType qu'on lui fournit :

  • UrlGeneratorInterface::ABSOLUTE_URL : une URL absolue (ex: http://example.com/dir/file)
  • UrlGeneratorInterface::ABSOLUTE_PATH : un chemin absolu (ex: /dir/file)
  • UrlGeneratorInterface::RELATIVE_PATH : un chemin relatif au chemin de la requête courante (ex: ../parent-file)
  • UrlGeneratorInterface::NETWORK_PATH : un chemin réseau (ex: //example.com/dir/file)

Redirection systématique

Le RedirectController fourni par Symfony, permet des redirections temporaires ou permanente

  • d'un chemin donné vers un autre
  • d'un chemin vers une route donnée

Il s'utilise directement par configuration dans le routing.yaml.


Paramètres internes de routage

L'ArgumentResolver rend disponible automatiquement les attributs de la requête par injection dans l'action de contrôleur.
La variable injectée doit avoir le nom de l'attribut (commençant par un _). Ex: $_route_params, $_controller, ...

Note : On peut également les récupérer classiquement via la Request dans le bag attribute.


Conditions spécifiques

Il est possible de définir des conditions spécifiques de match pour une route.
Celles-ci sont définies par de l'expression language.

Ex :

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends AbstractController
{
    /**
     * @Route(
     *     "/contact",
     *     name="contact",
     *     condition="context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'"
     * )
     *
     * expressions can also include config parameters:
     * condition: "request.headers.get('User-Agent') matches '%app.allowed_browsers%'"
     */
    public function contact(): Response
    {
        // ...
    }
}

Commande Symfony pour le routing

Symfony fournit 2 commandes utiles pour travailler avec le routage :

  • bin/console debug:router --show-controllers : pour lister toutes les routes gérées et par quels contrôleurs
  • bin/console debug:router name_of_the_route : pour afficher la configuration complète d'une route
  • bin/console router:match /some/url [--method=GET] : pour afficher si l'URL match avec une route et si oui laquelle

Route Loader

Documentation

Pour pouvoir charger des routes provenant d'une source spécifique (ex: base de donnée, fichier .ini, ...), on peut créer un Route Loader spécifique.

Celui-ci doit étendre Symfony\Component\Config\Loader\Loader\Loader.
En surchargeant la méthode supports(), il peut gérer des types de route spécifiques.