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"
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.