Documentation

Separate Template Engine
Version 1.5 (9. Jan 2013)

What is Separate Template Engine?

Separate Template Engine, or short Separate, is an object-oriented Template Engine for PHP. With Separate, it is possible to separate business logic (e.g. reading data from the database) from the presentation layer and thus produce a neat, clear and well-structured source code. In the course of this, generation of complete HTML pages is managed by the Template Engine.
 

Architecture of Separate

Important characteristics of the architecture

During development, great importance to the dynamic functional extension (such as Value Formatter, or the possibility of inheritance of the Separate Template Class) was attached. In total, the following characteristics, which are important for the development, were implemented:
  • Minimal functional restrictions (easy extension with own features is possible)
  • Simple API (e.g. only the SeparateTemplate.php file is needed)
  • Independent of other libraries (such as Pear,...)

Structure of a Separate-based Application

Applications based on Separate consist of two layers - the presentation layer and the business logic. The presentation layer consists of an HTML source code and of Template Variables, or other Separate-relevant constructs, respectively. In the business logic, certain calculations are carried out (e.g. reading data from a database) and the then generated values are assigned to certain Template Variables.
 

 
The upper figure shows the business logic as well as the presentation layer which is processed by Separate. As a result, an HTML source code is returned.
 

Integration in own project

Separate needs PHP5 (or higher). In order to use Separate, the supplied SeparateTemplate Class has to be included into your project.
require_once './SeparateTemplate.php';

Next, a Template file has to be loaded. For this, the method SeparateTemplate.loadSourceFromFile(...) is used.
$t = SeparateTemplate::instance()->loadSourceFromFile('./index.htm');

After successful loading of the Template file, the actual implementation such as the assignment of values to certain Template Variables can take place.
$t->assign('MY_VARIABLE', 'my value');

The generation of the HTML page takes place with the SeparateTemplate.display() method.
$t->display();

The following source code sums up all above-mentioned steps.
<?php

require_once './SeparateTemplate.php';

$t = SeparateTemplate::instance()->loadSourceFromFile('./index.htm');
$t->assign('MY_VARIABLE', 'my value');
$t->display();

Template Variables

For each dynamically generated information unit, a Template Variable has to be compiled in the Template file. During generation of the page, the Template Engine replaces these variables by a prior assigned value. The syntax looks as follows:
${<Variable Name>}

Dynamic Blocks

With dynamic blocks, you can separate an HTML source code into sections. These sections can be repeated as often as you like during runtime. This is useful for generating e.g. a table with dynamic content. The syntax looks as follows:
<!-- BEGIN <Block Name> -->
    HTML source...
<!-- END <Block Name> -->

In the PHP source code, every block is represented by a SeparateTemplate object. The SeparateTemplate.fetch(...) method creates a new block. With the SeparateTemplate.assign(...) method, the modified block is then forwarded to the root template. Depending on the number of datasets, this process has to be repeated several times.
 
The example below shows a simple implementation of dynamic blocks.

PHP source code:
<?php

require_once './SeparateTemplate.php';

$rootTemplate = SeparateTemplate::instance()->loadSourceFromFile('./index.htm');

for($row = 1; $row <= 3; $row++)
{
    //fetch row block from root template
    $rowBlock = $rootTemplate->fetch('row');
    
    for($column = 1; $column <= 3; $column++)
    {
        //fetch column block from row block
        $columnBlock = $rowBlock->fetch('column');
        
        $columnBlock->assign('ROW_NUMBER', $row);
        $columnBlock->assign('COLUMN_NUMBER', $column);
        
        //assign modified column block back to row block
        $rowBlock->assign('column', $columnBlock);
    }
    
    //assign modified row block back to root template
    $rootTemplate->assign('row', $rowBlock);
}

$rootTemplate->display();

?>

Template source code (index.htm):
<html>
    <body>
        <table>
            <!-- BEGIN row -->
                <tr>
                    <!-- BEGIN column -->
                        <td>Row: ${ROW_NUMBER} Column: ${COLUMN_NUMBER}</td>
                    <!-- END column -->
                </tr>
            <!-- END row -->
        </table>
    </body>
</html>

