Div is a template engine for PHP developed by the Eng. Rafa Rodriguez in 2011,
that allows the separation of labor between the programmer and
the designer. As the designer built templates with some specific tags, the programmer uses the
template to replace these tags with the information. Div have a compact a descriptive syntax for template's designers.
Of course, the replacement of tags is a basic functionality. More extensions
of the substitutions exist, for example, replace repeatedly N times, replace conditionally, among others.
The programmer creates an instance of a class with 2 parameters: the
first is the designer's code
or name of the file that he built, and the second is the information
represented by an array, objects, or a combination of arrays and
objects to replace the design's tags. The array's indexes, array's keys
and object's properties must correspond with
the design's tags.
The syntax of Div is very compact. If the programmer wants to do a
cycle, the designer only needs to know a name for that cycle, and
if he wants to hide a part of the GUI, the designer is only responsible
for tag the part that will be
hidden or displayed conditionally.
For example, see the following code of Smarty and compare it with Div:
Smarty:
1
{include file="header.tpl"}
2
3
{foreach from = $products name = products}
4
Product name: {$products.name}
5
{if !$smarty.foreach.products.last},{/if}
6
{/foreach}
7
8
{include file="footer.tpl"}
Div:
1
{% header %}
2
3
[$products]
4
Product name: {$name}
5
!$_is_last,$_is_last!
6
[/$products]
7
8
{% footer %}
Which is it more descriptive? Which is it easier of learning?
Twig:
1
{% for user in users %}
2
{{ user.name }}
3
{% else %}
4
No user have been found.
5
{% endfor %}
Div:
1
[$users]
2
{$name}
3
@empty@
4
No user have been found.
5
[/$users]
Reasons
Div is developed with the philosophy of the knowledge reused. Of course, Div is released in time of
recognized template engines that are widely used. For this reason, Div develop a minimum new knowledge
so that the developers can quickly become familiar with this engine and they can understand when, how
and why to use it.
The features are added if it is really necessary. That is, if there is a need to add another functionality,
we first analyzed whether there is a mechanism to resolve this functionality, and then we publish an article
that explains how to implement this mechanism.
The argument to develop Div was obtained from various tests with PHP and we concluded that it is faster replace
the portions of string than includes of PHP scripts.
The fact remains, that the replacement of substrings is a fast process but it require more memory. However,
this consumption is so small that it is worthwhile the sacrifice.
Div development is to avoid creating a cache system because we believe that it is unnecessary according
to their characteristics as an engine. A learning system can be sufficient: it can prevent the repeated processing
of the same templates.
Finally, it is known that the most popular engines are composed of more than one file, classes and libraries.
Div sought since its inception, the implementation of everything in one class, in a single file. This allows easy
adaptation to existing development platforms.
Goals?
One class, one file!, considering the template like an object.
Create a minimum of highly descriptive syntax.
Avoid a cache system.
Improve the algorithms.
Reuse the knowledge, write mechanisms and extend!.
Possibilities for the designer
The designer carries out its work in text files and he can use different tags. Div does not provide for the
design obtrusive code. All that is programmed in the templates has a single goal: design.
Replace tags
Apply variable's modifiers: uppercase, lowercase, word count, paragraph count,
string length, URL encode, convert everything to HTML entities
Working with substrings
Loops, iterations, cycles or repetitive parts
Parts of templates displayed conditionally
Evaluation conditions
Definition of variables
Divide the design into parts and then include or pre-process it
Formatting Numbers and Dates
Working with Formulas
Comments
Position of content
Recursion: the engine processes the template over and over again until there is
nothing to process
Mechanism for the inheritance among templates
Ignoring parts of the template
Access to any specific value of the information passed by the programmer
Access to methods of information's objects
Aggregate functions: sum, average, minimum, maximum, count on.
Clean the output
Convert HTML to readable text
Using the custom subparsers implemented by the programmer.
Possibilities for the programmer
The programmer creates an instance of div class, specifying in its constructor, the template
created by the designer and the information that will be displayed.
Rename the div class
Define default file extensions
Div class inheritance and object-oriented programming
Define variables
Defining global variables
Define replacement values per variable
Load data from a JSON file
Ignore information variables passed to the constructor of the div class
Debug
Use class div instance as a string
Implement some hooks
The div class
All implementation of Div is the div class and different forms exist of using it.
Always: include the file div.php.
1
<?php
2
3
include "div.php";
4
5
// ...
Variant 1: All in one instruction
1
<?php
2
3
echonew div('Hello {$name}', array(
4
'name' => 'Peter'
5
));
Variant 2: First instance, then show
1
<?php
2
3
$t = new div('Hello {$name}', array(
4
'name' => 'Peter'
5
));
6
7
echo $t; /* or $t->show(); */
Variant 3: The template in external file
1
<?php
2
3
/* The file index.tpl contain
4
the template code */
5
6
echonew div('index.tpl', array(
7
'name' => 'Peter'
8
));
Variant 4: The data as JSON code
1
<?php
2
3
echonew div('Hello {$name}',
4
'{name: "Peter"}');
Variant 5: The data in JSON file
1
<?php
2
3
/* The file index.json contain
4
the data as JSON code */
5
6
echonew div('index.tpl', 'index.json');
Ignore specific variables (the third parameter of constructor)
If you want that the engine ignore some variables in template,
specify the variables as a list of names in the third parameter of constructor:
The design should not "guess" the content:
The developers in occasions give this task to the template, and they obtain content
using the possibilities of the language of templates, when in fact this it is the
programmer's task. For example, it is an error to calculate in the template the
amounts of the products of an invoice and the total amount, although this it can
seem an example of the use of aggregate functions. The language of templates
is not conceived to obtain the lacking information, but to make a good design.
The design should be very wrapped to the content and vice versa:
Try to balance the content built in the programming, with the content manipulated in the
template, so that it doesn't have more than enough content, which the motor has to discard,
neither have more than enough template code, which the motor also ends ignoring.
Divide the design as much as it is possible and not so much that it is absurd:
Try to build the templates so that they complete the smallest quantity in objectives and that they are the
smallest possible, and therefore reusable. Don't build big templates with many conditions where most is
discarded. The developers sometimes mix the templates some with other, to have everything in a file and this
diminishes the performance of the project. For example, it is not good practice to have two templates in one,
prepared for two different contents separated by a since condition this implies to have another decision variable.
If you have not found another solution, divide the template in two parts, make a third and use the inclusions or the
pre-processed templates. But remember, it is not good practice to have an isolated template that it is
included and always for one template, and therefore it is not reused neither conditionally loaded.
Variables (information, content...)
The designer doesn't have reason to know what are a data type to
make their work. It should simply consider to the variables of the
design as "the information". For this reason, in the templates, Div
normalizes all the information coming from PHP, considering an array,
objects or combination of arrays and objects as "same things".
The information represents a hierarchy. You can access to all thier "pieces" using the dot "." operator.
Example
index.php
1
<?php
2
3
include'div.php';
4
5
/* This code... */
6
7
echonew div('index.tpl', array(
8
'single' => 'something',
9
'complex' => array(
10
'single' => 45,
11
'subcomplex' => array(
12
'single' => '60'
13
)
14
)
15
));
16
17
/* ... is similar to this another code ... */
18
19
$complex = new stdClass();
20
$complex->single = 45;
21
$complex->subcomplex = array('single' => 60);
22
23
echonew div('index.tpl', array(
24
'single' => 'something',
25
'complex' => $complex
26
));
index.tpl
1
Single value: {$single}
2
Single value into complex var: {$complex.single}
3
And more: {$complex.subcomplex.single}
Output
1
Single value: something
2
Single value into complex var: 45
3
And more: 60
String's dissection
The scalar values as a complex values. All the scalar values can be used as a strings. Then, the strings
can be used like complex values, that is to say, as group of characters. For example:
Variable's modifiers allow you to change the value of a variable or obtain information about the value in the templates, so
they change the way they are displayed, such as a text in capital letters, etc..
Syntax in templates:
The following variable's modifiers can be used with the current version of Div:
Modifier
Description
{$variable}
Nonthing to change
{^variable}
Capitalize the first character of the string.
{^^variable}
Capitalize the first character of each word of the string.
The programmers can create new modifiers of variables. For this the programmers should use the static method
"addCustomModifier." The modifier can be a function or a static method of class. The modifier function should have
a single parameter.
Example
index.php
1
<?php
2
3
include'div.php';
4
5
class MyModifiers {
6
7
/* The modifier function should have a single parameter. */
The way of define a part of the template and ignore their code.
Syntax in templates
1
{ignore}
2
3
... some ignored code here ...
4
5
{/ignore}
Example
index.php
1
<?php
2
3
include'div.php';
4
5
echonew div('index.tpl', array(
6
'name' => "Peter"
7
));
index.tpl
1
{ignore}
2
3
Name: {$name}
4
5
{/ignore}
Output
1
Name: {$name}
Comments
Syntax in templates
1
<!--{ inline comment here }-->
2
3
<!--{
4
5
Multi-line comment here
6
This multiline comment is not sent to browser.
7
8
}-->
9
Example
index.tpl
1
<h1>Hello world</h1>
2
3
<!--{ This is a comment }-->
4
<span>Powered by Div</span>
Output
1
<h1>Hello world</h1>
2
<span>Powered by Div</span>
HTML to plain text
Syntax in templates
1
{txt}
2
... some html code here ...
3
{/txt}
4
5
{txt} width =>
6
... some html code here ...
7
{/txt}
Example
index.tpl
1
{txt}
2
3
<h1>Document title</h1>
4
5
{/txt}
Output
1
Document title
Lists (loops)
With a list you can repeat some part of template code and work with each item of the list.
Syntax in templates
1
[$listvar]
2
... some code here ...
3
@empty@
4
... some code when the list is empty ...
5
[/$listvar]
Example
index.php
1
<?php
2
3
echonew div('index.tpl',array(
4
'employees' => array(
5
'Salvi',
6
'Peter',
7
'John'
8
),
9
'products' => array()
10
));
index.tpl
1
Employees:
2
3
[$employees]
4
{$value}
5
[/$employees]
6
7
Products:
8
9
[$products]
10
{$name}
11
@empty@
12
Empty list of products!
13
[/$employees]
Output
1
Employees:
2
3
Salvi
4
Peter
5
John
6
7
Products:
8
9
Empty list of products!
Dynamic/injected vars for each cycle
Var
Data type
Description
$_item
mixed
Current item
$_previous
mixed
The previous item
$_next
mixed
The next item
$_key
mixed
The key of the item in the PHP array
$_index
integer
The index of the item (0..n-1)
$_index_random
integer
Random index of the list (0..n-1)
$_order
integer
The order of the item (1..n)
$_list
string
The name of the list
$_is_last
boolean
True if the current item is the last
$_is_first
boolean
True if the current item is the first
$_is_odd
boolean
True if the current index is odd
$_is_even
boolean
True if the current index is even
Iterations (perform a N iterations of cycle)
The iterations are loops that increment a variable in each cycle. The
value of this variable can be accessed by $value. You can also specify the name of the
variable and the steps of the increments.
Syntax in templates
1
[:from,to,var,step:]
2
... some code here ...
3
[/]
Example
index.tpl
1
[:1,10:] {$value} [/]
2
[:1,10,x:] {$x} [/]
3
[:1,10,x,2:] {$x} [/]
Output
1
1 2 3 4 5 6 7 8 9 10
2
1 2 3 4 5 6 7 8 9 10
3
1 3 5 7 9
Conditional parts
One of the most commonly used functions in the GUI is to show or
hide part of the interface. This is achieved with Div in various ways,
and one of them is the use of the conditional parts.
Some conditional on the template is defined by a block that begins
and ends with the character question tag (?) or exclamation (!)
otherwise, accompanied by a variable that must be a boolean value. For
example, you can do this in the template:
1
?$showproducts
2
... some template here ...
3
$showproducts?
If the value of "showproducts" is true, it shows the code between
both tags. If the value is false or if you not pass the variable
"showproducts", that part of code will be hidden.
In general, the boolean value is defined by the method div::mixedBool, which takes into account the following criteria:
False if the value is false
False if the value is null
False if the value is not greater than zero
False if is "0"
False if is an empty string
False if is an object without properties
The same value in any other case
Syntax in templates
1
2
For test the var as TRUE:
3
4
?$var
5
... some code here ...
6
@else@
7
... some another code here
8
$var?
9
10
For test the var as FALSE:
11
12
!$var
13
... some code here ...
14
@else@
15
... some another code here
16
$var!
17
Example
index.php
1
<?php
2
3
echonew div('index.tpl', array(
4
'products' => array(
5
array('name' => 'Banana', 'price' => 20.5),
6
array('name' => 'Potato', 'price' => 10.8)
7
)
8
));
index.tpl
1
2
Products:
3
4
?$products
5
[$products]
6
{$name} - {$price}
7
[/$products]
8
@else@
9
No products
10
$products?
11
12
Similar result:
13
14
!$products
15
No products
16
@else@
17
[$products]
18
{$name} - {$price}
19
[/$products]
20
$products!
21
Output
1
Products:
2
3
Banana - 20.5
4
Potato - 10.8
5
6
Similar result:
7
8
Banana - 20.5
9
Potato - 10.8
Conditions
The conditions is more complicated than conditional parts. With conditions, you can show conditional parts based on a boolean expression and not only from a boolean value.
See the allowed PHP functions. The expression can be an expression of PHP, blended with code of Div.
This feature is dedicated to designers. The designers can declare
variables in the template and to use them for different reasons.
The values of variables can be:
A string
Another var
An object or an array in JSON
A call to method of the current PHP class
The path of JSON file
Important:If the value is not valid JSON, it will be considered as
a template and will be parsed before decoding. See the next sequence:
1. Value is not valid JSON: {= digits: [[:0,8:]{$value},[/]9] =}
2. Value was parsed: {= digits: [0,1,2,3,4,5,6,7,8,9] =}
3. Now "digists" is an array.
4. Replacement: {$digits} <!--{ OUTPUT "10" }-->
See the difference:
1. Value is valid JSON: {= digits: "[[:0,8:]{$value},[/]9]" =}
2. Value was not parsed: {= digits: "[[:0,8:]{$value},[/]9]" =}
3. Now "digists" is an string.
4. Replacement: {$digits} <!--{ OUTPUT "[0,1,2,3,4,5,6,7,8,9]" }-->
In this section you can learn how the programmer can create classes that inherits from the div class.
Syntax in templates
The constructor should respect the parent's constructor. Change the default
constructor is not recommended. IMPORTANT: The recommended way for do something
before build is the implementation of beforeBuild() hook.
1
<?php
2
3
include'div.php';
4
5
class MyPage extends div{
6
7
/* IMPORTANT: Change the default constructor is not recommended */
The information or content that it is passed to the constructor of the div class, can
be an object and/or it can contain objects and you can access to the methods of these objects.
The access to those methods to obtain information depends on the context or scope in which is
you working.
Example: "template scope"
index.php
1
<?php
2
3
include'div.php';
4
5
class MyData{
6
7
var $values;
8
9
function __construct($values){
10
$this->values = $values;
11
}
12
13
publicfunction implode(){
14
return implode(",",$this->values);
15
}
16
17
}
18
19
echonew div('index.tpl', new MyData(array("A","B","C","D")));
index.tpl
1
2
{= data: ->implode() =}
3
4
{$data}
5
Output
1
A,B,C,D
Example: "capsule scope"
index.php
1
<?php
2
3
include'div.php';
4
5
// create a class ...
6
7
class MyString{
8
9
var $value;
10
11
function __construct($value){
12
$this->value = $value;
13
}
14
15
publicfunction upper(){
16
return strtoupper($this->value);
17
}
18
19
}
20
21
// using the class
22
23
echonew div('index.tpl', array('name' => new MyString('peter')));
index.tpl
1
2
[[name
3
{$value}
4
5
{= up: ->upper() =}
6
7
{$up}
8
name]]
9
Output
1
peter
2
PETER
Example: accesing to any var/object method (new from 4.7)
index.tpl
1
{= up: ->name.upper() =}
2
{$up}
Output
1
PETER
Example: "loop's body scope"
index.php
1
<?php
2
3
include'div.php';
4
5
class Person{
6
7
var $first_name;
8
var $last_name;
9
10
function __construct($first_name, $last_name){
11
$this->first_name = $first_name;
12
$this->last_name = $last_name;
13
}
14
15
publicfunction getName(){
16
return $this->first_name.' '.$this->last_name;
17
}
18
19
}
20
21
echonew div('index.tpl', array(
22
'people' => array(
23
new Person('John', 'Nash'),
24
new Person('Peter', 'Joseph'),
25
new Person('Jacque', 'Fresco')
26
)
27
));
index.tpl
1
2
[$people]
3
{= complete_name: ->getName() =}
4
5
First name: {$first_name}
6
Last name: {$last_name}
7
Complete name: {$complete_name}
8
9
[/$people]
10
Output
1
First name: John
2
Last name: Nash
3
Complete name: John Nash
4
5
First name: Peter
6
Last name: Joseph
7
Complete name: Peter Joseph
8
9
First name: Jacque
10
Last name: Fresco
11
Complete name: Jacque Fresco
The hooks
The hooks are methods that can be implemented by the programmer in a class that
inherit from div. This methods will be executed by div in some events. For example,
before or after parse of template.
At the moment, the hooks are beforeBuild, afterBuild, beforeParse and afterParse.
In the beforeBuild hook, you can modify the $src and $items optional parameters of the div constructor.
If an object has implemented the method __toString, you can work with the object as a character string
in three possible scopes: template's scope, loop body's scope and capsule's scope. You can use two possible variables
to put the content returned by the implemented __toString() method:
The variable $_to_string in template's scope.
The variables $_to_string and $value in capsule and loop's body scopes.
The global variables conserve their value and they are independent of the instances of the div class.
Syntax in PHP
1
<?php
2
3
div::setGlobal('var-name', $mixed_value);
Example
index.php
1
<?php
2
3
div::setGlobal('today', date('Y-m-d'));
4
5
echonew div('index.tpl', array(
6
'name' => 'Peter'
7
));
8
9
echonew div('index.tpl', array(
10
'name' => 'Jack'
11
));
index.tpl
1
Hello {$name}
2
Today is: {$today}
Output
1
Hello Peter
2
Today is 2012-08-17
3
4
Hello Jack
5
Today is 2012-08-17
Strip/clean the resulting code
Clean the resulting code of the parser, eliminating double spaces, unnecessary new lines, etc.
Syntax in templates
1
{strip}
2
... some ugly code here ...
3
{/strip}
Example
index.tpl
1
{strip}
2
Hello Jack, ...
3
4
...the previous lines are of more.
5
{/strip}
Output
1
Hello Jack, ...
2
...the previous lines are of more.
System vars ($div reserved variable)
Some system vars are available in the templates. This vars are
provided by the engine. The following table shows the system vars:
System var
Description
div.now
The result of time() PHP function
div.post
$_POST
div.get
$_GET
div.server
$_SERVER
div.session
$_SESSION
div.version
div::$__version
div.script_name
The cuurent script file name - $_SERVER['SCRIPT_NAME']
div.ascii
The ASCII chars. For example, the {$div.ascii.64}
to replace with character 64 (@ symbol). You don't made a mistake, this replacement is different to
use the HTML entities just as "@".
Now then, all the variables of the system are not enabled by default. The system vars enabled by default are div.now, div.version, div.get and div.post.
If you need enable some system vars use the method div::enableSystemVar($varname).
If you need disable a system var use the method div::disableSystemVar($varname).
Example
index.php
1
<?php
2
3
session_start();
4
5
include'div.php';
6
7
div::enableSystemVar('div.session');
8
9
if (isset($_GET['user'])){
10
if ($_GET['user'] == 'peter'){
11
$_SESSION['user'] = $_GET['user'];
12
}
13
}
14
15
echonew div('index.tpl');
index.tpl
1
?$div.session.user
2
?$div.get.user
3
- Welcome {$div.get.user}
4
@else@
5
- Access denied for user {$div.session.user}
6
- Show the login form
7
$div.get.user?
8
@else@
9
Show the login form
10
$div.session.user?
Output
Testing the script with index.php?user=peter in the URL.
1
Welcome peter
Including another templates
A complex design, require split of the template. Then you can include the design's parts in a container template.
Syntax in templates
1
{% var with path to the template's part %}
2
3
OR
4
5
{% path/to/the/template/part %}
6
Example
part.tpl
1
Hello world!
index.tpl
1
This is the container template:
2
3
{% part %}
Output
1
This is the container template:
2
3
Hello world!
Including pre-processed templates
Similar to include a template, but in this case, first the engine parse the template, and then include it.
Syntax in templates
1
2
{%% var with path to the template's part %%}
3
4
OR
5
6
{%% path/to/the/template/part %%}
7
Example
index.php
1
<?php
2
3
echonew div('test.tpl',array(
4
'name' => 'Unnamed',
5
'products' => array(
6
array('name' => 'Banana'),
7
array('name' => 'Potato')
8
)
9
));
index.tpl
1
2
Include:
3
4
[$products]
5
{% part %}
6
[/$products]
7
8
Preprocessed:
9
10
[$products]
11
{%% part %%}
12
[/$products]
part.tpl
1
{$name}
Output
1
Banana
2
3
Potato
4
5
Unnamed
6
7
Unnamed
Capsules
An capsule is a part of template for reduce their code, make the template more readable, among other advantages.
Syntax in templates
1
[[varname
2
... In this section you can use the properties of variable if it is
3
an object or their keys if it is an array ...
4
varname]]
Example
index.php
1
<?php
2
3
echonew div('index.tpl', array(
4
'product' => array(
5
'name' => 'Banana',
6
'price' => 20.5,
7
'tax' => 1.5
8
)
9
));
index.tpl
1
Product:
2
3
[[product
4
Name: {$name}
5
Price: {$price}
6
Tax: {$tax}
7
product]]
8
9
Similar:
10
11
Name: {$product.name}
12
Price: {$product.price}
13
Tax: {$product.tax}
Output
1
Product:
2
3
Name: Banana
4
Price: 20.5
5
Tax: 1.5
6
7
Similar:
8
9
Name: Banana
10
Price: 20.5
11
Tax: 1.5
Multi replacements
Replace X with Y.
Syntax in templates
1
{:varname}
2
... some code here ...
3
{:/varname}
The variable should be an array where each item of array is an array with 3 element: string to search, string to replace and use or not regular expressions.
Example
index.php
1
<?php
2
3
echonew div('index.tpl', array(
4
/* str_replace */
5
'customtags' => array(
6
array('[b]', '<b>'),
7
array('[/b]', '</b>')
8
),
9
/* preg_replace */
10
'highlight' => array(
11
array('/\*.*\*/', '<span class = "comment">$0</span>', true)
12
)
13
));
index.tpl
1
{= htmlfix: [
2
['<b>','<strong>']
3
['</b>','</strong>']
4
] =}
5
6
{:customtags}
7
{:htmlfix}
8
9
[b]Hello World[/b]
10
11
{:/htmlfix}
12
{:/customtags}
13
14
{:highlight}
15
16
/* this is a PHP comment */
17
18
{:/highlight}
Output
1
<strong>Hello World</strong>
2
3
<span class = "comment">/* this is a PHP comment */</span>
IDE's friendly tags
IDE sometimes detects the code of Div in HTML templates like a syntax error,
because they don't have a plugin that identify the syntax of Div. Then, to avoid
that it is shown as an error, Div provides two tags to encapsulate its code making it
a comment.
Syntax in templates
1
2
<!--| ... some Div code here ... |-->
3
Example
index.tpl
1
2
This:
3
4
<!--| [$products] |-->
5
Name: {$name}
6
Price: {$price}
7
<!--| [/$products] |-->
8
9
Is equal to:
10
11
[$products]
12
Name: {$name}
13
Price: {$price}
14
[/$products]
15
Aggregate functions
The aggregate functions similar to SQL. With this feature you can get some results
from list's operations, like as "sum", "average", etc. Think of "aggregate functions"
as "list's modifiers", similarly to "variable's modifiers".
Showed blocks: {$blocks-weight} or {$count:blocks-weight}
9
10
<!--{ array of atomic values }-->
11
12
Minimum weight: {$min:widths}
13
Maximum weight: {$max:widths}
14
Weight average: {$avg:widths}
15
Weight sum: {$sum:widths}
16
Showed blocks: {$widths}
17
Output
1
Minimum weight: 0
2
Maximum weight: 2
3
Weight average: 1
4
Weight sum: 3
5
Showed blocks: 2 or 2
6
7
Minimum weight: 500
8
Maximum weight: 800
9
Weight average: 650
10
Weight sum: 2600
11
Showed blocks: 4
Locations
The locations are tags that identify some positions into template. With this
feature you can define a location in any part of the template, and then collocate
any content in this location. The tag that represent the location can be repeated
in other positions. Also, you can locate several template pieces in the same location.
Now you can separate two concepts: the content from their location in the template.
This advantage can be resolved with simple replacements
of template's variables, but this
is not sufficient and it is not equal.
Syntax
1
Define the location:
2
3
(( location_name ))
4
5
Define the content:
6
7
{{location_name
8
9
... some content here ...
10
11
location_name}}
12
Example
layout.tpl
1
<html>
2
<body>
3
<div id="header">(( header ))</div>
4
<div id="content">(( content ))</div>
5
<div id="footer">(( footer ))</div>
6
</body>
7
</html>
8
index.tpl
1
{% layout %}
2
3
{{header
4
This is the header
5
header}}
6
7
{{footer
8
This is the footer
9
footer}}
10
11
{{content
12
This is the content
13
content}}
14
15
{{header
16
<br/>.... more in the header .....
17
header}}
18
Output
1
<html>
2
<body>
3
<div id="header">This is the header<br/>.... more in the header .....</div>
4
<div id="content">This is the content</div>
5
<div id="footer">This is the footer</div>
6
</body>
7
</html>
Custom sub-parsers
The sub-parsers are parsers that run before the main parser of div, like as ignore parts.
The custom sub-parsers are built by the programmer to perform pre-processing part of the template. The
PHP implementation can be a function or static method. If you have implemented a class that
inherits from div, and uses it to process your templates, then the sub-parser can be implemented in
any method of that class.
For security reasons, the sub-parsers implemented as functions and static methods, must be registered prior
to processing the template with div::setSubParser() method. Each sub-parser receive the template
code to process and optionally the information provided to the engine. The string returned by the sub-parser
will replace the content between pre-parse's tags.
Syntax in templates
1
2
{sub-parser-name}
3
4
... this code will be sent to the sub-parser function/method ...
5
6
{/sub-parser-name}
7
Example
index.php
1
<?php
2
3
include "div.php";
4
5
/* Sub-parser as a function */
6
function literal($code){
7
return "{ignore}$code{/ignore}";
8
}
9
10
/* Sub-parser as a function more complex */
11
function body($code, &$items){
12
$items['body'] = '<p>'.$code.'</p>';
13
return "";
14
}
15
16
/* Sub-parser as a method */
17
class MyPage extends div{
18
19
/* You can set the sub-parsers in the constructor */
20
publicfunction beforeBuild(){
21
22
// Sub-parser with their name different to the name of function
/* Same as MyPage::setSubParser("literal", "literal"); */
52
MyPage::setSubParser('literal');
53
54
/* Alias for'literal' */
55
MyPage::setSubParser('noparse','literal');
56
57
/* Name of sub-parser equal to name of function */
58
MyPage::setSubParser('body');
59
60
/* Similar way ... */
61
div::setSubParser('upperthis');
62
63
echonew MyPage('index.tpl');
index.tpl
1
{body}
2
Hello world, this is my first sub-parser
3
{/body}
4
5
{combobox}
6
name: 'cboCities',
7
options: [
8
{v: 'NY', c: 'New York'},
9
{v: 'PA', c: 'Paris'},
10
{v: 'TK', c: 'Tokio'}
11
]
12
{/combobox}
13
14
{upperthis}body{/upperthis}
15
16
{$body}
17
18
{literal}
19
{$body}
20
{/literal}
Output
1
<select name = "cboCities">
2
<option value="NY">New York</option>
3
<option value="PA">Paris</option>
4
<option value="TK">Tokio</option>
5
</select>
6
7
<P>
8
HELLO WORLD, THIS IS MY FIRST SUB-PARSER
9
</P>
10
11
{$body}
Pre-defined sub-parsers
Div provide pre-defined sub-parsers. See the next list:
{parse} ... {/parse}: Make a pre-proccess of enclosed code.
This means that a new instance of div will be created, similar to the loops
and the capsules.
Sub-parser's events
Each sub-parser is processed in some different moments. At the moment, the events are:
beforeParse, afterInclude and afterParse. Now in the templates's code you can specify when
a sub-parser will be executed. The moment, or the event, can be specified in the template as following example:
A macro is a restricted PHP code dedicated to execute the
design's complex tasks. For this reason, Div assures that the PHP
code will be not intrusive or insecure.
You can change the proposed Div tags for templates. By doing this, you are
creating a "dialect" for the template language. The dialects can be very useful when you
want to zoom in Div language to a known template language or easier to understand
by its developers. It can also be useful when you want to process template contains
tags similar to Div.
The dialect in Div is defined by a set of constants that begin with the prefix
DIV_TAG. A dialect have required tags and rules that are verified. You can use
the tool provided by our team (Div Dialect Creator)
to create dialects.
To create a new dialect you should define the constants before including the file
div.php. You are not forced to define all the constants, so alone those that
you need to change. The following table show the set of constants that define a dialect
in Div.
Constant
Default value
DIV_TAG_VAR_MEMBER_DELIMITER
.
DIV_TAG_REPLACEMENT_PREFIX
{
DIV_TAG_REPLACEMENT_SUFFIX
}
DIV_TAG_MULTI_MODIFIERS_PREFIX
{$
DIV_TAG_MULTI_MODIFIERS_SEPARATOR
|
DIV_TAG_MULTI_MODIFIERS_OPERATOR
|
DIV_TAG_MULTI_MODIFIERS_SUFFIX
|}
DIV_TAG_SUBMATCH_SEPARATOR
:
DIV_TAG_MODIFIER_SIMPLE
$
DIV_TAG_MODIFIER_CAPITALIZE_FIRST
^
DIV_TAG_MODIFIER_CAPITALIZE_WORDS
^^
DIV_TAG_MODIFIER_UPPERCASE
^^^
DIV_TAG_MODIFIER_LOWERCASE
_
DIV_TAG_MODIFIER_LENGTH
%
DIV_TAG_MODIFIER_COUNT_WORDS
%%
DIV_TAG_MODIFIER_COUNT_SENTENCES
%%%
DIV_TAG_MODIFIER_COUNT_PARAGRAPHS
%%%%
DIV_TAG_MODIFIER_ENCODE_URL
&
DIV_TAG_MODIFIER_ENCODE_RAW_URL
&&
DIV_TAG_MODIFIER_ENCODE_JSON
json:
DIV_TAG_MODIFIER_HTML_ENTITIES
html:
DIV_TAG_MODIFIER_NL2BR
br:
DIV_TAG_MODIFIER_TRUNCATE
~
DIV_TAG_MODIFIER_WORDWRAP
/
DIV_TAG_MODIFIER_SUBSTRING_SEPARATOR
,
DIV_TAG_MODIFIER_SINGLE_QUOTES
'
DIV_TAG_MODIFIER_JS
js:
DIV_TAG_MODIFIER_FORMAT
DIV_TAG_DATE_FORMAT_PREFIX
{/
DIV_TAG_DATE_FORMAT_SUFFIX
/}
DIV_TAG_DATE_FORMAT_SEPARATOR
:
DIV_TAG_NUMBER_FORMAT_PREFIX
{#
DIV_TAG_NUMBER_FORMAT_SUFFIX
#}
DIV_TAG_NUMBER_FORMAT_SEPARATOR
:
DIV_TAG_FORMULA_BEGIN
(#
DIV_TAG_FORMULA_END
#)
DIV_TAG_FORMULA_FORMAT_SEPARATOR
:
DIV_TAG_SUBPARSER_BEGIN_PREFIX
{
DIV_TAG_SUBPARSER_BEGIN_SUFFIX
}
DIV_TAG_SUBPARSER_END_PREFIX
{/
DIV_TAG_SUBPARSER_END_SUFFIX
}
DIV_TAG_IGNORE_BEGIN
{ignore}
DIV_TAG_IGNORE_END
{/ignore}
DIV_TAG_COMMENT_BEGIN
<!--{
DIV_TAG_COMMENT_END
}-->
DIV_TAG_TXT_BEGIN
{txt}
DIV_TAG_TXT_END
{/txt}
DIV_TAG_TXT_WIDTH_SEPARATOR
=>
DIV_TAG_STRIP_BEGIN
{strip}
DIV_TAG_STRIP_END
{/strip}
DIV_TAG_LOOP_BEGIN_PREFIX
[$
DIV_TAG_LOOP_BEGIN_SUFFIX
]
DIV_TAG_LOOP_END_PREFIX
[/$
DIV_TAG_LOOP_END_SUFFIX
]
DIV_TAG_EMPTY
@empty@
DIV_TAG_BREAK
@break@
DIV_TAG_LOOP_VAR_SEPARATOR
=>
DIV_TAG_ITERATION_BEGIN_PREFIX
[:
DIV_TAG_ITERATION_BEGIN_SUFFIX
:]
DIV_TAG_ITERATION_END
[/]
DIV_TAG_ITERATION_PARAM_SEPARATOR
DIV_TAG_CONDITIONAL_TRUE_BEGIN_PREFIX
?$
DIV_TAG_CONDITIONAL_TRUE_BEGIN_SUFFIX
DIV_TAG_CONDITIONAL_TRUE_END_PREFIX
$
DIV_TAG_CONDITIONAL_TRUE_END_SUFFIX
?
DIV_TAG_CONDITIONAL_FALSE_BEGIN_PREFIX
!$
DIV_TAG_CONDITIONAL_FALSE_BEGIN_SUFFIX
DIV_TAG_CONDITIONAL_FALSE_END_PREFIX
$
DIV_TAG_CONDITIONAL_FALSE_END_SUFFIX
!
DIV_TAG_ELSE
@else@
DIV_TAG_CONDITIONS_BEGIN_PREFIX
{?(
DIV_TAG_CONDITIONS_BEGIN_SUFFIX
)?}
DIV_TAG_CONDITIONS_END
{/?}
DIV_TAG_TPLVAR_BEGIN
{=
DIV_TAG_TPLVAR_END
=}
DIV_TAG_TPLVAR_ASSIGN_OPERATOR
:
DIV_TAG_TPLVAR_PROTECTOR
*
DIV_TAG_DEFAULT_REPLACEMENT_BEGIN
{@
DIV_TAG_DEFAULT_REPLACEMENT_END
@}
DIV_TAG_INCLUDE_BEGIN
{%
DIV_TAG_INCLUDE_END
%}
DIV_TAG_PREPROCESSED_BEGIN
{%%
DIV_TAG_PREPROCESSED_END
%%}
DIV_TAG_CAPSULE_BEGIN_PREFIX
[[
DIV_TAG_CAPSULE_BEGIN_SUFFIX
DIV_TAG_CAPSULE_END_PREFIX
DIV_TAG_CAPSULE_END_SUFFIX
]]
DIV_TAG_MULTI_REPLACEMENT_BEGIN_PREFIX
{:
DIV_TAG_MULTI_REPLACEMENT_BEGIN_SUFFIX
}
DIV_TAG_MULTI_REPLACEMENT_END_PREFIX
{:/
DIV_TAG_MULTI_REPLACEMENT_END_SUFFIX
}
DIV_TAG_FRIENDLY_BEGIN
<!--|
DIV_TAG_FRIENDLY_END
|-->
DIV_TAG_AGGREGATE_FUNCTION_COUNT
count
DIV_TAG_AGGREGATE_FUNCTION_MAX
max
DIV_TAG_AGGREGATE_FUNCTION_MIN
min
DIV_TAG_AGGREGATE_FUNCTION_SUM
sum
DIV_TAG_AGGREGATE_FUNCTION_AVG
avg
DIV_TAG_AGGREGATE_FUNCTION_SEPARATOR
:
DIV_TAG_AGGREGATE_FUNCTION_PROPERTY_SEPARATOR
-
DIV_TAG_LOCATION_BEGIN
((
DIV_TAG_LOCATION_END
))
DIV_TAG_LOCATION_CONTENT_BEGIN_PREFIX
{{
DIV_TAG_LOCATION_CONTENT_BEGIN_SUFFIX
DIV_TAG_LOCATION_CONTENT_END_PREFIX
DIV_TAG_LOCATION_CONTENT_END_SUFFIX
}}
DIV_TAG_MACRO_BEGIN
<?
DIV_TAG_MACRO_END
?>
DIV_TAG_SPECIAL_REPLACE_NEW_LINE
{\n}
DIV_TAG_SPECIAL_REPLACE_CAR_RETURN
{\r}
DIV_TAG_SPECIAL_REPLACE_HORIZONTAL_TAB
{\t}
DIV_TAG_SPECIAL_REPLACE_VERTICAL_TAB
{\v}
DIV_TAG_SPECIAL_REPLACE_NEXT_PAGE
{\f}
DIV_TAG_SPECIAL_REPLACE_DOLLAR_SYMBOL
{\$}
DIV_TAG_TEASER_BREAK
<!--break-->
Understanding the syntax
Div parse the template language locating some syntax structures that have rules. In
this section the structures and their rules are explained.
Rigid blocks
PREFIX
RIGID SYNTAX
SUFFIX
The rigid blocks are those that are compound for a rigid syntaxis with prefix and
a suffix. The rigid syntax is that in the one that each character has a meaning for the
interpreter, in such way that characters are not allowed of more. That is to say,
characters like the space (chr(32)), the tabs (\t) and the new lines (\n), that allow to
beautify the code, won't be ignored by the interpreter and it will consider them like part
of their syntactic analysis. In this blocks, the prefix and the suffix are required.
For example, if you write "{$text }" the name of the variable
to substitute will include the space at the end, that is to say, it will be "text ".
The simple blocks are similar to the rigid blocks, with the difference that the
prefix is named "begin", the suffix is named "end", and the syntaxis of the block
is flexible. A flexible syntax is the opposite to a rigid syntax, where it is allowed
to write characters to space or to format. In this blocks, the aperture tag and the closing tag are required.
The blocks without keywords are those where the aperture tag and the closing tag have
a structure or specific content, so that it is not necessary a prefix and a suffix for
the closing tag. In this sense the prefix and the suffix of the aperture tag are required,
and as well as the closing tag.
The blocks with keywords are those where the aperture tag and the closing tag
contain the name a variable, either simple or complex, accompanied by a prefix and a
suffix in both cases. The prefix of the aperture tag and the suffix of the closing tag
are required.
Div provide a translator for dialects. This translator can translate from any
dialect to current dialect. Div use the current template's variables for self help
in the translation. For this reason, you only translate having a instance of div.
Example
index.php
1
<?php
2
3
include'div.php';
4
5
$tpl = new div('index.tpl');
6
7
$tpl->translateFrom(array(
8
'DIV_TAG_IGNORE_BEGIN' => '{literal}',
9
'DIV_TAG_IGNORE_END' => '{/literal}'
10
));
11
12
$tpl->show();
index.tpl
1
2
{= name: "Peter" =}
3
4
{literal}
5
{$name}
6
{/literal}
7
8
{$name}
9
index.tpl (translated)
1
2
{= name: "Peter" =}
3
4
{ignore}
5
{$name}
6
{/ignore}
7
8
{$name}
9
Multiple dialects
With the template's property @__DIALECT you can specify the dialect for current template source.
This dialect should be written in a separeted file with JSON code. For example:
Example
index.tpl
1
@_DIALECT = smarty.dialect
2
{* this is a comment *}
3
Name: {$name}
4
{literal}
5
{$name}
6
{/literal}
7
{% other %}
other.tpl
1
@_DIALECT = twig.dialect
2
{{ foo.bar }}
smarty.dialect
1
{
2
'DIV_TAG_IGNORE_BEGIN': '{literal}',
3
'DIV_TAG_IGNORE_END': '{/literal}',
4
'DIV_TAG_COMMENT_BEGIN': '{*',
5
'DIV_TAG_COMMENT_END': '*}'
6
}
twig.dialect
1
{
2
'DIV_TAG_REPLACEMENT_SUFFIX': ' }}',
3
'DIV_TAG_MODIFIER_SIMPLE': '{ '
4
}
index.php
1
<?php
2
3
include "div.php";
4
5
echonew div("index.tpl", array(
6
'name' => 'Peter',
7
'foo' => array(
8
'bar' => 45
9
)
10
));
Output
1
Name: Peter
2
3
{$name}
4
5
45
Template's properties
Each template can have properties and the designer is responsible for establishing
them. The properties apply only to the file where they are defined.
The properties are defined in a single line using the following syntax:
For example, the following code sets the dialect of the template, where the value
is the name of the file containing the dialect.
Properties are identified by the prefix @_.
Template's documentation
Div provides a functionality that create a documentation of your templates. The
template's documentation is written in the comments with a specific syntax, similar
to some programming languages. In each comment's line, the parser recognizes the
documentation's properties and their values . The documentation's properties begin
with @. See the example.
Now, a specific or restricted list of properties not exists. All the properties that
you want to write in the comments will be saved by the parser. After parsing, getDocs
returns the saved documentation's properties. With this information and a template, you
can build the documentation that you want.
Now, don't invent the wheel. Use getDocsReadable method and obtain a readable
documentation based on the saved properties and a template provided by Div. You can
specify a custom template.
Important, the template given by Div if it is prepared to recognize certain
properties that are listed now:
Variable/property
Description
title
Documentation's title. This variable can be passed to the
method with $items parameter. For example:
List of the template's variables.
The fourth part can contain several spaces, but the three first not, because Div considers them
as words. Remember that this is specifically for the documentation template that Div provides.
You can build your own documentation template with defined variables by your work team:
optional/required
data type
variable's name
variable's description
For example:
<!--{
...
@vars required string title Blog's title
optional string body Blog's body
...
}-->
include
The list of included templates. The parser will add
all includes automatically. Also you can specify it, for example, when the include tag use a variable
and not the template's specific path.
example
The example of how to use this template
Syntax in templates
1
<--{
2
3
... unsaved content here ....
4
5
@fist_saved_property value
6
@other_property value
7
@other_property value
8
@other_property value
9
@multiline_property: line1
10
line2
11
line3
12
@other_multiline_property:
13
line1
14
line2
15
line3
16
...
17
18
}-->
Example
index.tpl
1
<--{
2
3
The next comments are the documentation of this template
Add or set a default replacement of value for a specific var
div::unsetAllowedFunction(string $funcname)
Unset the allowed function
div::utf162utf8(string $utf16)
Convert string from UTF16 to UTF18
div::varExists(string $var, mixed &$items = null)
Return true if var exists in the template's items recursively
Recursion
Div interprets the template until it is not anything to interpret. For that reason,
the recursion is implicit and is an intrinsic characteristic of the eninge.
If you have a code like '{${$list}}' and $list = 'products'
then the engine convert this code to '{$products}' and if you have another
variable $products with your list of products, the engine replace it, in this example,
with the count of products.
Low performance? No! The implementation of Div is not a recursive algorithm. The
recursion is only a mechanism for the designer. Don't worry.
The recursion is very useful in the creation of components. Now, we
Example
index.php
1
<?php
2
3
include'div.php';
4
5
$product = new stdClass();
6
7
$product->name = 'Banana';
8
$product->price = 20.5;
9
10
echonew div('index.tpl', array(
11
'product' => $product,
12
'object' => 'product'
13
));
index.tpl
Origin
1
[${$object}]
2
3
{$_key} = {$value}
4
5
[/${$object}]
Step 1
1
[$product]
2
3
{$_key} = {$value}
4
5
[/$product]
Step 2
1
[$product]
2
3
name = {$value}
4
5
[/$product]
Step 3
1
[$product]
2
3
name = Banana
4
price = {$value}
5
6
[/$product]
Step 4
1
name = Banana
2
price = 20.5
Templates inheritance
The inheritance allows you to construct a base template that contains all the common
elements and defines "zones" that other templates can change. At the moment Div doesn't
provide the template inheritance explicitly. But we wonder if it is really necessary.
For those that don't know about this topic, the template inheritance means that a
template can inherit the design of another template and then redesign the necessary
parts.
The templates inheritance can be solved with inclusions in engines that don't provide
the inheritance, but it can be a not very elegant solution. Does Div have some mechanism
that can be considered a solution for the templates inheritance?
Div considers that the templates inheritance can be solved with some of their features,
like as inclusions, default values, template vars, locations and recursion. This section explain
three variants for implement the inheritance.
Variant 1: Switch
This way, when you write
{% block %}
Or
{% {$block} %}
the variable $block can have a default value and then this code can be include different
templates. You can call this mechanism as "switch".
Variant 2: Using protected template's variables
Another way to implement inheritance is using the template variables. In the parent template
defines a block as it defines a template variable, then the variable positions in place of the
template you want. In the child template redefines the "blocks" (protected template's variables) and then includes the parent template.
Example
parent.tpl
1
... any code ...
2
{= block1:
3
4
... code of block 1 ...
5
6
=}
7
8
... another code...
9
10
{$block1}
child.tpl
1
{= *block1:
2
3
... another code for block 1 ...
4
5
=}
6
7
{% parent %}
Variant 3: Using locations
This is the most elegant solution because you not need to define a variable. In the parent template
you define the locations of the common content (for example "top", "header", "footer", "left", "right",
etc), and then in the child template you can locate contents in the parent's locations.
Example
parent.tpl
1
... any code ...
2
3
(( block1 ))
4
5
... another code...
6
7
{= parent_block1:
8
9
... code block 1 written by the parent ...
10
11
=}
12
child.tpl
1
{% parent %}
2
3
{{block1
4
5
{$parent_block1}
6
7
... The child's content ...
8
9
block1}}
Output.tpl
1
... any code ...
2
3
... code block 1 written by the parent ...
4
... The child's content ...
5
6
... another code...
Components
Complex GUIs are created with components. A component can reduces
the effort dedicated in the production. Create a component with Div and
for Div, is a very simple mechanism to implement. See the next example: