comprendre les bases d'un framework en PHP


CV web  - precedent    sommaire    suivant   


V. Moteur de template
V-A. Introduction
V-B. Chargement du fichier
V-C. Fonction affiche
V-D. Conclusion


V. Moteur de template


V-A. Introduction

Bien que nous ayons vu brièvement une définition de ce qu'est un moteur de template, il peut être sage de s'y arrêter un moment :
Leur utilisation divise le monde informatique : certains crient a l'hérésie, a la perte de performance... Si le sujet vous intéresse vous pouvez lire un article en ici ou bien fr la
Si ces pages n'existent plus, une simple recherche google, comme toujours, vous permettra de trouver de nombreux fils de discussion a ce sujet, et de, pourquoi pas, vous faire votre propre idée.
Une dernière mise en garde : les moteur de template sont décriés, entre autre, car ils entraînent une baisse de performance, en cas, je peut vous assurer que celui que vous allez voir n'est en aucuns cas optimisé, il n'a aucune autre prétention que d'être un outil didactique. Si vous décidez de l'utiliser, vous en avez bien sur le droit, mais c'est a vos risques et périls (comme pour tout le reste du programme ;p )



V-B. Chargement du fichier

La première fonction est loin d'être la plus complexe : nous allons tout simplement ouvrir le fichier HTML contenant le template.
fonction chargeTemplate()
function chargeTemplate($fichier) {

	//on ouvre le fichier, et on affiche pas d'erreure si elle arrive : renvoyer null suffit!
    if (! $file = @file_get_contents($fichier)) {
		$file = null;
    }
	$file = ouvreSousFichiers($file);
    return $file;
}
Seule une fonction doit vous poser problème : ouvreSousFichiers() : nous allons voir tout de suite son code :
fonction ouvreSousFichiers()
function ouvreSousFichiers(&$template) {
	//definnition du motif de recherche :
	$motif = "\[ *fileOpen *; *([[:alnum:]_/]*) *\]";   //ex : "[ fileOpen; toto]"
	while ( eregi($motif, $template, $balises)) {
        //on stocke la balise pour la remplacer plus tard
	    $balise = $balises[0]; 
        $nomFichier = "templates/" . $balises[1] . ".html";
		if (! $file = @file_get_contents($nomFichier) ) {
			dbgStore("Erreure, le fichier a inserer dans le template n'a pas put etre ouvert : " 
				. $nomFichier, TEMPLATE);
			return $template;
		}
		$template = str_replace($balise, $file, $template) ; 
	}   
	return $template;
}
Ici, ça commence a se corser! Mais accrochez vous, tout le reste du code va se voir truffé de ce mystérieux eregi Et toute la difficulté consiste a comprendre la signification de la chaîne qui lui est passée en paramètre :
"\[ *fileOpen *; *([[:alnum:]_/]*) *\]"; //ex : "[ var; toto]"
cette chaîne est une
expression régulière POSIX

Les expressions régulières sont un langages a elles seules, elles servent a codifier de façon très puissante une chaîne de caractère a rechercher, de nombreux tutoriaux sont disponibles a leur sujet, en voici quelques uns :

  • document très clair de cyberzoïde : fr lien
  • définition du dico des développeurs : lien
  • un document de l'l'université de creteil : lien
De nombreuses autres sources existent, cependant, le premier lien fournit devrait être suffisant, si vous le lisez avec attention. Nous n'allons pas nous attarder sur ce domaine, sachez juste que :

  • "/[" : est un échappement du caractère "[" qui a une signification particulière
  • "*" : signifie que le caractère précédent doit être présent de 0 a n fois
  • "[]" : indique une liste, tout caractère présent dans cette liste est acceptable, de plus, les crochets peuvent êtres imbriqués.
  • "[:alnum:]" : est un alias pour alpha numérique ce qui signifie, bien entendu que tout caractère alpha numérique doit être accepté,
  • "[[:alnum:]_/]*" : signifie donc "de 0 a n fois peuvent être présent : a-zA-Z0-9_/"

