Bonjour,

Je débute sous Symfony et j'ai un petit souci avec les routes dynamiques.
Malgré le fait que je me base bien sur la documentation (et malgré recherche sur le net évidement...), le framework ne parviens pas à traiter la route "app_lucky_word" que j'ai définie dans mon fichier "\config\routes.yaml" et me renvoi une 404 si j'appel le chemin, avec ou sans paramètre supplémentaire.

Contenu du fichier "\config\routes.yaml" :

#index:
#    path: /
#    controller: App\Controller\DefaultController::index
# the "app_lucky_number" route name is not important yet

app_lucky_number:
    path: /lucky/number
    controller: App\Controller\LuckyController::number

app_lucky_word:
    path: /lucky/word/{tag}
    controller: App\Controller\LuckyController::word
    requirements:
        tag: '[a-z]'

app_lucky_country:
    path: /lucky/country
    controller: App\Controller\LuckyController::country

Contenu du fichier "\src\Controller\LuckyController.php" :

<?php

// src/Controller/LuckyController.php
namespace App\Controller;

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

class LuckyController extends AbstractController {

    private array $words = ['fr' => ['bonjour','bonsoir','au revoir'],
                            'en' => ['good morning', 'good evening', 'good bye']];

    /**
     * @Route("/lucky/number/", name="app_lucky_number")
     */
    public function number(): Response
    {
        $number = random_int(0, 100);

        return $this->render('lucky/number.html.twig', ['number' => $number]);
    }

    /**
     * @Route("/lucky/word/{tag}", name="app_lucky_word")
     */
    public function word(string $tag) : Response {

        $lang_tag = $tag;

        if(!in_array($lang_tag, $this->words)) {

            throw new Exception($lang_tag.' is not a valid lang tag');

        }

        return $this->render('lucky/word.html.twig', ['word' => $this->words[$lang_tag][rand(0, 2)]]);

    }

    /**
     * @Route("/lucky/country/", name="app_lucky_country")
     */
    public function country(): Response
    {
        $countries = ['france','usa','italie'];
        $country = $countries[random_int(0, 2)];

        return $this->render('lucky/country.html.twig', ['country' => $country]);
    }

}

Ce que je veux :

Je veux que Symfony parse la route et pointe vers la méthode "word" de la class "LuckyController".

Ce que j'obtiens :

Une belle erreur 404 avec le message "No route found for "GET http://synfony.local/lucky/word/" en en-tête.

L'exception est levée au niveau de la ligne 137 du fichier "\vendor\symfony\http-kernel\EventListener\RouterListener.php"

Par contre, c'est OK avec les routes statiques "app_lucky_country", "app_lucky_number".

Ce que j'ai déjà fait :

  • recherche dans le code de Symfony (j'ai un peu grimacé...) : je suis allé jusqu'au fichier "\vendor\symfony\routing\Matcher\Dumper\CompiledUrlMatcherTrait.php", il semblerait que ma route ne se trouve pas dans le tableau "$dynamicRoutes";
  • "php bin/console router:match /lucky/word" : me retourne [ERROR] None of the routes match the path "/lucky/word"
  • recherche sur le net (tuto, forum,...);

Franchement, je ne vois pas ce que je fais mal... ou, ce que je fais que je ne devrais pas faire... c'est surement un truc de base... mais là je vois pas...

Merci d'avance pour votre aide,

5 réponses


Gulivert
Réponse acceptée

ok, alors essaye d'enlever le requirements temporairement, je ne suis pas sur que ton expression est écrite correctement. Et regarde si ça passe.
Si toujours pas essaye déplacer la route en première position dans ton ficher yaml.

Hello,

Premier constat, tu déclares tes routes à deux endroits ! Dans le controlleur via les annotations, et également dans le fichier yaml. Il ne faut pas faire les deux.
Choisit la manière dans laquelle tu es le plus allaise.
Pour ma part je préfère déclarer les routes via annotations dans les controlleurs, c'est un choix purement personel, il n'y a pas un meiilleur choix que l'autre.

Autre chose, dans la route app_lucky_word, sur l'annotation tu n'as pas mis le "requirment" pour le paramêtre alors que tu le mets dans le fichier yaml.

Mis à part ça à première vu tout semble correct.

Pour déboguer que te donnes :
php bin/console --env=dev debug:router

Rien à voir, mais juste queslques constatations. Dans cette même route, tu mets en paramêtre tag la lang, et tu déclares un tableau avec une phrase, je constate 4 choses ici

  • Le tableau je le déclarerais avec une constante dans ce cas, et je l'appelerait avec self::words
  • Le tag déclaré ici semble correspondre à une locale, du coup j'utiliserais le paramêtre "_locale" dans la route si c'est bien ce que tu souhaites faire
  • Le tableau correspond à des traductions, symfony à un translator qui fait ça très bien en utilisant le TranslatorInterface ainsi que les fichiers messages.fr.yml, messages.en.yml etc...
  • Tu retournes une Exception code 500 pour le tag non trouvé, je retournerais plutôt un code 400 BadRequestHttpException, ou 404 NotFoundHttpException, une erreur 500 ne devrait pas être utilisé pour une mauvaise requête utilisateur mais uniquement pour un problème serveur

URL avec la locale en param : https://symfony.com/doc/current/translation/locale.html#the-locale-and-the-url

Paramêtre requis : https://symfony.com/doc/current/routing.html#parameters-validation

Translator : https://symfony.com/doc/current/translation.html

Hello Gulivert,

Désolé, je ne l'ai pas précisé mais j'avais déjà essayé de retirer les annotations au niveau de la méthode "word()".

Je viens de refaire un essai en retirant toutes notions d'annotation présentes dans mon controleur, les commentaires + le "use Symfony\Component\Routing\Annotation\Route"
J'ai malheureusement toujours le même problème...

La commande php bin/console --env=dev debug:router affiche bien la liste des Routes.

Personnelement, je prefere regrouper mes routes dans un fichier "à part", c'est ce que je fait dans les autres framework que j'utilise, donc je vais garder mes habitudes.

Concernant la qualité du code, je suis en mode brouillon, c'est code de "remplissage" qui ne correspond pas à un fonctionnel définitif.
Je note tes remarques concernant le Translator et l'Exception (j'en suis au niveau 0.2 de mon apprentissage de Symfony...).

re

Bon c'est bon j'ai trouvé en refaisant un php bin/console router:match sur ma Route app_lucky_word.

Le problème venait du paramétrage du "requirements" dans le fichier Yaml, apparement l'expression régulière ne convient pas... bref je l'ai retiré et ça fonctionne (je ferai le contrôle des paramètres moi-même à l'intérieur de la méthode...).

Au passage, il y a une autre coquille dans le code, au niveau de la ligne if(!in_array($lang_tag, $this->words)) {, je fais un "in_array" au lieu d'un "array_key_exists" ^^

Encore merci pour tes infos et bon dimanche.

Pas de problème et bien joué :)
Pour l'expression je pense qu'elle devrait être :

    requirements:
        tag: '\[a-z\]'