MOTEUR DE TEMPLATE PHP5

Messages postés
373
Date d'inscription
samedi 9 juillet 2005
Statut
Membre
Dernière intervention
11 août 2008
- - Dernière réponse : cs_garfield90
Messages postés
388
Date d'inscription
lundi 7 juillet 2003
Statut
Webmaster
Dernière intervention
10 février 2009
- 21 avril 2008 à 22:01
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/45263-moteur-de-template-php5

cs_garfield90
Messages postés
388
Date d'inscription
lundi 7 juillet 2003
Statut
Webmaster
Dernière intervention
10 février 2009
-
errata :

sur mon dernier post, le code est plutot :
$i = 0 ;
if ( mysql_num_row($dbResult) > 0 ){
// on a plusieurs resultats
$cTSql = array();
while ( $row = mysql_fetch_array($dbResult) || $i < 10 ){
$oTSql = new ND_Template;
$oTSql->setContent('<tr><td>#sql.id#</td><td>#sql.nom#</td><td>#sql.prenom#</td><td>#sql.role#</td></tr>'); // erreur ici
$oTSql->addValue('sql', $row );
$cTSql[] = $oTSql ;
$i++;
}
}else{
// on n'a aucun résultat
$cTsql = '<tr><td>aucun contenu</td></tr>';
}
$oTPrincipal = new ND_template;
$oTPrincipal->setTemplateFile('tpl/tableau.tpl'); // contenu de tableau.tpl ('#content#
')
$oTPrincipal->addValue('content', $cTSql); // erreur présente ici également

Ca m'apprendra a poster quand on est HS :D
cs_garfield90
Messages postés
388
Date d'inscription
lundi 7 juillet 2003
Statut
Webmaster
Dernière intervention
10 février 2009
-
Concernant la doc, c'est pas tellement que c'est complexe... C'est juste qu'il faut se plonger dans le code source pour savoir ce qu'on peut faire, avec quoi et comment. C'est juste plus long, faut aussi comprendre comment t'as vu les choses en écrivant cette classe, etc. Disons que pour quelqu'un qui veut juste utiliser le moteur de template, c'est pas évident... Y'a pas besoin de grand chose pour expliquer en 2 ou 3 lignes l'intérêt et le fonctionnement des méthodes publiques.
=> la doc a été faite, si tu as des choses a dire, expliquer n'hésites pas

Pour l'assignation de variables, que tu aies fait ça pour le fun ou pas, il n'en demeure pas moins que c'est pas hyper pratique... Encore que... j'ai du mal à bien piger comment ça marche, parce que là, dans ton exemple, tu utilises addGlobal pour assigner un tableau... Alors je suis perdu... et un peu de doc m'aiderait, là, en fait ;)
=> Je n'ai pas vu en quoi c'est pas hyper pratique car tu peux utiliser des tableaux voire des objets, et donc ainsi gérer plusieurs variables d'un coup (via notation pointé [tableau.clé] ou doublement pointé [objet..propriété] ), mais bon je connais mon moteur par coeur, j'ai donc pas forcement le recul nécessaire :S

PCRE : ok... Effectivement, pour supprimer les variables restantes non assignées... Moi, je suis parti du principe que s'il reste des variables, c'est qu'elles n'ont pas été correctement gérées.
=> Je suis pas forcement d'accord avec toi, si tu utilises un (sous-template) utilisées par 2 pages et/ou une variable du template ne doit être affiché que dans un certain cas, ca t'évites de faire 2 templates sensiblement identiques.

return $this => linker les méthodes... Ouais, admettons. C'est vrai que c'est pratique. Mais d'un point de vue sémantique, ça me chiffone un peu, quand même...
=> J'ai suivi en grande partie la nomenclature du Zend Framework, il l'utilise énormement, et quand tu y a gouté tu n'arretes pas. Ca evite une verbosité génante quand tu assignes beaucoup d'entrées

Pour clear() : c'est ce que je viens d'implémenter dans la v0.4 de ma classe (pas encore en ligne). Moi, je trouve ça très pratique. Soit je passe une variable en argument, il la supprime, soit je ne passe rien, il supprime tout.
=> J'ai normalement le meme fonctionnement, mais le fait d'avoir 2 portées différentes (local / global), fait que mon clear est un peu plus complexe. En inversant l'ordre des variables, ca devrait etre plus simple.

