HTML::Template - Module Perl pour utiliser les modèles HTML depuis des scripts CGI
D'abord vous créez un modèle - c'est juste un fichier HTML normal avec quelques balises supplémentaires, la plus simple étant <TMPL_VAR>
Par exemple, test.tmpl :
<html> <head><title>Modèle Test</title> <body> Mon répertoire personnel est <TMPL_VAR NAME=HOME> <p> Mon Path est actuellement <TMPL_VAR NAME=PATH> </body> </html>
Maintenant écrivons un petit script CGI :
#!/usr/bin/perl -w use HTML::Template;
# ouvrir le modèle html my $template = HTML::Template->new(filename => 'test.tmpl');
# lui donner quelques paramètres $template->param(HOME => $ENV{HOME}); $template->param(PATH => $ENV{PATH});
# envoyer le Content-Type obligatoire et afficher le modèle print "Content-Type: text/html\n\n", $template->output;
Si tout va pour le mieux dans le meilleur des mondes vous devez voir quelque chose comme çà dans votre navigateur quand vous appelez le CGI :
Mon répertoire personnel est /home/some/directory Mon Path est actuellement /bin;/usr/bin
Ce module tente de créer une page HTML en utilisant des modèles simples et classiques. Il modifie le HTML standard avec quelques balises supplémentaires - <TMPL_VAR>, <TMPL_LOOP>, <TMPL_INCLUDE>, <TMPL_IF>, <TMPL_ELSE> et <TMPL_UNLESS>. Le fichier écrit en HTML et avec ces balises est appelé un modèle. Il est généralement sauvé séparément de votre script - il est même possible qu'il soit créé par quelqu'un d'autre ! En utilisant ce module vous remplacez par des valeurs les variables, boucles et conditions déclarées dans le modèle. Cela vous permet de séparer la conception - le HTML - des données, que vous générez dans le script Perl.
Ce module est sous licence GPL. Voir la section LICENCE plus bas pour plus de détails.
Si vous ne connaissez pas HTML::Template, je vous suggère de commencer avec l'article de présentation disponible sur le site web d'HTML::Template :
http://html-template.sourceforge.net
Il est vrai qu'il y a bon nombre d'autres packages pour faire des modèles HTML. D'un côté vous avez des choses comme HTML::Embperl qui vous permettent de mélanger librement Perl et HTML. D'un autre côté il y a des solutions de substitution de variables maison. Heureusement le module peut trouver sa place entre les deux.
Un avantage de ce module par rapport à une solution 100% HTML::Embperl est qu'il oblige une séparation complète entre la conception et la programmation. En limitant le programmeur à seulement utiliser de simples variable et boucles dans le HTML, le modèle reste accessible aux concepteurs et autres non-perlistes. L'utilisation d'une syntaxe type HTML fait en sorte que le format soit compréhensible pour les autres. Plus tard cette similitude pourra être utilisée pour étendre la compréhension d'HTML::Template aux éditeurs/analyseurs HTML existants.
Un autre avantage de ce module par rapport aux solutions maison est le support des boucles. Dans mon travail je suis souvent appelé à produire des tables de données en html. Les produire en utilisant des modèles HTML simplistes revient à faire des CGI contenant plein de HTML sachant que le HTML lui-même ne peut pas faire des boucles. L'introduction de déclarations de boucles dans le HTML simplifie cette situation considérablement. Le concepteur peut écrire une seule ligne et la programmeur peut s'en servir autant de fois que nécessaire - ils ont juste à se mettre d'accord sur les noms des paramètres.
Pour tout ça, je pense que la meilleure chose à propos de ce module est qu'il ne fait qu'une chose et qu'il le fait rapidement et sans erreur. Il n'essaie pas de remplacer Perl et HTML, il les améliore juste un peu pour qu'ils interagissent un petit peu mieux. Et c'est assez rapide.
<TMPL_VAR NAME="NOM_PARAMETRE">
La balise <TMPL_VAR> est très simple. Pour chaque balise <TMPL_VAR> dans le modèle vous appelez $template->param(NOM_PARAMETRE => ``VALEUR''). Quand le modèle s'affiche le <TMPL_VAR> est remplacé par la VALEUR que vous avez spécifié. Si vous ne mettez pas de paramètre celui-ci est juste enlevé de l'affichage.
Éventuellement vous pouvez utiliser l'option ``ESCAPE=HTML'' dans la balise pour indiquer que vous voulez que la valeur soit HTML-encodée avant d'être affichée (l'ancienne syntaxe ESCAPE=1 est toujours supportée). Cela veut dire que les caractères ``, <, > et & sont transformés respectivement en ", <, > et &. C'est très pratique quand vous voulez utiliser un TMPL_VAR dans un contexte où ces caractères peuvent poser problème. Exemple :
<input name=param type=text value="<TMPL_VAR NAME="PARAM">">
Si vous avez appelé param()
avec une valeur comme sam``my vous aurez des problèmes
avec la manière dont HTML interprète un guillemet double. D'un autre côté, si vous utilisez
ESCAPE=HTMl, comme ça :
<input name=param type=text value="<TMPL_VAR ESCAPE=HTML NAME="PARAM">">
Vous aurez ce que vous voulez peut importe la valeur que vous aurez passé en paramètre. Vous pouvez aussi écrire ESCAPE=``HTML'', ESCAPE='HTML' and ESCAPE='1'. Remplacez par 0 le HTML et vous stopperez l'encodage, qui est le mode par défaut de toutes façons.
Il y a aussi l'option ``ESCAPE=URL'' qui peut être utilisée pour les variables qui se trouvent dans une URL. Cela fera l'encodage de l'URL, par exemple en remplaçant ' ' par '+' et '/' par '%2F'.
Il y a aussi l'option ``ESCAPE=JS'' qui peut être utilisée pour les variables qui doivent être mises dans une chaîne Javascript. Tous les caractères \n, \r, ' et `` sont encodés.
Vous pouvez assigner une valeur par défaut à une variable avec l'attribut DEFAULT. Par exemple, ceci affichera ``Le diable m'a donné une voiture'' si la variable ``QUI'' n'est pas renseignée.
Le <TMPL_VAR NAME=QUI DEFAULT=diable> m'a donné une voiture.
<TMPL_LOOP NAME="LOOP_NAME"> ... </TMPL_LOOP>
La balise <TMPL_LOOP> un peu plus compliquée que <TMPL_VAR>. La balise
<TMPL_LOOP> vous permet à délimiter une section de texte et à lui donner un
nom. Dans cette boucle vous mettez des <TMPL_VAR>. Maintenant vous donnez à
param()
une liste (une référence à un tableau) de paramètres associés (hash
refs) pour cette boucle. La boucle va lire toute la liste et va afficher le
bloc de texte pour chaque élément. Les paramètres non renseignés sont passés.
Voici un exemple :
Dans le modèle :
<TMPL_LOOP NAME=EMPLOYE_INFO> Nom: <TMPL_VAR NAME=NAME> <br> Job: <TMPL_VAR NAME=JOB> <p> </TMPL_LOOP>
Dans le script :
$template->param(EMPLOYE_INFO => [ { nom => 'Sam', job => 'programmeur' }, { nom => 'Steve', job => 'soda jerk' }, ] ); print $template->output();
L'affichage dans un navigateur :
Nom: Sam Job: programmeur
Nom: Steve Job: soda jerk
Comme vous pouvez voir au-dessus le <TMPL_LOOP> prend une liste de paramètres et ensuite les affiche en passant le corps de la boucle pour chaque élément.
Souvent vous voudrez générer le contenu d'une boucle en programmant. Voici un exemple pour le faire (il y a plein d'autres possibilités !) :
# un couple de tableaux de données à mettre dans une boucle: my @words = qw(Je suis Calme); my @numbers = qw(1 2 3);
my @loop_data = (); # initialise an un tableau pour contenir votre boucle
while (@words and @numbers) { my %row_data; # créez un tableau associatif pour ranger votre ligne de données
# remplissez cette ligne $row_data{WORD} = shift @words; $row_data{NUMBER} = shift @numbers;
# l'étape cruciale - mettez une référence à cette ligne dans la boucle! push(@loop_data, \%row_data); }
# enfin, assignez les données de la boucle au paramètre de celle-ci, de nouveau avec # une référence: $template->param(THIS_LOOP => \@loop_data);
L'exemple ci-dessus marchera avec un modèle comme :
<TMPL_LOOP NAME="THIS_LOOP"> Mot: <TMPL_VAR NAME="WORD"> <br> Nombre: <TMPL_VAR NAME="NUMBER"> <p> </TMPL_LOOP>
Cela produira un affichage comme :
Mot: Je Nombre: 1
Mot: suis Nombre: 2
Mot: Calme Nombre: 3
Les <TMPL_LOOP> dans des <TMPL_LOOP> sont sympa et marchent comme vous le
pensez. Si la syntaxe pour l'appel à param()
vous a séché, voici un exemple
d'appel à param avec une boucle imbriquée :
$template->param(LOOP => [ { nom => 'Bobby', nicknames => [ { nom => 'le grand méchant loup' }, { nom => 'Musclor' }, ], }, ], );
Classiquement, chaque <TMPL_LOOP> prend une référence à un tableau. Dans ce tableau se trouvent plein de références à des tableaux associatifs. Ces tableaux associatifs contiennent des paires nom=>valeur pour un seul passage dans le modèle de la boucle.
Dans un <TMPL_LOOP>, les seules variables utilisables sont celles
venant de <TMPL_LOOP>. Les variables d'autres blocs en dehors ne sont pas
visible dans le modèle de boucle. Pour les geeks qui sont parmi vous,
un <TMPL_LOOP> apporte une nouvelle portée un peu comme un appel
à une sous-routine Perl. Si vous voulez que vos variables soient globales vous pouvez utiliser
l'option 'global_vars' à new()
décrit plus bas.
<TMPL_INCLUDE NAME="fichier.tmpl">
Cette balise inclut un modèle directement dans le modèle actuel là où se trouve la balise. Le contenu du modèle inclus est utilisé exactement comme s'il était physiquement inclus dans le modèle principal.
Le fichier spécifié peut être avec un path absolu (commençant par '/' sous
Unix, par exemple). S'il n'est pas absolu, le path du fichier à inclure
est d'abord testé. Après çà, le path dans la variable d'environnement
HTML_TEMPLATE_ROOT est testé, s'il existe. Ensuite, l'option ``path'' est
essayée, d'abord réellement et ensuite avec HTML_TEMPLATE_ROOT prépondérant si
disponible. En dernier recours, le nom du fichier est passé à open()
directement. Voyez plus bas pour plus d'informations sur HTML_TEMPLATE_ROOT
et l'option ``path'' de new().
Pour une protection contre les inclusions récursives, une limite arbitraire à 10 niveaux est imposée. Vous pouvez modifier cette limite avec l'option ``max_includes''. Regardez la section sur l'option ``max_includes'' plus bas pour plus de détails.
<TMPL_IF NAME="NOM_PARAMETRE"> ... </TMPL_IF>
La balise <TMPL_IF> vous permet d'inclure ou de ne pas inclure un bloc du modèle basé sur la valeur d'un paramètre donné. Si le paramètre est à une valeur considéré comme vraie par Perl - comme '1' - alors le bloc est inclus dans l'affichage. S'il n'est pas défini, ou à une valeur fausse - comme '0' - alors il est sauté. Les paramètres sont spécifiés de la même manière que TMPL_VAR.
Modèle d'exemple :
<TMPL_IF NAME="BOOL"> Du texte qui est affiché seulement si BOOL est vrai! </TMPL_IF>
Maintenant si vous appelez $template->param(BOOL => 1) alors le bloc ci-dessus sera affiché.
Les blocs <TMPL_IF> </TMPL_IF> peuvent inclure n'importe quelle construction HTML::Template valide - VAR et LOOP et autres blocs IF/ELSE. Notez, toutefois, que croiser un <TMPL_IF> et un <TMPL_LOOP> est invalide.
Ne marchera pas :
<TMPL_IF BOOL> <TMPL_LOOP SOME_LOOP> </TMPL_IF> </TMPL_LOOP>
Si le nom d'un TMPL_LOOP est utilisé dans un TMPL_IF, le bloc IF sera affiché si la boucle a au moins une ligne. Exemple :
<TMPL_IF LOOP_ONE> Ceci s'affichera si la boucle n'est pas vide. </TMPL_IF>
<TMPL_LOOP LOOP_ONE> .... </TMPL_LOOP>
ATTENTION : L'essentiel de l'intérêt de HTML::Template est de séparer
votre Perl et votre HTML. Si vous mettez beaucoup de choix où vous avez
des TMPL_IF et correspondants à des if()
Perl, vous allez créer un problème
de maintenance pour garder les deux synchronisés. Je vous suggère de prendre
l'habitude d'utiliser TMPL_IF seulement si vous pouvez faire sans utiliser un
if()
correspondant dans votre code Perl.
<TMPL_IF NAME="NOM_PARAMETRE"> ... <TMPL_ELSE> ... </TMPL_IF>
Vous pouvez inclure un bloc alternatif dans votre bloc TMPL_IF en utilisant TMPL_ELSE. NOTE : vous devez tout de même finir le bloc par </TMPL_IF>, pas par </TMPL_ELSE> !
Exemple :
<TMPL_IF BOOL> Du texte qui est inclus seulement si BOOL est vrai <TMPL_ELSE> Du texte qui est inclus seulement si BOOL est faux </TMPL_IF>
<TMPL_UNLESS NAME="NOM_PARAMETRE"> ... </TMPL_UNLESS>
Cette balise est le contraire de <TPML_IF>. Le bloc est affiché si NOM_PARAMETRE est faux ou non défini. Vous pouvez utiliser <TMPL_ELSE> avec <TMPL_UNLESS> aussi bien qu'avec <TMPL_IF>.
Exemple :
<TMPL_UNLESS BOOL> Du texte qui est inclus seulement si BOOL est faux <TMPL_ELSE> Du texte qui est inclus seulement si BOOL est vrai </TMPL_UNLESS>
Si le nom d'un TMPL_LOOP est utilisé dans un TMPL_UNLESS, le bloc UNLESS est affiché si la boucle n'a aucune ligne.
<TMPL_UNLESS LOOP_ONE> Ceci s'affichera si la boucle est vide. </TMPL_UNLESS>
<TMPL_LOOP LOOP_ONE> .... </TMPL_LOOP>
Les balises HTML::Template sont censées imiter les balises HTML normales. Cependant, elle sont autorisées à ``briser les règles''. Quelque chose comme :
<img src="<TMPL_VAR IMAGE_SRC>">
n'est pas vraiment du HTML valide, mais c'est un usage tout à fait valide et marchera comme prévu.
Le ``NAME='' dans une balise est optionnel, mais ...................... je recommande de l'utiliser. Exemple - ``<TMPL_LOOP LOOP_NAME>'' est acceptable.
Si vous êtes fanatique du HTML valide et que vous voulez que vos modèles soit conformes à la syntaxe du HTML valide, vous pouvez éventuellement mettre vos balises dans le modèle sous la forme de commentaires HTML. Cela peut être utilisé par des auteurs de HTML qui veulent valider la syntaxe HTML de leurs modèles avant d'utiliser HTML::Template, ou ceux qui utilisent des outils d'édition DTD-savvy.
<!-- TMPL_VAR NAME=PARAM1 -->
Pour économiser un maximum de bande passante, les balises standards (sans commentaires) seront utilisées au travers de cette documentation.
new()
Appelle new()
pour créer un nouvel objet Modèle :
my $template = HTML::Template->new( filename => 'file.tmpl', option => 'valeur' );
Vous devez appeler new()
avec au moins une paire nom => valeur en spécifiant comment
accéder au texte du modèle. Vous pouvez utiliser ``filename => 'file.tmpl''' pour
spécifier un nom de fichier qui doit être ouvert comme modèle. Sinon, vous pouvez
utiliser :
my $t = HTML::Template->new( scalarref => $ref_to_template_text, option => 'valeur' );
et
my $t = HTML::Template->new( arrayref => $ref_to_array_of_lines , option => 'valeur' );
Ça initialise le modèle avec les ressources en mémoire. Dans la plupart des cas vous voudrez utiliser le paramètre du nom de fichier. Si vous êtes embêté par l'accès disque représenté par la lecture du fichier modèle, utilisez mod_perl et l'option cache détaillée plus bas.
Vous pouvez également lire le modèle à partir d'un handle de fichier déjà ouvert, aussi bien comme si c'était un glob ou un handle de fichier :
my $t = HTML::Template->new( filehandle => *FH, option => 'valeur');
Les quatre méthodes pour appeler new()
peuvent évidemment être utilisées comme ci-dessous, si vous
préférez.
my $t = HTML::Template->new_file('file.tmpl', option => 'valeur');
my $t = HTML::Template->new_scalar_ref($ref_au_fichier_texte_modele, option => 'valeur');
my $t = HTML::Template->new_array_ref($ref_a_un_tableau_de_lignes, option => 'valeur');
my $t = HTML::Template->new_filehandle($fh, option => 'valeur');
Et comme dernière option, pour ceux qui préfèrent, vous pouvez appeler new comme ceci :
my $t = HTML::Template->new(type => 'filename', source => 'file.tmpl');
Qui marche pour chacun des trois types de source.
Si la variable d'environnement HTML_TEMPLATE_ROOT est renseignée et que votre
nom de fichier ne commence pas par /, alors le path sera relatif à la valeur
de $HTML_TEMPLATE_ROOT. Exemple - si la variable d'environnement
HTML_TEMPLATE_ROOT est ``/home/sam'' et que j'appelle
HTML::Template->new()
avec le nom de fichier ``sam.tmpl'',
HTML::Template essaiera d'ouvrir ``/home/sam/sam.tmpl'' pour accéder au
fichier modèle. Vous pouvez aussi modifier le path de recherche pour vos fichier avec
l'option ``path'' de new()
- Voir plus bas pour plus d'information.
Vous pouvez modifier le comportement de l'objet Template avec new(). Les options disponibles sont :
<TMPL_HUH NAME=ZUH>
Devrait normalement renvoyer une erreur, mais si vous appelez new avec strict => 0, HTML::Template l'ignorera. Par défaut à 1.
C'est l'usage de base dans un environnement persistant comme Apache/mod_perl. Ça n'a absolument aucun intérêt dans un environnement CGI normal puisque le script est déchargé de la mémoire après chaque requête. Pour un cache qui fonctionne avec les CGI normaux, voyez l'option 'shared_cache' plus bas.
Notez que les différents réglages des paramètres de new()
ne cause pas
de rafraîchissement du cache, seul un changement dans la date de modification d'un modèle
déclenchera un rafraîchissement du cache. Dans la plupart des cas c'est bien. Mon simple test
montre qu'utiliser le cache rapporte 90% de performance en plus sous
mod_perl. Cache est par défaut à 0.
Par défaut HTML::Template utilise la clé IPC 'TMPL' comme segment racine partagé
(0x4c504d54 en hexa), mais cela peut être changé en initialisant le paramètre
'ipc_key' de new()
à une autre valeur de clé sur 4 caractères ou avec un entier.
D'autres options peuvent être utilisées pour modifier le cache de mémoire partagé et correspondent
aux options d'IPC::SharedCache - ipc_mode, ipc_segment_size et
ipc_max_size. Voyez la page de manuel IPC::SharedCache pour une description de leur
fonctionnement - dans la plupart des cas vous n'avez pas besoin de les modifier
par rapport à leur valeur par défaut.
Pour plus d'informations à propos du système de mémoire cache partagé utilisé par HTML::Template voyez la page de manuel IPC::SharedCache.
NOTE : Mélanger cette option avec shared_cache peut faire en sorte que les modèles soient en permanence chargés dans la mémoire partagée !
Si vous activez cette option vous devez activer l'option ``file_cache_dir''. Voir plus bas pour les détails.
NOTE : Storable utilise flock()
pour assurer un accès fiable aux fichiers de cache.
Utiliser file_cache sur un système ou un système de fichiers (NFS) qui ne connaît pas
flock()
est dangereux.
new()
et les fichiers
inclus dans la balise <TMPL_INCLUDE>. Cette liste est utilisée uniquement
quand le nom de fichier est relatif. La variable d'environnement
HTML_TEMPLATE_ROOT est toujours testée en premier si elle existe. Bien sûr, si
HTML_TEMPLATE_ROOT est active alors un essai sera fait pour utiliser
HTML_TEMPLATE_ROOT devant les paths de la liste de path. Dans le cas d'un
fichier <TMPL_INCLUDE>, le path du fichier inclus est bien sûr testé avant de
consulter path.
Exemple :
my $modele = HTML::Template->new( filename => 'file.tmpl', path => [ '/path/des/modeles', '/path/alternatif' ] );
NOTE : les paths de la liste de path doivent être sous la forme UNIX, séparés par le caractère slash ('/').
param()
qui fonctionne comme celle d'HTML::Template.
Un bon exemple peut être un objet query CGI.pm. Exemple :
my $query = new CGI; my $modele = HTML::Template->new(filename => 'modele.tmpl', associate => $query);
Maintenant, $modele->output()
marchera comme ça
$modele->param('FormField', $cgi->param('FormField'));
comme spécifié pour chaque paire clé/valeur qui peut être fourni par la méthode $cgi->param(). Les paramètres que vous activez directement sont prioritaires sur les paramètres associés.
Vous pouvez spécifier des objets multiples à associer en passant un tableau anonyme à l'option associate. Ils sont cherchés comme paramètres dans l'ordre où ils apparaissent :
my $modele = HTML::Template->new(filename => 'modele.tmpl', associate => [$query, $other_obj]);
L'ancien appel associateCGI()
est toujours supporté, mais doit être
considéré comme obsolète.
NOTE : Les noms des paramètres sont testé de manière non sensible à la casse. Si vous avez deux paramètres dans un objet CGI comme 'NAME' et 'Name', l'un sera choisi de manière aléatoire par associate. Ce comportement peut être changé par l'option suivante.
my $modele = HTML::Template->new(filename => 'modele.tmpl', case_sensitive => 1); $modele->param( FieldA => 'foo', fIELDa => 'bar', );
Cette option est par défaut désactivée.
NOTE : avec case_sensitive et loop_context_vars les variable de boucle spéciales ne sont disponibles qu'en minuscule.
En plus de cela, une variable __counter__ est également disponible quand les variables de contexte de boucle sont activées.
Exemple :
<TMPL_LOOP NAME="FOO"> <TMPL_IF NAME="__first__"> Cela n'affiche que le premier passage. </TMPL_IF>
<TMPL_IF NAME="__odd__"> Cela affiche tous les autres passages, sur les passages impairs. </TMPL_IF>
<TMPL_UNLESS NAME="__odd__"> Cela affiche tous les autres passages, sur les mêmes passages. </TMPL_IF>
<TMPL_IF NAME="__inner__"> Cela affiche les passages qui ne sont ni le premier ni le dernier. </TMPL_IF>
Ceci est le numéro de passage <TMPL_VAR NAME="__counter__">.
<TMPL_IF NAME="__last__"> Cela n'affiche que le dernier passage. <TMPL_IF> </TMPL_LOOP>
Un usage de cette possibilité est d'avoir un ``séparateur'' similaire à l'effet de la fonction perl join(). Exemple :
<TMPL_LOOP FRUIT> <TMPL_IF __last__> and </TMPL_IF> <TMPL_VAR KIND><TMPL_UNLESS __last__>, <TMPL_ELSE>.</TMPL_UNLESS> </TMPL_LOOP>
Affichera (dans un navigateur) quelque chose comme :
Pommes, Oranges, Cerveaux, Orteils, et Kiwi.
En fonction d'un appel à param()
approprié, bien sûr. NOTE : une boucle avec seulement
un seul passage mettra aussi bien __first__ et __last__ à vrai, mais pas
__inner__.
Exemple :
Ceci est une variable normale: <TMPL_VAR NORMAL>.<P>
<TMPL_LOOP NAME=FROOT_LOOP> Ici elle est dans la boucle: <TMPL_VAR NORMAL><P> </TMPL_LOOP>
En temps normal ceci ne pourrait pas fonctionner de cette manière, tant que la valeur <TMPL_VAR NORMAL> hors de la boucle n'est pas disponible dans celle-ci.
L'option global_vars vous permet bien sûr d'accéder aux valeurs d'une boucle qui en contient une autre. Par exemple, dans cette boucle la boucle interne aura accès à la valeur de OUTER_VAR correctement :
<TMPL_LOOP OUTER_LOOP> OUTER: <TMPL_VAR OUTER_VAR> <TMPL_LOOP INNER_LOOP> INNER: <TMPL_VAR INNER_VAR> INSIDE OUT: <TMPL_VAR OUTER_VAR> </TMPL_LOOP> </TMPL_LOOP>
NOTE : global_vars
n'est pas global_loops
(qui n'existe pas).
Cela signifie que les boucles que vous déclarez à un niveau ne sont pas disponibles
dans d'autres boucles même si global_vars
est actif.
Dans le cas le plus courant, vous assignez simplement un code de référence au paramètre de filtre. Ce sous-programme recevra un seul argument - une référence à une chaîne contenant le texte du fichier modèle. Voici un exemple qui accepte les modèles avec les balises qui ressemblent à ``!!!ZAP_VAR FOO!!!'' et qui les transforme en balises HTML::Template :
my $filter = sub { my $text_ref = shift; $$text_ref =~ s/!!!ZAP_(.*?)!!!/<TMPL_$1>/g; };
# ouvre zap.tmpl en utilisant le filtre ci-dessus my $template = HTML::Template->new(filename => 'zap.tmpl', filter => $filter);
Des usages plus complexes sont possibles. Vous pouvez demander que votre filtre reçoive les textes modèles comme un tableau de lignes plutôt que comme une variable scalaire. Pour faire cela vous devez spécifier votre filtre en utilisant une référence à un tableau associatif. De cette manière vous spécifiez le filtre en utilisant la clé ``sub'' et le format de l'argument désiré en utilisant la clé ``format''. Les formats disponibles sont ``scalar'' et ``array''. Utiliser le format ``array'' inclut une baisse de performance mais peut être plus pratique dans certains cas.
my $template = HTML::Template->new(filename => 'zap.tmpl', filter => { sub => $filter, format => 'array' });
Vous pouvez aussi utiliser des filtres multiples. Cela permet à de simples filtres d'être combinés pour des fonctionnalités plus élaborées. Pour faire cela vous spécifiez un tableau de filtres. Les filtres sont appliqués dans l'ordre où ils sont spécifiés.
my $template = HTML::Template->new(filename => 'zap.tmpl', filter => [ { sub => \&decompress, format => 'scalar' }, { sub => \&remove_spaces, format => 'array' } ]);
Les filtres spécifiés seront appelés pour n'importe quel fichier ``TMPL_INCLUDE'' s'ils sont pour le fichier modèle principal.
param()
param()
peut être appelé dans de nombreux cas
1) Pour renvoyer une liste de paramètres dans le modèle :
my @parameter_names = $self->param();
2) Pour renvoyer la valeur attribuée à un paramètre :
my $value = $self->param('PARAM');
3) Pour donner une valeur à un paramètre :
# Pour de simples variables TMPL_VAR: $self->param(PARAM => 'value');
# avec une référence à un sous-programme qui sera appelé pour donner la valeur # du scalaire. Le sub recevra l'objet du modèle comme un # paramètre. $self->param(PARAM => sub { return 'value' });
# Et les TMPL_LOOPs: $self->param(LOOP_PARAM => [ { PARAM => VALUE_FOR_FIRST_PASS, ... }, { PARAM => VALUE_FOR_SECOND_PASS, ... } ... ] );
4) Pour donner une valeur à plusieurs paramètres :
# Pour de simples variables TMPL_VAR: $self->param(PARAM => 'value', PARAM2 => 'value' );
# Et pour des TMPL_LOOPs: $self->param(PARAM => 'value', PARAM2 => 'value', LOOP_PARAM => [ { PARAM => VALUE_FOR_FIRST_PASS, ... }, { PARAM => VALUE_FOR_SECOND_PASS, ... } ... ], ANOTHER_LOOP_PARAM => [ { PARAM => VALUE_FOR_FIRST_PASS, ... }, { PARAM => VALUE_FOR_SECOND_PASS, ... } ... ] );
5) Pour donner la valeur à un nombre de paramètres en utilisant une référence à tableau associatif :
$self->param( { PARAM => 'value', PARAM2 => 'value', LOOP_PARAM => [ { PARAM => VALUE_FOR_FIRST_PASS, ... }, { PARAM => VALUE_FOR_SECOND_PASS, ... } ... ], ANOTHER_LOOP_PARAM => [ { PARAM => VALUE_FOR_FIRST_PASS, ... }, { PARAM => VALUE_FOR_SECOND_PASS, ... } ... ] } );
clear_params()
Mets tous les paramètres à undef. Utile en interne, pas ailleurs !
output()
output()
renvoie le résultat final du modèle. Dans beaucoup de cas
vous voudrez l'afficher, comme ça :
print $template->output();
Quand ouput est appelé chaque occurrence de <TMPL_VAR NAME=name> est remplacé avec la valeur attribué à ``name'' via param(). Si un paramètre nommé n'est pas renseigné il est simplement remplacé par ''. Les <TMPL_LOOPS> sont évalués une fois par paramètre renseigné, accumulant l'affichage à chaque passage.
Appeler output()
garantie de ne rien changer à l'état de
l'objet Template, au cas vous vous demandiez. Cette propriété est la plus importante
pour le fonctionnement inter des boucles.
Vous pouvez éventuellement utiliser un handle de ficher pour afficher dynamiquement au fur et à mesure que le modèle est généré. Cela peut améliorer les performance et moins de consommation de mémoire. Exemple :
$template->output(print_to => *STDOUT);
La valeur de retour est indéfinie quand on utilise l'option ``print_to''.
query()
Cette méthode vous permet d'obtenir des informations à propos de la structure du modèle.
Elle peut être appelée dans un certains nombre de cas. L'usage le plus courant de query est
tout simplement de vérifier si un nom de paramètre existe dans un modèle, en utilisant
l'option name
:
if ($template->query(name => 'foo')) { # Faire quelque chose si une variable de n'importe quel type # appelée FOO est dans le modèle }
Ce même usage renvoie le type du paramètre. Le type est la même chose que la deuxième partie dans une balise 'TMPL_'. Donc, par exemple, un paramètre TMPL_VAR renvoie 'VAR' dans query().
if ($template->query(name => 'foo') eq 'VAR') { # faire quelque chose si FOO existe et si c'est un TMPL_VAR }
Notez que les variables associées à des TMPL_IF et TMPL_UNLESS seront reconnues comme des 'VAR' sauf si elles sont également utilisées dans un TMPL_LOOP, dans quel cas elles renverront 'LOOP'.
query()
vous permet aussi d'obtenir une liste de paramètres dans une boucle
(et dans les boucles dans les boucles). Exemple de boucle :
<TMPL_LOOP NAME="EXAMPLE_LOOP"> <TMPL_VAR NAME="BEE"> <TMPL_VAR NAME="BOP"> <TMPL_LOOP NAME="EXAMPLE_INNER_LOOP"> <TMPL_VAR NAME="INNER_BEE"> <TMPL_VAR NAME="INNER_BOP"> </TMPL_LOOP> </TMPL_LOOP>
Et dans des appels à query :
# renvoie 'LOOP' $type = $template->query(name => 'EXAMPLE_LOOP');
# renvoie ('bop', 'bee', 'example_inner_loop') @param_names = $template->query(loop => 'EXAMPLE_LOOP');
# les deux renvoient 'VAR' $type = $template->query(name => ['EXAMPLE_LOOP', 'BEE']); $type = $template->query(name => ['EXAMPLE_LOOP', 'BOP']);
# et celui-ci renvoie 'LOOP' $type = $template->query(name => ['EXAMPLE_LOOP', 'EXAMPLE_INNER_LOOP']);
# et finalement, ceci renvoie ('inner_bee', 'inner_bop') @inner_param_names = $template->query(loop => ['EXAMPLE_LOOP', 'EXAMPLE_INNER_LOOP']);
# pour les noms de paramètres inexistants vous obtenez undef # ceci renvoie undef. $type = $template->query(name => 'DWEAZLE_ZAPPA');
# appeler une boucle avec un nom de paramètre ne correspondant pas à une boucle renverra une erreur. # celui-là plante: $type = $template->query(loop => 'DWEAZLE_ZAPPA');
Comme vous pouvez voir au-dessus l'option loop
renvoie une liste de noms de paramètres
et les deux name
et loop
prennent des références de tableaux pour se rapporter
aux paramètres dans les boucles. C'est une erreur d'utiliser loop
avec un
paramètres qui n'est pas une boucle.
Notez que tous les noms sont renvoyés en minuscule et les types en majuscule.
Tout comme param()
, query()
sans argument renvoie tous les noms
de paramètre dans le modèle de premier niveau.
Dans l'intérêt d'une meilleure compréhension j'ai commencé une section FAQ des perldocs. Merci de regarder ici avant de m'envoyer un email.
Réponse : Il y a une mailing-liste causant de HTML::Template à html-template-users@lists.sourceforge.net. Pour nous rejoindre :
http://lists.sourceforge.net/lists/listinfo/html-template-users
Si vous voulez seulement recevoir un email quand les nouvelles versions sont disponibles vous pouvez rejoindre la mailing-liste des annonces ici :
http://lists.sourceforge.net/lists/listinfo/html-template-announce
Réponse : Oui, vous pouvez trouver une archive de la liste SourceForge ici :
http://www.geocrawler.com/lists/3/SourceForge/23294/0/
Pour une archive de la vieille liste vm.com, montée par Sean P. Scanlon, voyez :
http://bluedot.net/mail/archive/
Réponse : Peut-être. J'encourage les gens à discuter de leurs idées pour HTML::Template sur la mailing-liste. Soyez prêts à m'expliquer comment une nouvelle balise peut s'adapter dans la mission d'HTML::Template de fournir un système rapide et léger pour utiliser des modèles HTML.
NOTE : Proposer de programmer un ajout et le fournir sous la forme d'un patch à la plus récente version d'HTML::Template aura certainement un un effet de ramollissement de la part d'opposants éventuels !
Réponse : Ça dépend. Est-ce que vous m'avez envoyé la VERSION d'HTML::Template, un script de test et un fichier de test ? Si oui, alors probablement.
Si vous êtes vraiment aventureux, HTML::Template a un serveur CVS disponible au public. Voyez plus bas pour plus d'informations dans la section SERVEUR CVS PUBLIC.
Réponse : C'est le comportement attendu. <TMPL_LOOP> présente une portée séparée pour les <TMPL_VAR> un peu comme un appel à un sous-programme dans Perl présente une portée séparée pour les variables ``my''.
Si vous voulez que vos <TMPL_VAR> aient une portée globale, vous pouvez activer l'option 'global_vars' quand vous appelez new(). Voyez plus haut pour la documentation l'option 'global_vars' de new().
Réponse : Simple - le switch de recherche non sensible à la casse est très inefficace.
A en croire _Maitrise_des_Expressions_Régulières_ de chez O'Reilly,
/[Tt]/ est plus rapide et plus économe de mémoire que /t/i - d'environ le double
pour les chaînes longues. //i fait surtout un lc()
sur la chaîne
et garde une copie temporaire en mémoire.
Dès que ça change, et c'est dans les séries de développement 5.6, je serais ravi d'utiliser //i. Croyez moi, je sais que [Tt] est affreusement laid.
Réponse : Ajoutez quelque chose comme ça dans votre startup.pl :
use HTML::Template; use File::Find;
print STDERR "Pré-chargement des modèles HTML...\n"; find( sub { return unless /\.tmpl$/; HTML::Template->new( filename => "$File::Find::dir/$_", cache => 1, ); }, '/path/des/modeles', '/path/des/autres/modèles/' );
Notez que vous devrez modifier la ligne ``return unless'' pour spécifier l'extension que vous utilisez pour vos fichiers modèle - j'utilise .tmpl, comme vous pouvez voir. Vous aurez aussi besoin de spécifier le path de vos fichiers modèles.
Un problème potentiel : le ``/path/des/modeles/'' doit être EXACTEMENT le même path que vous utilisez quand vous appelez HTML::Template->new(). Sinon le cache ne saura pas qu'ils sont le même fichier et chargera une nouvelle copie - au lieu d'avoir un gain de rapidité, vous doublerez votre utilisation mémoire. Pour vérifier si c'est bon mettez cache_debug => 1 dans votre code applicatif et regardez pour les messages ``CACHE MISS'' dans les logs.
Réponse : Nombres, lettres, '.', '/', '+', '-' and '_'.
Réponse : Réponse courte : vous ne pouvez pas. Réponse longue : vous ne devez pas puisque que cela viole le concept fondamental de HTML::Template - que le design et le code doivent être séparés.
Mais, inévitablement des gens veulent toujours faire ça. Si cela vous décrit vous devez regarder HTML::Template::Expr. En utilisant HTML::Template::Expr il sera facile d'écrire une une fonction run_program(). Et là vous pouvez faire des choses bien moches comme :
<tmpl_var expr="run_program('foo.pl')">
Seulement, merci de ne pas m'en parler. Je me sens déjà assez coupable d'avoir écrit HTML::Template::Expr.
Réponse : Oui vous pouvez. Voyez la traduction de Kawai Takanori à :
http://member.nifty.ne.jp/hippo2000/perltips/html/template.htm
Réponse : Il y a beaucoup de désaccords là-dessus. Ma préférence personnelle
est d'utiliser les excellentes fonctions excellent popup_menu()
et scrolling_list()
de CGI.pm pour remplir une simple variable <tmpl_var select_foo>.
Pour certaines personnes cela représente un mélange d'HTML et de code dans le sens où ils espéraient que HTML::Template allait les aider. Pour eux je voudrais dire que HTML est une violation du principe de séparation du design et de la programmation. Il n'y a pas de séparation claire entre les éléments de programmation des balises <form> et l'affichage des balises <form>. Vous devrez dessiner votre limite quelque part - clairement le designer ne peut pas être entièrement responsable de la création des formulaires.
Il y a un débat et vous devez peser le pour et le contre. Il est certainement possible de produire un élément <select> entièrement dans le modèle. Ce que vous devez obtenir est un mélange de boucles et de conditions. A côté de ça vous pouvez renoncer à une certaine flexibilité en échange de la simplification de vos modèles. Je choisis généralement cette dernière solution.
Une autre option est d'utiliser HTML::FillInForm qui a trouvé un certain succès pour résoudre ce problème.
Je suis à l'affût de tout bug - si vous en trouvez un, rejoignez la mailing-liste et parlez nous-en. Vous pouvez rejoindre la mailing-liste HTML::Template en visitant :
http://lists.sourceforge.net/lists/listinfo/html-template-users
Bien sûr, vous pouvez toujours m'envoyer un email directement (sam@tregar.com) avec les bugs, mais je me réserver le droit de faire suivre ces rapports de bug à la mailing-liste.
Quand vous envoyez des rapports de bug, soyez sûr d'inclure tous les détails, en incluant la VERSION du module, un script de test et un modèle de test pour montrer le problème !
Si vous êtes vraiment aventureux, HTML::Template a un serveur CVS disponible au public. Voyez plus bas pour plus d'informations dans la section SERVEUR CVS PUBLIC.
Ce module est le résultat de la réflexion de mon chef, Jesse Erlbaum ( jesse@vm.com ) chez Vanguard Media ( http://vm.com ) . La plus grand partie de l'idée d'origine dans ce module - le <TMPL_LOOP> - est entièrement de lui.
Les Fixes, Rapports de Bug, Optimisations et Idées ont été généreusement fournies par :
Richard Chen Mike Blazer Adriano Nagelschmidt Rodrigues Andrej Mikus Ilya Obshadko Kevin Puetz Steve Reppucci Richard Dice Tom Hukins Eric Zylberstejn David Glasser Peter Marelas James William Carlson Frank D. Cringle Winfried Koenig Matthew Wickline Doug Steinwand Drew Taylor Tobias Brox Michael Lloyd Simran Gambhir Chris Houser <chouser@bluweb.com> Larry Moore Todd Larason Jody Biggs T.J. Mather Martin Schroth Dave Wolfe uchum Kawai Takanori Peter Guelich Chris Nokleberg Ralph Corderoy William Ward Ade Olonoh Mark Stosberg Lance Thomas Roland Giersig Jere Julian Peter Leonard Kenny Smith Sean P. Scanlon Martin Pfeffer David Ferrance Gyepi Sam Darren Chamberlain Paul Baker Gabor Szabo Craig Manley
Merci beaucoup !
Vous pouvez trouver de l'information à propos d'HTML::Template et d'autres modules du genre à :
http://html-template.sourceforge.net
HTML::Template a désormais un serveur CVS publiquement accessible fourni par SourceForge (www.sourceforge.net). Vous pouvez y accéder en allant à http://sourceforge.net/cvs/?group_id=1075. Allez y jeter un oeil !
Sam Tregar, sam@tregar.com
HTML::Template : un module pour utiliser des modèles HTML avec Perl
Copyright(C)
2000-2002 Sam Tregar (sam@tregar.com)
This module is free software; you can redistribute it and/or modify it under the terms of either:
a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version,
or
b) the ``Artistic License'' which comes with this module.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the Artistic License for more details.
You should have received a copy of the Artistic License with this module, in the file ARTISTIC. If not, I'll be glad to provide one.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA