Le set est composé de :
- une classe basique qui permet uniquement l'inclusion du fichier template et le remplacement des variables-utilisateur
- une classe étendue qui ajoute la mise en cache via la classe LambdaCache
- une dernière classe qui cette fois ne supporte pas le PHP dans le fichier template mais un langage particulier (que je n'ai pas encore documenté mais qui est assez facilement identifiable en observant les expressions régulières utilisées pour le parsing)
Exemple d'utilisation :
//First, the basic templates class
$template = new LambdaTemplates();
$template -> firstname = 'Rasmus';
$template -> surname = 'Lerdorf';
$template -> call('basic.tpl');
//Now, the economic templates class, with a cache system
$ecotemplate = new EcoLambdaTemplates();
$ecotemplate -> firstname = 'Rasmus';
$ecotemplate -> surname = 'Lerdorf';
$ecotemplate -> call('basic.tpl');
//To finish, the extended templates class, with the cache system and a new template language
$extratemplate = new ExtraLambdaTemplates();
$extratemplate -> title = 'ExtraLambdaTemplates';
$extratemplate -> people = array ('Rasmus' => 'Lerdorf', 'Zeev' => 'Suraski');
$extratemplate -> call('extra.tpl');
?>
basic.tpl :
<html>
<head>
<title>Basic Template</title>
</head>
<body>
<p>
<?php
print $firstname.' '.$surname;
?>
</p>
</body>
</html>
extra.tpl :
Code : Tout sélectionner
<html>
<head>
<title>{tpl: title}</title>
</head>
<body>
<p>
<for i 1 to 4>
<foreach people>
{iterators: i} {key} {value}<br />
</foreach>
</for>
</p>
</body>
</html>
Rasmus Lerdorf
Rasmus Lerdorf
1 Rasmus Lerdorf
1 Zeev Suraski
2 Rasmus Lerdorf
2 Zeev Suraski
3 Rasmus Lerdorf
3 Zeev Suraski
4 Rasmus Lerdorf
4 Zeev Suraski
Code source de la classe :
<?php
/*
Lambda System - by Klomac ([email protected])
LambdaTemplates : These classes allows the user to parse templates files.
-----------------------------GNU GPL--------------------------------------
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
---------------------------------------------------------------------------
*/
//This set of classes require the LambdaCache class to work
require_once('LambdaCache.class.php');
class LambdaTemplates
{
private $userVars = array(); //The user-variables array
private $tplDir = 'templates/'; //The directory which contains the templates files
//The errors which may be displayed
private $errors = array(
'This directory doesn\'t exist',
'Unable to open the template file');
//Magical methods
public function __construct () {}
public function __set ($name, $value) //This method is called when the user try to set a variable
{
$this -> userVars[$name] = $value;
}
public function __get ($name) //Accessor
{
return $this -> userVars[$name];
}
//Protected methods
protected function returnTpl ($start, $print) //This method is used when trying to call a template file but without printing it. It starts a buffer at start, and return its contents at end
{
if ($start AND !$print) ob_start();
elseif (!$start AND !$print) return ob_get_clean();
}
protected function includeTpl ($file) //This method associates the user-variables and include the template file
{
foreach ($this -> userVars AS $key => $value)
{
${$key} = $value;
}
if (is_readable($this -> tplDir.$file)) include $this -> tplDir.$file;
else die($this -> errors[1]);
}
//Public methods
public function setTplDir ($dir) //This method change the template directory after checking if it exists
{
if (is_dir($dir)) $this -> tplDir = $dir;
else die ($this -> errors[0]);
}
public function call ($file, $print = TRUE) //This method include the template file and print (or not) its contents
{
$this -> returnTpl(TRUE, $print);
$this -> includeTpl($file);
return $this -> returnTpl(FALSE,$print);
}
}
class EcoLambdaTemplates extends LambdaTemplates
{
public $cacheDir = 'cache/templates/'; //The directory which contains the cache templates files
//The errors which may be displayed
private $errors = array(
'This directory doesn\'t exist',
'Unable to open the template file',
'Unable to create the cache directory');
//Magical methods
public function __construct () {}
//Protected methods
protected function loadCache ($file, $compression) //This method instanciate a new cache object and return it
{
$cache = new LambdaCache($file, $this -> cacheDir, $compression);
return $cache;
}
//Public methods
public function call ($file, $print = TRUE, $compression = TRUE) //This method is the same as the parent's one but with cache support
{
$this -> returnTpl(TRUE, $print);
$cache = $this -> loadCache($file, $compression);
if (!$cache -> show())
{
$this -> includeTpl($file);
$cache -> close();
}
return $this -> returnTpl(FALSE, $print);
}
}
class ExtraLambdaTemplates extends EcoLambdaTemplates
{
private $useCache; //Indicate if the cache system is used or not
private $parsingTime = array(); //This array contains the parsing time of each called template
//The errors which may be displayed
private $errors = array(
'This directory doesn\'t exist',
'Unable to open the template file',
'Unable to create the cache directory',
'Unable to include a file',
'Syntax error with the conditions',
'Syntax error with the loops');
//Magical methods
public function __construct ($useCache = TRUE) //The constructor just set if the cache system is used or not
{
$this -> useCache = $useCache === TRUE ? TRUE : FALSE;
}
//Static methods
private function solveIncludes ($code, $localPath = '') //This method solves the include instructions in the template file (with recursivity)
{
$firstSearch = '#<include src="(.+)">#sU';
if (preg_match_all($firstSearch, $code, $includes, PREG_SET_ORDER))
{
foreach ($includes AS $file)
{
if (file_exists($localPath.$file[1]) AND is_readable($localPath.$file[1]))
{
$dirs = explode(DIRECTORY_SEPARATOR, $file[1]);
array_pop($dirs);
$dirs = implode(DIRECTORY_SEPARATOR, $dirs);
if ($dirs) $dirs .= DIRECTORY_SEPARATOR;
$includeContent = file_get_contents($localPath.$file[1]);
$includeContent = $this -> solveIncludes($includeContent, $localPath.$dirs);
$secondSearch = '#<include src="'.$file[1].'">#';
$code = preg_replace($secondSearch, $includeContent, $code);
}
else die ($this -> errors[3]);
}
}
return $code;
}
private function parseCode ($code) //This method parse the template code to PHP code
{
$code = $this -> solveIncludes($code, $this -> tplDir);
$code = '$contents .= \''.str_replace('\'', '\\\'', $code).'\';';
//Parsing user variables
$searches[0] = '#\{tpl: (.+)\}#U';
$replaces[0] = '\'.\$this -> $1.\'';
//Parsing conditions
$searches[1] = '#<if \{(.+)\}(.+)>#U';
$replaces[1] = '\'; if (\$this -> $1$2) { $contents .= \'';
$searches[2] = '#</if>#U';
$replaces[2] = '\'; } $contents .= \'';
$searches[3] = '#<elseif \{(.+)\}(.+)>#U';
$replaces[3] = '\'; } elseif (\$this -> $1$2) { $contents .= \'';
$searches[4] = '#<else>#U';
$replaces[4] = '\'; } else { $contents .= \'';
//Parsing loops
$searches[5] = '#\{(key|value)\}#U';
$replaces[5] = '\'.\$$1.\'';
$searches[6] = '#<foreach (.+)>#U';
$replaces[6] = '\'; foreach (\$this -> $1 AS \$key => \$value) { $contents .= \'';
$searches[7] = '#<for (.+) ([0-9]+) to ([0-9]+)>#U';
$replaces[7] = '\'; for (\$$1 = $2 ; \$$1 <= $3 ; \$$1++) { $contents .= \'';
$searches[8] = '#</(for|foreach)>#U';
$replaces[8] = '\'; } $contents .= \'';
$searches[9] = '#\{iterators: (.+)\}#U';
$replaces[9] = '\'.\$$1.\'';
//Checking the conditions and loops validity
if (preg_match_all($searches[1], $code, $useless) != preg_match_all($searches[2], $code, $useless))
{
die ($this -> errors[4]);
}
elseif((preg_match_all($searches[6], $code, $useless) + preg_match_all($searches[7], $code, $useless)) != preg_match_all($searches[8], $code, $useless))
{
die ($this -> errors[5]);
}
//Return the result
return preg_replace($searches, $replaces, $code);
}
//User methods
public function parsingTime ($total = TRUE) //This method returns the parsing time (all or just the last)
{
if ($size = count($this -> parsingTime))
{
if ($total === TRUE)
{
$i = 0;
foreach ($this -> parsingTime AS $parsingTime) $i += $parsingTime;
return $i;
}
else return $this -> parsingTime[$size];
}
else return 'Nothing parsed yet';
}
public function call ($file, $print = TRUE, $compression = TRUE) //This method print the cache contents if it exists, or call and parse the template file if is doesn't
{
$microtime[0] = microtime(TRUE);
$this -> returnTpl(TRUE, $print);
if ($this -> useCache)
{
$cache = $this -> loadCache($file, $compression);
$cacheExists = $cache -> show();
}
else $cacheExists = FALSE;
if (!$cacheExists)
{
ob_start();
$this -> includeTpl($file);
eval($this -> parseCode(ob_get_clean()));
print $contents;
if ($this -> useCache) $cache -> close();
}
$microtime[1] = microtime(TRUE);
array_push($this -> parsingTime, $microtime[1] - $microtime[0]);
return $this -> returnTpl(FALSE, $print);
}
}
?>