Il y a quelques mois j’étais tombé sur ce router ultra léger, et je m’en suis servi pour quelques tests. Aujourd’hui je retombe dessus, et l’idée me vient de partager avec vous ce bout de code, mais surtout comment le faire évoluer.

Petit rappel

Pour mémoire, un Router est un code qui va prendre la dernière partie de l’URL (appelée URI) et la décomposer, afin de déterminer quel code exécuter, contrôleur à appeler etc.

Router light, trop light

Partons avec le code d’origine. Pour les plus attentifs, vous remarquerez que j’ai modifié 2 ou 3 trucs (notamment les délimiteurs dans le preg_match) mais rien d’important :

Code de l’application :

Et donc à l’URL http://exemple.com/blog/php/27, vous devriez voir apparaître : php:27

Jusqu’ici rien de compliqué.Si vous vous demandez d’où je sors les \w+ , je vous conseille de faire un tour du coté des Regex.

Mais il y a déjà un problème : Si mon site se trouve dans un sous-dossier, le router ne fonctionne plus.

La classe URI

Si notre Router ne fonctionne plus, c’est en fait lié à la REQUEST_URI, qui contient tous les arguments d’une URI, y compris les sous dossiers et noms de fichiers.

Dans mon cas, mon fichier se trouve à l’adresse http://localhost/tests/router.php. Si j’essaye d’accéder à l’adresse http://localhost/tests/router.php/blog/ok/555, la variable $_SERVER['REQUEST_URI']  me donne /tests/router.php/blog/ok/555. Or, la seule partie qui m’intéresse est blog/ok/555.
Nous allons donc créer une classe URI, chargée de récupérer la REQUEST_URI et de la préparer pour notre classe Router.

Un peu de bonnes pratiques

Pour commencer, nous allons créer une interface afin de définir le contrat que devra remplir notre classe :

Oui, c’est tout. Cette classe a pour seul but de nettoyer l’ URI de ses dossiers et nom de fichier.

Code de la classe

Implémentons maintenant notre classe :

Testons cette classe immédiatement, toujours sur la même URL :

Notre classe rempli bien le rôle que nous lui avions fixé.

Nous allons maintenant modifier notre Router afin qu’il accepte et utilise notre classe URI.

Classe Router, seconde partie

Afin d’implémenter la classe URI dans notre Router, nous allons y faire quelques modifications.

L’interface

Comme tout à l’heure, nous allons définir l’interface du router :

Rien de bien compliqué encore une fois, si ce n’est la fonction __construct, qui oblige à fournir une instance d’une classe implémentant l’interface URIInterface. Si vous n’êtes pas à l’aise avec ce procédé, jetez un œil au type-hinting 😉

Nouveau router

Sans plus tarder, voilà le code :

Pour plus de clarté, je vous ai surligné les lignes qui ont été modifiées. Vous devriez vous en sortir avec les commentaires.

Nouveau test

Passons immédiatement au test de notre router. Pour info, je teste avec l’URL http://localhost/tests/router.php/blog/ok/555

C’est pas génial tout ça ?

A vous la suite

Voici quelques éléments qui vous permettront d’améliorer votre router, si vous en avez besoin.

Un .htaccess

Ajouter un fichier à la racine de votre site vous permettra par exemple de rediriger toutes les requêtes vers un fichier unique, celui qui lancera le router, au hasard 😉 :

Avec ce code, nous allons rediriger toutes les requêtes qui ne pointent pas vers index.php, robots.txt ou le dossier assets (vous pourrez y mettre les images, css, ..) vers le fichier index.php situé à la racine du site.

GET et POST

En ajoutant 2 fonctions à votre Router ( ex : get() et post() ) et en utilisant $_SERVER['REQUEST_METHOD']  vous serez en mesure de modifier simplement le routage de votre application selon la méthode de la requête (GET et POST).

Ainsi, pour 2 URL identiques, vous pourrez appeler 2 fonctions ou controllers totalement différents.

404

Et si aucun masque (pattern) ne correspond à l’URL entrée ?
En plaçant un code après le  foreach  de la méthode run() , vous serez en mesure d’appeler une fonction si aucun masque ne correspond.

Pour conclure

Nous avons vu qu’il était facile de créer un Router simple, évolutif et qui fonctionne dans la plupart des cas. Il pourra être réutilisé dans de petits projets, ce qui nous évitera de mettre en place un micro-framework et de n’utiliser que la fonction de routage.

Bien entendu, je vous conseille de mettre en place quelques tests afin de le fiabiliser avant de passer tout ça en prod 😉

Si vous avez des remarques ou des idées d’améliorations simples, je suis tout ouï !