Accueil » Tous les articles » PHP » Faire un petit MVC avec des routes
Vue aérienne d'un échangeur

Faire un petit MVC avec des routes

Pour bon nombre de petits projets, il n’est pas nécessaire de taper dans les frameworks MVC comme Zend ou Symfony qui sont très lourds et un petit truc maison doit suffire. Je vais essayer de donner quelques tuyaux pour pouvoir faire son MVC maison avec des routes qui dirigent vers les contrôleurs et les actions.

Tout d’abord, il faut créer un fichier index.php à la racine de votre site qui va contenir le lien vers tout ce dont vous avez besoin pour faire vos routes. Ensuite, vous devez créer un dossier controlleur (si vous voulez reproduire la faute de frappe de l’exemple) dans lequel vous aurez tous vos contrôleurs. Vous pouvez éventuellement diviser ce dossier en plusieurs dossiers distincts qui contiendront les différentes parties de votre site. Veillez à appeler vos classes en rapport avec vos règles de is_callable. Dans mon exemple, le chemin vers le dossier est en minuscule et la première lettre du fichier est en majuscule. Par exemple : la classe /controlleur/frontend/index.php sera frontendIndex.

La porte d’entrée du MVC

Contenu de /index.php

<?php
  /**
   * On inclue d'abord les fichiers nécessaires et on initialise la logique de routes
   */
  include("includes/routing.php");
  $fmk = new Routes();
  include("includes/routes.php");
  //Si la route est définie, on récupère la route en question
  if (isset($_GET["page"]))
  {
    $route = htmlentities(trim($_GET["page"]));
  }
  else
  {
    $route = "";
  }
  $fmkRoute = $fmk->getControlleur($route);
  if ($fmk->isError404())
  {
      header("HTTP/1.0 404 Not Found");
  }
  $controlleur = 'controlleurs/'.$fmkRoute[0];
  include($controlleur);
  $classe = preg_split('[\.|/]',$fmkRoute[0]);
  $classe = $classe[0].ucfirst($classe[1]);
  $methodVariable = array($classe, $fmkRoute[1]);

  if(is_callable($methodVariable, false, $callable_name)){
      call_user_func($methodVariable);
  }
PHP

Redirection

Ensuite, nous devons rediriger tous les appels de pages vers ce fichier index pour pouvoir traiter les routes.

RewriteEngine On <br />
RewriteBase /<br />
RewriteRule ^index\.html$ index.php?page=/<br />
RewriteRule ^([a-zA-Z0-9-]*\.html)$ index.php?page=$1 [L,QSA]
Bash

Le routage

Le fichier routing va vous permettre de créer votre interface de routage. Il se trouve chez moi dans /includes/routing.php

<?php
/**
 * Classe permettant le routing
 */
class Routes {

    /**
     * un tableau contenant toutes les données de chaque route
     * @var array 
     */
    private $routes = array();

    /**
     * un tableau ayant le nom de la route comme clef, qui a comme valeur l'id de la route
     * @var array 
     */
    private $routesName = array();

    /**
     * un tableau ayant le chemin (URL)) de la route comme clef, qui a comme valeur l'id de la route
     * @var array 
     */
    private $routesPath = array();

    /**
     * un tableau ayant le contrôleur de la route comme clef, qui a comme valeur l'id de la route
     * @var array 
     */
    private $routesControlleur = array();

    /**
     * un tableau ayant l'id de la page de la route comme clef, qui a comme valeur l'id de la route
     * @var array 
     */
    private $routesAction = array();

    /**
     * compteur de routes
     * @var integer 
     */
    private $idRoutes = 0;

    /**
     * Nom de la route de la page d'accueil
     * @var string 
     */
    private $routeIndexName;

    /**
     * Chemin de la route de la page d'accueil
     * @var string 
     */
    private $routeIndexPath;

    /**
     * Contrôleur de la route de la page d'accueil
     * @var string
     */
    private $routeIndexControlleur;

    /**
     * Action de la page d'accueil
     * @var type 
     */
    private $routeIndexAction;

    /**
     * Booléen pour déclarer une URL comme erreur 404
     * @var boolean 
     */
    private $error404 = false;

