I have been working on a php driven template engine. This is fairly light weight, and fast from all of my testing, but I was hoping to get some feed back on it. First I would like to show you an example usages before I show the actual library. For full documentation and more examples: http://plater.phpsnips.com/
This first part is a example users homepage
templates/user.tpl
<!DOCTYPE html>
<html>
<head>
<title>User Home Page</title>
</head>
<body>
<h2>Welcome, $session.first.ucfirst();</h2>
<p>
Here is where you will find the last 5 images that you have uploaded.
</p>
$each("myimages"):
<div style="border: solid 1px activeborder;margin-bottom: 5px;">
<p>
<img src="images/$image;" />
</p>
<p>
$description;
</p>
</div>
$endeach;
</body>
</html>
This next section is the php part for the above template.
user.php
<?php
session_start();
require_once "Plater.php";
require_once "db.php";
$tpl = new Plater();
// Query a database
$user_id = (int)$_SESSION["user_id"];
$sql = mysql_query("select * from images where user_id = $user_id order by date desc limit 5");
$images = [];
// put into the array
while($row = mysql_fetch_assoc($sql)){
$images[] = ["image" => $row["filename"], "description" => $row["descr"]];
}
// replacemet
$tpl->assign("myimages", $images);
// show
$tpl->show("templates/user.tpl");
That was just a little taste of the template system. Here are some of the current features that it has so far:
- Import templates within the template
- Run PHP functions
- Run Custom functions
- Tidy
- Import css (decreases http requests)
- Loops
- globals
- $get
- $post
- $session
- $cookie
- $server
- Template comments (Won't display in html output)
- Multi line: /$ Multiline comment $/
- Single line: $$ Single line comment
- Remove empty tags after all replacements are done
And finally, here is the main library:
<?php
/**
* @author php Snips <hi@phpsnips.com>
* @copyright (c) 2012, php Snips
* @version 0.0.1
* @see http://plater.phpsnips.com/docs/
*/
class Plater{
protected
$template = "",
$replacements = array(),
$cssFiles = array(),
$disableTidy = false;
public function __construct(){
}
public function show($filename){
try{
$this->template = $this->import($filename);
$this->format();
echo $this->template;
}catch(Exception $e){
echo $e->getMessage();
}
}
public function attachCSS($filename = null){
$tmp = $this->template;
if(empty($filename)){
$matches = array();
preg_match_all("/\\\$attachCSS\((\"|')(.+)(\"|')\);/U", $tmp, $matches);
$tmp = preg_replace("/\\\$attachCSS\((\"|')(.+)(\"|')\);/U", "", $tmp);
foreach($matches[2] as $filename){
$this->cssFiles[] = $this->import($filename);
}
$this->template = $tmp;
}else{
$this->cssFiles[] = $this->import($filename);
}
}
public function import($filename){
if(!is_file($filename)){
throw new Exception("Could not find \"<b>$filename</b>\" it does not exist.");
}
return file_get_contents($filename);
}
public function assign($key, $value){
$this->replacements[$key] = $value;
}
public function disableTidy($boolean){
$this->disableTidy = (bool)$boolean;
}
private function format(){
$this->loadIncludes();
$this->get();
$this->post();
$this->session();
$this->server();
$this->cookie();
$this->template = $this->removeComments();
$this->runWhileLoops();
$this->template = $this->replaceTags();
$this->loadIncludes();
$this->template = $this->replaceTags();
$this->template = $this->removeEmptyTags();
$this->attachCSS();
$this->template = $this->replaceCSS();
if(!$this->disableTidy){
$this->template = $this->tidy();
}
}
private function tidy(){
if(class_exists("tidy")){
$tmp = $this->template;
$tidy = new \tidy();
$config = array(
"indent" => true,
"indent-spaces" => 4,
"clean" => true,
"wrap" => 200,
"doctype" => "html5"
);
$tidy->parseString($tmp, $config, 'utf8');
$tidy->cleanRepair();
$string = $tidy;
}
return $string;
}
private function get(){
foreach($_GET as $k => $v){
$this->replacements["get." . $k] = $v;
}
}
private function post(){
foreach($_POST as $k => $v){
$this->replacements["post." . $k] = $v;
}
}
private function server(){
foreach($_SERVER as $k => $v){
$this->replacements["server." . $k] = $v;
}
}
private function session(){
if(isset($_SESSION)){
foreach($_SESSION as $k => $v){
$this->replacements["session." . $k] = $v;
}
}
}
private function cookie(){
foreach($_COOKIE as $k => $v){
$this->replacements["cookie." . $k] = $v;
}
}
private function loadIncludes(){
$tmp = $this->template;
$matches = array();
preg_match_all('/(\\$import\(("|\')(.+?)("|\')\).*;)/i', $tmp, $matches);
//print_r($matches);
$files = $matches[3];
$replace = 0;
foreach($files as $key => $file){
$command = preg_replace("/\\\$import\((\"|').+?(\"|')\)/", "", $matches[0][$key]);
$string = $this->import($file);
$string = $this->runFunctions($string, "blah" . $command);
$f = preg_quote($file, "/");
$tmp = preg_replace('/\\$import\(("|\')' . $f . '("|\')\).*;/i', $string, $tmp);
$replace++;
}
$this->template = $tmp;
if($replace > 0){
$this->loadIncludes();
}
}
private function runWhileLoops(){
$tmp = $this->template;
$matches = array();
preg_match_all("/\\\$each\((\"|')(.+)(\"|')\):(.+)\\\$endeach;/isU", $tmp, $matches);
if(isset($matches[4]) && !empty($matches[4])){
foreach($matches[4] as $id => $match){
$new = "";
$match = "";
$name = $matches[2][$id];
$ntmp = $matches[4][$id];
if(isset($this->replacements[$name])){
foreach($this->replacements[$name] as $val){
$new .= $this->replaceTags($val, $ntmp);
}
}
$name = preg_quote($name);
$tmp = preg_replace("/\\\$each\((\"|')$name(\"|')\):(.+)\\\$endeach;/isU", $new, $tmp);
}
}
$this->template = $tmp;
}
private function replaceCSS(){
$tmp = $this->template;
$css = "<style>\n";
foreach($this->cssFiles as $cssStr){
$css .= "$cssStr\n";
}
$css .= "</style>\n";
if(preg_match("/<\/head>/i", $tmp)){
$tmp = preg_replace("/<\/head>/i", "$css</head>", $tmp, 1);
}else{
$tmp .= $css;
}
return $tmp;
}
private function replaceTags($keys = null, $tmp = null){
if(empty($tmp)){
$tmp = $this->template;
}
if(!empty($keys)){
$replacements = $keys;
}else{
$replacements = $this->replacements;
}
foreach($replacements as $key => $value){
if(is_array($value)){
continue;
}
$matches = array();
preg_match_all('/\\$' . $key . '\..+?;/', $tmp, $matches);
if(!empty($matches[0])){
foreach($matches[0] as $match){
$result = $this->runFunctions($value, $match);
$m = preg_quote($match);
$tmp = preg_replace('/' . $m . '/', "$result", $tmp);
}
}
if(!is_array($value)){
$tmp = str_replace('$' . $key . ';', $value, $tmp);
}
}
return $tmp;
}
private function runFunctions($value, $functions){
$functions = explode(".", $functions);
array_shift($functions);
foreach($functions as $func){
$func = trim($func, "$();");
if(function_exists($func)){
$value = $func($value);
/* if(empty($value)){
throw new Exception("Invalid parameter for <b>$func</b> received \"<b>$v</b>\" within template.");
} */
}
}
return $value;
}
private function removeEmptyTags(){
$tmp = $this->template;
$tmp = preg_replace("/\\$[^\"' ]+?;/", "", $tmp);
return $tmp;
}
private function removeComments(){
$tmp = $this->template;
$tmp = preg_replace("/\/\\$.*\\$\//isU", "", $tmp);
$tmp = preg_replace("/.*\\$\\$.+(\n|$)/iU", "", $tmp);
return $tmp;
}
}
So, after review, what are your thoughts on this library?
Thanks!