New CPHP Templater class added

feature/node-rewrite
Sven Slootweg 13 years ago
parent 74d9576957
commit cb24748048

@ -18,10 +18,13 @@ $template_global_vars = array();
class Templater
{
private $basedir = "templates/";
private $extension = ".tpl";
public $basedir = "templates/";
public $extension = ".tpl";
private $tpl = NULL;
private $tpl_rendered = NULL;
public $templatename = "";
public $root = null;
public $debug_tree = array();
public function Load($template)
{
@ -64,13 +67,10 @@ class Templater
{
if(!is_null($this->tpl))
{
preg_match_all("/<%!([a-zA-Z0-9_-]+)>/", $this->tpl_rendered, $strlist);
foreach($strlist[1] as $str)
{
if(isset($strings[$str]))
foreach($strings as $key => $str)
{
$this->tpl_rendered = str_replace("<%!{$str}>", $strings[$str], $this->tpl_rendered);
}
$this->tpl_rendered = str_replace("<%!{$key}>", $str, $this->tpl_rendered);
$this->tpl_rendered = str_replace("{%!{$key}}", $str, $this->tpl_rendered);
}
}
else
@ -79,6 +79,8 @@ class Templater
}
}
/* Legacy parser code */
public function Compile($strings)
{
global $template_global_vars;
@ -271,4 +273,416 @@ class Templater
$template->Compile($compile);
return $template->Render();
}
/* New parser code */
public static function AdvancedParse($templatename, $localize = array(), $compile = array())
{
$template = new Templater();
$template->templatename = $template->basedir . $templatename . $template->extension;;
$template->Load($templatename);
$template->Localize($localize);
return $template->Parse($compile);
}
public function Parse($data)
{
$tree = $this->BuildSyntaxTree();
return $this->root->Evaluate($data);
}
public function BuildSyntaxTree()
{
$content = $this->tpl_rendered;
$length = strlen($content);
$offset = 0;
$depth = 1;
$current_tag = array();
$current_element = array();
$current_text_element = null;
$debug_tree = array();
$root = array();
$tag_start = 0;
$tag_end = 0;
$text_block = "";
define("CPHP_TEMPLATER_SWITCH_NONE", 1);
define("CPHP_TEMPLATER_SWITCH_TAG_OPEN", 2);
define("CPHP_TEMPLATER_SWITCH_TAG_SYNTAX", 3);
define("CPHP_TEMPLATER_SWITCH_TAG_IDENTIFIER", 4);
define("CPHP_TEMPLATER_SWITCH_TAG_STATEMENT", 5);
define("CPHP_TEMPLATER_SWITCH_TAG_VARNAME", 6);
define("CPHP_TEMPLATER_TYPE_TAG_NONE", 10);
define("CPHP_TEMPLATER_TYPE_TAG_OPEN", 11);
define("CPHP_TEMPLATER_TYPE_TAG_CLOSE", 12);
$switch = CPHP_TEMPLATER_SWITCH_NONE;
$type = CPHP_TEMPLATER_TYPE_TAG_NONE;
$current_element[0] = new TemplateRootElement();
while($offset < $length)
{
$char = $content[$offset];
if($char == "{" && $switch == CPHP_TEMPLATER_SWITCH_NONE)
{
$switch = CPHP_TEMPLATER_SWITCH_TAG_OPEN;
$tag_start = $offset;
}
elseif($char == "%" && $switch == CPHP_TEMPLATER_SWITCH_TAG_OPEN)
{
if($text_block != "")
{
$current_text_element->text = $text_block;
$text_block = "";
$current_element[$depth - 1]->children[] = $current_text_element;
}
// Look ahead to see whether this is going to be a variable or a logic element
if($content[$offset + 1] == "?")
{
$switch = CPHP_TEMPLATER_SWITCH_TAG_VARNAME;
$name = "";
}
else
{
$switch = CPHP_TEMPLATER_SWITCH_TAG_IDENTIFIER;
$identifier = "";
}
}
elseif($char != "%" && $switch == CPHP_TEMPLATER_SWITCH_TAG_OPEN)
{
// Not a templater tag, abort.
$switch = CPHP_TEMPLATER_SWITCH_NONE;
$type = CPHP_TEMPLATER_TYPE_TAG_NONE;
$text_block .= "{";
}
elseif($switch == CPHP_TEMPLATER_SWITCH_TAG_IDENTIFIER && $type == CPHP_TEMPLATER_TYPE_TAG_NONE)
{
if($char == "/")
{
$type = CPHP_TEMPLATER_TYPE_TAG_CLOSE;
}
else
{
$type = CPHP_TEMPLATER_TYPE_TAG_OPEN;
continue;
}
}
else
{
if(($char != " " && $switch == CPHP_TEMPLATER_SWITCH_TAG_IDENTIFIER && $type == CPHP_TEMPLATER_TYPE_TAG_OPEN) ||
($char != "}" && $switch == CPHP_TEMPLATER_SWITCH_TAG_IDENTIFIER && $type == CPHP_TEMPLATER_TYPE_TAG_CLOSE))
{
$identifier .= $char;
}
elseif($char != "}" && $switch == CPHP_TEMPLATER_SWITCH_TAG_VARNAME)
{
if($char != "?" || $name != "")
$name .= $char;
}
elseif($char == " " && $switch == CPHP_TEMPLATER_SWITCH_TAG_IDENTIFIER && $type == CPHP_TEMPLATER_TYPE_TAG_OPEN)
{
$switch = CPHP_TEMPLATER_SWITCH_TAG_STATEMENT;
$statement = "";
}
elseif($char != "}" && $switch == CPHP_TEMPLATER_SWITCH_TAG_STATEMENT)
{
$statement .= $char;
}
elseif(($char == "}" && $switch == CPHP_TEMPLATER_SWITCH_TAG_STATEMENT && $type == CPHP_TEMPLATER_TYPE_TAG_OPEN) ||
($char == "}" && $switch == CPHP_TEMPLATER_SWITCH_TAG_IDENTIFIER && $type == CPHP_TEMPLATER_TYPE_TAG_CLOSE))
{
$tag_end = $offset + 1;
if($type == CPHP_TEMPLATER_TYPE_TAG_OPEN)
{
// This was an opening tag.
$debug_tree[] = "[{$depth}]" . str_repeat("&nbsp;&nbsp;&nbsp;", $depth) . "{$identifier} {$statement}";
$child = $this->CreateSyntaxElement($identifier, $statement, $offset + 1);
$current_element[$depth] = $child;
if(isset($current_element[$depth - 1]) && !is_null($current_element[$depth - 1]))
{
$child->parent = $current_element[$depth - 1];
$child->parent->children[] = $current_element[$depth];
}
$current_tag[$depth] = $identifier;
$depth += 1;
}
elseif($type == CPHP_TEMPLATER_TYPE_TAG_CLOSE)
{
// This was a closing tag.
$depth -= 1;
if($identifier == $current_tag[$depth])
{
$debug_tree[] = "[{$depth}]" . str_repeat("&nbsp;&nbsp;&nbsp;", $depth) . "/{$identifier}";
}
else
{
throw new TemplateSyntaxException("Closing tag does not match opening tag (".$current_tag[$depth]." vs. {$identifier}) at position {$tag_start}.", $this->templatename, $tag_start, $tag_end);
}
}
else
{
throw new TemplateParsingException("The type of tag could not be determined.", $this->templatename, $tag_start, $tag_end);
}
$switch = CPHP_TEMPLATER_SWITCH_NONE;
$type = CPHP_TEMPLATER_TYPE_TAG_NONE;
$identifier = "";
$statement = "";
}
elseif($char == "}" && $switch == CPHP_TEMPLATER_SWITCH_TAG_VARNAME)
{
$debug_tree[] = "[{$depth}]" . str_repeat("&nbsp;&nbsp;&nbsp;", $depth) . "var {$name}";
$child = $this->CreateSyntaxElement("variable", $name);
if(isset($current_element[$depth - 1]) && !is_null($current_element[$depth - 1]))
{
$child->parent = $current_element[$depth - 1];
$child->parent->children[] = $child;
}
$switch = CPHP_TEMPLATER_SWITCH_NONE;
$type = CPHP_TEMPLATER_TYPE_TAG_NONE;
$name = "";
}
else
{
if($text_block == "")
{
$current_text_element = $this->CreateSyntaxElement("text", "", $offset);
}
$text_block .= $char;
}
}
$offset += 1;
}
if($text_block != "")
{
$current_text_element->text = $text_block;
$text_block = "";
$current_element[0]->children[] = $current_text_element;
}
$this->root = $current_element[0];
$this->debug_tree = $debug_tree;
}
function CreateSyntaxElement($identifier, $statement)
{
if($identifier == "if")
{
$element = new TemplateIfElement;
}
elseif($identifier == "foreach")
{
$element = new TemplateForEachElement;
}
elseif($identifier == "text")
{
$element = new TemplateTextElement;
}
elseif($identifier == "variable")
{
$element = new TemplateVariableElement;
}
else
{
$element = new TemplateRootElement;
}
if($identifier == "if" || $identifier == "foreach")
{
$element->statement = $statement;
}
if($identifier == "if")
{
$statement_parts = explode(" ", $statement, 3);
$element->left = $statement_parts[0];
$element->operator = $statement_parts[1];
$element->right = $statement_parts[2];
}
if($identifier == "foreach")
{
$statement_parts = explode(" ", $statement, 3);
$element->varname = $statement_parts[0];
$element->source = $statement_parts[2];
}
if($identifier == "variable")
{
$element->variable = $statement;
}
return $element;
}
}
/* Syntax element definitions */
class TemplateSyntaxElement
{
public $parent = null;
public $children = array();
public $data = array();
public function Evaluate($data)
{
$result = "";
foreach($this->children as $child)
{
$result .= $child->Evaluate($data);
}
return $result;
}
public function FetchVariable($name, $data)
{
if(strpos($name, "[") === false)
{
return $data[$name];
}
else
{
// Variable refers to a subset of the data, traverse up the tree to find the matching dataset
$open_brace = strpos($name, "[");
$closing_brace = strpos($name, "]");
$source = substr($name, 0, $open_brace);
$item = substr($name, $open_brace + 1, ($closing_brace - $open_brace - 1));
$current_element = $this;
while(!is_null($current_element))
{
$current_element = $current_element->parent;
if(isset($current_element->varname))
{
if($current_element->varname == $source)
{
if(isset($current_element->data[$item]))
{
return $current_element->data[$item];
}
else
{
return false;
}
}
}
}
}
}
}
class TemplateRootElement extends TemplateSyntaxElement {}
class TemplateVariableElement extends TemplateSyntaxElement
{
public $variable = "";
public function Evaluate($data)
{
return $this->FetchVariable($this->variable, $data);
}
}
class TemplateTextElement extends TemplateSyntaxElement
{
public $text = "";
public function Evaluate($data)
{
return $this->text;
}
}
class TemplateIfElement extends TemplateSyntaxElement
{
public $statement = "";
public $left = "";
public $right = "";
public $operator = "";
public function Evaluate($data)
{
$a = $this->FetchVariable($this->left, $data);
$b = $this->right;
switch($this->operator)
{
case "=":
case "==":
$result = ($a == $b);
break;
case ">":
$result = ($a > $b);
break;
case "<":
$result = ($a < $b);
break;
case ">=":
$result = ($a >= $b);
break;
case "<=":
$result = ($a <= $b);
break;
case "!=":
$result = ($a != $b);
break;
default:
$result = false;
}
if($result == true)
{
return parent::Evaluate($data);
}
}
}
class TemplateForEachElement extends TemplateSyntaxElement
{
public $statement = "";
public $source = "";
public $varname = "";
public $block = "";
public $data = array();
public function Evaluate($data)
{
$target = $this->FetchVariable($this->source, $data);
$result = "";
foreach($target as $iteration)
{
$this->data = $iteration;
foreach($this->children as $child)
{
$result .= $child->Evaluate($data);
}
}
return $result;
}
}

@ -21,3 +21,23 @@ class ConstructorException extends Exception {}
class MissingDataException extends Exception {}
class DatabaseException extends Exception {}
class TypeException extends Exception {}
class TemplateException extends Exception
{
public $message = "";
public $file = "";
public $startpos = 0;
public $endpos = 0;
public $code = 0;
public function __construct($message, $file, $startpos, $endpos, $code)
{
$this->message = $message;
$this->file = $file;
$this->startpos = $startpos;
$this->endpos = $endpos;
}
}
class TemplateSyntaxException extends TemplateException {}
class TemplateParsingException extends TemplateException {}

Loading…
Cancel
Save