This page is yet unfinished. It may contain remarks of what should be written here. If you’d like to help writing this page, please ask in the forum for details. This is a final state. See further details on the home page.
What are templates?
The idea behind what’s commonly called “templates” is separating the business logic from the presentation of data. This means mainly the separation of ‘complex’ PHP code from the HTML output. This, in theory, allows HTML designers with no PHP experience to modify the look of the site without having to look at any PHP code. (Reference) In this case, templates are basically partial HTML files with some control and data information coded in them. These partial files will later be assembled to entire web pages, with the control commands (conditionals, loops) interpreted and the data placeholders filled with actual information. You can have different sets of templates in different board designs so that you can freely alter the board’s appearance without touching the actual code and let the user choose one design in the end.
Templates handling
At the beginning there’s a number of template source files. They are all located in the tpl/ directory of each board design and usually have the filename extension “.html”. These are the files you can edit to make the board look differently. These are also the files that are referenced from the UNB code to display a certain element, posts, threadlists or the entire page, in the browser. Whenever a template file is to be used, the template engine will see if it’s there and if the cached version is still current, then if necessary compile the source file into the cache and then remember it for later inclusion. This remembering is done with the
UteRemember
function. The UteShow
function will instead display the template output immediately. So templates need to be compiled before they can be used. The result of this compilation is stored in the template cache directory, tpl/cache/ in each design, and can later be used without the relatively time-consuming compilation. The template compiler programme code will only be included by PHP if a template needs to be compiled. In every-day use, it doesn’t need to be parsed and won’t need any additional time to generate the page.
Template syntax
General usage
When a template file is parsed, only template code that is between the opening and closing tag will be processed. This allows you to use any file as a template source because anything outside the template tags will be ignored and used as output unchanged. This works much the same way as the PHP interpreter. The default opening and closing tags are
{
and }
but you can also change them in the template compiler configuration. An example of template code:
This is part of the HTML page.
{if $someVariable}Print me!{endif}
This is normal output again.
When you want to use JavaScript or CSS code that also uses the
{
character, you can double it to {{
to declare this is not the beginning of template code:
<script type="text/javascript">
function doNothingLoop()
{{
// This is normal JavaScript code, using a templated variable!
return {$someVariable};
}
</script>
As you can see, inside the template tags, control commands as well as variables may appear. If there’s only a variable or a function call that returns data, this data will be inserted in the page into this place at runtime. You can only include a single command or variable in a template code block. If you need multiple commands or variables, you need multiple code blocks.
Display data
The simplest way to include variable data in a page is to use variables. All variables begin with the
$
character, directly followed by their name. No spaces are allowed before or inside the name. Variables are parsed in a case-sensitive way, so $variable
and $VARiable
are two separate things. You can see an example of variables above.
To make use of data structures and group multiple data fields together you can use arrays. Only associative arrays can be used, that means that an array must contain named items. Those names are used to access the data in the template code. Again we have the
$
character, followed by the array name, then a .
(dot) and finally the name of the array item. The same rules as for variable names apply on array items except that you can also reference array items by their numeric index. You can use nested arrays up to two levels by simply appending another array item name. Examples of arrays are: $variable.item
, $variable.more.text
and $variable.2.14
. The PHP code to set these arrays would be:
$params['variable'] = array('item' => value);
$params['variable'] = array('more' => array('text' => value));
$params['variable'][2][14] = value;
// Note: The array structure must be initialised before.
You can also access PHP constants in your template files. The constants must be defined before the template is shown. Constants look similar to variables but begin with a
%
instead. Example: %PHP_VERSION
.
Statis strings can be used as in most other languages and interpreters by putting double quotes (
"
) around them. Strings may contain double quote characters but these must be escaped by prepending them each with a single \
(backslash). Strings can be used at any places where an expression is expected, for example as a function parameter. The same applies to numbers which must look like these: 5
, -4
, 20.1
or +405.221
.
More comples expressions consist of operators and functions. Operators can be used to perform arithmetic operations like addition, multiplication or to process or compare variables or other expressions in any other way. There are several operators predefined, the complete list can be viewed in the file ute-compiler.conf.php at the
__registeredFunctions
option. Operators can expect either one or two parameters that follow the operator name each with a space. Some of the unary operators (with one parameter) are not
(logical NOT), even
(is the number even, means a product of 2), round
(round to integer), ucase
(transform to uppercase) and sizeof
(length of an array). Some of the binary operators (with two parameters) are eq
(equal), neq
(not equal), lt
(less than), and
(logical AND), add
(addition), sub
(subtraction) and mod
(modulo).
The syntax of operators and functions is exactly the same. In fact their definition in the template compiler configuration goes the same way. First you write the function name, followed by as many parameters as the function expects, each separated by a single space. You may use brackets and commas to emphasize the structure of an expression but they’re not required and treated as a space. Multiple spaces where one is expected are allowed. Due to the lack of delimiters, functions cannot have optional parameters. The function name already says how many of the following parameters it will use. If you need “overloaded” functions as they exist in many other programming languages, you must define another function name for each of them. Of course you can insert further function calls with their own parameters whereever a function parameter or any other data expression is expected. Using brackets to group them may come in handy here.
These are several examples of operators and functions:
eq $var 10
(is $var equal to 10?)add 10 34
(10 + 34)ucase trim " Hello World "
(produces "HELLO WORLD")mod (round add (23, mult ($factor, 4.2))), 10
(round(23 + $factor * 4.2) mod 10)
There is a special command that is interpreted in a somewhat different way, the
The
set
command. You can use it to assign new values to variables. This may be useful in loops and conditional code as we’ll see later on. Its usage is as follows:set $variable $newValue
, for example set $variable 5
or set $variable "Text"
.The
$
character can be omitted for variable names here. Assigning new values also works with array items.
And there is a special function that is an exception to the constant number of parameters: the
In this example, the translation for the key
Both these functions “eat up” all parameters until the end or until an empty string (
tr
function. It is used to translate things accoring to the currently selected user interface language. It expects a string key as its first parameter that describes what text should be looked up. And it can take any number of additional parameter pairs to fill in variables in that translation. For example there are texts that include a numeric field that can be set this way:{tr "n days left until x", "n" $daysCount, "x" "Christmas"}
In this example, the translation for the key
"n days left"
contains a parameter named n
. This parameter will be set with the value of $daysCount
in that moment when it is displayed. The according translation text could look like this: "There are {n} days left until {x}."
. The trnum
function is very similar but it uses two parameters initially. The second one is a count index that can be used to select a more specialised translation for the given numerus. If the count was 1
in our example, the translation could be "There is one day left until {x}."
and you could use it by:{trnum "n days left until x" $daysCount, "n" $daysCount, "x" "Christmas"}
Both these functions “eat up” all parameters until the end or until an empty string (
""
) shows up. For details about the numerus selection refer to the translation documentation. (TODO: add link when it exists)
Conditions
What would a template be worth if you couldn’t make conditional output that is only displayed under certain circumstances? So there is also a way to express conditions in the template code. Conditions begin with the keyword
The middle part is only output to the page if
if
followed by the condition expression to check. The condition must be a single expression like a variable but it can also be constructed using functions as described above. The end of the conditional code is declared with the endif
keyword. A simple example would be:Before condition. {if $variable}Variable is set.{endif} After condition.
The middle part is only output to the page if
$variable
has been set before.
You can also define more complex conditions with multiple condition cases. Use the
elseif
keyword followed by a new expression for any further condition and the else
keyword with no expression for a final case:{if eq $var 1}Take 1{elseif eq $var 2}Take 2{else}something else{endif}
Loops
There are three kinds of loops:
while
, for
and foreach
loops. While loops repeat a certain code block as often as some condition is met. You don’t always know exactly how often that will be, it can reach from not at all to infinite times. The condition is always checked before the code block will be processed. An example:{while gt (someFunction $withParameter) 2}
Function is greater then 2.<br />
{endwhile}
For loops can count a local variable up from one value to another, inclusively. With every loop, the variable is increased by one. For loops expect three parameters: a local variable, a lower bound and an upper bound. It can be used to process a code block for multiple subsequent values like this:
{for $i 1 12}Month {$i}. {endfor}
Foreach loops should generally be a lot more useful. They can run the code block once for each of the elements in an array. This can be a list of objects that will each be displayed with another included template (see next subsection). This time you can choose to use a local variable name or not to. If you do, each array item will be accessible by the name of that variable inside the loop. Other variables from outside the loop can also be accessed as usual:
You can omit the local variable, if the array items theirselves are arrays again. In that case you’d have to access their items’ values like
As you can see, all array keys of the items inside the
You can access global variables from outside the loop with
{foreach $line in $text}Line: {$line} {$somethingElse}<br />{endforeach}
You can omit the local variable, if the array items theirselves are arrays again. In that case you’d have to access their items’ values like
$line.item
in the above example. This can be shortened to $item
inside the loop:{foreach $users}Name: {$name}, Phone: {$phone}<br />{endforeach}
As you can see, all array keys of the items inside the
$users
array are mapped into the ‘local variable namespace’ so that you can use them by their name directly inside the loop. This short form is good for small loops where you don’t have a lot variables. Things will look simpler and easier to understand. The long form of this would be:{foreach $u in $users}Name: {$u.name}, Phone: {$u.phone}<br />{endforeach}
You can access global variables from outside the loop with
$.somethingElse
then.
There are two loop control commands:
next
will immediately stop processing this loop run and continue with the next turn of the loop. If you use next
at the beginning of a loop inside a condition, you can selectively skip single loop turns. exit
will exit the loop completely. Anything that follows that command until the next loop end will be ignored.
Includes
You can split templates into multiple files to give them a better structure and make it easier to maintain them. To include another file insert the
include $filename
command with a relative filename as the only parameter. It is probably the best idea to keep all template files in a single directory. The included file will be textually inserted at the place of the include
command. You can use any variables in that file that are available at the place of the include
command as well. The parameter may also be an array of filenames. The template runtime will include each of them once and in-order in that case. A very simple example:{include "listitem.html"}
Comments
Comments can be used to make notes and annotations in the template file without actually showing them on the output page. They are introduced with a double hyphen and continue until the end of the template code tag. The space after the hyphens is not required. Example:
Normal text. {-- This comment will not appear on the page.} Normal text.
Aliases
You can define aliases that will be replaced by something else when they are used. These aliases begin with a
=
followed by their name. The name may contain spaces but there are no parameters. Thus aliases can only be used for a static text replacement and to shorten certain things. Aliases are defined in the file ute-compiler.conf.lib at the __aliasTable
option. Their replacement content can contain template code inside braces again that will then be evaluated.