As you can see from the example above, further blocks can be defined within blocks. The thus generated HTML source code looks as follows then:
<html>
    <body>
        <table>
            <tr>
                <td>Row: 1 Column: 1</td>
                <td>Row: 1 Column: 2</td>
                <td>Row: 1 Column: 3</td>
            </tr>
            <tr>
                <td>Row: 2 Column: 1</td>
                <td>Row: 2 Column: 2</td>
                <td>Row: 2 Column: 3</td>
            </tr>
            <tr>
                <td>Row: 3 Column: 1</td>
                <td>Row: 3 Column: 2</td>
                <td>Row: 3 Column: 3</td>
            </tr>
        </table>
    </body>
</html>

Assignment of placeholder values

Values for pre-defined template placeholders are assigned with the help of certain methods. There are three different types of assignment:
 

1. Simple assignment of placeholder values

With this type of assignment, the assigned values are restricted to a Template Block or a root template. Template placeholders, which are located outside this range, are simply ignored. The assignment takes place by the SeparateTemplate.assign(...) method.
$t->assign('MY_VARIABLE', 'my value');

2. Block-relevant assignment of placeholder values

With the block-relevant assignment of placeholder values, a value can be assigned to a variable, which is located within a block (including the sub-block). Variables, which are located in other blocks, are ignored.
$t->assignForBlock('MY_BLOCK_VARIABLE', 'my block value');

3. Global assignment of placeholder values

With this type of assignment, values can be assigned to all template variables. So, it does not matter if a template variable is located in a block or directly on the root level of the template. Using this assignment is only useful with variables, which often appear in many source code areas. For assigning global values, the SeparateTemplate.assignForGlobal(...) method is used.
$t->assignForGlobal('MY_GLOBAL_VARIABLE', 'my global value');

Formatting of placeholder values

By default, all values are displayed in the HTML source code without change. However, it is sometimes necessary to change these values, for example, if a certain text is displayed on a page, which contains HTML control characters (<, >, &, ...). These characters have to be changed when generating the page. In order to do this as elegantly and dynamically as possible, Separate supports so-called Value Formatters.
 
A Value Formatter consists of statements, which change a placeholder value. If a value is assigned to a template placeholder, which uses Value Formatters, the assigned value will be changed by the according Value Formatter before being displayed in the generated HTML source code. The syntax for a template placeholder with defined Value Formatter looks as follows:
${(<Value Formatter Name>)<Placeholder Name>}

The following example shows a simple Value Formatter implementation, which changes the Unix Timestamp into a legible date and time.
 
PHP source code:
<?php

require_once './SeparateTemplate.php';
require_once './formatter/DateFormatter.php';
require_once './formatter/TimeFormatter.php';

$t = SeparateTemplate::instance()->loadSourceFromFile('./index.htm');
$t->assign('UNIX_TIMESTAMP', time());
$t->display();

?>

Template source code (index.htm):
<html>
    <body>
        Timestamp: ${UNIX_TIMESTAMP}<br>
        Date: ${(Date)UNIX_TIMESTAMP}<br>
        Time: ${(Time)UNIX_TIMESTAMP}
    </body>
</html>

The generated HTML source code then looks as follows:
<html>
    <body>
        Timestamp: 1354175751<br>
        Date: 29.11.2012<br>
        Time: 08:55
    </body>
</html>

Default Value Formatter

With the method SeparateTemplate.setDefaultFormatter(...), a Value Formatter can be set, which is used by default with all template placeholders.
$t->setDefaultFormatter(new TextFormatter());

Existing Value Formatters

Several Value Formatters are already delivered with Separate.
 
Formatter Class Name Description
DateFormatter Date Changes Unix Timestamp into a legible date, e.g. 21.11.2012
TimeFormatter Time Changes Unix Timestamp into a legible time, e.g. 12:30
DateTimeFormatter DateTime Changes Unix Timestamp into a legible date with additional time, e.g. 21.11.2012 12:30
TextFormatter Text Replaces all HTML control characters (e.g. <, > or &) by HTML-encoded characters (e.g. &lt;, &gt; or &amp;).
UrlFormatter Url Creates an URL-conformal character string, which is primarily used for hyperlinks.
HashFormatter Hash Hash is used in an IF-Condition for comparing two unknown character strings.
IsEmptyFormatter IsEmpty IsEmpty is used in an IF-Condition for checking if a placeholder is empty.

