[[]] Div PHP Template Engine 4.8


Introduction

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 designer work in text files and use various types of tags: simple replacements, lists, iterations, conditional parts, separating the design into different files, default replacements, and so on.

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}
4Product name: {$products.name}
5{if !$smarty.foreach.products.last},{/if}
6{/foreach}
7
8{include file="footer.tpl"}
Div:
1{% header %}
2
3[$products]
4Product 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?

  1. One class, one file!, considering the template like an object.
  2. Create a minimum of highly descriptive syntax.
  3. Avoid a cache system.
  4. Improve the algorithms.
  5. 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.

Important

If you have another class named "div", you can rename the div class.

Always:
include the file div.php.

1<?php
2
3include "div.php";
4
5// ...

Variant 1:
All in one instruction

1<?php
2
3echo new 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
7echo $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
6echo new div('index.tpl', array(
7 'name' => 'Peter'
8));

Variant 4:
The data as JSON code

1<?php
2
3echo new 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
6echo new 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:

1<?php
2
3include 'div.php';
4
5/* Third parameter as array */
6
7echo new div('index.tpl', array('name' => 'Peter'), array('name'));
8
9/* Third parameter as string */
10
11echo new div('index.tpl', array('name' => 'Peter', 'age' => 25, 'sex' => 'M'), 'name,age');

The best practices

  1. 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.

  2. 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.

  3. 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
3include 'div.php';
4
5/* This code... */
6
7echo new 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
23echo new div('index.tpl', array(
24 'single' => 'something',
25 'complex' => $complex
26));
index.tpl
1Single value: {$single}
2Single value into complex var: {$complex.single}
3And more: {$complex.subcomplex.single}
Output
1Single value: something
2Single value into complex var: 45
3And 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:

