HTML5 / CSS 2.x/3 / PHP / MySQL ...

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:

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.

Tous les articles sur ce thème