Tutoriel de site dynamique - Classes d'abstraction


précédentsommairesuivant

III. Les gabarits

III-A. Introduction

Ici, il y a davantage de travail. En effet, pour afficher du HTML, nous n'utilisons aucune fonction spéciale. Il s'agit donc de mettre en place un système qui mette en évidence le fait que nous souhaitons afficher du HTML.
La démarche peut sembler complexe mais je vous assure qu'elle a d'énormes avantages, notamment de permettre d'extraire tout le code HTML du fichier PHP. Les avantages sont évidents : il est plus facile de trouver un bug dans le PHP (puisqu'il n'y a plus de HTML parasite) et il est plus facile de modifier l'apparence de la page (puisque le code PHP n'est pas dans le même fichier).
Tout comme pour les classes d'abstraction de base de données, il existe de nombreux moteurs de templates comme Smarty, PHPLib, etc. De plus, chaque collection de script telle que phpBB dispose là aussi de son propre moteur.

J'ai choisi d'utiliser le moteur de templates de phpBB2 car je l'utilise souvent et je l'apprécie. Je l'ai un peu modifié pour mes besoins : je lui fais gérer la convertion des variables en entités HTML. Pour cela, j'ai modifié la classe pour qu'elle appelle htmlentities() avec tous ses paramètres. La différence se fait lors de l'instanciation car il est possible de modifier le comportement par défaut (ENT_QUOTES et "iso-8859-1") :

Exemples de déclaration de l'objet $template
Sélectionnez
$template = new Template("./templates/default/");
$template = new Template("./templates/titoumimi", "ISO-8859-1");
$template = new Template("./templates/titoumimi", "UTF-8", ENT_QUOTES);



Voici le source du moteur de templates, à décompresser et à placer dans le répertoire "/includes" : [ FTP ] ou [ HTTP ].

Pour terminer cette introduction, voici le schéma minimum d'utilisation d'un template :

/index.php
Sélectionnez
define("TEMPLATE_FOLDER", "./templates/titoumimi");

$template = new Template(TEMPLATE_FOLDER);
$template->set_filenames(array("index" => "index.tpl"));

// Mettre ici le code de la page

$template->pparse("index");


Globalement, les modifications à apporter aux scripts de Pierre-Baptiste sont :
  • Les portions de code qui envoient du HTML et/ou du texte de manière répétitive seront remplacées par un appel à assign_block_vars() chacune ;
  • Les portions de code qui n'envoient du HTML et/ou du texte qu'une fois dans la page seront remplacées par un ou plusieurs appels à assign_vars().

III-B. Gabarit fondamental


Commençons par écrire notre gabarit général, c'est-à-dire la structure de la page d'index :

/templates/default/index.tpl
Sélectionnez
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <!-- Insère les mots-clés extraits de la DB dans les meta -->
    <META NAME="keywords" lang="fr" CONTENT="{HEAD_MOTS_CLES}">
    <!-- Insère la description extraite de la DB dans les meta -->
    <META NAME="Description" CONTENT="{HEAD_DESCRIPTION}">
    <meta http-equiv="Content-Type" content="text/html; charset={TPL_CHARSET}">
    <!-- Insère le titre extrait de la DB dans la balise correspondante -->
    <title>{HEAD_TITRE}</title>
    <link rel="stylesheet" type="text/css" href="{THEMES_FOLDER}/final.css">
</head>
<body>
    <div id="menu_horizontal">
    </div>
    <div id="chemin_fer">
    </div>
    <div id="bloc_central">
    	<div id="menu_vertical">
    	</div>
    	<div id="contenu">
    	   {PAGE_CONTENU}
    	</div>
    </div>


Il est intéressant de noter plusieurs choses :
  • Nous n'avons plus aucune des balises <?php et ?> ;
  • Toutes les portions <?php echo $var; ?> ont été remplacées par des sortes de variables entre accolades comme {HEAD_TITRE} ;
  • J'ai laissé vides les blocs DIV pour le moment car ils ont besoin de davantage d'attention ;
  • J'ai mis une variable {TPL_CHARSET} qui semble provenir de nulle part : c'est un cas particulier assigné par le moteur de templates (suite aux modifications apportées par mes soins) ;

III-C. Script PHP fondamental

Il faut maintenant modifier le script PHP afin qu'il utilise notre gabarit :

/index.php
Sélectionnez
<?php

// Active tous les warning. Utile en phase de développement
// En phase de production, remplacer E_ALL par 0
error_reporting(E_ALL | E_STRICT);

define("BDD_CONNECTION",  "mysql:host=localhost;dbname=developpez");
define("TEMPLATE_FOLDER", "./templates/titoumimi");
define("THEMES_FOLDER",   "./themes/titoumimi");

// Inclusions diverses
include_once("./includes/mes-fonctions.php");
include_once("./includes/template.php");

// Construction de l'objet de la classe de gabarit
$template = new Template(TEMPLATE_FOLDER);
$template->set_filenames(array("index" => "index.tpl"));

// Construction de l'objet de la classe de connexion à la base de données
set_exception_handler("exception_handler");
$db = new PDO(BDD_CONNECTION, "root", "");

// Définit l'Id de la page d'accueil (1 dans cet exemple)
// Pensez à le modifier si ce n'est pas le cas chez vous.
$id_page_accueil = 1;

// Récupère l'id de la page courante passée par l'URL
// Si non défini, on considère que la page est la page d'accueil
if (isset($_GET["id_page"]))
{
    $_ENV["id_page"] = $_GET["id_page"];
}
else
{
    $_ENV["id_page"] = $id_page_accueil;
}

// Extrait les informations correspondantes à la page en cours de la DB
extraction_infos_DB();

// Le reste des traitements viendra ici

// Envoi des variables 'globales' au gabarit
$template->assign_vars(array(
    "THEMES_FOLDER"    => THEMES_FOLDER,
    "HEAD_MOTS_CLES"   => $_ENV["mots_cles"],
    "HEAD_DESCRIPTION" => $_ENV["description"],
    "HEAD_TITRE"       => $_ENV["titre"],
    "PAGE_CONTENU"     => $_ENV["contenu"]
    ));

$template->pparse("index");

?>
Il est intéressant de noter plusieurs choses :
  • Nous ouvrons la balise <?php uniquement en début de script et la refermons avec ?> uniquement en fin de script (nous n'avons plus de code HTML brut) ;
  • Les divers affichages des variables de la superglobale $_ENV; ont été déplacés dans l'appel à assign_vars(), ce qui permet de les regrouper et donc de mieux les gérer.

III-D. Les "blocks"

Ensuite, occupons-nous des blocs qui se répètent. Nous aurons besoin de notre objet $template dans les deux fonctions concernées : affiche_chemin_fer() et affiche_menu(). Je propose de l'inclure à la liste des globales commes nous l'avons fait pour $db :

/includes/mes-fonctions.php
Sélectionnez
function affiche_chemin_fer($idpage)
{
    global $db, $template;
/includes/mes-fonctions.php
Sélectionnez
function affiche_menu($idpage)
{
    global $db, $template;


Tout d'abord, le chemin de fer :

/templates/index.tpl
Sélectionnez
<div id="chemin_fer">
    Vous &ecirc;tes ici :
<!-- BEGIN un_niveau -->
     -&gt; <a href="index.php?id_page={un_niveau.ID}">{un_niveau.TITRE}</a>
<!-- END un_niveau -->
</div>


Le moteur de templates saura qu'il devra répéter ce lien à chaque fois qu'on lui parlera du bloc "un_niveau".
Voici le code PHP associé :

/includes/mes-fonctions.php
Sélectionnez
function affiche_chemin_fer($idpage)
{
    global $db, $template;

    // Si l'id de la page en cours est différent de 0
    // (0 = page parente de la page racine = inexistante)
    if($idpage != 0)
    {
        $pages = array();

        $sql = "SELECT * FROM PAGES WHERE Id_page = :id_page";
        $statement = $db->prepare($sql);

        do
        {
            // on récupère les informations de la page en cours dans la DB
            $statement->execute(array(":id_page"   => $idpage));
            $tabl_results = $statement->fetch();

            // Envoi au template
            $pages[] = $tabl_results;

            $idpage = $tabl_results["Id_parent"];
        } while($idpage);

        if(!empty($pages))
        {
            $nb_pages = count($pages);
            for($i = $nb_pages-1; $i >= 0; --$i)
            {
                $template->assign_block_vars("un_niveau", array(
                    "ID"	=> $pages[$i]["Id_page"],
                    "TITRE" => $pages[$i]["Titre"]
                    ));
            }
        }
    }
}


Le principe est d'appeler assign_block_vars() à chaque itération. Ici, j'ai déporté ces appels dans une autre boucle afin de pouvoir afficher le menu à l'envers (comme Pierre-Baptiste l'a fait dans son article). J'ai enlevé la récursivité pour me simplifier la tâche.
Au passage, nous pouvons noter que PDO nous permet de ne pas préparer la requête avant chaque exécution. En effet, une fois la requête préparée, elle peut être exécutée plusieurs fois à la suite avec des paramètres différents. Il faut simplement prendre garde à toujours récupérer tous les tuples avant de l'exécuter à nouveau.

Voyons ensuite les deux menus :

/templates/index.tpl
Sélectionnez
<div id="menu_horizontal">
<!-- BEGIN menu_horizontal -->
    <ul>
<!-- BEGIN un_niveau -->
        <li><a href="index.php?id_page={menu_horizontal.un_niveau.ID}">{menu_horizontal.un_niveau.TITRE}</a></li>
<!-- END un_niveau -->
    </ul>
<!-- END menu_horizontal -->
</div>
/templates/index.tpl
Sélectionnez
<div id="bloc_central">
    <div id="menu_vertical">
<!-- BEGIN menu_vertical -->
        <ul>
<!-- BEGIN un_niveau -->
            <li>
                <a href="index.php?id_page={menu_vertical.un_niveau.ID}">{menu_vertical.un_niveau.TITRE}</a>
            </li>
<!-- END un_niveau -->
        </ul>
<!-- END menu_vertical -->
    </div>
    <div id="contenu">
        {PAGE_CONTENU}
    </div>
</div>
/includes/mes-fonctions.php
Sélectionnez
function affiche_menu($idpage, $menu)
{
    global $db, $template;

    $sql = "SELECT * FROM PAGES WHERE Id_parent = :id_page";
    $statement = $db->prepare($sql);
    $statement->execute(array(":id_page"   => $idpage));
    $tabl_results = $statement->fetchAll();

    // Si la page n'a pas de page fille, alors on modifie la requète pour obtenir ses pages soeurs.
    if (count($tabl_results) == 0)
    {
        $statement->execute(array(":id_page"   => $_ENV["id_parent"]));
        $tabl_results = $statement->fetchAll();
    }

    if(count($tabl_results))
    {
        $template->assign_block_vars($menu, array());

        foreach($tabl_results as $tabl_result)
        {
            $template->assign_block_vars($menu.".un_niveau", array(
                "ID"      => $tabl_result["Id_page"],
                "TITRE"   => $tabl_result["Titre"]
                ));
        }
    }
}


Ici, nous devons imbriquer deux blocs : le bloc racine ("menu_horizontal" ou "menu_vertical") permet d'initaliser la liste à puces dans le template et le bloc interne ("un_niveau") contient les éléments de cette liste.

Il faut maintenant appeler les fonctions de Pierre-Baptiste pour que nos blocks soient générés :

/index.php
Sélectionnez
// Le reste des traitements viendra ici
affiche_menu($id_page_accueil, 'menu_horizontal');
affiche_menu($_ENV['id_page'], 'menu_vertical');
affiche_chemin_fer($_ENV['id_page']);

III-E. Le pied de page

Terminons par le pied de page, ultra simple :

/templates/default/pied-page.tpl
Sélectionnez
    <hr />
Ceci est le pied de page...
</body>
</html>
/pied-page.php
Sélectionnez
<?php

$template->set_filenames(array("pied-page" => "pied-page.tpl"));
$template->pparse("pied-page");

?>

Voici le code complet de Pierre-Baptiste converti à cette étape : [ FTP ] ou [ HTTP ].


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2006 Guillaume Rossolini. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.