[php4.3.x-domxml]-creation d'un moteur de template grace a domxml

Soyez le premier à donner votre avis sur cette source.

Vue 7 221 fois - Téléchargée 229 fois

Description

Ce code est un banal moteur de template mais utilisant domxml pour arriver a parser les blocks et les variables. Ce n'est pas vraiment un moteur de template fonctionnel car le temps d'execution est assez catastrophique par rapport a d'autres mais il n'est la que pour l'apprentissage des fonctions DOM. Ayant recu pas mal de mp concernant la manipulation d'elements xml en php4 j'ai decide de poster cette source.
J'ai essaye de commenter le plus possible mais si il reste des parties obscures, n'hesitez pas, contactez moi !
Idem en ce qui concerne les bugs, le code est loin d'etre parfait ^^

Source / Exemple :


<?php
	/*
		Class DOMXMLEngine: Moteur de template
		5 fonctions :
		- Constructeur
			-> Indispensable lors de la creation de la nouvelle instance de la classe
		- SetTemplate()
			-> C'est la fonction qui fait tout. Suivant les parametres, elle va cherche une variable ou un block. Elle gere 
		parfaitement les block imbriques. Les balises : 

  • variable : <engine type="var" name="..." />
  • block : <engine type="block" name="...">...</engine>
  • variable de block : <engine type="var_of_block" name="..." />
- ParseBlock() -> Pas la peine de l'appeler directement, c'est SetTemplate() qui s'en occupe tout seul (elle prend en param un noeud en plus donc mieux vaut la laisser :p) - SetLog() -> Cree un fichier log propre au moteur afin d'y repertorier les eventuelles erreurs. Le moteur s'en charge tres bien tout seul egalement ^^ - Display() -> Affiche le modele une fois traite Auteur : IoNAce allias(jean84) Mail : ionace@c4.fr PHP : 4.3.x (minimum, en dessous il y aura des bugs) Lib annexe : DOMXML Version : 1.0
  • /
class DOMXMLEngine { /* Handle interne permettant de n'ouvrir qu'une seul fois le fichier est d'en faire profiter toute la classe
  • /
var $Handle; /* Contient le nom et le chemin complet du fichier log interne au moteur
  • /
var $Logs; /* Constructeur de la classe Param 1 : $Modele -> Nom du fichier a modele a charger (le fichier contenant les variables et les blocks a traites) Param 2 : $LogFile -> Nom et chemin du fichier log (en cas d'erreur du moteur). Par defaut, surcharge avec la valeur error.log Param 3 : $DebugEngine -> Active ou desactive le rapport d'erreur de php. -> Par defaut, regle a false (rapport desactive)
  • /
function DOMXMLEngine($Modele=NULL, $LogFile='error.log', $DebugEngine=FALSE) { // Descativation du rapport d'erreur de PHP if ( $DebugEngine ) error_reporting(0); // On affecte la valeur transmise a $LogFile a la classe $this->Logs = $LogFile; // Si aucun modele n'a ete transmis if ( $Modele === NULL ) $this->SetLog('Contructeur', 'Aucun modele transmis en parametre', TRUE); else $this->NameOfModele = $Modele; // Nouveau document domxml $this->Handle = domxml_open_file($Modele); // On verifie si le document a bien ete charge if ( $this->Handle === FALSE ) $this->SetLog('Constructeur', 'Chargement du modele '.$Modele.' echoue', TRUE); } /* Cette fonction gere a la fois les variables et les blocks (donc les variables propres aux blocks egalement ^^). La fonction (recursive) cherche a parcourir tous les noeuds qu'elle rencontre. Petite particularite : pour simplifier le traitement, le parsage des blocks est effectue dans une autre fonction qui s'occupera seule du traitement. Param 1 : $Name -> Nom de la variable ou du block a remplacer Param 2 : $Value -> Valeur de rempalcement. Si $Type correspond a un block, --> $Value est un tableau avec pour index le nom des variables a rempalcer Param 3 : $Type -> false = on recherche une variable -> true = on recherche un block
  • /
function SetTemplate($Name=NULL, $Value=NULL, $Type=NULL) { // Si il manque un parametre (ou plusieurs) if ( $Name === NULL || $Value === NULL || $Type === NULL ) { return $this->SetLog( 'SetTemplate', 'Parametres d\'appel manquant.'."\n".'$Name = '.$Name."\n".'$Value = '.$Value."\n".'$Type = '.$Type."\n", FALSE, // on arrete pas l'appli FALSE // on affiche rien a l'ecran ); } // Recupere toutes les balises destinee au moteur $Array = $this->Handle->get_elements_by_tagname('engine'); // On parcours le tableau $NbrOfCases = count($Array); for ( $i=0; $i<$NbrOfCases; $i++ ) { $NodeObject = $Array[$i]; // On cherche une variable if ( !$Type ) { // Regarde si on a trouve la balise qu'on cherchait if ( ($NodeObject->get_attribute('type') == 'var') && ($NodeObject->get_attribute('name') == $Name) ) { // On cree un nouveau noeud texte $TextNode = $this->Handle->create_text_node($Value); // On remplace le noeud courant par le nouveau $NodeObject->replace_node($TextNode); } } elseif ( $Type ) { // Test si le block correspond bien a ce que l'on cherche et que ce n'est pas un noeud clone // On met les valeurs des attributs dans des variables car il y a pas mal d'erreurs de parsage // --> si on les mets compare directement dans le if() (j'ai aps encore compris pourquoi ...) $Type = $NodeObject->get_attribute('type'); $NameOfBlock = $NodeObject->get_attribute('name'); $Cloned = $NodeObject->get_attribute('cloned'); if ( ($Type == 'block') && ($NameOfBlock == $Name) && empty($Cloned) ) { // On recherche le parent $ParentNode = $NodeObject->parent_node(); // Copy du noeud en cours $ClonedNode = $NodeObject->clone_node(TRUE); // On marque le noeud pour indiquer que c'est un clone $ClonedNode->set_attribute('cloned', 'true'); // On envoi au parser $this->ParseBlock($Value, $ClonedNode); // Ajout au parent du noeud original $ParentNode->append_child($ClonedNode); } } } } /* La fonction cherche a travers le noeud les balises <engine type="var_of_block" name="$Name" />. Param 1 : $Name -> Nom de la variable ou du block a remplacer Param 2 : $Node -> Noeud transmis par SetTemplate() juste apres l'avoir clone
  • /
function ParseBlock($ArrayOfValues=NULL, $Node=NULL) { if ( $ArrayOfValues === NULL || $Node === NULL ) return; // On parcours le premier tableau foreach ( $ArrayOfValues as $Balise => $Value ) { // Recupere toutes les balises <engine> $Array = $Node->get_elements_by_tagname('engine'); // Parcours le tableau transmis $NbrOfCases = count($Array); for ( $i=0; $i<$NbrOfCases; $i++ ) { // On verifie que se sont des variables pour le block (type="var_of_block") et qu'elle correspond a $Balise if ( $Array[$i]->get_attribute('type') == 'var_of_block' && $Array[$i]->get_attribute('name') == $Balise ) { // Creation d'un noueau noeud text $TextNode = $this->Handle->create_text_node($Value); // On remplace ... $Array[$i]->replace_node($TextNode); } } } } /* Rajoute une entree dans le fichier log propre au moteur. Si le fichier n'existe pas, il est cree Param 1 : $Methode -> Methode (fonction) qui renvoie l'erreur Param 2 : $ErrorValue -> La descrition de l'erreur Param 3 : $StopExecution -> Si cette variable est mise a true, la fonction arretera l'execution du moteur --> apres avoir traite le fichier log Param 4 : $DisplayError -> Si a true, on affiche un message prevenant l'utilisateur qu'il y a eu une erreur. Sinon on dit rien ^^
  • /
function SetLog($Methode=NULL, $ErrorValue=NULL, $StopExecution=FALSE, $DisplayError=TRUE) { // Ouverture du fichier $File = fopen($this->Logs, 'a+'); if ( $File === FALSE ) die('Erreur pendant l\'ouverture du fichier log.<br />'); // Preparation du texte a ecrire $Date = date('\[\l\e d/m/Y\ \à H\h:i\m:s\s]'); $Texte = $Date."\n".'- DOMXMLEngine::'.$Methode.'() a renvoye une erreur :'."\n".$ErrorValue."\n"; $Texte .= '- Adresse IP de la connexion : '.$_SERVER['REMOTE_ADDR']."\n"; $Texte .= '- Navigateur & OS : '.$_SERVER['HTTP_USER_AGENT']."\n"; $Texte .= '_________________'."\n\n"; // Ecriture dans le fichier $Result = fwrite($File, $Texte, strlen($Texte)); if ( $Result === FALSE ) die('Erreur pendant l\'ecriture du fichier log.<br />'); // Fermetture du Handle fclose($File); // On informe qu'il y a eu une erreur if ( $DisplayError ) echo $Date, '<br />Il y a eu une erreur interne. Consulter le fichier log.'; // Si StopExecution est a true, on arrete l'execution du script if ( $StopExecution ) exit(); else return false; } /* Cette fonction affiche le contenu du modele une fois le traitement realise. A appeller uniquement a la fin !! Aucun param
  • /
function Display() { /* Commme lors du parsage d'un block on ne modifie que les enfants du noeud, on ne peut pas se permettre d'effacer tout le noeud sinon on aurait travaille pour rien. On est oblige de trouver les noeuds modele pour les effacer (ansi que leurs contenu, chose qui n'aurait pas pu etre possible avec une regex)
  • /
// En premier on efface le(s) block(s) modele(s) (ce(eux) qui a/ont ete clone(s)) $Array = $this->Handle->get_elements_by_tagname('engine'); // Recupere le nombre de case et parcours le tableau $NbrOfCases = count($Array); for ( $i=0; $i<$NbrOfCases; $i++ ) { $Node = $Array[$i]; // Recupere les attributs voulus $Type = $Node->get_attribute('type'); $Cloned = $Node->get_attribute('cloned'); // Test des resultats pour savoir si on efface ou pas if ( ($Type == 'block') && empty($Cloned) ) { // On efface le noeud $Node->unlink_node(); } } // Pour virer les balises restantes (les var qui n'ont pas ete remplace et les contenueur des blocks clones), on // -- cree une regex permettant de tout virer $Regex = '`(<engine.+/?>)|(</engine>)`i'; echo preg_replace($Regex, '', $this->Handle->html_dump_mem(FALSE, 'iso-8859-1')); } } ?>

Conclusion :


Je tiens a preciser que votre version de php doit etre obligatoirement la 4.3 (voir au dessus mais evidement en dessous de la 5) car sinon, il risque (c'est meme certains) d'y avoir des bugs en cascade (d'apres la doc officielle, certaines fonctions renvoient des valeurs FALSE ou TRUE alors que dans les versions precedentes, elles renvoyaient des valeurs differentes qui ne seront evidement pas comprises par le code).

Vous pouvez l'utiliser pour un petit site mais jamais en production (DOMXML n'est pas specialement rapide et l'utilisation de regex a certains moment n'arrange rien).
Vous pourrez telecharger les mises a jour (si il y en a) directement sur mon site : http://info-party.c4.fr rubrique "mes codes sources"

Codes Sources

A voir également

Ajouter un commentaire Commentaires
cs_jean84 Messages postés 449 Date d'inscription jeudi 26 août 2004 Statut Membre Dernière intervention 5 mars 2009
27 nov. 2006 à 18:07
Arf merci Loubiou ^^
Sympa de m'indiquer WAMP mais je connais deja ^^ => si tu regardes mes codes, j'ai deja attaque php5 ;-) (d'ailleurs en ce moment je me farcie toute la doc officielle sur les objets en php5. Je me suis dit qu'il y avait surement plus de choses a faire que de simple classe avec des privates, protected et public... lol)

Pour info, mon herbegeur n'a pas l'air motive... tant pis je continuerai sans lui. Je pense sans doute finir un code que j'ai sur le feu depuis quelques temps deja (parser xml) et apres je m'attaque au moteur :-)

@++
Loubiou Messages postés 150 Date d'inscription mercredi 26 juin 2002 Statut Membre Dernière intervention 5 décembre 2008
27 nov. 2006 à 03:21
Très bon code !
J'utilise perso la dom de PHP 5 qui me permet de passer des flux XML entre flash et mysql.
Je trouve que c'est bien rapide si l'arbo n'est pas trop complexe, et surtout préférant charger les attributs pour les données.

Tu peux utiliser WAMP qui intègre les dernières versions de php et phpmyadmin !
http://www.webmaster-hub.com/publication/+wamp-Nouvelle-version+.html

En attendant que ton hébergeur saute le pas, tu pourras déjà tester en local ;-))
cs_jean84 Messages postés 449 Date d'inscription jeudi 26 août 2004 Statut Membre Dernière intervention 5 mars 2009
24 nov. 2006 à 19:21
Salut !

Merci de tes compliments, c'est sympa d'avoir zieute mon code ;-)
Pour la version php5, j'y pense (surtout en raison de la vitesse d'execution, je me doutais bien que dom, etant present dans le coeur de php5, serait nettement plus rapide). En plus, je doit dire que j'ai bien souffert pour realiser cette appli parce que DOMXML est vraiment MAL DOCUMENTE ! (surtout par rapport a DOM). Pas mal de fonctions tres utiles sont deprecies par rapport a d'autre censes les remplaces mais ne faisant pas exactement la meme chose (je pense a unlink_node() par exemple).
Je vais voir en fonction de mon hebergeur (qui est actuellement en php4) et demander une migration vers php5. Si ce n'est pas faisable, soit je change d'hebergeur (ce qui me parait le mieux de toute facon), soit je reste avec mon "vieux" truc ...lol
Cela influencera directement sur le temps de migration du code en php5 (l'idee me plait de plus en plus ;-))

Pour la regex final, j'ai hesite longuement avant de me resigner a l'utiliser (j'etais content d'avoir realise un code tel quel sans regex) mais c'est vrai que s'il il avait fallu implementer une nouvelle fonction rien que pour parser les balises orphelines, sa aurait fait beaucoup de code en plus pour pas grand chose au final (et puis j'ai eu une crise de flemme aigu ^^). Donc je me susi resigne (faute grave je sais :p)

Allez, pour la prochaine version, je promet des logs de fichier en xml (tant qu'a faire) et PAS UNE SEULE expression reguliere. Je testerai egalement les try() catch(), faudra bien que je m'y mette un jour ou l'autre alors tant qu'a faire :-)

Merci encore d'avoir regarde ma source, je suis content que tu y ai trouve un interet !

@++
malalam Messages postés 10839 Date d'inscription lundi 24 février 2003 Statut Membre Dernière intervention 2 mars 2010 25
21 nov. 2006 à 08:07
Hello,

je trouve que c'est une très bonne idée :-) C'est pas mal réalisé. Mais je conçois que ce soit long, surtout à cause de l'expression régulière finale. A la limite, tu devrais pouvoir virer ces balises via domxml. A voir si c'est plus rapide.
Sinon, ben, il ne te reste plus qu'à créer une version php5, qui elle sera nettement plus rapide (dom est plus optimisé que domxml), et plus intéressante pour la gestion des erreurs et du log.
Mais c'est très bien :-)

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.