Routes

Nous allons maintenant passer à la mise en place du routage. Après avoir redirigé toutes les requêtes vers index.php et supprimé les extensions .php des liens, nous pouvons contrôler précisément quelle URL correspond à quelle ressource. Le routage nous permettra de créer des URLs personnalisées, lisibles et indépendantes de la structure des fichiers, en associant chaque URL à un contrôleur et à une action définis dans un tableau de routes.

Méthodeapp/routes.php

Exemples de routes :

  • utilisateurs[utilisateur, index]

  • utilisateur/afficher-3[utilisateur, show]

1
<?php
2
$routes = [];
3
// $routes[] = [path, name, [controller, action]];
4
// path : url de la ressource. {param} indique l'utilisation d'un paramètre
5
// name : clé unique de la route
6
// controller : dossier où se trouve réllement la ressource
7
// action : nom du fichier de la ressource sans son extension
8
$routes[] = ['/', 'home.index', ['home', 'index']];
9
$routes[] = ['/utilisateurs', 'utilisateur.index', ['utilisateur', 'index']];
10
$routes[] = ['/utilisateur/ajouter', 'utilisateur.create', ['utilisateur', 'create']];
11
$routes[] = ['/utilisateur/afficher-{id}', 'utilisateur.show', ['utilisateur', 'show']];
12
$routes[] = ['/utilisateur/modifier-{id}', 'utilisateur.update', ['utilisateur', 'update']];
13
$routes[] = ['/utilisateur/supprimer-{id}', 'utilisateur.delete', ['utilisateur', 'delete']];

path — le chemin de l’URL

  • Définition : C’est l’URL publique qui sera utilisée par les visiteurs pour accéder à la ressource.

  • Format : Chaîne commençant par /, avec possibilité de paramètres dynamiques indiqués par {param}.

  • Paramètres dynamiques :

    • Tout segment entouré de {} devient une variable capturable.

    • Exemple : {id}/utilisateur/afficher-3 donne id = 3.

  • But : Permet d’avoir des URLs propres, lisibles et indépendantes des noms de fichiers réels.

name — identifiant unique de la route

  • Définition : C’est une clé unique qui identifie la route dans votre application.

  • Utilité :

    • Générer des URLs dans votre code sans les coder en dur.

    • Référencer une route de manière stable même si le path change.

On peut penser à name comme à un alias pour la route.

[controller, action] — le contrôleur et l’action associée

controller

  • Définition : Le dossier dans app/controllers où se trouvent les fichiers PHP qui gèrent cette route.

  • Exemple : utilisateur → les fichiers se trouvent dans app/controllers/utilisateur/.

action

  • Définition : Le fichier PHP correspondant à la route, sans l’extension .php.

  • Exemple : show → le fichier complet est app/controllers/utilisateur/show.php.

Rôle du couple controller/action

  • Le contrôleur contient la logique de traitement de la requête.

  • L’action correspond à la ressource exacte à exécuter pour cette route.

  • Ensemble, ils permettent à index.php (le front controller) de savoir quel fichier inclure et exécuter pour répondre à l’URL demandée.

Méthodeapp/helpers.php

Le fichier helpers sert à regrouper des fonctions destinées à simplifier l’écriture du code. Nous devons y ajouter les fonctions suivantes dans app/helpers.php.

Méthodefunction url(): string

La fonction url sert à récupérer l’URL demandée

1
function url(): string
2
{
3
    // Nettoyer le chemin du script (remplace \ par / pour Windows)
4
    $scriptDir = str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME']));
5
6
    // Supprimer les paramètres GET
7
    $requestUri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
8
9
    // Supprimer le dossier du script
10
    if (strpos($requestUri, $scriptDir) === 0) {
11
        $requestUri = substr($requestUri, strlen($scriptDir));
12
    }
13
14
    // Nettoyer les éventuels / en début et fin, ajouter un / au début
15
    return '/' . ltrim($requestUri, '/');
16
}

Méthodefunction getRoute(array $routes, string $url): ?array

