URL Rewriting souple : les routes de CakePHP

CakePHP offre une réelle souplesse dans la gestion de l’URL Rewriting à condition d’utiliser des « routes » et de toujours définir les liens de la même façon.

Imaginons un catalogue de produits : nous créons une table « references », un Modèle « Reference » et un Contrôleur « ReferencesController ». Ce Contrôleur contient l’action « voir » qui prend en paramètre l’id d’une référence et affiche la fiche produit. L’url pour accéder à la fiche produit dont l’id est 5 : /references/voir/5.

Dans une Vue, par exemple la liste des produits, nous avons :

1
2
3
4
5
6
7
8
9
foreach($references as $reference)
{
  e(
    $html->link(
      $reference['Reference']['nom'],
      '/references/voir/'.$reference['Reference']['id']
    )
  );
}

Nous aimerions une url plus élégante, par exemple : /produit/5. Or il n’existe pas de Contrôleur « ProduitsController », et il n’y a apparemment pas d’action définie. Nous définissons alors une « route » dans le fichier /config/routes.php :

1
2
3
4
5
6
7
Router::connect(
  '/produit/*',
  array(
    'controller' => 'references',
    'action' => 'voir'
  )
);

Ainsi, toute url commençant par « produit/ » sera renvoyée sur l’action « voir » du Contrôleur ReferencesController, avec l’id en paramètre.

Nous changeons la vue qui liste les références :

1
2
3
4
5
6
7
8
9
foreach($references as $reference)
{
  e(
    $html->link(
      $reference['Reference']['nom'],
      '/produit/'.$reference['Reference']['id']
    )
  );
}

Et nous finissons notre site en utilisant toujours ce type d’url pour pointer vers une fiche produit.

Maintenant, nous préférerions que l’url soit de la forme : /catalogue/reference/5. Nous changeons la route :

1
2
3
4
5
6
7
Router::connect(
  '/catalogue/reference/*',
  array(
    'controller' => 'references',
    'action' => 'voir'
  )
);

Mais nous devons alors changer tous les liens de nos vues qui pointent vers une fiche produit !

La solution est de toujours définir un lien en passant en paramètre à la fonction link() non pas une chaine de caratère (l’url telle que nous la voulons au final) mais un tableau associatif comme suit :

1
2
3
4
5
6
7
8
9
10
11
12
13
foreach($references as $reference)
{
  e(
    $html->link(
      $reference['Reference']['nom'],
      array(
        'controller' => 'references',
        'action' => 'voir',
        $reference['Reference']['id']
      )
    )
  );
}

De cette façon, l’url affichée dans le lien en sortie reflètera toujours la route définie dans routes.php, quelle qu’elle soit.

Pierre-Emmanuel Fringant

Articles connexes

Commentaires

Salut! Merci pour ces explications, mais je ne pige pas le dernier point :s

Avec Router::connect on peut à partir d’une url donnée appelée le controller qu’on veut.

Mais l’inverse, à partir de /controller/action avoir l’url visuelle que je veux ne marche pas chez moi.

En utilisant link(array(controller=>xControl, action=>yAction)), le lien html créé pointe toujours sur /xControl/yAction.

Donc on est obligé de changer le controller cible dans la partie view, non ? Et ensuite de masquer son url par une url plus sympathique.

Curieux de savoir comment tu t’y es pris… Merci, ciao !

Bonjour.

Merci pour cet article.

Une chose tout de même: Si vous avez plusieurs pages de produits, vous utilisez donc la pagination pour faire suivant/precedent avec ce genre de ligne: next(__(‘next’, true).’ >’, $options = array(), null, array(‘class’=>’disabled’)); ?>

Votre deuxième page aura pour lien l’ancienne forme non routé. Vous avez une idée pour remédier à cela?

merci

@Foob : c’est pourtant bien le principe… Peux-tu montrer ton code ?

@sophie99 : les liens de la pagination sont faits comme les autres. Si, une fois sur la page 2, le lien vers la première page n’est pas correct, c’est que ta route n’est pas bonne.

Participez

Pour insérer une portion de code, utilisez <pre lang="php">...</pre>