Template engine simple et puissant. extention de fonctions par plugins (fdml parser).

Soyez le premier à donner votre avis sur cette source.

Vue 7 539 fois - Téléchargée 392 fois

Description

      • Français: ***

Si vous cherchez un template engine en PHP, voici votre solution!

Un template engine, leger, flexible, mais tres puissant.
Pas de code php dans vos template, mais des tags html avec un namespace <fdml:tagname>.

Des fonctions sont intégrées au template engine: variables (sous la forme %var% coté template), boucles, sections (mettez plusieurs templates dans un fichier, et selectionnez quel partie du fichier vous souhaitez utiliser via useSection() ), affichage conditionnel (utilisez show() pour afficher ou pas une portion de code), ...

Mais l'intérêt de ce template engine, est la flexibilité: Vous pouvez creer vos propres tags sous forme de plugin; Une simple fonction php sous la forme codeparser_tagname().
Le contenu du tag sera remplacé par ce que cette fonction retourne. Pas besoin de declarer la fonction, ou de faire un include. PLacez le fichier qui la contient dans le repertoire /plugins/ (modifiable en runtime) et le parser va la trouver et la charger pour vous.

Le fichier zip contient une série d'exemples divers, simple et complexes.
      • English: ***


If you are searching for a new template parser for your PHP projects, here is your solution!

FDML stands for Flexible Dynamic Markup Language.