Own Value Formatters

It is possible to create own Value Formatters. For this, a class has to be set up, which inherits the AbstractValueFormatter class. Then, the method AbstractValueFormatter.formatValue(...) has to be overridden with own business logic.
 
Upon naming custom Value Formatter classes, a certain notation has to be complied with. The class name starts with a Formatter name, which is used with template placeholders, and always ends with the word "Formatter".
 
Syntax of the class name for a custom Value Formatter:
<Formatter Name>Formatter

The following example shows an implementation of Value Formatter, which changes the placeholder value into capital letters.
 
PHP source code:
<?php

require_once './SeparateTemplate.php';

class ToUpperFormatter extends AbstractValueFormatter
{
    public function formatValue($value)
    {
        return strtoupper($value);
    }
}


$t = SeparateTemplate::instance()->loadSourceFromFile('./index.htm');
$t->assign('MY_VARIABLE', 'my value');
$t->display();

?>

Template source code (index.htm):
<html>
    <body>
        ${(ToUpper)MY_VARIABLE}
    </body>
</html>

The generated HTML source code looks as follows:
<html>
    <body>
        MY VALUE
    </body>
</html>

Placeholder without formatting possibility

Sometimes, a maximally possible HTML source code rendering time is very important. For this requirement, there is a special type of placeholder, which is very fast in rendering on the one hand, but on the other hand does not support formatting by Value Formatters.
 
In the template source code, placeholder of this type start with a # character:
#{<Placeholder Name>}

For this, special assignment methods have to be used in the PHP source code. These methods are identical to normal assignment methods, but they start with an x character.
$t->xassign('MY_VARIABLE', 'my value');
$t->xassignForBlock('MY_BLOCK_VARIABLE', 'my block value');
$t->xassignForGlobal('MY_GLOBAL_VARIABLE', 'my global value');

Template Including

It is possible to include multiple template files in one template.
 
Syntax of the include command:
<!-- INCLUDE <File Name> -->

The following example shows an implementation of the include command in the template source code.
 
Header file (header.htm):
<html>
    <body>

Footer file (footer.htm):
    </body>
</html>

Template source code (index.htm):
<!-- INCLUDE header.htm -->
    <p>Hello</p>
<!-- INCLUDE footer.htm -->

IF-Condition

Sometimes, it is necessary to move certain decisions to the presentation layer. To make this possible, IF-conditions are supported. The syntax of an IF-condition looks as follows:
<!-- IF <Condition 1> -->
    HTML source...
<!-- ELSE IF <Condition 2> -->
    HTML source...
<!-- ELSE -->
    HTML source...
<!-- END IF -->

The condition can contain multiple placeholders. All compare operators from PHP can be used. A simple implementation example is illustrated below.
 
PHP source code:
<?php

require_once './SeparateTemplate.php';

$t = SeparateTemplate::instance()->loadSourceFromFile('./index.htm');
$t->assign('MY_VARIABLE', 'hello');
$t->display();

?>

Template source code (index.htm):
<html>
    <body>
        <!-- IF '${MY_VARIABLE}' == 'hello' -->
            The value of MY_VARIABLE is 'hello'
        <!-- ELSE -->
            The value of MY_VARIABLE is '${MY_VARIABLE}'
        <!-- END IF -->
    </body>
</html>

Particularities upon comparison of values

To provide fast rendering time, certain validations are not performed by the template engine. A developer has to follow some special particularities when creating an If-condition.
 
For comparing two placeholders with unknown values, a Hash Formatter has to be used, which changes the values into a Hash String when comparing.
<!-- IF '${(Hash)MY_VARIABLE_A}' == '${(Hash)MY_VARIABLE_B}' -->
    ...
<!-- END IF -->

For checking if a placeholder contains an empty string, the IsEmpty Formatter has to be used. If the placeholder contains an empty string, the value will be changed by the Formatter into "TRUE". Otherwise, the value will be changed to "FALSE".
<!-- IF '${(IsEmpty)MY_VARIABLE}' == 'TRUE' -->
    ...
