Nous allons voir comment créer un système de routing en PHP basique. Si vous avez appris Symfony, vous connaissez déjà le fonctionnement et l’intérêt des routes.

1) – Qu’est-ce qu’une route :
Une route possède un nom (un identifiant en quelque sorte…), une URL et un template à inclure (ou dans Symfony, une action pour être précis). Au lieu d’écrire vos liens en dur en HTML (ex: <a href= »/contact.html »>Exemple</a>), vous appelez une route (par exemple, de la forme: <a href= »<?php echo url_for(‘contact’); ?> »>Exemple</a>), et cela affichera l’URL de cette dernière.
En écrivant: <a href= »<?php echo url_for( Nom_De_La_Route); ?> »>Exemple</a>, notre système sera capable de chercher l’URL correspondant au nom de la route, et cela ressortira donc
du code: <a href= »/Url_De_La_Route »>Exemple</a>.
De plus, lorsque quelqu’un accède à une page de notre site, notre système devra être capable de retrouver à quelle route correspond l’URL « /Url_De_La_Route » et d’afficher son template correspondant.
Dans tout bon projet web qui se respecte, on déclare toutes nos routes dans un fichier dédié, histoire que cela ne devienne pas trop le bordel, et qu’on sache où modifier nos routes !
Moi je l’appelerai routing.php.
2) – Intérêt des routes
Lorsque vous voulez modifier l’URL de tous les liens de votre projet qui mène à la page « contact » (pour une raison de référencement par exemple !), vous avez juste à modifier l’URL de la route « contact » dans votre fichier routing.php, opération durant 2 secondes… A l’inverse, si vos liens étaient écris en HTML directement, vous auriez du modifier chaque lien dans vos pages HTML, pas du tout pratique !
De même, lorsque vous voulez modifier vers quel template mène une route, vous changez directement dans le routing !
Enfin, on rajoute une petite couche « controleur » au projet (voir modèle MVC).
3) – Structure de notre projet
Dans mon exemple, je vais faire une structure basique, le but étant plus de comprendre et de créer un framework de routing qu’un framework entier pour notre projet ^^
J’ai divisé mon projet en 3 répertoires principaux: lib où se trouve le « moteur » du framework et les class, templates où l’on met les fichiers de chaque page du site à inclure dans notre template principal (alias layout: notre fichier contrôleur index.php), enfin, web qui contient notre fichier de contrôle index.php qui sera dans cet exemple aussi notre layout principal.
Comme prérequis, nous devons pointer le fichier VHost de notre serveur vers le répertoire web de notre projet, où se trouve notre fichier de contrôle, ainsi les visiteurs ne pourront qu’avoir accès au contenu dans le répertoire web, et non dans des pages où ils n’ont rien à faire (comme les fichiers des class !):
Sur le serveur: /etc/apache2/sites-enabled:
<VirtualHost *:80>
ServerName monsite.com
DocumentRoot /home/sybio/www/monprojet/web/
<Directory /home/sybio/www/monprojet/web/>
Options -Indexes FollowSymLinks MultiViews
AllowOverride All
</Directory>
</VirtualHost>
Si vous n’avez pas accès aux VHost sur votre serveur, vous pouvez toujours enlever le répertoire web et mettre son contenu à la racine de votre projet !
4) – Fichier .htaccess et méthode GET
Notre système doit en effet reconnaître la correspondance de chaque URL avec une route. La première chose à faire va être de dire récupérer chaque URL comme si c’était une méthode GET, pour tester leur valeur.
Imaginons que l’on veut que tout ce qui se trouve après www.monsite.com/ soit considéré comme le contenu de la variable $_GET['page'], nous allons créer un .htaccess à mettre dans le répertoire web:
web/.htaccess:
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule ^index\.html$ index.php?page=/ RewriteRule ^([a-zA-Z0-9-]*\.html)$ index.php?page=$1 </IfModule>
5) – Class « RoutingFramework »
C’est la class de notre framework de routing, on initialisera un objet de cette class pour faire tourner le moteur du site. La création de routes, les vérifications etc… devront se faire grâce à cette dernière.
lib/Framework.class.php:
<?php /** * Class RoutingFramework du projet */ class RoutingFramework { private $routes = array(); // un tableau contenant toutes les données de chaque route private $routesName = array(); // un tableau ayant le nom de la route comme clef, qui a comme valeur l'id de la route private $routesPath = array(); // un tableau ayant le chemin (URL)) de la route comme clef, qui a comme valeur l'id de la route private $routesTemplate = array(); // un tableau ayant le template de la route comme clef, qui a comme valeur l'id de la route private $idRoutes = 0; // compteur de routes private $routeIndexName; // Nom de la route de la page d'accueil private $routeIndexPath; // Chemin de la route de la page d'accueil private $routeIndexTemplate; // Template de la route de la page d'accueil private $error404 = false; // Booléen pour déclarer une URL comme erreur 404 /** * Méthode pour déclarer une route **/ public function initRoute ($routeName, $urlPath, $template) { // On remplit les attributs de la class par des tableaux associatifs qui correspondent à l'id d'une route $this->routesName[$routeName] = $this->idRoutes; $this->routesPath[$urlPath] = $this->idRoutes; $this->routesTemplate[$template] = $this->idRoutes; // On remplit un tableau qui à comme clef l'id de la route et comme valeurs les données de la route $this->routes[$this->idRoutes] = array("name" => $routeName, "path" => $urlPath, "template" => $template); // Le nombre de routes augmente, on met à jour notre id $this->idRoutes++; } /** * Retourne l'URL du nom de la route en paramètre **/ public function urlFor ($routeName) { // Si la route existe, on retourne son URL if (array_key_exists($routeName, $this->routesName)) { return "/".$this->routes[$this->routesName[$routeName]]["path"]; } elseif ($routeName == $this->routeIndexName) // Sinon, on test si la route correspond à la page d'accueil { return "/".$this->routeIndexPath; } else // Sinon, on retourne une chaîne vide { return ""; } } /** * Retourne le template associé à une URL d'une route **/ public function getTemplate ($urlPath) { // Si l'URL existe, on retourne le template associé if (array_key_exists($urlPath, $this->routesPath)) { return $this->routes[$this->routesPath[$urlPath]]["template"]; } elseif ($urlPath == null || $urlPath == "" || $urlPath == $this->routeIndexName) // Si l'URL correspond à la page d'accueil, on retourne son template { return $this->routeIndexTemplate; } else // Sinon on déclare une erreur 404 { return $this->error404 = true; } } /** * Initialise la route de la page d'accueil **/ public function initIndexRoute ($routeName, $urlPath, $template) { $this->routeIndexName = $routeName; $this->routeIndexPath = $urlPath; $this->routeIndexTemplate = $template; } /** * Retourne true si il y a une erreur 404 **/ public function isError404 () { if ($this->error404 == true) { return true; } return false; } } ?>
6) – Fichier pour initialiser le Framework
Ce fichier va nous servir à inclure nos fichiers dans les librairies, initialiser une instance de la classe FrameworkRouting et appeler ses méthodes pour générer le template à inclure. Le fichier sera lui-même inclut par notre fichier de contrôle « index.php » qui se trouve dans le répertoire « web ». Il faudra donc le prendre en compte pour les « include ». Je l’appelle init.php dans mon exemple.
lib/init.php:
<?php /** * Fichier incluant toute la librairie du projet */ // On inclut la classe de notre framework de routing include("../lib/Framework.class.php"); // On instancie notre framework de routing $fmk = new RoutingFramework(); // on inclut notre fichier qui liste nos routes include("../lib/routing.php"); if (isset($_GET["page"])) { fmkRoutingTestPage = htmlentites(trim($_GET["page"])); } else { $fmkRoutingTestPage = ""; } // test de l'existence de la route, et génération du template adéquat $fmkRoute = $fmk->getTemplate($fmkRoutingTestPage); ?>
7) – Fichier pour déclarer nos routes
On déclare nos routes ici, libre à vous de créer vos pages et d’inclure les fichiers que vous voulez !
lib/routing.php:
<?php /** * Fichier de routing: déclaration des routes ici ! */ // Déclaration de la page d'accueil $fmk->initIndexRoute("accueil", "", "../templates/accueil.php"); // Déclaration des routes (nom, url, template) $fmk->initRoute("realisations", "realisations.html", "../templates/realisations.php"); $fmk->initRoute("galerie", "galerie-de-maisons.html", "../templates/galerie.php"); $fmk->initRoute("contact", "contact.html", "../templates/contact.php"); ?>
– Layout de notre projet
Enfin, on finit (ouf !) avec notre fichier de contrôle, qui sert dans notre projet également de layout:
web/index.php:
<?php /** * Fichier de contrôle et layout du site: tout passe par ce fichier **/ include("../lib/init.php"); // On inclue le fichier qui initialise le framework if ($fmk->isError404()) // On affiche une erreur 404 si la route correspondant à l'URL n'a pas été trouvée { header("HTTP/1.0 404 Not Found"); } ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr"> <head> <title>MonSite - Exemple</title> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <link rel="shortcut icon" href="images/design/favicon.jpg" /> <link href="css/main.css" rel="stylesheet" type="text/css" media="screen" /> </head> <body> <h1 id="header">MonSite</h1> <ul id="menu"> <!-- On appel quelques routes définies dans routing.php pour nos liens du menu --> <li class="menu_ul_li"><a href="<?php echo $fmk->urlFor("accueil"); ?>">Accueil</a></li> <li class="menu_ul_li"><a href="<?php echo $fmk->urlFor("realisations"); ?>">Realisations</a></li> <li class="menu_ul_li"><a href="<?php echo $fmk->urlFor("galerie"); ?>">Galerie</a></li> <li class="menu_ul_li"><a href="<?php echo $fmk->urlFor("contact"); ?>">Contact</a></li> </ul> <div id="content"> <?php // On test si le template existe (censé être dans le dossier templates), si oui on l'inclut if (file_exists($fmkRoute)) { include($fmkRoute); } else // Sinon on affiche pour nous même qu'on a pas encore créé le template associé à la route { echo "<span style='font-style: italic;'>Erreur: Le fichier de la route demandée n'existe pas !</span>"; } ?> </div> </body> </html>
On inclut notre fichier init.php pour faire fonctionner le framework, on test l’existence du template généré dans init.php et on l’inclut s’il existe bien… sinon on affiche une erreur pour nous-même (les développeurs). Notez que l’on fait quelques liens du menu avec nos routes fraîchement implémentées
Merci pour ton article qui m’a bien aidé sur le fonctionnement des routes pour le développement de mon framework
Bonne continuation ^^
Salut !
Merci tout d’abord pour ce très bon tuto.
J’ai juste un petit soucis, je veux mes url en .php et non en .html. J’ai fais les modifs dans le routing mais il ne trouve plus les templates associés. Il doit y avoir une modif a faire, mais laquelle. Merci d’avance