Instead of having nasty php code in your templates, or weird template tags (like smarty's tags for example), the FDML language is based on HTML. That mean you will have tags like <fdml:tagname arg="value" /> in your template.

To control your template from your php code, you have a few functions like: Loop() -> Loop the portion of code located between the <fdml:loop name=""> </fdml:loop> tags. Show() -> Display the portion of code located between the <fdml:show name=""> </fdml:show> tags. If the function is not called, the portion of code will not be displayed. UseSection?() -> Use only a section of the template as the main template. Allow you to put many templates in a single file. AddVar?() -> allow you to define and replace a variable in the template. Variable name are enclosed in % sign in the template. Example: %variable% will be replaced by addVar("variable","value");

But this parser is more interesting than other solution because it allows you to create your own tags; If you need for example a new function in your template, let say, you want a piece of code to be displayed only is the current user is an admin. Instead of putting in your template a lot of code based on conditions, simply create the <fdml:is_admin> tag! When the parser will find this unknown tag, it will automatically search for a function named fdml_is_admin() in the /plugins/ directory, and simply replace the content of the tag by the return of this function. The content of the tag and its attributes will be send to the function as an array.

Oh, and did I mentioned the parser is composed of just one single file with no dependency?

Source / Exemple :


<?php
/*

  • @Created: v2 - 15 avr. 07 - 14:25:10
  • v3 - 20 janv. 09 - 13:44:00
  • @author: blackwizzard <blackwizzard@gmail.com>
  • @project: FDML - Flexible Dynamic Markup Language
  • @filename: fdml.parser.php
  • /
class codeparser { // declarations var $_instance; var $_vars; // Constructor function codeparser($file, $pluginDir=null) { /** vars **/ $this->_vars = array(); $this->_vars["buffer"] = ""; $this->_vars["log"] = array(); $this->_vars["log"]["file"] = $file; $this->_vars["log"]["tags"] = array(); $this->_vars["vars"] = array(); $this->_vars["functionbuffer"] = array(); $this->_vars["namespace"] = "fdml"; // you can change the namespace here $this->pluginfolder = "plugins/"; // You can change the plugin directory here if ($pluginDir!=null) $this->pluginfolder = $pluginDir; // functions buffers $this->_vars["functionbuffer"]["loop"] = array(); $this->_vars["functionbuffer"]["loopbuffer"] = array(); $this->_vars["functionbuffer"]["onemptyloop"] = array(); $this->_vars["functionbuffer"]["onemptyloopbuffer"] = array(); $this->_vars["functionbuffer"]["show"] = array(); $this->_vars["functionbuffer"]["showbuffer"] = array(); $this->_vars["functionbuffer"]["section"] = array(); $this->_vars["functionbuffer"]["sectionbuffer"] = array(); $this->_vars["functionbuffer"]["savedloop"] = array(); $this->_vars["functionbuffer"]["savedloopbuffer"] = array(); /** read the template file **/ $this->_vars["buffer"] = $this->freadFile($file); /** plugin loader **/ $this->loadPlugins("preparser"); $this->loadPlugins("dynamics"); $this->_vars["buffer"] = $this->searchtags($this->_vars["buffer"]); } /**
  • Output the parsed template
  • @return Template buffer
  • /
function output() { $this->applyLoops(); return $this->_vars["buffer"]; } function applyLoops() { // apply loops foreach ($this->_vars["functionbuffer"]["loop"] as $loopName=>$loopOutput) { if ($loopOutput == "") { $loopOutput = $this->_vars["functionbuffer"]["onemptyloopbuffer"][$loopName]; } // required... $loopOutput = $this->searchtags($loopOutput); $this->_vars["buffer"] = str_replace("<loop_$loopName/>",$loopOutput,$this->_vars["buffer"]); } } function applySavedTags() { $this->applyLoops(); $regex = '#<savedloop id\=[\"]([\w-]+)[\"] name\=[\"]([\w-]+)[\"] \/>#mis'; while(preg_match($regex, $this->_vars["buffer"], $match)) { $loop_id=$match[1]; $loop_name=$match[2]; $this->_vars["buffer"] = preg_replace("#{$match[0]}#", "<".$this->_vars["namespace"].":loop name=\"$loop_name\">".$this->_vars["functionbuffer"]["savedloopbuffer"][$loop_id]."</".$this->_vars["namespace"].":loop>", $this->_vars["buffer"]); } $this->parseAgain(); } function parseAgain() { $this->_vars["buffer"] = $this->searchtags($this->_vars["buffer"]); } /**
  • Search and parse all FDML tags
  • @return pre-parsed template
  • /
function searchtags($in) { // match all tags in the form <type:name args>content</type:name> and singleton <type:name args /> // old versions: //$reg = "#<([a-z]+):(.*?)\s+(.*?)\s*(>(.*?)</\\1:\\2>|/>)#mis"; // global regex to match all tags with all namespaces. //$reg = "#<".$this->_vars["namespace"].":(.*?)\s+(.*?)\s*(>(.*?)</".$this->_vars["namespace"].":\\1>|/>)#mis"; //$reg = "#<".$this->_vars["namespace"].":(.*?)\s+(.*?)\s*(>(.*?)</".$this->_vars["namespace"].":\\1>|/>)#mis"; $reg = "#<".$this->_vars["namespace"].":([a-zA-Z0-9_-]+)\s*((?:(?!>).)*)\s*(>((?:(?!".$this->_vars["namespace"].":\\1).)*)</".$this->_vars["namespace"].":\\1>|/>)#mis"; if (preg_match($reg, $in)) { $in = preg_replace_callback($reg,array($this,"tagparser"),$in,-1); return $this->searchtags($in); //return $in; } else { return $in; } } /**
  • Parse a single tag
  • @return the parsed tag
  • /
function tagparser($array) { $query = $array[0]; //$tagType = $array[1]; $tagName = $array[1]; $tagArgs = $array[2]; $tagContent = $array[4]; $argsArray = array(); $tagArgs = str_replace("\\\"","QUOTE",$tagArgs); // attribute parser preg_match_all("#([a-z1-9]+)\s*=(([a-z0-9_-]+)|[\"?]([^\"]*)[\"?])#mis",$tagArgs,$args); foreach ($args[1] as $id=>$var) { $argsArray[$var] = $this->correctValue($args[2][$id]); } array_push($this->_vars["log"]["tags"],array( "Tag name"=>$tagName, "String args"=>$tagArgs, "Parsed args"=>$argsArray, "Complete tag"=>$query, "Content"=>$tagContent )); switch (strtolower($this->superTrim($tagName))) { case "loop": // a loop... if ($argsArray["waitforparsing"] == "true") { // put the content in the function buffer $this->_vars["functionbuffer"]["savedloopbuffer"][$argsArray["id"]] = $tagContent; // saved loop buffer using the loop ID. The localization loop name is saved in the tag itself. // replace by a localization tag return "<savedloop id=\"".$argsArray["id"]."\" name=\"".$argsArray["name"]."\" />"; } else { // put the content in the function buffer $this->_vars["functionbuffer"]["loop"][$argsArray["name"]] = ""; // output of the loop is empty $this->_vars["functionbuffer"]["loopbuffer"][$argsArray["name"]] = $tagContent; // loop buffer // replace by a localization tag return "<loop_".$argsArray["name"]."/>"; } break; case "onemptyloop": // emptyloop... $tagContent = $this->searchtags($tagContent); // put the content in the function buffer $this->_vars["functionbuffer"]["onemptyloop"][$argsArray["name"]] = ""; // output of the onemptyloop is empty $this->_vars["functionbuffer"]["onemptyloopbuffer"][$argsArray["name"]] = $tagContent; // onemptyloop buffer // strip the tag return ""; break; case "section": // a section tag... $tagContent = $this->searchtags($tagContent); // put the content in the function buffer $this->_vars["functionbuffer"]["section"][$argsArray["name"]] = ""; // output of the section is empty $this->_vars["functionbuffer"]["sectionbuffer"][$argsArray["name"]] = $tagContent; // section buffer // replace by a localization tag return "<section_".$argsArray["name"]."/>"; break; case "show": // a show tag... $tagContent = $this->searchtags($tagContent); // put the content in the function buffer $this->_vars["functionbuffer"]["show"][$argsArray["name"]] = ""; // output of the section is empty $this->_vars["functionbuffer"]["showbuffer"][$argsArray["name"]] = $tagContent; // section buffer // replace by a localization tag return "<show_".$argsArray["name"]."/>"; break; default: // Unknown type. Probably a plugin. Else, strip the tag. if (function_exists("codeparser_$tagName")) { $function = "codeparser_$tagName"; $return = $function($tagContent, $argsArray); $return = $this->searchtags($return); return $return; } else { $tagContent = $this->searchtags($tagContent); return $tagContent; } break; } } function parseAndApply($option=null) { $functions = get_defined_functions(); $functions = $functions["user"]; switch ($option) { case "before": foreach ($functions as $function) { if (substr($function,0,strlen("preparser_")) == "preparser_") { $func = $function; $this->_vars["buffer"] = $func($this->_vars["buffer"], $this); } } break; case "after": foreach ($functions as $function) { if (substr($function,0,strlen("postparser_")) == "postparser_") { $func = $function; $this->_vars["buffer"] = $func($this->_vars["buffer"], $this); } } break; } } /**
  • Register a template variable
  • @param String the variable name without the variable identifier (for variable "%var%", just "var")
  • String The value of the variable
  • @return nothing
  • /
function addVar($label, $value) { $this->_vars["vars"][$label] = $value; $this->_vars["buffer"] = str_replace("%".$label."%",$value,$this->_vars["buffer"]); } /**
  • Register more than one template variable at a time, in an array
  • @param Array an array of variables type array("var1"=>"value1","var2"=>"value2")
  • @return nothing
  • /
function addVars($array) { foreach ($array as $varLabel=>$varValue) { $this->addVar($varLabel, $varValue); } } /**
  • Loop a code section
  • @param String the loop name as defined in the template
  • Array an array of variables type array("var1"=>"value1","var2"=>"value2")
  • @return Template buffer
  • /
function loop($name, $array) { global $_PARSER; $buffer = $this->_vars["functionbuffer"]["loopbuffer"][$name]; foreach ($array as $label=>$value) { $buffer = str_replace("%".$label."%",$value,$buffer); } //$this->debug($name, $buffer); //$buffer = $this->searchtags($buffer); $this->_vars["functionbuffer"]["loop"][$name] .= $buffer; } /**
  • Function used to handle the <fn:section> tag. Any call to this function will replace the current buffer with the content of the <fn:section> tag.
  • @param String the name of the section to load, defined on the tag as name="[name]"
  • @return true
  • /
function useSection($sectionName) { global $_PARSER; $tmpBuffer = $this->_vars["functionbuffer"]["sectionbuffer"][$sectionName]; $this->_vars["buffer"] = $tmpBuffer; $this->parseAndApply(); return true; } /**
  • Function used to handle the <fn:show> tag. It will result as the display of the content of the tag.
  • If a tag is not called, it will be deleted before any output.
  • @param String the name of the <fn:show> tag to load, defined on the tag as name="[name]"
  • @return true
  • /
function show($name) { global $_PARSER; $tmpBuffer = $this->_vars["functionbuffer"]["showbuffer"][$name]; $this->_vars["buffer"] = str_replace("<show_$name/>",$tmpBuffer,$this->_vars["buffer"]); $this->parseAndApply(); return true; } function loadPlugins($type) { $pluginfolder=$this->pluginfolder; if ($handle = opendir($pluginfolder.$type)) { while (false !== ($file = readdir($handle))) { if ($file != "." && $file != "..") { if (!is_dir($pluginfolder.$type."/".$file) && strtolower($this->STRING_get_file_ext($file))=="php") { @include_once($pluginfolder.$type."/".$file); } } } closedir($handle); } $functions = get_defined_functions(); $functions = $functions["user"]; switch ($type) { case "preparser": foreach ($functions as $function) { if (substr($function,0,strlen("preparser_")) == "preparser_") { $func = $function; $this->_vars["buffer"] = $func($this->_vars["buffer"], $this); } } break; case "postparser": foreach ($functions as $function) { if (substr($function,0,strlen("postparser_")) == "postparser_") { $func = $function; $this->_vars["buffer"] = $func($this->_vars["buffer"], $this); } } break; } } function correctValue($value) { $firstChar = substr($value,0,1); $lastChar = substr($value,strlen($value)-1,1); if ($firstChar == "\"" && $lastChar == "\"") { // remove quotes $value = substr($value,1,strlen($value)-2); } $value = str_replace("QUOTE","\"",$value); $value = str_replace("\\>",">",$value); return $value; } function freadFile($file) { if (!$handle = fopen ($file, "r")) { exit; } $contents = fread ($handle, filesize($file)+1); fclose($handle); return $contents; } function STRING_get_file_ext($filename) { if (strrpos($filename, '.') >= 1) { return strtolower(substr($filename, strrpos($filename, '.') + 1)); } else { return ""; } } function debug($label, $value) { if (is_array($value)) { echo "<b>$label</b> :: <div style=\"border:1px dashed #000000;margin-left:20px;\">".nl2br(str_replace(" ","&nbsp;",str_replace("<","<",print_r($value,true))))."</div><br>"; } else { echo "<b>$label</b> :: <div style=\"border:1px dashed #000000;margin-left:20px;\">".nl2br(str_replace(" ","&nbsp;",str_replace("\t"," ",$value)))."</div><br>"; } } function tagLog() { $this->debug("Tag Log",$this->_vars["log"]["tags"]); } function superTrim($in) { /** remove extra spaces, line breaks, tabs **/ $in = str_replace("\t"," ",$in); $in = str_replace("\r"," ",$in); $in = preg_replace('/\s\s+/', ' ', trim($in)); return $in; } function encodeAsArg($in) { $in = str_replace("\"","\\\"",$in); $in = str_replace("}","\\}",$in); return $in; } } ?>

Conclusion :


Updates et code: http://code.google.com/p/fdml-php-template/

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

cs_Kimjoa
Messages postés
264
Date d'inscription
vendredi 6 mai 2005
Statut
Membre
Dernière intervention
19 septembre 2014
-
salut aKheNathOn, merci d'avoir répondue à ma question :) !!

bon je dois avoué que je suis toujours pas convaincue :( , pk il faut partir du principe de tout sécuriser?? c'est vraiment rare de trouver des fonctions hérité qui serait sensible si appelé hors de l'instance de la classe .... bon c'est vrai, ça peux arriver , et dans ce cas les private et protected sont utile , mais j'y ais jamais été confronté...

en tout cas c'est cool de me répondre ;)
a++
aKheNathOn
Messages postés
285
Date d'inscription
dimanche 22 juillet 2001
Statut
Modérateur
Dernière intervention
5 décembre 2013
-
Salut Kim,

L'encapsulation peut être faite en php4 ou php5. Elle sert à vérifier les valeurs de variables affectées à ton instance.

Un exemple d'encapsulation qui sert :
T'as un progressbar dont la valeur minimale est 0 et valeur maximale est 100. Tu encapsules les bornes pour vérifier que l'utilisateur en les configurant ne met pas une valeur maximale inférieure ou égale à la valeur minimale. Tu as une valeur value permettant d'indiquer la valeur de progression. Tu vérifies qu'elle est comprise dans les bornes.

Dans la POO si tu construit des classes étant réutilisées par d'autres, tu part du principe qu'il faut tout sécuriser, d'où l'encapsulation.
cs_Kimjoa
Messages postés
264
Date d'inscription
vendredi 6 mai 2005
Statut
Membre
Dernière intervention
19 septembre 2014
-
pile poile ce que je recherché , un script simple, léger et évolutif,..... merci !!

perso , j'ai appris comme BlackWizzard la POO en php4, et j 'ai jamais vraiment compris à koi ça servait l'encapsulation des données ... si quelequ'un trouve le temp de me répondre ....

super code a++
BlackWizzard
Messages postés
1277
Date d'inscription
mercredi 21 mars 2001
Statut
Modérateur
Dernière intervention
21 juin 2009
2 -
lol ça fait un moment!
6 ans et meme plus pour le VB...
Je code presque uniquement en PHP maintenant. Et un peut de flash AS2 pour un projet perso... Mais je suis plus tres actif...
aKheNathOn
Messages postés
285
Date d'inscription
dimanche 22 juillet 2001
Statut
Modérateur
Dernière intervention
5 décembre 2013
-
C'est vraiment dingue, au début tu m'avait même manqué un peu :) - il étais temps que je me socialise un peu plus.

Ca fait vraiment plaisir de te revoir, j'ai toujours en tête les codes que tu fesait y'à 6 ans de ça en VB 6 !!!

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.