Faut dire, on n'a pas la même approche des variables de template locales et globales. Dans ma classe, les variables assignées à l'objet sont globales (du fait que je n'ai pas besoin d'avoir plusieurs instances pour bosser sur plusieurs templates). Les variables locales ne sont pas sauvegardées et directement utilisées lorsque le template est parsé. Du coup, les seules variables que j'ai a supprimer, ce sont les globales. J'ai la même approche que la portée des variables dans les fonctions en PHP : celles qui sont définies dans une fonction ne sont pas accessible en dehors. C'est moins lourd aussi, parce que si j'ai beaucoup beaucoup de variables, celles qui ne sont utilisées qu'une seule fois dans un template (qui peut ne pas être utilisé, donc soumis à condition) ne sont pas stockées en mémoire.
=> En fait ma notion de variables globales est venues d'un besoin, l'internationalisation en particulier ou certaines variables devaient etre passées a plusieurs templates.


Enfin, concernant l'instanciation de plusieurs objets, je trouve ça dommage. Là encore, on n'a pas la même approche (il va sans dire que je préfère la mienne lol, sinon j'aurais pas fait comme ça hein...).
=> Ca reste un point de vue (je ne le dénigre pas), mais en fait le fait d'instancier plusieurs objet me permet de gerer en OO ma construction de page. J'ai en cours de réalisation une classe Template_HTML qui est hérite de ND_Template. Cette classe peut instancier les classes Template_CSS et Template_JS (héritant elles aussi de ND_Template) pour créer le code HTML qui va bien

Je considère ma classe comme un moteur. Un moteur qui peut faire plusieurs choses. Un moteur indépendant. C'est un peu une moulinette à template : tu lui en donnes un, tu récupères du code parsé, tu en passes un autre, etc.
Toi, tu vois plutôt ta classe comme une machine qui ne peut traiter qu'une seule information à la fois.
=> C'est réellement en ca que notre approche differe, tu constuits petit a petit ta page via le meme objet. Moi je considere qu'une page c'est un template qui peut ou pas etre construit a partir d'autre template (ceux ci sont independant hors variables globales). Tu es avec ton approche obligé de récuperer chaque sous template et parser chaque sous template avant son réel affichage, le mien parse tout d'un coup, ca m'évites d'avoir en mémoire le code parser(j'ai en revanche le code non parsé en mémoire, ce qui n'est pas forcement plus économique)

En fait, avec ta classe, on peut tout à fait utiliser plusieurs templates sans instancier d'autres objets. Il suffit de vider le contenu, pour que lors de l'affectation d'un nouvau fichier de template, il le charge complètement (ce qu'il ne fait pas s'il y a du contenu). Personnellement, je ne trouve pas ça très pratique.
=> Ce n'est pas le but du jeu, un template est un tout si tu dois avoir une sous partie template tu l'affecte a ton template master via un template enfant. J'aurai peut etre du définir cela dès le début car c'est un des points majeurs(voir le plus important).

Pour conclure ce commentaire, il est manifeste qu'on n'a pas eu la même approche du problème. Ca donne deux manières de voir, deux codes radicalement différents (pour ne pas dire opposés) dans la manière de fonctionner. Je ne sais pas si, dans l'absolu, l'une est meilleure que l'autre... Ta classe mériterait que tu te penches un peu plus sur la souplesse d'utilisation et l'ergonomie, parce qu'elle est quand même performante, hein. J'ai pas l'impression que tu aies du code qui fait des trucs inutiles.
Tout ça, c'est mon opinion à moi, et c'est quand même bien qu'il y ait de la diversité :)
=> En tout cas, je te remercie de ta patience d'avoir lu le code, de l'avoir commenté. Je pense que la diversité des implémentations de notions identiques sur ce site en fait son interet.

Vielle partie de commentaire non traitée (car lecture en diagonale, désolé)
- manque de souplesse concernant l'assignation des variables. Soit j'ai pas tout bien vu, soit on est obligé d'assigner les variables par couple, une par une. C'est un peu lourd quand on veut assigner le résultat d'une requête SQL.
tu peux normalement récuperer ton resultat sous forme de tableau et/ou d'objet ton ou tes resultats. Rien ne t'empeche avec mon systeme de créer un template associant un row SQL avec un template prédéfini et/ou de boucler sur x row si ta requete renvoi plusieurs rows.

avec un code du genre :
$i = 0 ;
if ( mysql_num_row($dbResult) > 0 ){
// on a plusieurs resultats
$cTSql = array();
while ( $row = mysql_fetch_array($dbResult) || $i < 10 ){
$oTSql = new ND_Template;
$oTSql->setContent('<tr><td>#sql.id#</td><td>#sql.nom</td><td>#sql.prenom</td><td>#sql.role</td></tr>');
$oTSql->addValue('sql', $row );
$cTSql[] = $oTSql ;
$i++;
}
}else{
// on n'a aucun résultat
$cTsql = '<tr><td>aucun contenu</td></tr>';
}
$oTPrincipal = new ND_template;
$oTPrincipal->setTemplateFile('tpl/tableau.tpl'); // contenu de tableau.tpl ('#content#
')
$oTPrincipal->addValue('content', $oTSql);

Voila, j'avoue que j'ai un doute quand a la performance d'un telle systeme si l'on doit instancier beaucoup de sous template a une page.
neigedhiver
Messages postés
2483
Date d'inscription
jeudi 30 novembre 2006
Statut
Membre
Dernière intervention
14 janvier 2011
13 -
Concernant la doc, c'est pas tellement que c'est complexe... C'est juste qu'il faut se plonger dans le code source pour savoir ce qu'on peut faire, avec quoi et comment. C'est juste plus long, faut aussi comprendre comment t'as vu les choses en écrivant cette classe, etc. Disons que pour quelqu'un qui veut juste utiliser le moteur de template, c'est pas évident... Y'a pas besoin de grand chose pour expliquer en 2 ou 3 lignes l'intérêt et le fonctionnement des méthodes publiques.

Pour l'assignation de variables, que tu aies fait ça pour le fun ou pas, il n'en demeure pas moins que c'est pas hyper pratique... Encore que... j'ai du mal à bien piger comment ça marche, parce que là, dans ton exemple, tu utilises addGlobal pour assigner un tableau... Alors je suis perdu... et un peu de doc m'aiderait, là, en fait ;)

PCRE : ok... Effectivement, pour supprimer les variables restantes non assignées... Moi, je suis parti du principe que s'il reste des variables, c'est qu'elles n'ont pas été correctement gérées.

return $this => linker les méthodes... Ouais, admettons. C'est vrai que c'est pratique. Mais d'un point de vue sémantique, ça me chiffone un peu, quand même...

Pour clear() : c'est ce que je viens d'implémenter dans la v0.4 de ma classe (pas encore en ligne). Moi, je trouve ça très pratique. Soit je passe une variable en argument, il la supprime, soit je ne passe rien, il supprime tout.
Faut dire, on n'a pas la même approche des variables de template locales et globales. Dans ma classe, les variables assignées à l'objet sont globales (du fait que je n'ai pas besoin d'avoir plusieurs instances pour bosser sur plusieurs templates). Les variables locales ne sont pas sauvegardées et directement utilisées lorsque le template est parsé. Du coup, les seules variables que j'ai a supprimer, ce sont les globales. J'ai la même approche que la portée des variables dans les fonctions en PHP : celles qui sont définies dans une fonction ne sont pas accessible en dehors. C'est moins lourd aussi, parce que si j'ai beaucoup beaucoup de variables, celles qui ne sont utilisées qu'une seule fois dans un template (qui peut ne pas être utilisé, donc soumis à condition) ne sont pas stockées en mémoire.

Enfin, concernant l'instanciation de plusieurs objets, je trouve ça dommage. Là encore, on n'a pas la même approche (il va sans dire que je préfère la mienne lol, sinon j'aurais pas fait comme ça hein...).
Je considère ma classe comme un moteur. Un moteur qui peut faire plusieurs choses. Un moteur indépendant. C'est un peu une moulinette à template : tu lui en donnes un, tu récupères du code parsé, tu en passes un autre, etc.
Toi, tu vois plutôt ta classe comme une machine qui ne peut traiter qu'une seule information à la fois.
En fait, avec ta classe, on peut tout à fait utiliser plusieurs templates sans instancier d'autres objets. Il suffit de vider le contenu, pour que lors de l'affectation d'un nouvau fichier de template, il le charge complètement (ce qu'il ne fait pas s'il y a du contenu). Personnellement, je ne trouve pas ça très pratique.

Pour conclure ce commentaire, il est manifeste qu'on n'a pas eu la même approche du problème. Ca donne deux manières de voir, deux codes radicalement différents (pour ne pas dire opposés) dans la manière de fonctionner. Je ne sais pas si, dans l'absolu, l'une est meilleure que l'autre... Ta classe mériterait que tu te penches un peu plus sur la souplesse d'utilisation et l'ergonomie, parce qu'elle est quand même performante, hein. J'ai pas l'impression que tu aies du code qui fait des trucs inutiles.
Tout ça, c'est mon opinion à moi, et c'est quand même bien qu'il y ait de la diversité :)
cs_garfield90
Messages postés
388
Date d'inscription
lundi 7 juillet 2003
Statut
Webmaster
Dernière intervention
10 février 2009
-
Documentation :
Je suis ok, rien n'a été fait concernant la doc, mais je pensais pas que c'était si complexe que ca. Je vais m'y mettre un de ces jous.

Assignation de variable:
On ne peut passer qu'une variable a la fois, peut etre faire une methode multiAssign qui prend un tableau en param. Mais bon, ce code a été fait rapidement pour le fun, est l'interet était surtout de pouvoir associé n'importe quel type de variable (tableau, chaine, objet)

Utilisation des PCRE:
normalement, il n'y a en a qu'une seule et c'est pour supprimer les patterns non utilisés.

le "return $this" dans la majorité des methodes permet de linker les methodes entre elle, c'est super pratique de pour faire :
$oT->addValue('to','ta')
->addValue('ti','tu');

Concernant les tests, je pense que je vais mettre ca a jour rapidement
pour la méthode clear, je pense qu'en inversant les params, ca sera plus simple et plus intuitif.
faire 2 methodes pour clear tout, rien ou un ensemble de valeur me semble AMHA pas forcement pertinent.

Sinon, je vais prendre en compte quelques modifs proposé (is_file en place de file_exists et pour le is_null ).

J'ai mis un exemple en fin de code, peut etre que ca permettra aux autres de comprendre mon code et ma facon de voir :P

pour pouvoir utiliser plusieurs template, tu instancies plusieurs templates que tu peux sans soucis associées a 1 template parent
neigedhiver
Messages postés
2483
Date d'inscription
jeudi 30 novembre 2006
Statut
Membre
Dernière intervention
14 janvier 2011
13 -
Ok, j'ai trouvé... Mais c'est quand même tordu...
Il faut utiliser ND_Template::setContent() et lui passer en argument une chaine vide...
neigedhiver
Messages postés
2483
Date d'inscription
jeudi 30 novembre 2006
Statut
Membre
Dernière intervention
14 janvier 2011
13 -
Salut,

Voilà, un ptit commentaire bien mérité :)

J'ai apprécié, en test, la légèreté (même si, sans vouloir te vexer, pour le même résultat ma classe va plus vite ^^ mais la raison vient plus loin...)

Par contre, quelques trucs qui m'ont un peu freiné...
- aucune doc sur l'utilisation : il faut se plonger dans le code pour savoir quelles sont les méthodes qui existent, comprendre à quoi elles servent, comment les utiliser et à quel moment...
- manque de souplesse concernant l'assignation des variables. Soit j'ai pas tout bien vu, soit on est obligé d'assigner les variables par couple, une par une. C'est un peu lourd quand on veut assigner le résultat d'une requête SQL. Sinon, on le fait en PHP en dehors du template, mais comme ça revient au même en performances, si c'était intégré, ça faciliterait la vie (surtout que c'est le genre de truc assez répétitif)
- je n'ai pas encore réussi à afficher 2 fichiers avec le même objet... Je ne sais pas si c'est voulu... Je continue de creuser...
- tu utilises des expressions régulières (des PCRE heureusement !) alors que ce n'est pas vraiment utile. Un simple str_replace ferait largement l'affaire : je pense que tu y perds en performances, là.
- tu utilises fil_exists() pour vérifier l'existence d'un fichier, c'est une petite erreur... file_exists() renverra true si un répertoire du même nom existe. Ca peut faire planter la suite... is_file() renvoit true si le fichier existe et un un fichier régulier (donc pas un répertoire).
- je ne comprends pas à quoi sert ton constructeur... un constructeur ne retourne rien, il se contente d'exécuter du code.
- setTemplateFile() : return $this; Tu y tiens :o) Si je fais $test = $template -> setTemplate('index.tpl'); ça va me retourner une référence (en PHP5 les objets sont toujours passés par référence) de l'instance en question... est-ce utile ? Si oui, je vois pas bien en quoi...
- méthode clear() : if ( false === is_null($key) tu gagnerais à tester directement $key !== null, ça fait un seul test au lieu des deux que tu fais
- méthode clear() encore : elle sert à la fois pour supprimer une valeur ou un tableau, ou pour tout supprimer... Je pense qu'il serait plus simple d'avoir deux méthodes : une pour supprimer une ou plusieurs variables, une autre pour tout supprimer (avec comme argument LOCAL_VAR, GLOBAL_VAR, ALL_VAR). Telle qu'elle est là, cette méthode n'est pas très pratique... devoir passer null comme argument, j'aime pas trop (c'est psychologique et subjectif, hein, sinon, ça semble fonctionner quand même).

Voilà pour l'instant... Je continue de chercher comment faire pour ne pas avoir à instancier 2 fois la classe...
cs_garfield90
Messages postés
388
Date d'inscription
lundi 7 juillet 2003
Statut
Webmaster
Dernière intervention
10 février 2009
-
Aucun commentaire ???
cs_garfield90
Messages postés
388
Date d'inscription
lundi 7 juillet 2003
Statut
Webmaster
Dernière intervention
10 février 2009
-
pour revenir à ton message d'hier, la nuit m'a porté conseil et j'ai lu avec moins de fatigue ton post.

Personnellement, je ne pense pas qu'un (moteur) template soit la pour moudre le café, je pense plutot qu'il est la pour servir de guideline à la présentation. Tu changes de guideline, tu changes de template. Mais ton code applicatifs ne va pas changer pour autant.

XSLT te permet de faire ca, mais l'inconvénient c'est qu'il te permet AUSSI de faire plein d'autre chose comme (transformer une date en calendrier julien en calendrier grégorien), faire des calculs et autres choses qu'un moteur de template de devrait/doit pas faire.

Après mon moteur ne t'empeche pas de te construire ton fichier XML qui sera associable a la feuille XSL de ton choix (les 2 sont compatibles :D)

Le but de ce moteur etait de faire de maniere simple une gestion affichage HTML et autre (LaTeX, XML, ...) et aussi de pouvoir construire gérer facilement les différentes vues que peuvent avoir un objet.
j'associe un objet avec son template de présentation et j'obtient une fiche produit
j'associe ce meme objet avec son template de formulaire et j'obtient le formulaire de création/modification du produit
j'associe ce meme objet avec son template d'export et j'obtient un fichier CSV
et je peux faire ca de maniere infinie sans avoir a "me prendre la tete" avec le langages XSL
cs_garfield90
Messages postés
388
Date d'inscription
lundi 7 juillet 2003
Statut
Webmaster
Dernière intervention
10 février 2009
-
get_object_vars permet de recuperer les propriétés d'un objet et donc permet au moteur de pouvoir recevoir des objects en valeur à instancier.

Concernant xsl(t), dire qu'il est plus puissant oui/non/peut-etre/ne se prononce pas, car il est assez rebutant a appréhender et a apprendre, et donc difficilement assimilable. De plus, il n'a d'interet que si tu travail avec du XML, donc par exemple si tu dois travailler avec un object/tableau PHP tu dois le transformer en XML pour pourvoir le traiter via XSL(T). A moins que je dise une connerie.
audayls
Messages postés
373
Date d'inscription
samedi 9 juillet 2005
Statut
Membre
Dernière intervention
11 août 2008
-
Salut,

Avant de commencer ce commentaire je tiens à tous vous souhaiter une très bonne année =)
Bon maintenant petit commentaire !

En lisant rapidement je n'ai pas compris pourquoi tu utilises "get_object_vars"... Sans vouloir te vexer c'est basique comme moteur de template. Perso je préfere un template xsl qui est plus puissant. Par contre avec ton template tu peux mettre en cache certaines parties ce qui semble impossible avec un template xsl (même si à vrai dire je m'y suis pas encore vraiment attardé).

Pas le temps de commenter plus maintenant mais j'essayerais de passer ce soir ;-)