    /**
     * 
     * @param string $routeName
     * @param string $urlPath
     * @param string $controller
     * @param string $action
     */
    public function initRoute($routeName, $urlPath, $controller, $action) {
        // 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->routesControlleur[$controller] = $this->idRoutes;
        $this->routesAction[$action] = $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, "controlleur" => $controller, "action" => $action);

        // Le nombre de routes augmente, on met à jour notre id
        $this->idRoutes++;
    }

    /**
     * 
     * @param string $routeName
     * @return string
     */
    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 "";
        }
    }

    /**
     * 
     * @param string $urlPath
     * @return array|bool
     */
    public function getControlleur($urlPath) {
        // Si l'URL existe, on retourne le contrôleur et l'action associés
        if (array_key_exists($urlPath, $this->routesPath)) {
            return array($this->routes[$this->routesPath[$urlPath]]["controlleur"], $this->routes[$this->routesPath[$urlPath]]["action"]);
        } elseif ($urlPath == null || $urlPath == "" || $urlPath == $this->routeIndexName) { // Si l'URL correspond à la page d'accueil, on retourne son template
            return array($this->routeIndexControlleur, $this->routeIndexAction);
        } else { // Sinon on déclare une erreur 404
            return $this->error404 = true;
        }
    }

    /**
     * 
     * @param string $routeName
     * @param string $urlPath
     * @param string $template
     */
    public function initIndexRoute($routeName, $urlPath, $template) {
        $this->routeIndexName = $routeName;
        $this->routeIndexPath = $urlPath;
        $this->routeIndexControlleur = $template;
        $this->routeIndexAction = 'index';
    }

    /**
     * Retourne true s'il y a une erreur 404
     * @return boolean
     */
    public function isError404() {
        if ($this->error404 == true) {
            return true;
        }
        return false;
    }

}
PHP

Enfin, vous allez devoir définir les routes que vous souhaitez utiliser. Personnellement, j’ai placé ce fichier dans /includes/routes.php. Chaque ligne définit une route :

<?php
// Déclaration de la page d'accueil
$fmk->initIndexRoute("accueil", "", "frontend/accueil.php", "index");
//cette ligne crée une route les arguments sont le nom, l'adresse lisible, le chemin vers le contrôleur et l'action
$fmk->initRoute("realisations", "realisations.html", "frontend/realisations.php", "index");
PHP

Dans un prochain post, nous verrons comment créer des liens à la volée grâce à ces routes.

Besoin d’aide pour mettre cela en place ?


Publié

dans

, , , ,

par