<!-- END IF -->

For facilitating boolean comparisons, the SeparateTemplate::booleanToString(...) method is available. This changes a boolean value into "TRUE" or "FALSE".
 
PHP source code:
$t->xassign('LOGGED_IN_FLAG', SeparateTemplate::booleanToString(...));

Template source code:
<!-- IF '#{LOGGED_IN_FLAG}' == 'TRUE' -->
    ...
<!-- END IF -->

Template Parameters

With Template Parameters it is possible to define any settings in the template. These parameters can then be read in the PHP source code. But what do you need this for? Here is an example from experience:
 
Sometimes, it happens that a web application has different layouts. For example, if, next to a normal layout, another layout for mobile devices is offered. In practice, two different templates are developed for the same business logic - one for standard layout and one for mobile devices. Imagine us having a dynamically generated table with many rows, which in turn are spread onto several pages. 100 rows will be displayed on every page with the standard layout. But maximally 10 rows per page are to be displayed in the layout for mobile devices because otherwise, it would be too much. For realizing this without making any changes in the PHP source code, so-called Template Parameters were developed.
 
Template Parameter Syntax:
<!-- PARAMETER <Parameter Name> '<Parameter Value>' -->

Example:
<!-- PARAMETER NUMBER_OF_ROWS '100' -->

All available parameters can be read with the SeparateTemplate.getParameters() method. With the SeparateTemplate.getParameterValue(...) method, the content of specified parameter can be read. Should a parameter not exist, an exception is thrown. So, it makes sense to check the selection with the SeparateTemplate.isParameterSet(...) method before. Parameters can be defined or changed during execution. For this, the SeparateTemplate.setParameterValue(...) method has to be used.
 

Template Comments

Everyone knows that there is a possibility to write source code comments in HTML. The comments look like this:
<!-- HTML comment... -->

Such source code comments have two disadvantages: They are sent to the client and produce unnessessary traffic. Another disadvantage is that such comments are visible on the client side (in the HTML source code). For this reason, Separate offers the possibility to create special template comments. These template comments are not visible in the generated HTML source code and are not forwarded to the client.
 
The syntax looks as follows:
<!--- Template comment... --->

Recommendations

Naming many source code components is left up to the programmer. Anyway, it is recommended to use a given naming.
 

Naming of SeparateTemplate placeholders in the PHP source code

It is recommended to store all SeparateTemplate objects in one array (e.g. $t). The block name is simply declared as a key. In the example below $t['.'] stands for the root template and $t['block']['.'] or $t['block']['sub_block']['.'] for corresponding blocks.
$t['.'] = SeparateTemplate::instance()->loadSourceFromFile('./index.htm');

for(...)
{
    $t['block']['.'] = $t['.']->fetch('block');
    
    for(...)
    {
        $t['block']['sub_block']['.'] = $t['block']['.']->fetch('sub_block');
        
        //...
        
        $t['block']['.']->assign('sub_block', $t['block']['sub_block']['.']);
    }
    
    $t['.']->assign('block', $t['block']['.']);
}

$t['.']->display();

Naming of template placeholders in large projects

It may occur that a placeholder name has several functional meanings. For example, the template placeholder NAME can stand for a user name (as e.g. "John Doe") as well as for the label in the current language (e.g. "Name"). In order to avoid these conflicts, it is useful to define a prefix for each functional meaning.
#{LANGUAGE.NAME}: ${VALUE.NAME}

In the example above, all template placeholders for phrases in the current language begin with LANGUAGE and all placeholders for dynamic values with VALUE.
 
Another advantage is that it is possible to set values for the LANGUAGE placeholders automatically. For detecting all LANGUAGE placeholders that exist in the current template, the method SeparateTemplate.getVariableNames() can be used. Then, the values can be set with the method SeparateTemplate.xassignForGlobal(...).
 

License

Separate Template Engine was developed by Eduard Sudnik and is an open-source framework for PHP, which is available under the MIT-License.
© 2004—2024 Eduard Sudnik E-Mail: separate@esud.info