index.tpl
1{= name: "Peter" =}
2
3<!-- Show the first character -->
4{$name.0}
5
6<!-- Show the second character -->
7{$name.1}
8
9{= x: 537 =}
10
11<!-- Show the first digit -->
12{$x.0}
13
14<!-- Show the second digit -->
15{$x.1}
16
17<!-- Spacify the name -->
18[$name]{$value} [/$name]
19
20<!-- Multiply the digits of x -->
21[$x] {$value} * [/$x] = (# [$x] {$value} * [/$x] 1 #)
Output
1P
2
3e
4
55
6
73
8
9P e t e r
10
115 * 3 * 7 = 105

Simple replacements

A simple replacement is the replacement of parts of the template with any content. The variable can be contain a mixed value:

  • If the value is a string, the replacement is the string.
  • If the value is a number, the replacement is the "number".
  • If the value is an array, the replacement is the length of the array.
  • If the value is an object without __toString method implemented, the replacement is the count of properties of the object.

Syntax in templates

1{$varname}

Example

index.php
1<?php
2
3include 'div.php';
4
5echo new div('index.tpl', array(
6 'first_name' => 'Peter',
7 'last_name' => 'Pan'
8));
index.tpl
1First name: {$first_name}
2Last name: {$last_name}
Output
1First name: Peter
2Last name: Pan

Special replacements

Tags for output special characters that can be used always. The following table show the available tags and their replacements:

TagReplacement
{\n}\n
{\r}\r
{\t}\t
{\v}\v
{\f}\f
{\$}$

Example

index.tpl
1Hello{\n}Peter
2{\t}Today is {/div.now:Y-m-d/}
Output
1Hello
2Peter
3 Today is 2013-07-24

Variable's modifiers


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:
ModifierDescription
{$variable} Nonthing to change
{^variable} Capitalize the first character of the string.
{^^variable} Capitalize the first character of each word of the string.
{^^^variable} Convert the entire string to uppercase.
{_variable} Convert the entire string to lowercase.
{%variable} Count of characters.
{%%variable} Count of words.
{%%%variable} Count of sentences.
{%%%%variable} Count of paragraphs.
{&variable} URL encode (see also urlencode).
{&&variable} Raw URL encode (see also rawurlencode).
{html:variable} Convert all aplicable characters to HTML entities (see also htmlentities).
{br:variable} Convert new lines to HTML line breaks (see also nl2br).
{json:variable} Encode the value as JSON.
{[other-modifier]variable:~truncate-length} Truncate the content for create a teaser content. If the content have the break tag (<!--break-->) the parser truncate the content in this tag.
{[other-modifier]variable:/wordwrap-length} Word wrap.
{[other-modifier]variable:from,length} Sub-string
{'variable} Escape unescaped single quotes
{js:variable} Output JavaScript code (or similar) - Escape quotes and backslashes, newlines, etc.
{$variable:[string format]} Format the string with sprintf PHP function

Example

index.tpl
1{= title: mozilla firefox =}
2{= body: A wonderful web browser =}
3
4
5
6Nothing to change:
7{$title}
8
9Capitalize the first character
10of the string:
11{^title}
12
13Capitalize the first character
14of each word of the string:
15{^^title}
16
17Convert to uppercase:
18{^^^title}
19
20Convert to lowercase:
21{_title}
22
23Count of characters:
24{%title}
25
26Sub-string:
27
28{$body:12,11}
29
30Truncate:
31
32{$body:~25}...
33
34Word wrap:
35
36{$body:/30}
37
38Combining the modifiers:
39
40{^^^body:12,11}
41
42{^^^body:/40}
43
44String format:
45
46{= value: 10 =}
47
48{$value:%1$04d}
49
Output
1
2Nothing to change:
3mozilla firefox
4
5Capitalize the first character
6of the string:
7Mozilla firefox
8
9Capitalize the first character
10of each word of the string:
11Mozilla Firefox
12
13Convert to uppercase:
14MOZILLA FIREFOX
15
16Convert to lowercase:
17mozilla firefox
18
19Count of characters:
2015
21
22Sub-string:
23
24web browser
25
26Truncate:
27
28This is a new company of...
29
30Word wrap:
31
32A wonderful web browser
33
34
35
36
37Combining the modifiers:
38
39A WONDERFUL WEB BROWSER
40
41A WONDERFUL WEB BROWSER
42
43
44
45String format:
46
470010

Multiple variable's modifiers

Syntax

1{$varname|modifier1|modifier2|modifier3|...|}

Example

index.tpl
1{= word: "ABCDEFG" =}
2
3{$word|0,3|}
4{$word|0,3|_|}
5{$word|0,3|_|^|}
6{$word|0,3|_|^|~2|}
Output
1ABC
2abc
3Abc
4Ab

Custom modifiers

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
3include 'div.php';
4
5class MyModifiers {
6
7 /* The modifier function should have a single parameter. */
8 static function upper($value){
9 return strtoupper($value);
10 }
11
12}
13
14function lower($value){
15 return strtolower($value);
16}
17
18div::addCustomModifier('upper:', 'MyModifiers::upper');
19div::addCustomModifier('lower:', 'lower');
20
21echo new div('index.tpl', array('text' => 'Hello World'));
index.tpl
1
2{upper:text}
3
4{lower:text}
5
Output
1HELLO WORLD
2
3hello world

Data formats

The data formats are modifiers of variables that need more information than a symbol.

Date format {Format a timestamp}

Syntax in templates

1{/variable:php-format-date/}

Example

index.php
1<?php
2
3include 'div.php';
4
5echo new div('index.tpl', array(
6 'today' => time()
7));
index.tpl
1Timestamp: {$today}
2Today is: {/today:Y-m-d/}
3Now is: {/today:h:i:s/}
Output
1Timestamp: 1341956900
2Today is: 2012-07-10
3Now is: 05:48:20

Number format

Syntax in templates

1{#variable:decimals separator miles-separator#}

Example

index.php
1<?php
2
3include 'div.php';
4
5echo new div('index.tpl', array(
6 'number' => 2900200.4567
7));
index.tpl
1The number: {$number}
2The integer part: {#number:0#}
3Two decimals: {#number:2#}
4Two decimals and separators: {#number:2,.#}
5Two decimals and other separators: {#number:2.'#}
6More decimals and other separators: {#number:9|-#}
Output
1The number: 2900200.4567
2The integer part: 2900200
3Two decimals: 2900200.46
4Two decimals and separators: 2.900.200,46
5Two decimals and other separators: 2'900'200.46
6More decimals and other separators: 2-900-200|456700000

Formulas

To make calculations and other advantages. The formula is a valid PHP expression. See the list of allowed PHP functions.

Syntax in templates

1
2(# formula #)
3
4OR
5
6(# formula : number format #)
7

The number format are explained in Data formats.

Example

index.tpl
1
2{= number: 200.000 =}
3{= price: 20.000 =}
4{= tax: 0.345 =}
5
65 + {$number} = (# 5 + {$number} #)
7
8Price with tax: ${$price} + ${#tax:2.#} = $(# {$price} + {$tax} :2. #)
9
Output
15 + 200 = 205
2
3Price with tax: $20 + $0.35 = $20.35

Ignored parts (escaping Div parsing)

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
3include 'div.php';
4
5echo new div('index.tpl', array(
6 'name' => "Peter"
7));
index.tpl
1{ignore}
2
3Name: {$name}
4
5{/ignore}
Output
1Name: {$name}

Comments

Syntax in templates

1<!--{ inline comment here }-->
2
3<!--{
4
5Multi-line comment here
6This 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
1Document 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
3echo new div('index.tpl',array(
4 'employees' => array(
5 'Salvi',
6 'Peter',
7 'John'
8 ),
9 'products' => array()
10));
index.tpl
1Employees:
2
3[$employees]
4 {$value}
5[/$employees]
6
7Products:
8
9[$products]
10 {$name}
11@empty@
12 Empty list of products!
13[/$employees]
Output
1Employees:
2
3Salvi
4Peter
5John
6
7Products:
8
9Empty list of products!

Dynamic/injected vars for each cycle

VarData typeDescription
$_itemmixedCurrent item
$_previousmixedThe previous item
$_nextmixedThe next item
$_keymixedThe key of the item in the PHP array
$_indexintegerThe index of the item (0..n-1)
$_index_randomintegerRandom index of the list (0..n-1)
$_orderintegerThe order of the item (1..n)
$_liststringThe name of the list
$_is_lastbooleanTrue if the current item is the last
$_is_firstbooleanTrue if the current item is the first
$_is_oddbooleanTrue if the current index is odd
$_is_evenbooleanTrue 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:

  1. False if the value is false
  2. False if the value is null
  3. False if the value is not greater than zero
  4. False if is "0"
  5. False if is an empty string
  6. False if is an object without properties
  7. The same value in any other case

Syntax in templates

1
2For test the var as TRUE:
3
4?$var
5... some code here ...
6@else@
7... some another code here
8$var?
9
10For 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
3echo new 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
2Products:
3
4?$products
5 [$products]
6 {$name} - {$price}
7 [/$products]
8@else@
9 No products
10$products?
11
12Similar result:
13
14!$products
15 No products
16@else@
17 [$products]
18 {$name} - {$price}
19 [/$products]
20$products!
21
Output
1Products:
2
3Banana - 20.5
4Potato - 10.8
5
6Similar result:
7
8Banana - 20.5
9Potato - 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.

Syntax in templates

1{?( ... expression ... )?}
2
3... some code here ...
4
5@else@
6
7... some another code here ...
8
9{/?}

Example

index.php
1<?php
2
3echo new 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{?( {$products} > 0 )?}
2 There are {$products} products in the warehouse
3@else@
4 There are not products in the warehouse
5{/?}
Output
1There are 2 products in the warehouse

Template's variables

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]" }-->
     

Syntax in templates

1{= varname: ... value ... =}
2
3A string
4
5{= varname: some string here =}
6
7An array in JSON
8
9{= varname: [item1, item2, .... ] =}
10
11An object in JSON
12
13{= varname: {
14 prop1: value1,
15 prop2: value2,
16 ...
17} =}
18
19Get the value of another var
20
21{= var1: value1 =}
22{= var2: $var1 =}
23
24Call to method of current PHP class
25
26{= sum: ->sum(20,30) =}
27

See also OOP section.

Important note The dollar symbol used to get a variable's value in the JSON, is not the modifier in simple replacements (DIV_TAG_MODIFIER_SIMPLE). This symbol can not be changed with a custom dialect. Is a strict rule in Div.

Example

index.php
1<?php
2
3echo new div('index.tpl', array(
4 'price' => 40
5));
index.tpl
1
2{= price: 20 =}
3
4Price: {$price}
5
6{= labels: ['A','B','C','D'] =}
7
8Labels: [$labels] {$value}!$_is_last, $_is_last! [/$labels]
9
10{= product: {
11 name: "Potato",
12 price: 45
13} =}
14
15Product: {$product.name}
16
17Product's price: {$product.price}
18
19{= somestring: Blah blah blah =}
20
21String: {$somestring}
22
23{= somevar: $price =}
24
25Some var: {$somevar}
Output
1Price: 40
2
3Labels: A, B, C, D
4
5Product's price: Potato
6
7Price: 45
8
9String: Blah blah blah
10
11Some var: 40

Protected template's vars

To protect the value of a teplate's variable, type an asterisk (*) before the variable's name:

Example

1{= *protectedvar: "protected value" =}

Protect a template's variable means that after this protection, any intent of changing its value will be failed.

How to load the content of an external template into a variable?

If you have a external template and its content is needed into a variable, the next trick can help you:

{= varname: {% external-template %} =}

The "external content" are loaded "on demand". This means that the content will be loaded in first replacement of variable.

Object Oriented Programming


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
3include 'div.php';
4
5class MyPage extends div{
6
7 /* IMPORTANT: Change the default constructor is not recommended */
8 public function __construct($src = null, $items = array(), $ignored = array()){
9
10 /*.. some code here */
11
12 parent::__construct($src, $items, $ignored);
13 }
14
15 /* IMPORTANT: The recommended way for do something before */
16 /* construct the object is the implementation of beforeBuild() hook. */
17 public function beforeBuild(&$src = null, &$items = null, &$ignore = array()){
18
19 // something to do before build the object
20
21 }
22
23 /* ... custom methods here... */
24
25}

Example

index.php
1<?php
2
3class MyPage extends div{
4
5 public function getProducts(){
6 return array(
7 array(
8 'name' => 'Banana',
9 'price' => 20
10 ),
11 array(
12 'name' => 'Potato',
13 'price' => 30
14 )
15 );
16 }
17
18 public function sum($x, $y){
19 return $x + $y;
20 }
21
22}
index.tpl
1{= products: ->getProducts() =}
2{= result: ->sum(20,30) =}
3
4[$products]
5 {$name}
6[/$products]
7
8{$result}
Output
1Banana
2Potato
3
450
Important note The arrow symbol used to get a method's result in the template example, can not be changed with a custom dialect. Is a strict rule in Div.

The content as an "object" (intelligent data)

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
3include 'div.php';
4
5class MyData{
6
7 var $values;
8
9 function __construct($values){
10 $this->values = $values;
11 }
12
13 public function implode(){
14 return implode(",",$this->values);
15 }
16
17}
18
19echo new div('index.tpl', new MyData(array("A","B","C","D")));
index.tpl
1
2{= data: ->implode() =}
3
4{$data}
5
Output
1A,B,C,D

Example: "capsule scope"

index.php
1<?php
2
3include 'div.php';
4
5// create a class ...
6
7class MyString{
8
9 var $value;
10
11 function __construct($value){
12 $this->value = $value;
13 }
14
15 public function upper(){
16 return strtoupper($this->value);
17 }
18
19}
20
21// using the class
22
23echo new div('index.tpl', array('name' => new MyString('peter')));
index.tpl
1
2[[name
3 {$value}
4
5 {= up: ->upper() =}
6
7 {$up}
8name]]
9
Output
1peter
2PETER

Example: accesing to any var/object method (new from 4.7)

index.tpl
1 {= up: ->name.upper() =}
2{$up}
Output
1PETER

Example: "loop's body scope"

index.php
1<?php
2
3include 'div.php';
4
5class 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 public function getName(){
16 return $this->first_name.' '.$this->last_name;
17 }
18
19}
20
21echo new 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
1First name: John
2Last name: Nash
3Complete name: John Nash
4
5First name: Peter
6Last name: Joseph
7Complete name: Peter Joseph
8
9First name: Jacque
10Last name: Fresco
11Complete 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.

Example

index.php
1<?php
2
3include 'div.php';
4
5class Page extends div{
6
7 public function beforeBuild(&$src = null, &$items = null){
8 $this->title = 'Hello World';
9 $items['body'] = 'This is the hook!';
10 }
11
12}
13
14echo new Page('index.tpl');
index.tpl
1<h1>{$title}</h1>
2<p>{$body}</p>
Output
1<h1>Hello World</h1>
2<p>This is the hook!</p>

The __toString magic method

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.

Suppose that you have the following class:

Person.php
1<?php
2
3class Person{
4
5 public function __construct($first_name, $last_name){
6 $this->first_name = $first_name;
7 $this->last_name;
8 }
9
10 public function __toString(){
11 return $this->first_name." ".$this->last_name;
12 }
13
14}

Then, the following examples show the use of the variables:

Example 1: Template's scope

index.php
1<?php
2
3include 'div.php';
4
5include 'Person.php';
6
7echo new div('index.tpl', new Person("Albert", "Einstein"));
index.tpl
1{$_to_string}
Output
1Albert Einstein

Example 2: Loop body's scope

index.php
1<?php
2
3include 'div.php';
4
5include 'Person.php';
6
7echo new div('index.tpl', array(
8 "persons" => array(
9 new Person("Albert", "Einstein"),
10 new Person("John", "Nash")
11 )
12));
index.tpl
1
2If Person not have a $value property:
3
4[$persons]
5 {$value}
6[/$persons]
7
8You can always use the variable $_to_string:
9
10[$persons]
11 {^^^_to_string}
12[/$persons]
13
Output
1If Person not have a $value property:
2
3 Albert Einstein
4 John Nash
5
6You can always use the variable $_to_string:
7
8 ALBERT EINSTEIN
9 JOHN NASH

Example 3: Capsule's scope

index.php
1<?php
2
3include 'div.php';
4
5include 'Person.php';
6
7echo new div('index.tpl', array(
8 "person" => new Person("Albert", "Einstein")
9));
index.tpl
1[[person
2
3{$_to_string}
4
5{^^^value}
6
7person]]
Output
1Albert Einstein
2
3ALBERT EINSTEIN

Default replacements

Replace some values for another values.

Syntax in PHP

1<?php
2
3div::setDefault($value_to_search, $replace_with);
4

Syntax in templates

1{@ [value_to_search, replace_with] @}

Example

index.php
1<?php
2
3div::setDefault(true, "YES");
4
5echo new div("index.tpl", array(
6 "haveproducts" => true,
7 "havemoney" => false
8));
index.tpl
1{@ [false, "NO"] @}
2
3Have products: {$haveproducts}
4Have money: {$havemoney}
5
Output
1Have products: YES
2Have money: NO

Default replacement for a variable

How to define a default replacement for a specific variable? It is really simple:

Syntax in PHP

1<?php
2
3div::selDefaultByVar($varname, $value_to_search, $replace_with, $update);
4

Syntax in templates

1{@ ['varname', value_to_search, replace_with ] @}

Global vars

The global variables conserve their value and they are independent of the instances of the div class.

Syntax in PHP

1<?php
2
3div::setGlobal('var-name', $mixed_value);

Example

index.php
1<?php
2
3div::setGlobal('today', date('Y-m-d'));
4
5echo new div('index.tpl', array(
6 'name' => 'Peter'
7));
8
9echo new div('index.tpl', array(
10 'name' => 'Jack'
11));
index.tpl
1Hello {$name}
2Today is: {$today}
Output
1Hello Peter
2Today is 2012-08-17
3
4Hello Jack
5Today 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}
2Hello Jack, ...
3
4 ...the previous lines are of more.
5{/strip}
Output
1Hello 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 varDescription
div.nowThe result of time() PHP function
div.post$_POST
div.get$_GET
div.server$_SERVER
div.session$_SESSION
div.versiondiv::$__version
div.script_nameThe cuurent script file name - $_SERVER['SCRIPT_NAME']
div.asciiThe 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 "&#64;".

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
3session_start();
4
5include 'div.php';
6
7div::enableSystemVar('div.session');
8
9if (isset($_GET['user'])){
10 if ($_GET['user'] == 'peter'){
11 $_SESSION['user'] = $_GET['user'];
12 }
13}
14
15echo new 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.
1Welcome 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
3OR
4
5{% path/to/the/template/part %}
6

Example

part.tpl
1Hello world!
index.tpl
1This is the container template:
2
3{% part %}
Output
1This is the container template:
2
3Hello world!
Important The engine does not accept that a template is included itself.

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
4OR
5
6{%% path/to/the/template/part %%}
7

Example

index.php
1<?php
2
3echo new div('test.tpl',array(
4 'name' => 'Unnamed',
5 'products' => array(
6 array('name' => 'Banana'),
7 array('name' => 'Potato')
8 )
9));
index.tpl
1
2Include:
3
4[$products]
5{% part %}
6[/$products]
7
8Preprocessed:
9
10[$products]
11{%% part %%}
12[/$products]
part.tpl
1{$name}
Output
1Banana
2
3Potato
4
5Unnamed
6
7Unnamed

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
3an object or their keys if it is an array ...
4varname]]

Example

index.php
1<?php
2
3echo new div('index.tpl', array(
4 'product' => array(
5 'name' => 'Banana',
6 'price' => 20.5,
7 'tax' => 1.5
8 )
9));
index.tpl
1Product:
2
3[[product
4 Name: {$name}
5 Price: {$price}
6 Tax: {$tax}
7product]]
8
9Similar:
10
11 Name: {$product.name}
12 Price: {$product.price}
13 Tax: {$product.tax}
Output
1Product:
2
3 Name: Banana
4 Price: 20.5
5 Tax: 1.5
6
7Similar:
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
3echo new 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
2This:
3
4<!--| [$products] |-->
5 Name: {$name}
6 Price: {$price}
7<!--| [/$products] |-->
8
9Is 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".

Syntax in templates

1
2{$function:variable-property}
3
Aggregate functionSyntax for list of lists/objectsSyntax for array of atomic valuesDescription
min{$min:list-property}{$min:arrayname}Minimum "property"
max{$max:list-property}{$max:arrayname}Maximum "property"
sum{$sum:list-property}{$sum:arrayname}Sum of "properties"
avg{$avg:list-property}{$avg:arrayname}Average of "properties"
count{$list-property}{$arrayname}Count of true "properties"

Example

index.tpl
1<?php
2
3echo new div('index.tpl', array(
4 'blocks' => array(
5 array('title' => 'Who is online', 'weight' => 0, "show" => true),
6 array('title' => 'Last comments', 'weight' => 1, "show" => false),
7 array('title' => 'Forum topics', 'weight' => 2, "show" => true)
8 ),
9 'widths' => array(800,700,600,500)
10));
11
index.tpl
1
2<!--{ array of array/object }-->
3
4Minimum weight: {$min:blocks-weight}
5Maximum weight: {$max:blocks-weight}
6Weight average: {$avg:blocks-weight}
7Weight sum: {$sum:blocks-weight}
8Showed blocks: {$blocks-weight} or {$count:blocks-weight}
9
10<!--{ array of atomic values }-->
11
12Minimum weight: {$min:widths}
13Maximum weight: {$max:widths}
14Weight average: {$avg:widths}
15Weight sum: {$sum:widths}
16Showed blocks: {$widths}
17
Output
1Minimum weight: 0
2Maximum weight: 2
3Weight average: 1
4Weight sum: 3
5Showed blocks: 2 or 2
6
7Minimum weight: 500
8Maximum weight: 800
9Weight average: 650
10Weight sum: 2600
11Showed 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

1Define the location:
2
3(( location_name ))
4
5Define the content:
6
7{{location_name
8
9... some content here ...
10
11location_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
4This is the header
5header}}
6
7{{footer
8This is the footer
9footer}}
10
11{{content
12This is the content
13content}}
14
15{{header
16<br/>.... more in the header .....
17header}}
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
3include "div.php";
4
5/* Sub-parser as a function */
6function literal($code){
7 return "{ignore}$code{/ignore}";
8}
9
10/* Sub-parser as a function more complex */
11function body($code, &$items){
12 $items['body'] = '<p>'.$code.'</p>';
13 return "";
14}
15
16/* Sub-parser as a method */
17class MyPage extends div{
18
19 /* You can set the sub-parsers in the constructor */
20 public function beforeBuild(){
21
22 // Sub-parser with their name different to the name of function
23 self::setSubParser('combobox', 'buildCombobox');
24 }
25
26 /* A sub-parser ... */
27 public function buildCombobox($properties){
28
29 $prop = self::jsonDecode('{'.$properties.'}');
30
31 $html = "<select name = \"{$prop->name}\">\n";
32 foreach($prop->options as $option) {
33 $html .= "<option value=\"{$option->v}\">{$option->c}</option>\n";
34 }
35 $html .= "</select>\n";
36
37 return $html;
38 }
39
40 /* Other sub-parser */
41 public function upperthis($text, &$items){
42 $text = trim($text);
43 if (self::issetVar($text, $items)) {
44 $items[$text] = strtoupper($items[$text]);
45 }
46 }
47}
48
49/* Set sub-parsers before */
50
51/* Same as MyPage::setSubParser("literal", "literal"); */
52MyPage::setSubParser('literal');
53
54/* Alias for 'literal' */
55MyPage::setSubParser('noparse','literal');
56
57/* Name of sub-parser equal to name of function */
58MyPage::setSubParser('body');
59
60/* Similar way ... */
61div::setSubParser('upperthis');
62
63echo new MyPage('index.tpl');
index.tpl
1{body}
2Hello 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>
8HELLO 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:

index.tpl
1{= name: "Peter" =}
2{= products: [
3 {
4 name: "banana",
5 price: 40
6 },
7 {
8 name: "potato",
9 price: 25
10 }
11] =}
12
13[$products]
14 {parse:beforeParse}
15 Name: {$name}
16 {/parse:beforeParse}
17
18 Product name: {$name}
19
20 {% other %}
21[/$products]
other.tpl
1{parse:beforeParse}
2 Other name: {$name}
3{/parse:beforeParse}
Output
1Name: Peter
2Product name: banana
3Other name: banana
4Name: Peter
5Product name: potato
6Other name: potato

Macros

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.

Syntax

1<?
2
3// ... some PHP code here ...
4
5?>

Example

index.php
1<?php
2
3include 'div.php';
4
5class page extends div{
6
7 public function upper($str){
8 return strtoupper($str);
9 }
10}
11
12echo new page('index.tpl', array(
13 'products' => array('Banana', 'Potato')
14));
index.tpl
1
2{= text: "hello" =}
3
4{$text}
5
6<?
7 // upper() is a method of current class
8 $text = upper($text);
9?>
10
11{$text}
12
13Products:
14
15<?
16
17$i = 0;
18
19foreach($products as $product) {
20 $i++;
21 echo "$i - $product\n";
22}
23
24?>
25
26They are {$i} products
27
Output
1hello
2
3HELLO
4
5Products:
6
71 - Banana
82 - Potato
9
10They are 2 products

Restrictions

  • It is not allowed to use $this or self
  • It is only allowed to use some functions of PHP by default. You can enable the use of another function through the method setAllowedFunction.
  • It is not allowed to create functions neither classes.
  • It is not allowed to include other script.

Features

  • Create new template's variables
  • Change the value of any template's variable
  • ECHO any content (take care of not provoking an infinite loop)
  • Use the allowed methods of div as a functions:
    • asThis
    • atLeastOneString
    • getCountOfParagraphs
    • getCountOfSentences
    • getCountOfWords
    • getLastKeyOfArray
    • getRanges
    • htmlToText
    • isArrayOfArray
    • isArrayOfObjects
    • isCli
    • isNumericList
    • isString
    • jsonDecode
    • jsonEncode
    • mixedBool
  • Use the methods of current class without restrictions if it is a class that extends div

Custom "dialects"

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.

ConstantDefault 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_JSONjson:
DIV_TAG_MODIFIER_HTML_ENTITIEShtml:
DIV_TAG_MODIFIER_NL2BRbr:
DIV_TAG_MODIFIER_TRUNCATE~
DIV_TAG_MODIFIER_WORDWRAP/
DIV_TAG_MODIFIER_SUBSTRING_SEPARATOR,
DIV_TAG_MODIFIER_SINGLE_QUOTES'
DIV_TAG_MODIFIER_JSjs:
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_COUNTcount
DIV_TAG_AGGREGATE_FUNCTION_MAXmax
DIV_TAG_AGGREGATE_FUNCTION_MINmin
DIV_TAG_AGGREGATE_FUNCTION_SUMsum
DIV_TAG_AGGREGATE_FUNCTION_AVGavg
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 ".

Example of rigid blocks are simple replacements and include.

Simple blocks

BEGIN FLEXIBLE SYNTAX END

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.

Example of simple blocks are ignored parts, strips and comments.

No-keyword blocks

BEGIN_PREFIX FLEXIBLE SYNTAX BEGIN_SUFFIX
ANY CODE + SPECIAL TAGS
END

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.

Example of no-keyword blocks are conditions and iterations.

Keyword blocks

BEGIN_PREFIX KEYWORD BEGIN_SUFFIX
ANY CODE + SPECIAL TAGS
END_PREFIX KEYWORD END_SUFFIX

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.

Example of keyword blocks are conditional parts and lists (or loops).

Translator

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
3include '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 *}
3Name: {$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
3include "div.php";
4
5echo new div("index.tpl", array(
6 'name' => 'Peter',
7 'foo' => array(
8 'bar' => 45
9 )
10));
Output
1Name: Peter
2
3{$name}
4
545

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:

@_property_name = property's value

For example, the following code sets the dialect of the template, where the value is the name of the file containing the dialect.

@_DIALECT = smarty.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/propertyDescription
titleDocumentation's title. This variable can be passed to the method with $items parameter. For example:
echo div::getDocsReadable(null, array('title' => 'My docs'));
nameTemplate's name
descriptionDescription of the template in one line
versionVersion of the template
authorAuthor
updateDate of last update
varsList 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:
  1. optional/required
  2. data type
  3. variable's name
  4. variable's description
For example:
<!--{  
...
@vars required string title Blog's title 
      optional string body Blog's body
...			
}-->
			
includeThe 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.
exampleThe 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
4
5 @name My template
6 @description My first template with documentation
7 @author Me
8 @vars: required string title
9 optional string body
10
11 @example:
12 {= title: "My first blog" =}
13 {= body: "This is my first blog" =}
14 {% blog.tpl %}
15
16}-->
index.php
1<?php
2
3include 'div.php';
4
5div::docsOn();
6
7$tpl = new div('index.tpl');
8$tpl->parse();
9
10echo $tpl->getDocsReadable();

Methods's reference

Static methods

div::addCustomModifier(string $prefix, string $function)

Add a custom variable's modifier. The modifier function should have a single parameter.

div::asThis(mixed $mixed)

Return mixed value as HTML format, (util for debug and fast presentation)

div::atLeastOneString(string $haystack, array $needles)

Return true if at least one needle is contained in the haystack

div::delDefault(mixed $search)

Remove a default replacement

div::delDefaultByVar(string $var, mixed $search)

Remove a default replacement for specific variable

div::delGlobal(string $var)

Remove a global var

div::disableSystemVar(string $var)

Disable system var for performance

div::enableSystemVar(string $var)

Enable system var for utility

div::error(string $errmsg, string $level = 'WARNING')

Show error and die

div::fileExists(string $filename)

Secure 'file exists' method

div::getLastKeyOfArray(array $arr)

Return the last key of array or null if not exists

div::getCountOfParagraphs(string $text)

Count a number of paragraphs in a text

div::getCountOfSentences(string $text)

Count a number of sentences in a text

div::getCountOfWords(string $text)

Count a number of words in a text

div::getDefault(mixed $value)

Return a default replacement of value

div::getDefaultByVar(string $var, mixed $value)

Return a default replacement of value by var

div::getSystemData()

Return the loaded data from the system

div::getVarsFromCode(string $code)

Return a list of vars from PHP code

div::haveVarsThisCode(string $code)

Return true if the PHP code have any var

div::htmlToText(string $html, integer $width = 50)

Convert HTML to plain and formated text

div::isArrayOfArray(array $arr)

Return true if $arr is array of array

div::isArrayOfObjects(array $arr)

Return true if $arr is array of objects

div::isCli()

Return true if the script was executed in the CLI enviroment

div::isNumericList(array $arr)

Return true if $arr is array of numbers

div::isValidExpression(string $code)

Check if code is a valid expression

div::isDir(string $dirname)

Secure 'is_dir' method

div::isString(mixed $valur)

Secure 'is_string' method

div::jsonDecode(string $str)

JSON Decode

div::jsonEncode(mixed $data)

JSON Encode

div::log(string $msg, string $level = ' ')

Write a message in the log file

div::logOn(string $logfile)

Activate the debug mode for Div and write the logs into $logfile.

div::mixedBool(mixed $value)

Return any value as a boolean

div::setAllowedFunction({$src} $funcname)

Allow a function for the formulas

div::setDefault(mixed $search, mixed $replace)

Add or set a default replacement of value

div::setDefaultByVar(string $var, mixed $search, mixed $replace, bool $update = true)

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
3include 'div.php';
4
5$product = new stdClass();
6
7$product->name = 'Banana';
8$product->price = 20.5;
9
10echo new 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
3name = {$value}
4
5[/$product]
Step 3
1[$product]
2
3name = Banana
4price = {$value}
5
6[/$product]
Step 4
1name = Banana
2price = 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
9block1}}
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:

1. Create the component:

combobox.tpl
1<select id="{$id}" name="{$name}">
2 [${$options}]
3 <option value="{$val}">{$text}</option>
4 [/${$options}]
5</select>

This component use: simple replacements, lists and recursion.

2. Use your component:

index.tpl
1[[_empty
2 {= id: "products" =}
3 {= name: "products" =}
4 {= options: "products" =}
5 {% combobox %}
6_empty]]

"Use a component" means "include the component", for example, into a capsule, that can be the _empty variable.

3. Write your PHP code:

index.php
1<?php
2
3echo new div('index.tpl', array(
4 'products' => array(
5 array('val' => 1, 'text' => 'Banana'),
6 array('val' => 2, 'text' => 'Potato'),
7 array('val' => 3, 'text' => 'Apple')
8 )
9));

And when you run your script:

1<select id="products" name="products">
2 <option value="1">Banana</option>
3 <option value="2">Potato</option>
4 <option value="3">Apple</option>
5</select>

Appendix A: Allowed PHP functions

These are the PHP functions that can be used in conditions, formulas and another expressions in the templates:

abs acos acosh
addcslashes addslashes asin
atan2 atanh base_convert
bcadd bccomp bcdiv
bcmod bcmul bcpow
bcpowmod bcscale bcsqrt
bcsub bin2hex bindec
cal_days_in_month cal_from_jd cal_info
cal_to_jd ceil checkdate
chop chr chunk_split
convert_cyr_string convert_uudecode convert_uuencode
cos cosh count
count_chars crc32 crypt
date date_default_timezone_get date_sunset
decbin dechex decoct
deg2rad easter_date easter_days
empty exp explode
expm1 floatval floor
fmod frenchtojd getrandmax
gmdate gmmktime gmstrftime
gregoriantojd hebrev hebrevc
hex2bin hexdec html_entity_decode
htmlentities htmlspecialchars htmlspecialchars
htmlspecialchars_decode htmlspecialchars_decode hypot
idate implode intval
is_bool is_double is_finite
is_float is_infinite is_int
is_integer is_long is_nan
is_null is_numeric is_real
is_scalar is_string isset
jddayofweek jdmonthname jdtofrench
jdtogregorian jdtojewish jdtojulian
jdtounix jewishtojd jewishtojd
lcfirst lcg_value levenshtein
log log10 log1p
ltrim max md5
metaphone microtime min
mktime money_format mt_getrandmax
mt_rand mt_srand nl2br
nl_langinfo number_format octdec
ord pi pow
quoted_printable_decode quoted_printable_encode quotemeta
rad2deg rand rand
round rtrim sha1
similar_text sin sinh
sizeof soundex sprintf
sprintf sqrt srand
str_ireplace str_pad str_repeat
str_replace str_rot13 str_shuffle
strcasecmp strchr strcmp
strcoll strcspn strftime
strip_tags stripcslashes stripos
stripslashes stristr strlen
strnatcasecmp strnatcmp strncasecmp
strncmp strpbrk strpos
strptime strrchr strrev
strripos strrpos strspn
strtolower strtotime strtotime
strtoupper strtr strtr
strval substr substr_compare
substr_count substr_replace tan
tanh time timezone_name_from_abbr
timezone_version_get trim ucfirst
ucwords uniqid unixtojd
urldecode urlencode wordwrap

Appendix B: Comparison of syntax of Smarty and Div

Loops

Smarty:
1{foreach $foo as $bar}
2 <a href="{$bar.zig}">{$bar.zag}</a>
3 <a href="{$bar.zig2}">{$bar.zag2}</a>
4 <a href="{$bar.zig3}">{$bar.zag3}</a>
5{foreachelse}
6 There were no rows found
7{/foreach}
Div:
1[$foo]
2 <a href="{$zig}">{$zag}</a>
3 <a href="{$zig2}">{$zag2}</a>
4 <a href="{$zig3}">{$zag3}</a>
5@empty@
6 There were no rows found
7[/$foo]

Include

Smarty:
1{include file="header.tpl"}
Div:
1(% header %}

Iterations

Smarty:
1{for $x = 1 to 20 step 2}
2 {$x}
3{/for}
Div:
1[:1,20,x,2:]
2 {$x}
3[/]

This documentation was compiled with Div at 2015-12-24
Written by Rafa Rodríguez <rafacuba2015@gmail.com>


Powered by Div
Table of contents