Un modèle MVC simplifié
Le modèle MVC est à la base de nombreux projets professionnels. Plus d'informations
ici:
http://fr.wikipedia.org/wiki/Mod%C3%A8le-Vue-Contr%C3%B4leur
La base de notre contrôleur
Le programmeur débutant aura tendance à gérer l'enchaînement de ses pages de cette manière:
- une page
index.phpqui contient les éléments de la page d'accueil et des menus; - chaque lien d'un menu pointe vers un autre script php, reproduisant en celà ce qu'on a l'habitude de réaliser en HTML pur.
Ainsi, chaque page php va commencer avec le même en-tête html puis head
puis body:
<!DOCTYPE HTML> <html> <head> <title>titre de la page</title> <meta charset='UTF-8'> <link rel="stylesheet" type="text/css" href="css/styles.css" title="style"> </head> <body> ...partie du script propre à cette page... </body> </html>
Si d'aventure il fallait intégrer un nouveau composant d'usage général, avec cette méthode de programmation, il faudrait retoucher tous les scripts. par exemple, supposons que nous ayons une bête fonction chargée de compter le nombre d'accès à une page:
function tagPage($maPage) { // ici la partie de code qui va incrémenter le compteur de page }
Donc, pour exploiter cette fonction dans une page quelconque, par exemple une page listeAnnonces.php:
<?php include 'inc/functionTagPage.inc.php'; tagPage('listeAnnonces'); ?> <!DOCTYPE HTML> <html> <head> <title>liste des annonces</title> <meta charset='UTF-8'> <link rel="stylesheet" type="text/css" href="css/styles.css" title="style"> </head> <body> ...affichage liste des annonces... </body> </html>
Il en est de même si on veut rajouter un appel vers un css particulier, une librairie javascript, ou plus simplement avoir un menu commun à toutes nos pages. Bref, une vraie corvée si on a des centaines de scripts!
On va donc découpler la partie emballage de la partie contenu et appelant le contenu
à charger dans l'emballage via un parametre page:
index.php?page=listeAnnonces
La partie de code qui se situait entre body et /body dans notre script
listeAnnonces.php va être recopié dans un nouveau script listeAnnonces.phtml
et placé dans un sous-répertoire templates. Naturellement, tous les liens qui faisaient
référence directement à listeAnnonces.php doivent être remplacés par
index.php?page=listeAnnonces. Et voici comment index.php va charger ce contenu:
<!DOCTYPE HTML> <html> <head> <title>titre de mon site</title> <meta charset='UTF-8'> <link rel="stylesheet" type="text/css" href="css/styles.css" title="style"> </head> <body> <?php if (isset($_GET['page']]) && $_GET['page']=='listeAnnonces') { include 'templates/listeAnnonces.phtml'; } ?> </body> </html>
Déja à ce niveau, on sent rapidement l'intérêt de n'avoir plus qu'un seul script. Par exemple, nos scripts chargés de gérer les annonces pourraient avoir besoin d'une classe applicative spécifique. Voici un moyen de mutualiser ladite classe:
<!DOCTYPE HTML> <html> <head> <title>titre de mon site</title> <meta charset='UTF-8'> <link rel="stylesheet" type="text/css" href="css/styles.css" title="style"> </head> <body> <?php if (isset($_GET['page']]) && $_GET['page']=='listeAnnonces') { include 'inc/class.Annonces.inc.php'; $Annonces = new Annonces(); include 'templates/listeAnnonces.phtml'; } ?> </body> </html>
Notre script index.php est à ce stade un embryon de contôleur. On y gère
le chargement des ressources en fonction de nos besoins.
Protection de la page
Question: oui, c'est bien joli ce principe, mais si on doit taper autant de lignes if { }
qu'il y a de templates, où est l'intérêt?
La première solution venant à l'esprit est de modifier notre include comme ceci:
if (isset($_GET['page']])) { include 'templates/'.$_GET['page'].'phtml'; }
Sauf que là, nous avons une très belle faille de sécurité! Voici la solution simple pour la combler:
$listePagesAutorisees = array( 'accueil', 'accueilSaisieAnnonce', 'formulaireSaisieDerangement', 'enregistreAnnonce', // ... et autant de lignes qu'il y a de templates ); $page = 'accueil'; if (isset($_GET['page']) && in_array($_GET['page'], $listePagesAutorisees)) { $page = $_GET['page']; } include 'templates/'.$_GET['page'].'phtml';
A chaque page autorisée, par exemple enregistreAnnonce doit correspondre dans le répertoire
templates un fichier de même nom que la page avec l'extension phtml, pour notre
exemple un fichier nommé enregistreAnnonce.phtml.
Pratiquement tous les sites web sous PHP sont construits sur ce modèle, avec des variantes, même pour des liens comme ceux-ci:
http://www.monsite.com/detailAnnonces/france/4432/
Des règles de réécriture d'URL vont interpréter ce type de lien et construire un vrai lien exploitable par PHP qui pourrait ressembler à ceci:
http://www.monsite.com/index.php?page=detailAnnonces&pays=france&idAnnonce=4432
Si nous avons des centaines de templates à gérer, il peut devenir fastidieux de modifier perpétuellement notre
script index.php. Voici une solution alternative qui fait appel à une fonction chargée de vérifier
si la page demandée existe physiquement:
/** * sécurisation de l'inclusion dynamique d'un template * * teste si la page demandée existe en tant que fichier physiquement implanté * sur le serveur. Si oui, on renvoie la page, sinon on arrête. * * @param $page string * @return string page à charger par include */ function includePageDuSite($page) { if (file_exists($page)) { return $page; } die("Ce Fichier n'existe pas sur le Serveur"); }
Et dans notre page index.php, on réécrit notre include:
$maPage = 'templates/'.$_GET['page'].'phtml'; include includePageDuSite($maPage);
Seules les pages physiquement présentes sur le site pourront être chargées.
Le squelette MVC minimal
Le squelette MVC présenté ici est un modèle minimal:
<!DOCTYPE HTML> <html> <head> <title>titre de mon site</title> <meta charset='UTF-8'> <link rel="stylesheet" type="text/css" href="css/styles.css" title="style"> </head> <body> <?php if (isset($_GET['page']])) { $page = $_GET['page']; $template = 'templates/'.$page.'.phtml'; if (file_exists($template)) { include $template; } else { include 'templates/accueil.phtml'; } } ?> </body> </html>
Toutes les pages sont appélées templates et stockées dans un répêrtoire templates
et pour chaque page correspond un fichier de même nom avec l'extension .phtml:
/
index.php
/templates
accueil.phtml
annonces.phtml
forum.phtml
contact.phtml
infos.phtml
Exemple de contenu d'un template:
<header> <h1>Accueil</h1> <nav> <a href="index.php?page=annonces">annonces</a> <a href="index.php?page=forum">forum</a> </nav> </header> <article> <p>Bienvenue sur le site de notre association</p> </article> <footer> <p>Association les amis de la bière malgache - <a href="index.php?page=contact">nous contacter</a></p> </footer>
Ici on a écrit un embryon de contenu de la page accueil, c'est à dire du fichier
accueil.phtml dans le répertoire templates.
Dans un template, on peut insérer du code php:
<header> <h1>Annonces</h1> <nav> <a href="index.php?page=accueil">retour accueil</a> <a href="index.php?page=saisieAnnonce">saisir une nouvelle annonce</a> </nav> </header> <article> <h2>Liste des annonces</h2> <?php $listeAnnonces = $Annonces->getListeAnnonces(); ?> ....ici boucle affichage annonces.... </article>
Le mécanisme général est très simple. On n'a plus qu'un seul script index.php
qui se charge d'inclure les templates correspondants aux pages demandées. Par exemple, si
on demande la page accueil et qu'on regarde le code HTML généré, on aura ceci:
<!DOCTYPE HTML> <html> <head> <title>titre de mon site</title> <meta charset='UTF-8'> <link rel="stylesheet" type="text/css" href="css/styles.css" title="style"> </head> <body> <header> <h1>Annonces</h1> <nav> <a href="index.php?page=accueil">retour accueil</a> <a href="index.php?page=saisieAnnonce">saisir une nouvelle annonce</a> </nav> </header> <article> <h2>Liste des annonces</h2> <?php $listeAnnonces = $Annonces->getListeAnnonces(); ?> ....ici boucle affichage annonces.... </article> </body>
Pourquoi l'extension de fichier .phtml pour un template? Par convention, un template
est une sorte de moule, en général du code HTML pouvant contenir accessoirement des portions de
code PHP. Cette mixité HTML et PHP est indiquée par l'extension phtml pour signifier
que le fichier n'est pas du code PHP exécutable directement par PHP. Pour rappel, seuls les
fichiers d'extension .php sont traités par l'interpréteur PHP. De même, un navigateur
ne saura pas quoi faire du contenu d'un fichier d'extension .phtml.
index.php via la fonction include va récupérer le contenu d'un template
et assurer la fusion afin de produire une page avec du code HTML parfaitement interprétable par
le navigateur du client final.
Dans la page suivante comment bien organiser son site.