Ainsi, le programme agit de la sorte :
tant q'une balise correspondant a l'expression régulière est trouvée, on ouvre le fichier HTML correspondant, et on remplace (cf : str_replace() ) la balise par le fichier ouvert.



Passons a la fonction suivante :


V-C. Fonction affiche

Cette fonction est la dernière du moteur appelée, au cours de l'exécution, d'autres fonction vont être exécutées, cependant, au vue de leur complexité, mieux vaut les voir en dernier.
Le principe de cette fonction est très simple :
elle va effectuer une substitution des balises de type :

[var;nomDeVariable]

avec nomDeVariable qui est un nom de variable globale de PHP.
Ensuite, un simple echo va permettre d'afficher le template sur la sortie standard (l'envoyer au client) :
focntion affiche
function affiche(&$template) {
    //definition du motif des balises fixes
    $motif = "\[ *var *; *([[:alnum:]_]*) *\]";  //ex : "[ var; toto]"
    
    //on charge les balises dans le tableau balises	
    while ( eregi($motif, $template, $balises)) {
    
        //on stocke la balise pour la remplacer plus tard
	    $balise = $balises[0]; 
        $variable = $balises[1];
        
		if (isset($GLOBALS[$variable])) {
		        
			dbgStore("On va substituer $balise par {$variable} qui possede la valeur : {$GLOBALS[$variable]}",
				TEMPLATE);
			$template = str_replace($balise, $GLOBALS[$variable], $template) 
				or die("erreure lors de l'insertion du substitu : non trouvé");
				
		} else {		
			dbgStore("La variable globale '$variable' n'a pas ete trouvée..." .
				" On la remplace par ''", TEMPLATE);
			$template = str_replace($balise, "", $template) 
				or die("erreure lors de l'insertion du substitu : non trouvé");				
		}	
    }	
    
    //on envoie le template sur la sortie standard
    echo $template;
}
plus qu'une fonction, et vous retrouvez votre liberté! Mais attention, c'est une fonction championne! Si vous avez eu du mal a comprendre les codes précédents accrochez vous!
Afin de faciliter votre travail, nous allons l'étudier pas a pas.
Tout d'abord, son but : remplacer une série de "blocs" situés dans le template HTML par le résultat d'une requête au serveur MySQL.
le "bloc" se présentera ainsi :
exemple d'un bloc a substituer
<ul>
	<li>
		[bloc1;block = li]
		nom : [bloc1; nom], <br />
		prénom : [bloc1; prenom ] ,<br />
		adresse : [ bloc1 ;adresse]
	</li>
</ul>
ce code est composé de deux types de balises :
le premier type définit quelle est l'étendue du code HTML a répéter : ici le tag "li"
le second informe le programme sur la colonne (du résultat de la requête SQL) qui doit remplacer notre balise.



