Saturday, September 22, 2012

Simple PHP-TemplateEngine

So today I started to program a simple browsergame and I found an interesting input to use an TemplateEngine.
A TemplateEngine parse a "template HTML-File" and enter the output variables into the shown file.
One of the called TemplateEngines was Smarty. It looks like it's easy to use but I was interested in how it works.
I tried by myself to create a really simple TemplateEngine by using RegEx.

One of the first template for my engine looks like this:


<html>
    <head>
        <title>
TemplateEngine</title>
    </head>
    <body>

        <table style="font-family: Arial, sans-serif; border: 3px solid #000;">
            <tbody>
                <tr>
                    <td>
Name:</td>
                    <td>
{name}</td>
                </tr>
                <tr>
                    <td>
Prename:</td>
                    <td>
{prename}</td>
                </tr>
            </tbody>
        </table>
    </body>
</html>



The template variables {name} and {prename} should be replaced with php-variables.
I think one simple way is to use RegEx.

This is the RegEx pattern to get the full variable "{name}" and the string between the brackets "name":

#\{(.*)\}#e

We need to build up a little class in PHP and we should be able to assign variables to the TemplateEngine and render a template file:

class Template
{
    private $Variables = array();

    function __construct()
    {
    }
   
    function Assign($key, $value)
    {
        //Add the $value to the $key
        $this->Variables[$key] = $value;
    }
   
    function Render($tpl)
    {
        $content = file_get_contents($tpl);
        echo $this->ReplaceVariables($content);
    }
   
    private function ReplaceVariables($content)
    {
        return @preg_replace('#\{(.*)\}#e', '$this->Variables[\'$1\']', $content);
    }
}


So, we can assign variables and render a file to replace the template-variables with assigned variables.
The most important line is the RegEx-line:

@preg_replace('#\{(.*)\}#e', '$this->Variables[\'$1\']', $content);

We replace the template-variable with the assigned variable from the array. The RegEx-Pattern returns one variable with the string between the brackets and this string is our key to find the value in the array.

To test this code i made a little test.php file:


include('framework/TemplateEngine/Template.php');

$tpl = new Template();
$s = new thesample();
$tpl->Assign('name', 'Hodler');
$tpl->Assign('prename', 'Martin');
$tpl->Render('index.tpl')
;
 


But thats not enough for me :).
I want to be able to assign objects or arrays so i worked a bit at the Assing-Function in our Template-Class:

    function Assign($key, $value)
    {
        //Check if the $value is an object
        if (is_object($value))
        {
            //Get an array of variable-values of the $value
            $vars = get_object_vars($value);
            //Get an array of the variable-names of the $value
            $keys = array_keys($vars);
            for ($i = 0; $i < count($vars); $i++)
            {
                //Create index key. For example "{$key:objectvariable}"
                $k = $key.":".$keys[$i];
                //Add the value to the key
                $this->Variables[$k] = $vars[$keys[$i]];
            }
        }
        //Check if the $value is an array
        else if(is_array($value))
        {
            //Get the keynames by default it is numeric
            $keys = array_keys($value);
            for ($i = 0; $i < count($value); $i++)
            {
                //Create index key. For example "{$key:0}"
                $k = $key.":".$keys[$i];
                //Add the value to the key
                $this->Variables[$k] = $value[$i];
            }
        }
        else
            //By default add the $value to the $key
            $this->Variables[$key] = $value;
    }


Now we can assign a class, for example an user-class with the variables 'name' and 'prename' and call them with the template-variable '{user:name}' or '{user:prename}'.

Here the final test code:

include('framework/TemplateEngine/Template.php');
class User
{
    var
$name = "Hodler";
    var $prename = "Martin";
}

$user = new User();

$tpl = new Template();
$tpl->Assign('user', $user);
$tpl->Render('index.tpl');

 
 

 
And the template file 'index.tpl':

<html>
    <head>
        <title>
TemplateEngine</title>
    </head>
    <body>
        <table
style="font-family: Arial, sans-serif; border: 3px solid #000;">
            <tbody>
                <tr>
                    <td>
Name:</td>
                    <td>
{user:name}</td>
                </tr>
                <tr>
                    <td>
Prename:</td>
                    <td>
{user:prename}</td>
                </tr>
            </tbody>
        </table>
    </body>
</html>



And the final result looks like this: