Bonjour à vous,

J'suis entrain de développer une application en ce moment, pour des besoins SEO, j'me suis dis de faire en sorte que les url de mes pages contiennent l'id et le slug. Exemple : monapp.com/45-titre-de-ma-page. Dans ce cas je pourrais toujours trouver l'entrée avec son id (vu que ça change pas) même si le titre arrive à changer (slug).

J'utilise Gedmo de stof/doctrine-extensions-bundle pour la génération de mon slug, après la méthode suivante dans mon entité pour intégrer l'id dans le slug :

/**
 * @ORM\PostPersist
 */
public function updateSlug(EventLifecycleEventArgs $args)
{
    $this->setSlug($this->getId(). '-' . $this->getSlug());

    $args->getObjectManager()->flush();
}

Pour récupérer l'entrée j'utilise la méthode suivante dans mon controller :

/**
 * @Route("/{slug}", name="category_show", methods={"GET"})
 */
public function show(CategoryRepository $categoryRepository, $slug): Response
{
    $id = (int) explode('-', $slug, 2)[0];
    return $this->render('category/show.html.twig', [
        'category' => $categoryRepository->find()
    ]);
}

Le fonctionnement escompté marche, sauf que si par exemple monapp.com/45-titre-de-ma-page je mets monapp.com/45-titre-de-ma-page-autre-chose ça passe toujours.

Je trouve pas trop User friendly l'url du coup, ce serait mieux si l'url machait avec le titre

Donc je voudrais savoir s'il y'a une autre démarche plus robuste (je pose déjà des questions de performance de mon app) d'intégrer ce fonctionnement à mon app ?

Merci d'avance à vous 🙏🙏.

11 réponses


lhapaipai
Réponse acceptée

oups je suis allé un peu vite...

/**
 * @Route("/category/{id}-{slug}", name="category_show", requirements={"id"="\d+"})
 */
public function show(CategoryRepository $categoryRepository, $slug, $id): Response
{

    $category = $categoryRepository->find($id);
    if($category->getSlug() !== $slug) {
        return $this->redirectToRoute('category_show', [
            'id' => $id,
            'slug' => $category->getSlug()
        ]);
    }
    return $this->render('category/show.html.twig', [
        'category' => $category
    ]);
}

il n'y a pas plus de requêtes db du coup.

Salut bahahmadou94,
peut-être que tu peux vérifier si le permalien correspond et faire une redirection vers la bonne url si n'est pas le cas.
du genre

/**
 * @Route("/category/{id}-{slug}", name="category_show", requirements={"id"="\d+"})
 */
public function show(CategoryRepository $categoryRepository, $slug, $id): Response
{

    $category = $categoryRepository->find($id);
    if($category->getSlug() !== $slug) {
        $this->redirectToRoute('category_show', [
            'id' => $id,
            'slug' => $slug
        ]);
    }
    return $this->render('category/show.html.twig', [
        'category' => $categoryRepository->find()
    ]);
}

Bonjour bahahmadou94.
Si tu est déjà sous la v5 , symfony as un composant qui permet de gérer les slugs : https://symfony.com/doc/current/components/string.html#slugger.

Tu as un bonne exemple à cette adresse , qui ce génère au niveau de ton entité : https://symfony.com/doc/current/the-fast-track/fr/13-lifecycle.html#generating-slugs

Tu pourras par exemple enregistrer ton slug en faisant ce bout de code :

$this->slug = (string) $slugger->slug((string) $this->Id() . ' ' . $this->getTitle())->lower();

Ensuite dans t'as route en passant un param {slug} , il connaîtra automatiquement à la ligne qui correspond en BD.
Par contre faut faire gaffe que ça soit unique, mais comme tu concatène avec l'ID y'aura pas de soucis.
NB : Les ' ' sera remplacer automatiquement par des -

Bonjour OcB974, merci pour le tuyau. J'y jeterai un coup d'oeil.

Bonjour lhapaipai, ta méthode fait pareil que la mienne.
Je viens de tester, ça affiche toujours la catégorie, mais le lien reste invalide (j'veux dire pour une url monapp.com/4-titre-categorie, les liens suivants passent aussi : monapp.com/4-titre-categorie-autre, monapp.com/4-65-titre-categorie ) et j'en passe.
En plus à vue d'oeil, ta méthode fait appel à la BD 3 fois de suite.

Dans mon template voici comment je génère ducoup le lien :

<a href="{{ path('category_show', {'slug': category.slug, 'id': category.id}) }}">show</a>

Est-ce exact ??

Dans l'url je vois l'id répété : Exemple pour une url monapp.com/categorie/26-sport ça rédirige vers monapp.com/categorie/26-26-sport.

Une idée ?

tu as écrit

$this->slug = (string) $slugger->slug((string) $this->Id() . ' ' . $this->getTitle())->lower();

du coup ton lien contiens déjà ton id concaténé : id -> 26, slug -> 26-sport

$this->slug = (string) $slugger->slug($this->getTitle())->lower();

de cette manière : id -> 26, slug -> sport

Oui j'suis allé un peu à la hâte.
C'était bien le cas, l'id se trouvait déjà dans mon slug.
Maintenant j'ai plus bésoin cette méthone là :

/**
 * @ORM\PostPersist
 */
public function updateSlug(EventLifecycleEventArgs $args)
{
    $this->setSlug($this->getId(). '-' . $this->getSlug());

    $args->getObjectManager()->flush();
}

Merci beaucoup 🙏🙏🙏

de rien cool que tu aies résolu ton problème !

Bonjour lhapaipai, désolé de revenir 🤭. Ce matin j'étais entrain de faire mes tests et j'me suis rendu compte que la méthode donne une erreur au cas où il trouvait pas l'id de la categorie.

$category = $categoryRepository->find($id);
if($category->getSlug() !== $slug)
{
    return $this->redirectToRoute('category_show', [
        'id' => $id,
        'slug' => $category->getSlug()
    ]);
}

Sur la ligne de la condition car catégorie n'existe pas dans ce cas : Call to a member function getSlug() on null, une idée ??

Merci d'avance.

Bonsoir.
Tu pourrais par exemple commencer par vérifier que tu récupères bien un enregistrement avant de faire ta condition sur le slug.
Si ce n'est pas le cas, tu pourrais par exemple rediriger l'utilisateur avec un message vers une autre page.