Etudions le code qui permet de trouver le code HTML a dupliquer :
function mergeDyn($indexBalise, $resultQuery) {
    global $template; 
    dbgStore("on est dans MergeDyn", TEMPLATEDYN);
	
    $motifBaliseBlock = "\[ *$indexBalise *; *block *= *([[:alnum:]]+) *\]";
		//ex : "[ balise1; block= toto]"
    eregi($motifBaliseBlock, $template, $blockNom);   
    
	$baliseMere = $blockNom[0];  //recuperation de la balise correspondante trouvée 		
    $blockNom = ($blockNom[1]);
    $blockDebut = "<" . $blockNom . ">";
    $blockFin = str_replace("<", "<\/", $blockDebut);  
	
	dbgStore("Balise mere : '$baliseMere'", TEMPLATEDYN);
la variable $motifBaliseBlock contient la chaîne de recherche, elle est du type : "[ $indexBalise; block = blocHTML]" $indexBalise est une variable passée en paramètre.
La fonction eregi retourne un tableau, dont :
le premier élément est la balise trouvée (dans notre exemple, ce serait [bloc1;block = li])
le second élément est le tag HTML correspondant a la portée du bloc (dans notre exemple : "li") celui ci est fournit par eregi grâce aux parenthèses entourant ([[:alnum:]]+) qui spécifient que cet élément doit aussi être retourné individuellement.

A partir de ces données, le programme renseigne les variables $blockDebut et $blockFin.


la fonction continue en effectuant ce traitement :
trouver tout le bloc HTML
    //extraction du block defini dans la balise extraite
    $motifBlock = "/$blockDebut(.(?<!$blockDebut))*\[ *$indexBalise *; *block *= *$blockNom *\]
		.*$blockFin/sU"; 
	//ex : "<li>.\[ *testBDD *; *block *= *([[:alnum:]]+)* *]\].</li>"       
    dbgStore("Motif de recherche du block : $motifBlock", TEMPLATEDYN);
	preg_match($motifBlock, $template, $block);
    $block = $block[0];
    dbgStore("Bloc de travail : $block", TEMPLATEDYN);
Le bloc HTML global (celui de notre exemple) est trouvé a partir des données trouvées plus haut.
la séquence :
$blockDebut(.(?<!$blockDebut))*
signifie : "trouver le dernier bloc de début (ici <li>) avant la suite du motif.
Un exemple peut être plus parlant :
exemple
<ul>
	<li>
		texte a ne pas prendre en compte
	</li>
	<li>
		[bloc1; block = li]
		...
	</li>
</ul>
Dans cet exemple, si nous n'avions pas mis
$blockDebut(.(?<!$blockDebut))*
le "texte a ne pas prendre en compte" aurait été compris dans le motif... Une fois le motif créé, la fonction preg_match() s'occupe de récupérer le bloc HTML entier allant de <li> a </li>.
la variable $block contient ce bloc.


ensuite, cette série d'instruction est suivie :
remplacement des secondes balises
	//recherche de toutes les sous balises, et remplacement par leur equivalent BDD
    $motifSousBalises = "/\[ *$indexBalise *; *([[:alnum:]_]+) *\]/";
    preg_match_all($motifSousBalises, $block, $SousBalises, PREG_SET_ORDER);    
    $mergedBlock = "";
    
	//interrogation de la base, a partir de la ressource recue en parametre
    while ($row = mysql_fetch_array($resultQuery, MYSQL_BOTH ) ) { 
	
	//boucle de duplication par les valeur BDD

    $blockEntraitement = $block;

        foreach ($SousBalises as $SousBalise) {      		
            $blockEntraitement = str_replace($SousBalise[0],$row[$SousBalise[1]], 
				$blockEntraitement); 
	    }	
		
        $mergedBlock .= $blockEntraitement;
    }
De nombreux traitements s'enchaînent ici :

Dorénavant, vous devez être habitués aux expressions régulières ainsi, le début ne doit pas vous poser de problème : définition du motif des sous blocs, puis leur recherche. Le tableau $SousBalises contiendras toutes les occurrences trouvées. Ensuite, la base de donnée est interrogée a l'aide d'une ressource de requête passée en paramètre.
Tant qu'il existe des réponse de la part de la base non lues, chaque sous balise est passée en revue et est remplacé par la colonne correspondante :
tout comme précédemment,

"/\[ *$indexBalise *; *([[:alnum:]_]+) *\]/"

comporte une parenthèse permettant d'isoler la chaîne située après le ";" (ex : dans [bloc1; nom], la chaîne "nom" sera isolée et remplacée par une colonne de la requête s'appelant "nom". au fur et a mesure, $mergedBlock se voit remplit des résultats de la base, tout en gardant la mise en forme originale (tags <li>...).


V-D. Conclusion

Voila, notre programme est terminé, il est apte a accueillit un site en PHP, et d'offrir a son auteur un support de tous les concepts évoqués plus haut.


CVweb de l'auteurprecedent    sommaire    suivant   

 

Les sources présentés sur cette pages sont libre de droits, et vous pouvez les utiliser à votre convenance. Par contre cette page de présentation de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright ©2006 . 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'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérets. .

Cet article devait etre a la base publié sur www.developpez.com