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"
27 nov. 2006 à 18:07
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 :-)
@++
27 nov. 2006 à 03:21
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 ;-))
24 nov. 2006 à 19:21
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 !
@++
21 nov. 2006 à 08:07
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.