Commentaires

  1. Avatar de Unknown

    Bonjour,

    les lignes ci-dessous doivent être placé dans quel fichier ?

    "RewriteEngine On
    RewriteBase /
    RewriteRule ^index.html$ index.php?page=/
    RewriteRule ^([a-zA-Z0-9-]*.html)$ index.php?page=$1 [L,QSA]"

  2. Avatar de Christophe Ferreboeuf

    Ces lignes doivent être placées dans un fichier .htaccess si vous utilisez apache et dans un fichier de configuration si vous utilisez nginx (elles doivent être traduites avant). N'ayant pas des connaissances étendues d'nginx, je ne pourrais pas vous aider plus.

  3. Avatar de Unknown

    Merci la rapidité de votre réponse. Je travaille actuellement en local avec Wamp. J'ai mis en place le fichier .htaccess et la redirection vers la page de connexion de mon site fonctionne. Cependant, le lien pour la page d'accueil, lui, ne fonctionne pas.

    // Déclaration de la page d'accueil
    $fmk->initIndexRoute("connexion","", "Controller/connexion.php", "index");
    //cette ligne crée une route les arguments sont le nom, l'adresse lisible, le chemin vers le contrôleur et l'action
    $fmk->initRoute("accueil", "accueil", "Controller/accueil.php", "index");

    J'utilise l'adresse suivant pour accéder à la page de connexion :
    http://localhost/EasyStage/

    Donc normalement l'adresse http://localhost/EasyStage/accueil devrait me rediriger vers la bonne page non ?

  4. Avatar de Christophe Ferreboeuf

    Il est nécessaire que vous ayez créer le controller correspondant dans votre dossier Controller. De plus, vous devez adapter votre .htaccess pour que les pages sans ".html" fonctionnent également car ce n'est pas prévu dans le .htaccess que j'ai fourni. accueil.html doit fonctionner, non ?

  5. Avatar de Unknown

    D'accord. Je n'ai aucune connaissance en .htaccess, c'est peut-être de la que vient le problème. Et pour répondre a votre question, non. Je suis redirigé vers l'accueil du serveur wamp. J'ai tenté de reprendre la ligne ci-dessous en ne modifiant que le controleur mais rien n'y fait

    $fmk->initRoute("realisations", "realisations.html", "Controller/accueil.php", "index");

  6. Avatar de Christophe Ferreboeuf

    Dans ce cas, il faut que vous modifiez le RewriteBase…

    Par exemple :
    RewriteBase /EasyStage/

    Normalement, cela devrait solutionner le problème de redirection vers la base de wamp.

  7. Avatar de Unknown

    En effet, le problème semble être solutionné.
    Merci beaucoup pour votre aide !

  8. Avatar de Unknown

    J'aurais juste une dernière requête. J'ai voulu modifié le fichier .htaccess que vous avez fourni pour prendre en compte les extensions .php plutôt que .html mais cela ne semble pas trop fonctionné. Je me retrouve avec une erreur PHP m'indiquant que le nom du fichier ne peut pas être vide ?

    Erreur php :

    Warning: include(): Filename cannot be empty in C:wampwwwEasyStageindex.php on line 20

    .htaccess :

    RewriteEngine On
    RewriteBase /EasyStage/
    RewriteRule ^index.html$ index.php?page=/
    RewriteRule ^([a-zA-Z0-9-]*.php)$ index.php?page=$1 [L,QSA]

  9. Avatar de Christophe Ferreboeuf

    C'est possible de le mettre en place mais un tout petit peu plus compliqué. Je pense qu'il faut exclure des dossiers des redirections pour que les fichiers php annexes (hors vues) ne soient pas pris en compte.
    Pour l'instant, init.php est redirigé vers index.php?page=init et la route n'est pas trouvée. Cela se fait avec des RewriteCond.

    Par exemple (pour que tous les fichiers sous includes ne soient pas traités) :
    RewriteCond %{REQUEST_URI} !includes/.*

    PS : je suis moins sûr pour ce problème que pour les autres soucis que vous avez rencontrés

  10. Avatar de Unknown

    Puis-je vous contacter par email ? ça serait bien plus simple

  11. Avatar de Unknown

    J'ai réglé le problème. Il faut définir une route avec pour chemin index.php et ça fonctionne 🙂

  12. Avatar de Anonyme
    Anonyme

    Bonjour, je sais que cet article est vieux mais je m'y interesse 🙂
    Je ne comprends pas l'utilisation et l’intérêt du 4eme param dans $fmk->initRoute();
    Est-ce un param a utiliser dans le contrôleur pour la modèle ?
    SI c'est le cas, avez-vous un exemple svp ?
    Merci d'avance.

  13. Avatar de Christophe Ferreboeuf

    Bonjour,

    Je n'ai pas les sources de ce projet sous la main mais le quatrième paramètre est l'action à appeler. On va charger le fichier contenant le controller dans l'exemple ça sera realisation.php et dans ce contrôleur, on appellera la fonction qui sera nommé index() si mes souvenirs sont bon. On pourra avoir pour un même fichier les différentes actions correspondant au CRUD (Create Read Update Delete). Par exemple, on pourra avoir un contrôleur qui s'appelle utilisateur avec les actions create, list, show, edit et delete. Le dernier paramètre d'initRoute servira à savoir quelle action on veut appeler.
    Pour finir, si la création d'un MVC comme ça est intéressant pour comprendre les principes de ce pattern, il vaut mieux avoir recours à des framework du marché comme symfony qui sont plus robustes.

  14. Avatar de Anonyme
    Anonyme

    Super, merci tu en as fait bien asse pour que je comprenne 🙂

Laisser un commentaire