La fonction getRoute sert à trouver quelle route correspond à l’URL demandée et à récupérer les informations nécessaires pour exécuter la bonne ressource.

En pratique :

  1. Elle parcourt toutes les routes définies dans $routes.

  2. Elle compare l’URL demandée avec le path de chaque route.

  3. Si l’URL correspond :

    • Elle retourne le contrôleur à utiliser (controller).

    • Elle retourne l’action à exécuter (action).

    • Elle extrait les paramètres dynamiques de l’URL (comme {id}) pour que le contrôleur puisse les utiliser.

  4. Si aucune route ne correspond, elle retourne null

1
function getRoute(array $routes, string $url): ?array
2
{
3
    foreach ($routes as $route) {
4
        $path = $route[0];
5
6
        // Transformer le path en expression régulière pour détecter les paramètres
7
        $pattern = preg_replace('/\{(\w+)\}/', '(?P<$1>[^/]+)', $path);
8
        $pattern = "#^$pattern$#";
9
10
        if (preg_match($pattern, $url, $matches)) {
11
            // Extraire uniquement les paramètres nommés
12
            $params = array_filter(
13
                $matches,
14
                fn($key) => !is_int($key),
15
                ARRAY_FILTER_USE_KEY
16
            );
17
18
            return [
19
                'controller' => $route[2][0],
20
                'action'     => $route[2][1],
21
                'params'     => $params
22
            ];
23
        }
24
    }
25
26
    // Aucun route trouvée
27
    return null;
28
}

Méthodefunction route(string $name, array $params = []): string

La fonction route permet de générer automatiquement l’URL correspondant à une route définie, sans avoir à l’écrire manuellement.

  • Elle prend en entrée le nom de la route (name) et éventuellement des paramètres dynamiques (par exemple id).

  • Elle retourne l’URL complète prête à être utilisée dans un lien ou un formulaire.

Exemples dans vos liens href ou dans vos header :

< ?= route('home.index') ?>

< ?= route('utilisateur.show', ['id' => 3]) ?>

header('location:' . route('utilisateur.index'));

1
function route(string $name, array $params = []): string
2
{
3
    global $routes;
4
5
    foreach ($routes as $route) {
6
7
        if ($route[1] == $name) {
8
            $url = $route[0];
9
            foreach ($params as $key => $val) {
10
                $url = str_replace('{' . $key . '}', $val, $url);
11
            }
12
            return dirname($_SERVER['SCRIPT_NAME']) . $url;
13
        }
14
    }
15
16
    return '';
17
}

Méthodefunction getParams($key, $default=null): string|int|null

La fonction getParams permet de retourner la valeur de la clé se trouvant dans la route.

1
function getParams($key, $default = null): string|int|null
2
{
3
    return $GLOBALS['route']['params'][$key] ?? $default;
4
}

Méthodefunction view($name, $vars = []): void

La fonction view() permet d’inclure une vue (un fichier PHP de app/views) et de lui transmettre des variables. Elle simplifie donc l’affichage du contenu depuis un contrôleur.

Exemple dans vos contrôleurs :

return view('utilisateur.update', compact('page_title', 'page_styles', 'utilisateur'));

La fonction calcule et transmet désormais $page_base ; les contrôleurs n’ont donc plus besoin de le fournir.

1
function view($name, $vars = []): void
2
{
3
    extract($vars);
4
5
    // Calcul du chemin relatif vers la racine du site
6
7
    $nbPath = max(0, count(explode('/', trim(url(), '/'))) - 1);
8
    $page_base = str_repeat('../', $nbPath);
9
10
    // On remplace les . par des / pour obtenir le chemin du fichier
11
    $url = str_replace(".", "/", $name);
12
    
13
    // Inclusion du fichier de la vue s'il existe
14
    if (is_file("../app/views/$url.php")) {
15
        require "../app/views/$url.php";
16
        return;
17
    }
18
19
    // Inclusion du fichier index.php dans le dossier de la vue s'il existe
20
    if (is_file("../app/views/$url/index.php")) {
21
        require "../app/views/$url/index.php";
22
        return;
23
    }
24
25
    // Sinon, message d'erreur
26
    echo "La vue $name est introuvable.";
27
}

Méthodefunction redirect(string $routeName, array $vars = []): void

La fonction redirect() permet de rediriger l’utilisateur vers une autre page du site en utilisant le nom d’une route. Elle simplifie le code en encapsulant l’appel à header() et exit.

Exemple dans vos contrôleurs :

return redirect('utilisateur.index');

1
function redirect(string $routeName, array $vars = []): void
2
{
3
    // Génération de l'URL à partir du nom de la route
4
    $url = route($routeName, $vars);
5
    // Redirection HTTP
6
    header("Location: " . $url);
7
    exit;
8
}

Méthodepublic/index.php

Il est nécessaire de mettre à jour le Front Controller pour qu’il exploite les fonctions définies dans le fichier helpers ainsi que le système de routes.

1
<?php
2
// ==============================
3
// INCLUSION DES FONCTIONS
4
// ==============================
5
require '../app/models/model.php';
6
require '../app/helpers.php';
7
require '../app/routes.php';
8
9
// ==============================
10
// RÉCUPÉRATION DE L’URL    
11
// ==============================
12
$url = url();
13
14
// ==============================
15
// RÉCUPÉRATION DE LA ROUTE 
16
// ==============================
17
$route = getRoute($routes, $url);
18
19
// ==============================
20
// RECUPERATION DU CONTRÔLEUR ET DE L’ACTION
21
// ==============================
22
if ($route) {
23
   $controller = $route['controller'];
24
   $action = $route['action'];
25
} else {
26
   $controller = 'error';
27
   $action = 'index';
28
}
29
30
// ==============================
31
// INCLUSION DE LA RESSOURCE
32
// ==============================
33
$file = "../app/controllers/$controller/$action.php";
34
35
if (!file_exists($file)) {
36
    http_response_code(404);
37
    $file = "../app/controllers/error/index.php";
38
}
39
40
require $file;
41
42

Méthodecontrollers

  • Il est nécessaire de mettre à jour les Controllers afin qu’ils utilisent les fonctions définies dans le fichier helpers.

  • On supprime les références à $page_base.

  • Tous les require vers les vues sont remplacés par la fonction view().

  • Les lignes $id = (int)($_GET['id'] ?? 0); deviennent $id = (int)getParams('id');.

  • Enfin, toutes les fonctions header et le exit sont remplacées par la fonction redirect().

Par exemple :

1
require '../app/views/utilisateur/show.php';

devient

1
return view('utilisateur.show', compact('page_title', 'page_styles', 'utilisateur'));

La fonction view() ne connaît que ce qu’on lui transmet. En PHP, une fonction possède son propre scope (espace de variables).

Les variables définies dans le contrôleur ne sont donc pas automatiquement disponibles dans la vue. Il faut les passer explicitement en paramètre.

1
header('location:index');
2
exit;

devient

1
return redirect('utilisateur.index');

Méthodeviews

Toutes les références aux liens du site dans les attributs href des vues doivent être mises à jour.

Ainsi que tous les require vers les vues sont remplacés par la fonction view().

Par exemple :

1
<li><a href=''>Accueil</a></li>

devient

1
<li><a href='<?= route('home.index') ?>'>Accueil</a></li>
1
<a href="utilisateur/show?id=<?= $utilisateur['id'] ?>">

devient

1
<a href="<?= route('utilisateur.show', ['id' => $utilisateur['id']]) ?>">
1
<?php require '../app/views/head.php'; ?>

devient

1
<?php view('head', compact('page_title', 'page_styles')); ?>

view étant une fonction, il ne faut pas oublier de lui transmettre les variables utiles à la vue.

1
$photoDir = '../images/photos/';

devient

1
$photoDir = 'images/photos/';

Méthode

Nous pouvons désormais vérifier le bon fonctionnement du site et constater que les URLs sont réécrites conformément à celles définies dans les routes.