| eZ components - Template component |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| .. contents:: Table of Contents |
| |
| |
| Introduction |
| ============ |
| The template component provides a manageable way to separate |
| application logic from presentation data. The application logic is the PHP code |
| of your application, including the call to the Template component. Presentation |
| data are the template files. |
| |
| The separation of application logic and presentation data is easier to |
| maintain and allows different people to work on separate parts. Another |
| advantage is that the Template language is more suitable for non programmers and |
| web designers. The language is designed to be easier to use and contains more |
| expressive constructs for repetitive tasks in the presentation data. |
| |
| |
| Class overview |
| ============== |
| |
| The following list sums up the most important API classes: |
| |
| ezcTemplate |
| This class provides the main API for processing templates. This class |
| compiles the template to PHP code, executes it, and returns the result. |
| |
| ezcTemplateConfiguration |
| This class configures the Template engine. Settings like: where to find the |
| source templates, where to store the compiled templates, the type of |
| context to use, are stored in this class. |
| |
| ezcTemplateVariableCollection |
| The variables that should be send to the template or retrieved from the |
| template are stored in the object from this class. |
| |
| More information about these classes can be found in the documentation of the |
| class itself. |
| |
| |
| Template component |
| ================== |
| |
| This section describes how to use the template component in your PHP |
| application. How to write the templates itself is described in the next |
| section. |
| |
| |
| Getting started |
| --------------- |
| |
| The simplest example we can come up with is writing "Hello world" to your |
| standard output. Basically it consists of two steps: |
| |
| The first step is to create a text file "hello_world.ezt" that contains |
| only one line:: |
| |
| Hello world |
| |
| and store it in the directory where your application sources reside. |
| |
| The next step is to copy the following PHP script, and check if the application |
| works. |
| |
| .. include:: tutorial_simple.php |
| :literal: |
| |
| If you run your application, it should print "Hello world". Otherwise |
| check that: |
| |
| - The base class can be found. Check your 'include\_path' in the PHP.ini |
| settings, and see if the components are included. |
| - The template "hello\_world.ezt" can be found. Write the absolute |
| path to your hello\_world template in the 'process' method. |
| - The Template engine can write to the current directory. By default it tries |
| to create the directory compiled_templates with the permissions of the |
| running PHP process. The next section explains how another output |
| directory can be specified. |
| |
| |
| Configuring the Template engine |
| ------------------------------- |
| Templates are not always stored in your local directory and neither do you |
| want to store the compiled templates among your source files. Therefore we |
| have to change the configuration: |
| |
| .. include:: tutorial_configuration.php |
| :literal: |
| |
| If you try to copy/paste and run this example, you'll probably get the |
| following output:: |
| |
| Fatal error: Uncaught exception 'ezcTemplateFileNotFoundException' with message |
| 'The requested template file </usr/share/templates/hello_world.ezt> does not exist.' |
| |
| This error shows that the Template engine looks in the "/usr/share/templates" directory |
| for the templates. If the *hello_world.ezt* template was present at |
| */usr/share/templates/* then the Template engine tries to write to the |
| */tmp/compiled_templates/* directory. Make sure that this directory is writable |
| by the current running PHP process. Under Linux the following code makes the |
| directory accessible for anyone:: |
| |
| mkdir /tmp/compiled_templates |
| chmod a+rwx /tmp/compiled_templates |
| |
| |
| The ezcTemplate class calls the getInstance() method from the ezcTemplateConfiguration |
| class and retrieves the "default" configuration. It is possible to set multiple |
| configurations, which is demonstrated in the next example: |
| |
| .. include:: tutorial_multi_configuration.php |
| :literal: |
| |
| Running this example will produce the following output:: |
| |
| The requested template file <html/hello_world.ezt> does not exist. |
| |
| The requested template file <printer/hello_world.ezt> does not exist. |
| |
| The requested template file <pdf/hello_world.ezt> does not exist. |
| |
| |
| As demonstrated, the Template configuration can be set in the 'configuration' property, |
| given as second parameter in the process method, or use the 'default' |
| getInstance configuration. |
| |
| |
| Lazy initialization |
| ------------------- |
| |
| Lazy initialization is a mechanism to load and configure a component, only |
| when it is really used in your application. This mechanism saves time for |
| parsing the classes and configuration, when the component is not used at all |
| during one request. You can find a description how you can use it for your |
| own components and how it works in the `ezcBase tutorial`__. The keyword for |
| the template component is *ezcInitTemplateConfiguration*. |
| |
| __ introduction_Base.html#lazy-initialization |
| |
| .. include:: tutorial_lazy_initialization.php |
| :literal: |
| |
| This examples shows how to configure the template component like shown in the |
| first example. The main difference is, that we roll out the configuration to |
| an own class, and define a callback using ezcBaseInit::setCallback to this |
| class, which will be called with a template configuration object as first |
| parameter on the first instantiation of the template component. |
| |
| ezcBaseInit::setCallback accepts as a first parameter a component specific key, |
| which lets the component later request the right configuration callback. The |
| second parameter is the name of the class to perform the static callback on. |
| This class must implement the ezcBaseConfigurationInitializer class. |
| Each component's lazy initialization calls the static method configureObject() |
| on the referenced class. |
| |
| When the template component is finally instantiated in line 19 of the example, |
| the configureObject() method will be called with an ezcTemplateConfiguration |
| instance used by the Template engine, which can be modified by the method. |
| |
| |
| Send and receive template variables |
| ----------------------------------- |
| More often than not a PHP application sends variables to the Template engine. |
| Commonly those variables are displayed. It is also possible to retrieve |
| variables from a template. The next example sends two variables to a template. |
| The values are added and placed in a new variable that is returned. The code |
| below is the PHP code needed to send the variables to the template. |
| |
| |
| .. include:: tutorial_variable_send_receive.php |
| :literal: |
| |
| |
| The template code is as follows: |
| |
| .. include:: tutorial_variable_send_receive.ezt |
| :literal: |
| |
| |
| As you can expect the result is:: |
| |
| Answer: 5 |
| |
| |
| Template locations |
| ------------------ |
| |
| Since version 1.2 it is possible to send a location object instead of a |
| *location* parameter of the *process* method. A location object is an object |
| that implements the ezcTemplateLocation interface. The interface is as |
| follows:: |
| |
| interface ezcTemplateLocation |
| { |
| public function getPath(); |
| } |
| |
| |
| The Template engine calls the *getPath* method on the object implementing this |
| interface when needed. The *getPath* method returns a |
| string specifying the template to execute. If the return value is a relative |
| path, if it does not start with a slash, then the *templatePath* from the |
| configuration is prepended. |
| |
| The next example executes the *hello\_world.ezt* template via a location |
| object:: |
| |
| class MyLocation implements ezcTemplateLocation |
| { |
| public function getPath() |
| { |
| return "hello_world.ezt"; |
| } |
| } |
| |
| $t = new ezcTemplate(); |
| $t->process( new MyLocation() ); |
| |
| It is also possible to provide a callback for every time a template's location |
| is requested. Instead of supplying an object to the process() method of the |
| ezcTemplate object like we do above we configure the callback with the template |
| system's configuration:: |
| |
| $c = ezcTemplateConfiguration::getInstance( 'templates' ); |
| $c->locator = new PathResolver(); |
| |
| The PathResolver class implements the ezcTemplateLocator interface and is |
| responsible for translating the paths that processed by the template engine. In |
| the example below it simply prepends "overridden/" to the path. The |
| *templatePath* from the configuration is prepended. The implementation:: |
| |
| class PathResolver implements ezcTemplateLocator |
| { |
| public function translatePath( $path ) |
| { |
| return 'overridden/'. $path; |
| } |
| } |
| |
| For every path that now passes through the template engine, "overridden/" is |
| prepended. Which means that the following code actually processes |
| "overridden/test1.ezt":: |
| |
| $template = new ezcTemplate(); |
| $out = $template->process( 'test1.ezt', $c ); |
| |
| |
| Template syntax |
| =============== |
| This section explains the syntax that can be used in the template itself. |
| |
| Basic syntax |
| ------------ |
| The Template engine considers statements embedded in curly braces '{ .. }' as |
| code. Everything outside a block is parsed as text. The following example |
| shows a template that does a simple calculation:: |
| |
| 5 times 3 equals: { 5*3 } |
| |
| This example consists of two parts. The first part is the text up to the |
| opening curly brace. The second part is the code between the braces. Text |
| outside braces will always be printed. The code inside braces will be executed. |
| If the code does not modify a variable then the output of the executed code |
| will also be printed. The example will of course print:: |
| |
| 5 times 3 equals: 15 |
| |
| |
| Curly braces separate text from template code. Therefore these braces cannot be |
| used in the text directly. To use curly braces there are several |
| possibilities. The most common are to use escape characters or use the literal |
| tag. |
| |
| |
| Escape characters |
| ````````````````` |
| A character can be escaped with a backslash (\\). In the text, there are three |
| groups of sequences that can be escaped. Those are: |
| |
| - Open and close curly braces: '\\{' turns into '{' and '\\}' turns into '}'. |
| - The escape character, backslash: '\\\\' turns into '\\'. |
| - All newline character combinations: '\\[LF]', '\\[CR]' and '\\[CR][LF]' all |
| turn into '' (nothing). |
| |
| The next example shows how to escape those characters:: |
| |
| Draw line: \{ (4, 10), (3, 5) \} |
| Game path: C:\\Program files\\games\\ |
| Multiple \ |
| lines \ |
| becomes one |
| |
| The output of the template is without the backslash and the characters appear |
| normally:: |
| |
| Draw line: { (4, 10), (3, 5) } |
| Game path: C:\Program files\games\ |
| Multiple lines becomes one |
| |
| All other uses of the escape character '\\' result in the escape character |
| being printed. This includes '\\' *just* before an EOF. |
| |
| Literal tags |
| ```````````` |
| Literal tags are used when the text needs to be processed as it is (literally). The |
| curly braces don't need to be escaped and escape characters can be used. |
| Usually javascript is surrounded by literal tags in the templates. The curly |
| braces don't need to be escaped. |
| |
| The next example demonstrates how the escaped characters from the previous example can be |
| omitted with literal tags: :: |
| |
| {literal} |
| Draw line: { (4, 10), (3, 5) } |
| Game path: C:\Program files\games\ |
| {/literal} |
| |
| |
| Comments |
| -------- |
| Comments are text blocks which are stripped away from the output when the |
| template is compiled and executed. The Template engine supports three types |
| of comments: |
| |
| - Code comments start and end with, respectively, '{\*' and '\*}' tags. |
| - Multi-line in-line comment, starts with '/\*' and ends with '\*/'. |
| - Single-line in-line comment that starts with '//' and reads until the end of |
| the line or until a closing curly brace '}'. |
| |
| |
| Code comments |
| ````````````` |
| Code comments start and end with:'{\*' and '\*}' tags, respectively. |
| Everything inside those tags is considered as comment:: |
| |
| {* Variable $i alternates the value 0 and 1 *} |
| {$i = 1 - $i} |
| |
| {* {if $i == 0} |
| {$i = 1} |
| {else} |
| {$i = 0} |
| {/if} |
| *} |
| |
| Writing only *{$i = 1 - $i}* would have had the same output. |
| |
| |
| Multi-line in-line comment |
| `````````````````````````` |
| Multi-line in-line comments are created using \/\* and \*\/. Use this comment to |
| comment a part of a line or comment multiple lines:: |
| |
| {var $a = 1, /*$b = 2, */ $c = 3 } |
| |
| {$a = 2, /* |
| $b = 3, |
| $c = 4 |
| */} |
| |
| |
| If the result after removing the in-line comments is an empty block then the |
| block will be ignored. The next example has an empty block that won't be |
| visible in the output:: |
| |
| { /* var $a = 1 */ } |
| |
| And is of course the same as writing: *{ }*. The empty block will be ignored. |
| |
| |
| Single-line in-line comment |
| ``````````````````````````` |
| Single-line in-line comments are created using two slashes: \/\/ . Use this |
| to start a comment which continues to the end of the line or until the closing |
| curly brace '}':: |
| |
| {var $a = 1, // $b = 2, |
| $c = 3} |
| |
| {$a = 4 //, $b = 5, $c = 6} |
| |
| This example declares the variables *$a* and *$c* and assigns in the second |
| statement the value 4 to variable *$a*. |
| |
| Primitive types |
| --------------- |
| |
| The Template language supports several primitive types: |
| |
| :Boolean: Expresses the truth value, which is either 'true' or 'false'. |
| :Integer: Is a number of the set: { .., -1, 0, 1, .. } |
| :Float: Is a real (floating point) number. |
| :String: A series of characters which are enclosed between single or double quotes. |
| :Array: Contains a set of primitive types. |
| :Object: A PHP object (imported via the user application). |
| |
| |
| Boolean |
| ``````` |
| The boolean type contains either the value: *true* or the value |
| *false*. The next example set the *$isValid* variable to *true*. :: |
| |
| {var $isValid = true} |
| |
| Some of the operators return boolean values. An example is the '==' operator. |
| The Expressions_ section discusses the operators in more detail. The next |
| example uses the '==' operator:: |
| |
| {var $isValid = ($number == 6) } |
| |
| It checks first whether the variable *$number* is equal to the value 6. The |
| result is either *true* or *false*. The result is assigned |
| to the variable *$isValid*. |
| |
| |
| Integer |
| ``````` |
| Integers are specified in a decimal notation only. To use octals or hexadimals |
| the number needs to be converted with the appropriate function. Examples are:: |
| |
| {2} |
| {4} |
| {math_hex_to_dec("1F")} |
| |
| See the methods: math_bin_to_dec, math_hex_to_dec, math_oct_to_dec, math_dec_to_bin, |
| ath_dec_to_hex, and math_dec_to_oct for more information about those |
| conversions. |
| |
| |
| Float |
| ````` |
| Floating point numbers are values that contain a real value. Some examples:: |
| |
| {1.0} |
| {-100.234214} |
| {3.14} |
| |
| It is also possible to express an exponent in the float. The exponent is marked |
| with the character 'e' or 'E' followed by one or more digits:: |
| |
| {1.0e3 // 1000 } |
| {2e4 // 20000 } |
| {1e-2 // 0.01 } |
| {0.1e-2 // 0.001 } |
| {-3.1e2 // -310 } |
| |
| |
| String |
| `````` |
| The string consist of a series of characters enclosed between single or double |
| quotes:: |
| |
| {'a string' // Using single quotes } |
| {"hello world" // Using double quotes } |
| |
| In the string we use the backslash (\\) as escape character. For the single |
| quoted string the escape characters are: |
| |
| +-------------+-------------+ |
| | **String** | **Output** | |
| +-------------+-------------+ |
| | \' | ' | |
| +-------------+-------------+ |
| | \\ \\ | \\ | |
| +-------------+-------------+ |
| | \\ | \\ | |
| +-------------+-------------+ |
| |
| Examples of the single quoted strings are:: |
| |
| {'This string contains a \'quotes\' and backslashes (\\).'} |
| {'A single \ works also.'} |
| {'Characters like \n, \t, ", {, }, $, etc can be used without problems'} |
| |
| |
| The double quoted string allows more special characters than the single quoted |
| string. Most useful escape characters are probably the variables and newlines |
| that can be included in the string. The escape characters for the double quoted |
| strings are: |
| |
| +-------------+-------------------+ |
| | **String** | **Output** | |
| +-------------+-------------------+ |
| | \" | " | |
| +-------------+-------------------+ |
| | \\ \\ | \\ | |
| +-------------+-------------------+ |
| | \\ | \\ | |
| +-------------+-------------------+ |
| | \\n | <newline> | |
| +-------------+-------------------+ |
| | \\t | <tab> | |
| +-------------+-------------------+ |
| | $ | $ | |
| +-------------+-------------------+ |
| | \\r | <carriage return> | |
| +-------------+-------------------+ |
| |
| |
| The next example inserts newlines in the string:: |
| |
| {"Hello\nHello"} |
| |
| The output of the template above is:: |
| |
| Hello |
| Hello |
| |
| Some other examples of using single and double quoted strings:: |
| |
| {" a \"quoted\" string "} |
| {'Newlines are added with the \\n command.'} |
| {'\tThis string starts with a tab (\\t).'} |
| |
| |
| Array |
| ````` |
| The array is just like in PHP an ordered map. It can be used as an array or as |
| a table that maps values to keys. There are two ways to create an array. The |
| first method has the following syntax:: |
| |
| array( [ key => ] value, [ key2 => ] value2, ... ) |
| |
| The parts between brackets are optional. So the *key* can be omitted. In that |
| case, it would simply create an array. First value has the index |
| 0, the next value has index 1, and so on. The next example creates an array |
| which consists of 3 elements:: |
| |
| {var $names = array( "Bernard", "Manny", "Fran" )} |
| |
| The array values, and in this case the names, can be accessed:: |
| |
| {$names[0] // Outputs "Bernard"} |
| {$names[2] // Outputs "Fran"} |
| {$names[3] // Is not allowed } |
| |
| The array with *keys* maps the key to a value:: |
| |
| {var $personInfo = array( "first_name" => "Bernard", "last_name" => "Black" ) } |
| |
| To access the information:: |
| |
| {$personInfo["first_name"] // Outputs "Bernard"} |
| {$personInfo["last_name"] // Outputs "Black"} |
| |
| |
| The second method to create an array is to use the *..* (dot-dot) operator :: |
| |
| <number1>..<number2> |
| |
| The operator creates an array that contains the numbers from *number1* to |
| *number2*. The next example creates an array that contains the numbers: 3, 4, 5, 6, |
| and 7. |
| |
| {var $nrs = 3..7 } |
| {$nrs[0] // Outputs 3} |
| |
| This method is especially useful to use in a foreach loop. The following |
| example loops 10 times, and prints the number from 1 until 10:: |
| |
| {foreach 1..10 as $i} |
| Number: {$i} |
| {/foreach} |
| |
| The Foreach_ section describes this loop in more detail. |
| |
| |
| Object |
| `````` |
| Objects are only available when they are sent from the user application. It is |
| not possible to create an object inside the Template language. The template |
| language restricts the accessibilities from the object only to its properties; |
| thus function calls are not permitted. The next example is a part of an user |
| application that sends an object to a template:: |
| |
| <?php |
| |
| class MyClass |
| { |
| public function __get( $name ) |
| { |
| return "Hello $name"; |
| } |
| |
| public function __set( $name, $value ) |
| { |
| throw new Exception ("Setting $name is not allowed"); |
| } |
| } |
| |
| $t = new ezcTemplate(); |
| $t->send->obj = new MyClass; // Create an object and assign it to "obj" |
| $t->process("my_template.ezt"); |
| |
| ?> |
| |
| The class in the example above has two 'magic' PHP functions. Fetching any |
| property is allowed, whereas setting a property value throws an Exception. The |
| template code that belongs to the user application:: |
| |
| {use $obj // Import the "obj" } |
| |
| {$obj->Bernard // Calls the __get method on the object which returns "Hello Bernard"} |
| {$obj->Bernard = "Fran" // Calls the __set method that throws an exception} |
| |
| |
| More information about importing objects is described in the `External variable |
| declaration (use)`_ section. |
| |
| |
| Variables |
| --------- |
| A variable can only be used after it has been declared. A |
| declaration defines a unique variable name that will be available from now |
| until the end of the template. The next example declares a local variable:: |
| |
| {* Declare the variable *} |
| {var $the_answer_to_life_the_universe_and_everything} |
| |
| {* Assign it to 42 *} |
| {$the_answer_to_life_the_universe_and_everything = 42} |
| |
| |
| Switching the assignment with the declaration results in a compiler error. |
| |
| Variables in the syntax languages are represented by a dollar sign followed by |
| the name of the variable. The variable name is case-sensitive. A valid variable |
| name starts with a letter or underscore, followed by any number of letters, |
| numbers, or underscores:: |
| |
| {* valid declarations *} |
| {var $abcdEFG} |
| {var $_hello_} |
| {var $hello12} |
| |
| {* invalid declarations *} |
| {var $12monkeys} |
| {var $dumb&dumber *} |
| |
| |
| The Template language has three types of variable declaration: *var*, *use* and |
| *cycle*. *Var* declares a local variable as used in the previous |
| example, *use* imports an external variable, and *cycle* declares a cycle |
| variable. |
| |
| |
| Local variable declaration (var) |
| ```````````````````````````````` |
| The declaration of a local variable creates a variable that has only a value |
| inside the current template. |
| |
| The syntax to declare a local variable is:: |
| |
| {var $<unique_name> [ = <value> ] [ , $<unique_name2> [ = <value> ] ] } |
| |
| |
| One or multiple variables can be declared with one *var* statement. A value can |
| be assigned to the variable name, directly. If no value is given to the |
| variable, then it will get the default value *null*. |
| |
| The next example declares four variables at the same time:: |
| |
| {var $a = 2, $b = "Hello World", $c = true, $d} |
| |
| All variables are initialized to a value. (The last variable is initialized to |
| *null*.) |
| |
| |
| External variable declaration (use) |
| ``````````````````````````````````` |
| The declaration of an external variable creates a variable that usually has a |
| value from outside the current template. Outside the current template is, for |
| example, the application that compiles and executes the template. |
| |
| The syntax for this type of variable |
| is as follows:: |
| |
| {use $<unique_name> [ = <value> ] [ , $<unique_name2> [ = <value> ] ] } |
| |
| Besides the *use* tag it is the same syntax as a local variable declartion. |
| |
| The variable will be imported from the user application or another template and |
| is now available in the current template. If the declared *use* variable is not |
| sent to the current template an exception will be raised **unless** the |
| declared variable is initialized to a value. :: |
| |
| {use $a, $b = 2} |
| |
| Variable *$b* will be assigned to the value *2* if the variable is not sent to |
| the template. Variable *$a* will raise an Exception when the variable is not |
| sent. |
| |
| |
| The next example shows a part of the user application:: |
| |
| $t = new ezcTemplate(); |
| |
| // Send some information to the Template |
| $t->send->item1 = "Toaster"; |
| $t->send->item2 = "Manny"; |
| |
| // Process the template and print it. |
| echo $t->process(); |
| |
| |
| The variables $item1 and $item2 are now available in the template if they are |
| declared with *use*:: |
| |
| {use $item1 = "unknown", $item2 = "unknown"} |
| |
| Use {$item1} on {$item2} |
| |
| |
| |
| Cycles |
| `````` |
| A cycle is a special type of variable that contains a set of values. The cycle |
| variable must be assigned to an array. Values are retrieved one array element at |
| the time. Specific control structures are available to cycle |
| through the set of values. The syntax for the cycle is:: |
| |
| {cycle $<unique_name> [ = <array_value> ] [ , $<unique_name2> [ = <array_value> ] ] } |
| |
| An array must be assigned to the cycle variable. Otherwise the template |
| compiler *may* give a compiler error. (Sometimes it is not possible to know at |
| compile time whether the assignment is an array or not.) |
| |
| The next example declares a cycle, assigns a value, and retrieves the first and |
| second value:: |
| |
| {cycle $rgb = array( "red", "green", "blue" ) } |
| |
| {$rgb // Print "red"} |
| {$rgb // Print "red"} |
| {increment $rgb // Go to the next element} |
| |
| {$rgb // Print "green"} |
| |
| See the Increment_, Decrement_ and Reset_ section for more information. |
| |
| |
| Scopes |
| `````` |
| Variable declarations must be done at the highest scope of the template. |
| Declaring a variable in a lower scope will result in a compiler error. |
| |
| Scopes are usually opened and closed with a start and end template block. |
| Template blocks that open a new scope are: {if .. }{/if}, {while ..} {/while}, |
| {foreach ..} {/foreach}, {switch .. } {/switch}, etc. The next example |
| demonstrates this scoping:: |
| |
| {var $a = 2 // Correct } |
| |
| {if 2 == 3} |
| {* This opens a new scope *} |
| |
| {var $b // ERROR! } |
| {/if} |
| |
| |
| Returning variables |
| ``````````````````` |
| Templates itself can also return variables to the user application or other |
| templates. The return statement defines the variables that need to be |
| returned:: |
| |
| {return ( <expression> as <variable> | <variable> ) [, ( <expression> as <variable> | <variable> ), ... ] } |
| |
| The return statement returns one or multiple variables. The caller of the |
| template can retrieve the return values. Consider the following template:: |
| |
| {* Return 6! and "Hello world" *} |
| |
| {var $fac6 = 6 * 5 * 4 * 3 * 2 } |
| {return $fac6, "Hello world" as $helloWorld} |
| |
| |
| The user application can retrieve these values via the receive property of the |
| template. See the next example for a demonstration:: |
| |
| $t = new ezcTemplate(); |
| |
| // Process the template. |
| $t->process(); |
| |
| // Retrieve the values from the return. |
| $fac6 = $t->receive->fac6; |
| $hw = $t->receive->helloWorld; |
| |
| // Output Hello world: |
| echo $hw; |
| |
| More information about returning variables is described in the Include_ section. |
| |
| Capturing content into variables |
| ```````````````````````````````` |
| Sometimes it's useful to capture a specific part of a template in a variable |
| for reuse. This you can do with the capture statement:: |
| |
| {var $var} |
| {capture $var} |
| Add some content. |
| {/capture} |
| |
| Output it a few more times: |
| {$var} |
| {$var} |
| |
| Be aware that you still have to declare the variable with the {var} block. |
| |
| Expressions |
| ----------- |
| An expression is anything you write in a template block that doesn't start with |
| a special tag. But expressions are also used in template blocks with a tag and |
| gives merely a value. PHP quotes the expression as "Anything that gives a |
| value", that is also true for the template syntax. |
| |
| Expressions can be a single *operand* that returns a value. It is also possible |
| to combine multiple operands with *operators*. The value returned depends |
| on the used operands and operators. |
| |
| The operands are: |
| |
| - Boolean_ |
| - Integer_ |
| - Float_ |
| - String_ |
| - Array_ |
| - Variables_ |
| - Functions_ |
| |
| The operands Boolean, Integer, Float, String, and Array are described in the |
| `Primitive types`_ section. Variables are described in the Variables_ section. Functions |
| will be described in the Functions_ section. |
| |
| Variables and functions are considered as operands since they return one |
| value. The type of this return value is also a: Boolean, Integer, Float, |
| String, or Array. |
| |
| An operand returns a single value. Some examples are:: |
| |
| {5} |
| {"Hello"} |
| {str_len("Hello")} |
| |
| The values returned are, respectively: 5, Hello, and 5. |
| |
| Operators are things that you feed with one or multiple values and will result |
| another value. Examples of operators are adding two numbers together with the |
| plus (+) operator. This operator expects two integers or floats (in any |
| combination) and returns either a integer of float. Another example is the |
| equal operator (==). It expects two types operands of the same type and |
| returns a Boolean. |
| |
| |
| Arithmetic operators |
| ```````````````````` |
| The arithmetic operators can be used on all expressions which return a |
| numerical value. The operator itself returns also a numeric value. The table |
| below describes the available arithmetic operators: |
| |
| ============== =========== |
| Negation -$o |
| Ignored +$o |
| Addition $ol + $or |
| Subtraction $ol - $or |
| Multiplication $ol * $or |
| Division $ol / $or |
| Modulus $ol % $or |
| ============== =========== |
| |
| Note: The negation in this table is the arithmetic negation. Don't confuse this |
| with the logic negation. |
| |
| The unary plus operator can also be used, but it doesn't affect the value. It's |
| usually used to clarify that it's not a negative value. |
| |
| Examples:: |
| |
| { 2 + 5 // Returns value 7} |
| { 2 - 5 } |
| { 4 + 3 * 2 // Due to the operator precedence, first the * |
| // will be evaluated and thereafter the +. } |
| |
| {var $a = 2} |
| {var $b = -$a} |
| |
| |
| |
| Comparison operators |
| ```````````````````` |
| All comparison operators return a boolean value. The left-hand side and |
| right-hand side should be of the same type. The available comparison operators |
| are: |
| |
| ===================== ============ |
| Equal $ol == $or |
| Identical $ol === $or |
| Not equal $ol != $or |
| Not identical $ol !== $or |
| Less than $ol < $or |
| Greater than $ol > $or |
| Less than or equal $ol <= $or |
| Greater than or equal $ol >= $or |
| ===================== ============ |
| |
| Examples:: |
| |
| { 4 == 5 } |
| { 2 <= 5 } |
| { true != false } |
| { 4 == 5 == 6 } |
| |
| |
| The last example compares 4 with 5. This returns the boolean *false*. After the |
| first step the comparison is:: |
| |
| { false == 6 } |
| |
| The number 6 will be changed into a boolean. Every number except zero will get |
| the boolean value *true*. Basically the last step of the comparison is:: |
| |
| { false == true } |
| |
| And this return the boolean value *false*. |
| |
| |
| Logical operators |
| ````````````````` |
| The logical operators are used on all expressions which return a boolean |
| value. The operator returns also a boolean: |
| |
| === ========== |
| Not ! $o |
| And $ol && $or |
| Or $ol || $or |
| === ========== |
| |
| Some usage examples:: |
| |
| { true || false } |
| { $a == 5 && $a != 7 } |
| { $a || $b } |
| |
| |
| Assignments |
| ----------- |
| Assignments set a value to a variable. If the variable does already contain a |
| value, it will be overwritten. As explained in the Variables_ section the |
| variable must be declared first. Notice that an assignment can be used in the |
| declaration itself. |
| |
| The syntax language has two types of assignments. The former type assigns a new |
| value to the variable:: |
| |
| { <variable> = <expression> } |
| |
| The expression is evaluated and assigned to the variable. The next example |
| assigns the value 4 to the variable *$myVar*:: |
| |
| {var $myVar} |
| { $myVar = 3 + 5 / 5 } |
| |
| The latter assignment type updates the existing value with a modifier. There are |
| multiple operators available: |
| |
| ============== =========== |
| Addition $var += $or |
| Subtraction $var -= $or |
| Multiplication $var \*= $or |
| Division $var /= $or |
| Modulus $var %= $or |
| Pre increment ++$var |
| Pre decrement --$var |
| Post increment $var++ |
| Post decrement $var-- |
| ============== =========== |
| |
| The Addition, Subtraction, Multiplication, Division, and Modulus assignment |
| operators do an arithmetic calculation between the left (variable) and the |
| right operand (expression) and assigns the value in the left operand |
| (variable) again. Notice that the variable must already contain a value. |
| |
| The increment operators increment the number of the current variable by one. |
| The decrement operators do the opposite and decrement the value of the current |
| variable by one. There is no difference between the pre and post operators, |
| and both are present for convenience purposes. |
| |
| Examples:: |
| |
| {var $myVar = 5 } |
| |
| {$myVar += 5 // $myVar has the value 10 } |
| {$myVar++ // is the same as $myVar += 1 } |
| |
| {$myVar *= 10 // Multiply with 10} |
| {--$myVar // Same as: $myVar -= 1 } |
| |
| |
| |
| Functions |
| --------- |
| The Template language has lots of built-in functions. These |
| functions are categorized in a few groups: String, Array, Regular expression, |
| Type information, and Arithmetic (math) functions. The functions are explained |
| in the appendix. |
| |
| A function call has the following syntax:: |
| |
| <function_name> ( [ Parameter1 [, Parameter2, ... ] ] ) |
| |
| An example:: |
| |
| {var $res = str_compare( "Hello", "world" ) } |
| {$res // prints the result} |
| |
| |
| All template functions follow these rules: |
| |
| - Function output is always returned. No variables are changed via references. |
| - If the function contains a "haystack" and a "needle" then the first |
| parameter will be the "haystack". The "needle parameter is a parameter that |
| operates on another parameter, the "haystack". |
| |
| |
| Contexts |
| -------- |
| The purpose of the context is to simplify the development of the templates and |
| make the templates more secure. The context defines the purpose of the template |
| output. For example the XHTML context should be set for the templates that |
| generate (X)HTML output. |
| |
| When a template is processed and executed, it runs in a specific context. The |
| context is set to XHTML by default. The |
| next example shows a part of a user application that specifies the XHTML |
| context:: |
| |
| $config = ezcTemplateConfiguration::getInstance(); |
| $config->context = new ezcTemplateXhtmlContext(); |
| |
| $t = new ezcTemplate(); |
| $t->process( "hello_world.ezt" ); |
| |
| |
| Configuring the Template engine is discussed in the tutorial in more detail. |
| |
| The available context are described in the next subsections. |
| |
| XHTML Context |
| ````````````` |
| The XHTML Context escapes the HTML characters from the output from the |
| expression blocks. Output outside the blocks are not escaped. See the next |
| example:: |
| |
| {var $lt = "3 < 5"} |
| <b>{$lt}</b> |
| |
| This template contains the HTML character '<' in an expression block. This |
| character will be escaped. The output of the template is:: |
| |
| <b>3 < 5</b> |
| |
| The escape characters of the XHTML context are: |
| |
| ========= =========== |
| Character Translation |
| ========= =========== |
| & & |
| " " |
| < < |
| > > |
| ========= =========== |
| |
| If the HTML characters in the expression block should not be escaped then the |
| "raw" block should be used. The next example demonstrates a "raw" block:: |
| |
| {var $myBoldText = "<b>Hello world</b>"} |
| |
| {raw $myBoldText} |
| |
| This template outputs:: |
| |
| <b>Hello world</b> |
| |
| |
| See the Raw_ section for more information. |
| |
| Additional required escaping |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| Even inside XHTML there are still different output contexts, which might |
| require different escaping. For example when using variables inside JavaScript |
| the default escaping is *not sufficient*, but additional characters are |
| required to be escaped, like shown in the following example. If the following |
| template is called with the ``$input = '\' ); alert( \' XSS Alert ';``, it will |
| show an JavaScript alert box, even with XHTML context escaping:: |
| |
| {use $input} |
| <body onLoad="JavaScript: doSomething( '{$input}' );"> |
| ... |
| |
| To work around this issue you can either write a custom template function which |
| wraps around the PHP function ``addslashes()`` or do the following in your |
| template:: |
| |
| {use $input} |
| <body onLoad="JavaScript: doSomething( '{ |
| str_find_replace( "'", "\\'", |
| str_find_replace( '"', '\\"', |
| str_find_replace( '\\', '\\\\', $input ) |
| ) |
| )}' );"> |
| ... |
| |
| This should be safe afterwards. Remember that there might be other contexts in |
| your XHTML files, like other client side scripting languages, which again |
| require different additional output escaping. |
| |
| No Context |
| `````````` |
| The No Context does not escape any characters. Usefull for text output and |
| testing purposes. |
| |
| |
| Control structures |
| ------------------ |
| Control structures are elements which help you control the flow of the code, |
| either by doing conditional statements or by repeating certain actions. |
| |
| Increment |
| ````````` |
| The increment construct sets the cycle variable to the next value in the cycle |
| array:: |
| |
| {cycle $rgb = array("red", "green", "blue" )} |
| |
| {$rgb // Print "red" } |
| {increment $rgb} |
| {$rgb // Print "green" } |
| |
| If the end of the cycle array is reached, it will jump again to the first |
| value of the array. |
| |
| |
| Decrement |
| ````````` |
| The decrement construct sets the cycle variable to the previous value in the cycle |
| array:: |
| |
| {cycle $rgb = array("red", "green", "blue" )} |
| |
| {$rgb // Print "red" } |
| {decrement $rgb} |
| {$rgb // Print "blue" } |
| |
| If the begin of the cycle array is reached, it will jump again to the last |
| value of the array. |
| |
| |
| Reset |
| ````` |
| The reset construct sets the cycle variable to the first value in the cycle |
| array:: |
| |
| {cycle $rgb = array("red", "green", "blue" )} |
| |
| {$rgb // Print "red" } |
| {increment $rgb} |
| {$rgb // Print "blue" } |
| |
| {reset $rgb} |
| {$rgb // Print "red" } |
| |
| |
| |
| If, else, elseif |
| ```````````````` |
| The *if* construct allows conditional execution of code fragments. The |
| structure is:: |
| |
| {if <expression> } |
| <code> |
| {/if} |
| |
| If the <expression> evaluates to true, the <code> fragment will be executed. |
| For instance the following code will show "$a is less than $b" if $a is |
| less than $b:: |
| |
| {if $a < $b } |
| $a is less than $b. |
| {/if} |
| |
| |
| The *else* construct can be used in an *if* statement. It contains a code |
| fragment that will be executed if the *expression* evaluates to false:: |
| |
| {if expression } |
| code1 |
| {else} |
| code2 |
| {/if} |
| |
| The *code2* is executed when the expression is false. Otherwise *code1* is |
| executed. |
| |
| The *elseif* construct can be used in an *if* statement. It adds an extra |
| expression and code block that will be evaluated and executed when the |
| (previous) expression from the *if* statement does not evaluate to true:: |
| |
| {if $weekday == 0} |
| Monday |
| {elseif $weekday == 1} |
| Tuesday |
| {elseif $weekday == 2} |
| Wednesday |
| {else} |
| Thursday, Friday, Saturday, or Sunday. |
| {/if} |
| |
| |
| Writing an *elseif* statement is actually the same as writing them with |
| separate *if* and *else* statements. The previous example could be written as:: |
| |
| {if $weekday == 0} |
| Monday |
| {else} |
| {if $weekday == 1} |
| Tuesday |
| {else} |
| {if $weekday == 2} |
| Wednesday |
| {else} |
| Thursday, Friday, Saturday, or Sunday. |
| {/if} |
| {/if} |
| {/if} |
| |
| |
| As you can see, this makes the code harder to read. |
| |
| |
| Switch, Case, Default |
| ````````````````````` |
| The switch construct is quite similar to multiple *if* and *elseif* statements. |
| The syntax is as follows:: |
| |
| {switch <expression>} |
| |
| <case1> [ case2 [ case3, .. ] ] |
| [ default ] |
| |
| {/switch} |
| |
| |
| A *case* block has the following syntax:: |
| |
| {case <literal> [, <literal>, ..]} |
| <code> |
| {/case} |
| |
| And the *default* is as follows:: |
| |
| {default} |
| <code> |
| {/default} |
| |
| The switch statement expects an expression. This expression will then be |
| compared with the literal values from the *case* statements. The comparison |
| starts and goes to the next literal as the values from the <expression> and |
| <literal> are not equal. The <code> from the first match will be executed and |
| the rest of the cases are skipped. |
| |
| If none of the cases match, then the default block will be executed. See the |
| example switch statement below:: |
| |
| {switch $weekDay} |
| |
| {case 0} Monday {/case} |
| {case 1} Tuesday {/case} |
| {case 2} Wednesday {/case} |
| {case 3, 4, 5, 6} |
| Thursday, Friday, Saturday, or Sunday |
| {/case} |
| |
| {default} |
| The $weekDay should be a number between 0 and 6. |
| {/default} |
| |
| {/switch} |
| |
| This switch converts the weekday number to a name. |
| |
| |
| Foreach |
| ``````` |
| A very important construct in the Template language is the *foreach*. The |
| foreach is a loop structure that iterates over an array. Since this loop |
| is used so often in the templates, it has several convenience tags build in. |
| First we'll show the basic syntax:: |
| |
| {foreach <array> as <value> } |
| <code> |
| {/foreach} |
| |
| {foreach <array> as <key> => <value> } |
| <code> |
| {/foreach} |
| |
| Two foreach structures are shown. The first structure takes each element from |
| the *array*> and assigns it to the variable *<value*>. The second structure does |
| the same, except that the key of the array is assigned to the variable *key*. |
| |
| An example for each structure:: |
| |
| {var $rgb = array( "red", "green", "blue" ) } |
| {foreach $rgb as $color} |
| The color is: {$color} |
| {/foreach} |
| |
| {foreach $rgb as $key => $color} |
| Array key {$key} contains the color: {$color} |
| {/foreach} |
| |
| The output for this example will be:: |
| |
| The color is: red |
| The color is: green |
| The color is: blue |
| |
| Array key 0 contains the color: red |
| Array key 1 contains the color: green |
| Array key 2 contains the color: blue |
| |
| |
| With this syntax we can easily loop any number, and is more convenient than |
| using the while_ structure. This is demonstrated next:: |
| |
| {foreach 1..10 as $i} |
| Iteration {$i} |
| {/foreach} |
| |
| This works because the *1..10* statement creates an array with the |
| values from 1 until 10. |
| |
| Often a foreach is used to create some kind of table or list. Several extensions |
| are made available to ease the development: |
| |
| :Cycles: Increments or decrements a cycle variable. |
| :Offset: Start the loop at a given offset. |
| :Limit: Limits the number of iterations. |
| |
| The foreach loop can have an increment and decrement tag. These tags increment and/or decrement an |
| cycle value, and work exactly the same as the Increment_ and Decrement_ control |
| structures. The syntax is almost the same in the foreach:: |
| |
| [increment <variable1> [, variable2, ... ] ] |
| [decrement <variable1> [, variable2, ... ] ] |
| |
| These tags are the same as the Increment_ and Decrement_ control structures. |
| |
| This tag is added at the end of the foreach construct. The next example |
| increments the cycle value in every iteration of the loop:: |
| |
| {cycle $blackAndWhite = array( '#00000', '#FFFFFF' )} |
| |
| {foreach 1..5 as $value increment $blackAndWhite} |
| <font color="{$blackAndWhite}">Number: {$value}</font> |
| {/foreach} |
| |
| |
| This loop outputs the following code:: |
| |
| <font color="#000000">Number: 1</font> |
| <font color="#FFFFFF">Number: 2</font> |
| <font color="#000000">Number: 3</font> |
| <font color="#FFFFFF">Number: 4</font> |
| <font color="#000000">Number: 5</font> |
| |
| The offset and limit code constructs are specified after the cycle increment or |
| decrement tag. The offset and limit constructs are extremely useful for |
| splitting a long table or list over multiple page views. The next example |
| demonstrates this:: |
| |
| {use $hugeArray = array(), $offset = 0} |
| {foreach $hugeArray as $tableEntry offset $offset limit 100} |
| |
| {* Show the information from the $tableEntry *} |
| |
| {foreach} |
| |
| |
| See the `External variable declaration (use)`_ section for more |
| information. The loop will start at the $offset and won't show the previous |
| elements. The maximum iterations of the loop is 100. Another example shows |
| the numbers from 50 until 100:: |
| |
| {var $hugeArray = 1..1000} |
| |
| {foreach $hugeArray as $value offset 50 limit 50} |
| {$value} |
| {/foreach} |
| |
| |
| While |
| ````` |
| The while loop loops over a code fragment as long as the expression in the |
| while evaluates to true. The syntax of the while loop is as follows:: |
| |
| {while <expression>} |
| <code> |
| {/while} |
| |
| Usually the expression evaluates whether a counter reaches a certain number. In |
| the *code* the counter is increased or decreased:: |
| |
| {var $i = 0} |
| {while $i < 10} |
| The number is: {$i}. |
| {$i++} |
| {/while} |
| |
| This example prints the numbers from 0 until 9. If you write a while loop, make |
| sure that the loop eventually ends. The next example demonstrates another while |
| loop. This loop increments a value from a Cycle. Compare how the same example |
| can be done with a Foreach_:: |
| |
| {cycle $blackAndWhite = array( '#00000', '#FFFFFF' )} |
| {var $i = 1} |
| |
| {while $i <= 5 } |
| <font color="{$blackAndWhite}">Number: {$i}</font> |
| {$i++} |
| {increment $blackAndWhite} |
| {/while} |
| |
| |
| Delimiter |
| ````````` |
| The delimiter can be used (only) inside a loop to do every given iteration a specific |
| action. The syntax is as follows:: |
| |
| {delimiter [modulo <expression> [is <expression>]]} |
| <code> |
| {/delimiter} |
| |
| The "module...<expression>" part can be omitted and by default the delimiter |
| will be inserted between every iteration of the loop. If a modulo is used, the |
| "is <expression>" part of the delimiter can be omitted and will be interpreted |
| as "is 0". |
| |
| The delimiter will always be executed between two iterations of the loop. In |
| the next example between every name a comma is inserted:: |
| |
| {var $names = array( 'Bernard', 'Fran', 'Manny' )} |
| {foreach $names as $name} |
| {$name} |
| {delimiter}, {/delimiter} |
| {/foreach} |
| |
| The next example demonstrates creates a matrix with 4 rows and 4 columns. The |
| delimiter closes the current row and opens a new one every forth column as the |
| delimiter is only added when "internal counter modulo 4" equals 0. The |
| "internal counter" simply counts the number of executed iterations:: |
| |
| {var $columns = 4} |
| <table> |
| <tr> |
| {foreach 1..16 as $nr} |
| <td>{$nr}</td> |
| |
| {delimiter modulo $columns} |
| </tr><tr> |
| {/delimiter} |
| {/foreach} |
| </tr> |
| |
| |
| Continue |
| ```````` |
| The continue statement is used within the looping structures to skip the rest of the current loop |
| iteration and continue execution at the condition evaluation and then the beginning of the next |
| iteration. If a delimiter is available in the looping structure then this |
| delimiter will be added. Use the Skip_ statement to skip also the delimiter. |
| |
| The next example show the numbers 1 to 5 separated with a comma. After the |
| numbers 1, 2, and 3 is the token # appended. As the example shows, the |
| numbers higher than 3 will not execute the rest of the foreach anymore. The |
| delimiter is added anyway:: |
| |
| {foreach 1..5 as $i} |
| |
| {delimiter} |
| , |
| {/delimiter} |
| |
| {$i} |
| {if $i > 3} {continue} {/if} |
| # |
| {/foreach} |
| |
| The output of the template is:: |
| |
| 1 #, |
| 2 #, |
| 3 #, |
| 4 , |
| 5 |
| |
| |
| |
| Skip |
| ```` |
| The skip is the same as a continue, except that the delimiter in the loop will |
| be skipped also. The next example show the numbers 1 to 5. The number 1, 2, |
| and 3 have the token # appended and are separated with a comma. |
| As the example shows, the numbers higher than 3 will not execute the rest of the |
| foreach anymore and the delimiter is not appended:: |
| |
| {foreach 1..5 as $i} |
| |
| {delimiter} |
| , |
| {/delimiter} |
| |
| {$i} |
| {if $i > 3} {skip} {/if} |
| # |
| {/foreach} |
| |
| And outputs:: |
| |
| 1 #, |
| 2 #, |
| 3 #, |
| 4 |
| 5 |
| |
| |
| Break |
| ````` |
| The break ends execution of the current foreach or while structure. The example |
| below prints the numbers 1 and 2. Due to the break, the rest of the loop is |
| skipped:: |
| |
| {foreach 1..10 as $i} |
| {$i} |
| {if $i == 2} {break} {/if} |
| {/foreach} |
| |
| |
| Include |
| ``````` |
| The include calls other templates which will be executed within the current |
| template. Variables can be passed on and retrieved from the included template. |
| The generic template could then be used at multiple places and is configurable |
| via the given variables. |
| |
| The syntax of the include is as follows:: |
| |
| {include <template_name | location_object > |
| [ send <send_variables> ] |
| [ receive <receive_variables> ] |
| |
| The file that needs to be included is either specified with a string |
| (template\_name) or with a location object. The location object is explained in |
| the section `Template locations`_. |
| |
| The <send\_variables> has this syntax:: |
| |
| <expression> as <variable> | <variable> |
| |
| And the <receive\_variables> has almost the same syntax as the |
| <send\_variables>:: |
| |
| <variable> as <variable> | <variable> |
| |
| A next example will clarify the syntax a bit more:: |
| |
| {include "calc_a_plus_b.ezt" |
| send 2 as $a, |
| 5 as $b |
| receive $c as $sum } |
| |
| The included template calculates the sum of the given variables $a and $b, and |
| returns the answer in variable $c. The expressions "2" and "5" are assigned to |
| the variables $a and $b of the included template. The value of the (returned) |
| variable $c is directly assigned to the variable $sum. The variable $sum does |
| not need to be declared first. |
| |
| The template "calc\_a\_plus\_b.ezt" is:: |
| |
| {use $a = false, $b = false} |
| |
| {if $a === false || $b === false} |
| Variable $a or $b has an incorrect value. |
| {/if} |
| |
| {return $a + $b as $c} |
| |
| |
| The next templates includes the "calc\_a\_plus\_b.ezt" but does not use the |
| expression part of the include:: |
| |
| {var $a = 2, $b = 5} |
| {include "calc_a_plus_b.ezt" |
| send $a, $b |
| receive $c } |
| |
| {var $sum = $c} |
| |
| |
| Raw |
| ``` |
| The raw construct outputs raw information and is not affected by the Contexts_. |
| |
| For example, the XHTML context is set and an expression contains HTML |
| characters (which should be sent to the output) then use the "raw" block:: |
| |
| {var $myBoldText = "<b>Hello world</b>"} |
| {raw $myBoldText} |
| |
| This template outputs:: |
| |
| <b>Hello world</b> |
| |
| Translation Constructs |
| ---------------------- |
| |
| Translation constructs allow you to embed translatable strings in your |
| templates. Every construct requires at least a string and a context, the |
| context can however be set by default to be valid for subsequent translatable |
| string entries. |
| |
| tr_context |
| `````````` |
| Is used to set a default translation context. All tr_ entries below this |
| construct will then use this translation context if none is specified |
| explicitly. Information on contexts can be found in the `Qt Linguist format |
| specification`__. |
| |
| This construct is used like:: |
| |
| {tr_context "admin/forget_password"} |
| |
| Each template can have multiple tr_context statements. The default context that |
| is set with this construct is valid until the next one is encountered. |
| |
| __ Translation_linguist-format.html#contexts |
| |
| |
| tr |
| `` |
| The tr construct defines a translatable string, the simplest form of this |
| construct is:: |
| |
| {tr "String to translate"} |
| |
| This will only work however, if there is a default context set with |
| `tr_context`_. In case there is none set, you have to specify it yourself with |
| the "context" parameter. The following two templates are equivalent:: |
| |
| {tr_context "admin/forget_password"} |
| {tr "String to translate"} |
| |
| and:: |
| |
| {tr "String to translate" context "admin/forget_password"} |
| |
| When a translator translates a text, it is sometimes useful to have slightly |
| more information than just the context and the string itself. The tr construct |
| therefore allows to add a comment to the translatable string with the "comment" |
| parameter. This has no effect on how the tr construct is interpreted however. |
| An example:: |
| |
| {tr "Login" context "user/login" comment "Text before login input box"} |
| |
| In many occasions, the translatable strings allow positional or named |
| parameters to allow for changing the order of arguments. For example |
| the English string "Search for 'appelmoes' returned 3 matches" can be |
| translated in Dutch as: "Er zijn 3 items gevonden bij het zoeken naar |
| 'appelmoes'". A simple concatenation mechanism of multiple translatable strings |
| would no longer work. The tr construct supports parameterized strings in two |
| different ways: with numerical replacement identifiers (such as %1 and %2) and |
| with associative identifiers (such as %search_string and %matches). The |
| following example illustrates how this is done in the simplest possible way:: |
| |
| {tr "Search for '%1' returned '%2' matches" vars 'appelmoes', 3} |
| |
| If no key is specified for variables, like in the above example, they are |
| automatically given numbers, starting by 1. It is also possible to add specific |
| positions to variables, like:: |
| |
| {tr "Search for '%1' returned '%2' matches" vars 2 => 'appelmoes', 1 => 3} |
| |
| This is perhaps not so useful for positional parameters like here, but it is |
| necessary for named parameters as illustrated in the example here:: |
| |
| {tr "Search for '%what' returned '%matchcount' matches" vars 'what' => 'appelmoes', 'matchcount' => 3} |
| |
| It is of course also possible to mix those two cases:: |
| |
| {tr "Search for '%1' returned '%matchcount' matches" vars 'matchcount' => 3, 'appelmoes'} |
| |
| or:: |
| |
| {tr "Search for '%1' returned '%matchcount' matches" vars 'appelmoes', 'matchcount' => 3} |
| |
| Variables without any key, are always given positional identifiers in |
| sequential order. When doing so, variables with a named key are ignored, while |
| variables with a numerical key reset the next number in the auto-numbering |
| sequence to the number of the key. The following example shows that:: |
| |
| {tr "%1 %2 %3 %4 context "test" vars 3 => 'three', 'four', 1 => 'one', 'two'} |
| |
| For information on how to setup translations for your templates, please refer |
| to the section `Translations`_. |
| |
| Extensions |
| ========== |
| |
| This section explains how you can extend your Template language. Extending the |
| Template language gives you the opportunity to add more application specific |
| functionality. Some examples of Template language extensions are: |
| |
| - Adding a method to fetch information from a data structure. This data |
| structure could be a single or a group of objects, a database, an array, etc. |
| - Creating an HTML table using your own customized template blocks. |
| - Doing an application specific calculation. |
| |
| Currently, there are two ways of adding custom functionality to the template. |
| The methods are named: **custom blocks** and **custom functions**. Together we call |
| them **custom extensions**. |
| |
| First, we'll explain how to create a custom block. With the knowledge of these |
| custom blocks, we explain - much shorter - the custom functions. |
| |
| |
| Custom blocks |
| ------------- |
| Custom blocks are extra functionality that could be used inside the template |
| language. These blocks are implemented in PHP. The next section explains how an |
| custom block can be used. The sections thereafter discuss how to add a new |
| custom block. |
| |
| |
| Custom blocks in the Template language |
| `````````````````````````````````````` |
| Custom blocks add specific behavior to the Template language. The most basic |
| structure of a custom block - without any parameters - is:: |
| |
| '{' <name> '}' |
| |
| The block starts and ends with curly braces. The *<name>* identifies the custom |
| block. Optionally, a custom block has also a closing block:: |
| |
| '{' '/' <name> '}' |
| |
| The name must be the same as the start block, but starts with a forward slash ('/'). The |
| text between the open and close tag is considered as input data. Whether a |
| custom block should have a close tag is up to the developer. |
| |
| The next example demonstrates a custom block with an open and close tag that |
| capitalizes the text in between:: |
| |
| {capitalize} |
| Guybrush Threepwood. |
| {/capitalize} |
| |
| Another example that uses a custom block without a close tag:: |
| |
| {capitalize "Guybrush Threepwood."} |
| |
| Whether or not a custom block has a close tag, it handles the parameters the |
| same. The structure of a custom block is as follows:: |
| |
| '{' block_name [start_expression] [ <param_name> ['='] <value> ... ] '}' |
| |
| Basically, it describes that a custom block can have: |
| |
| - One optional expression which is not bound to a parameter name. |
| - Zero or more named parameters with a value. Between the parameter name and |
| value is an optional equal sign. |
| |
| Some example blocks that use parameters:: |
| |
| {link "eZ systems" to "http://ez.no"} |
| {table border=true bgcolor="red"} |
| {debug} |
| {calculate 5 plus 5} |
| {join array( 'Hello', "world" ) with "_"} |
| |
| {header style="bold"} |
| Hello world |
| {/header} |
| |
| Note that the values used in the examples are just ordinary expressions. |
| Therefore it is possible to write:: |
| |
| {link "eZ" . " systems" to 'http'. "://" . "ez.no"} |
| {calculate 2 + 3 plus 1 * 2 + 3} |
| |
| Again, the optional and required parameters are up to the developer. |
| |
| |
| Adding a custom block |
| ````````````````````` |
| New custom blocks are added to the Template engine with the |
| ezcTemplateConfiguration::addExtension() method. This method expects the class |
| name which implements the new custom block. The next example adds a custom |
| block to the Template engine which is implemented in MyClass:: |
| |
| $config = ezcTemplateConfiguration::getInstance(); |
| $config->addExtension( "MyClass" ); |
| |
| The custom block class should implement the ezcTemplateCustomBlock interface. |
| This interface has only one method getCustomBlockDefinition(). The class |
| implementing this method should return an ezcTemplateCustomBlockDefinition |
| object from a given block name, if possible. |
| |
| |
| Custom block definition |
| ``````````````````````` |
| The custom block definition describes how the Template engine should interpret |
| the custom block. The information is provided by returning an instance of the |
| ezcTemplateCustomBlockDefinition:: |
| |
| class ezcTemplateCustomBlockDefinition extends ezcTemplateCustomExtension |
| { |
| public $class; |
| public $method; |
| |
| public $hasCloseTag; |
| |
| public $startExpressionName; |
| public $optionalParameters = array(); |
| public $requiredParameters = array(); |
| |
| public $isStatic; |
| } |
| |
| The member variables that should be set in this class are: |
| |
| :class: String value that specifies the (static) class that implements the function to be executed. |
| :method: String value that specifies the (static) method that should be run. |
| :hasCloseTag: Boolean value that specifies whether the class has an open and close tag or only a open tag. |
| :startExpressionName: The first parameter of a custom block without a name is |
| called the start expression. If the custom block should have a start |
| expression then this variable specifies a name for it. The name should reappear |
| in either the optionalParameters or the requiredParameters. |
| :optionalParameters: Optional named parameters for this custom block. |
| :requiredParameters: Required named parameters for this custom block. |
| :excessParameters: When this is set to true, additional parameters are also |
| available in the implementation of the custom block as elements of the |
| $parameters array. |
| :isStatic: The custom block is only called during compilation. At run time the |
| static output from the custom block at compile time is displayed. |
| |
| The following custom block creates a hyper-link from a name and an URL:: |
| |
| {link "name" to "url" [title "title"]} |
| |
| This custom block has a: |
| |
| - Required unnamed parameter that contains the name. |
| - Required named parameter "to" that contains the URL. |
| - Optional named parameter "title" that contains the title. |
| |
| Except for the class and the method name the CustomBlockDefinition should look |
| like:: |
| |
| $def = new ezcTemplateCustomBlockDefinition; |
| |
| $def->class = "MyLink"; |
| $def->method = "linkMethod"; |
| |
| $def->hasCloseTag = false; |
| $def->startExpressionName = "from"; |
| $def->optionalParameters = array( "title" ); |
| $def->requiredParameters = array( "from", "to" ); |
| |
| |
| The CB definition should be made available to the Template engine via a class |
| implementing the ezcTemplateCustomBlock interface:: |
| |
| interface ezcTemplateCustomBlock |
| { |
| public static function getCustomBlockDefinition( $name ); |
| } |
| |
| |
| The class implementing the getCustomBlockDefinition() method should |
| return an ezcTemplateCustomBlockDefinition for the given block name $name. |
| The next code demonstrates a class that implements the interface:: |
| |
| class MyLink implements ezcTemplateCustomBlock |
| { |
| public static function getCustomBlockDefinition( $name ) |
| { |
| switch ($name ) |
| { |
| case "link": |
| $def = new ezcTemplateCustomBlockDefinition; |
| $def->class = "MyLink"; |
| // |
| // Create definition |
| // |
| |
| return $def; |
| } |
| |
| return false; |
| } |
| } |
| |
| |
| Implementing the custom block |
| ````````````````````````````` |
| In the CB definition is specified which class and what method should produce the |
| custom block output. A typical implementation to create a hyper-link would be:: |
| |
| public static function link( $parameters ) |
| { |
| $title = ""; |
| if( isset( $parameters["title"] ) ) |
| { |
| $title = "title='". $parameters["title"] ."'"; |
| } |
| |
| return "<a href='".$parameters["to"]."' $title>".$parameters["from"]."</a>" |
| } |
| |
| |
| The method implementing the custom block returns a string that will be |
| inserted in the template output. The custom block parameters are provided in |
| the first parameter as an array. The method itself must check whether the |
| optional parameters are sent or not. Required parameters are always available |
| as the template compiler throws a compiler exception if these parameters are |
| absent. |
| |
| The custom blocks that do have a close tag need a method that accepts two |
| parameters. For example the following custom block has a close tag:: |
| |
| {capitalize} |
| Guybrush Threepwood |
| {/capitalize} |
| |
| The method that implements the custom block:: |
| |
| public static function capitalize( $parameters, $text ) |
| { |
| return strtoupper( $text ); |
| } |
| |
| The $parameters parameter is never used. The text between the open and close |
| tag of the custom block is always passed in the second parameter. |
| |
| |
| Example |
| ``````` |
| The 'calc' custom block calculates the sum of the given values. The sum is |
| calculated from the initial value plus or minus the values added to the "plus" |
| and or "minus" parameter. Some usage examples are:: |
| |
| {calc 5 plus 3} |
| {calc 5 plus array(2,5,2) minus 2} |
| {calc 2 minus 5} |
| |
| |
| The custom block could be implemented like:: |
| |
| class CalcCustomBlock implements ezcTemplateCustomBlock |
| { |
| public static function getCustomBlockDefinition( $name ) |
| { |
| switch ($name ) |
| { |
| case "calc": |
| $def = new ezcTemplateCustomBlockDefinition; |
| $def->class = __CLASS__; |
| $def->method = "calculate"; |
| $def->hasCloseTag = false; |
| $def->startExpressionName = "init"; |
| $def->requiredParameters = array("init"); |
| $def->optionalParameters = array("plus", "minus"); |
| return $def; |
| } |
| |
| return false; |
| } |
| |
| public static function calculate( $params ) |
| { |
| $result = $params["init"]; |
| |
| if ( isset( $params["plus"] ) ) |
| { |
| if( is_array( $params["plus"] ) ) |
| { |
| foreach( $params["plus"] as $value ) |
| { |
| $result += $value; |
| } |
| } |
| else |
| { |
| $result += $params["plus"]; |
| } |
| } |
| |
| if ( isset( $params["minus"] ) ) |
| { |
| if( is_array( $params["minus"] ) ) |
| { |
| foreach( $params["minus"] as $value ) |
| { |
| $result -= $value; |
| } |
| } |
| else |
| { |
| $result -= $params["minus"]; |
| } |
| } |
| |
| return $result; |
| } |
| } |
| |
| This new custom block needs to be assigned to the Template configuration:: |
| |
| $config = ezcTemplateConfiguration::getInstance(); |
| $config->addExtension( "CalcCustomBlock" ); |
| |
| |
| And of course the template can be run like:: |
| |
| $t = new ezcTemplate(); |
| $t->process( "my_template.ezt" ); |
| |
| |
| |
| Custom functions |
| ---------------- |
| This section explains how the custom function can be implemented. Custom |
| blocks and custom functions are very similar. |
| |
| |
| Custom functions in the Template language |
| ````````````````````````````````````````` |
| Custom functions are extra functions that can be used in the Template |
| expressions. Some examples are:: |
| |
| Greatest common divisor: {gcd(8, 12)} |
| {sin( $angle ) * 2} |
| {matrix_multiply( $m1, $m2)} |
| {fetch_from_database("items", 2)} |
| |
| Basically, the second line in the example runs a custom function and multiplies |
| the result with two. This demonstrates that the difference between a custom |
| block and a custom function. Custom functions can be used within an |
| expression. Custom blocks are directly generating an output result. |
| |
| |
| Adding a new custom function |
| ```````````````````````````` |
| As with the custom block, custom functions are added to the Template engine |
| by the ezcTemplateConfiguration::addExtension() method. The class name given to |
| this method should implement the ezcTemplateCustomFunction interface. Notice |
| that this is the same as adding a custom block. :: |
| |
| $config = ezcTemplateConfiguration::getInstance(); |
| $config->addExtension( "MyClass" ); |
| |
| The example above adds *MyClass* to the ezcTemplateConfiguration. MyClass |
| implements the getCustomFunctionDefinition() from the ezcTemplateCustomFunction |
| interface. This function returns an ezcTemplateCustomFunctionDefinition object:: |
| |
| class ezcTemplateCustomFunctionDefinition extends ezcTemplateCustomExtension |
| { |
| public $class; |
| public $method; |
| public $sendTemplateObject = false; |
| |
| // Deprecated: |
| // public $parameters = array(); |
| } |
| |
| |
| The $class and $method parameter are the same as for custom blocks. The |
| $parameters variable is obsolete with version 1.2. It used to specify |
| the required and optional parameters for the custom function. |
| |
| - Required parameters are named strings. |
| - Optional parameters are named strings enclosed with square brackets. These |
| parameters should be specified after the required parameters. |
| |
| In version 1.2 and up it uses reflection to find the required and optional |
| parameters. Due some bugs in the reflection classes it works properly in PHP |
| version 5.2 and up. |
| |
| It is also possible to accept a variable number of (extra) arguments. For this |
| you need to set the *variableArgumentList* property of the |
| ezcTemplateCustomFunctionDefinition. |
| |
| The variable *$sendTemplateObject* adds the possibility to send the current |
| template object to the custom function. |
| |
| As with functions in PHP the order of the unnamed parameters matter. The next example |
| demonstrates a complete custom function implementation:: |
| |
| class MyClass implements ezcTemplateCustomFunction |
| { |
| public static function getCustomFunctionDefinition( $name ) |
| { |
| switch ($name ) |
| { |
| case "func": |
| $def = new ezcTemplateCustomFunctionDefinition(); |
| $def->class = "MyClass"; |
| $def->method = "customFunction"; |
| |
| // Deprecated: |
| // $def->parameters = array( "firstParam", "secondParam", "[thirdParam]"); |
| |
| return $def; |
| } |
| |
| return false; |
| } |
| |
| |
| public static function customFunction( $firstParam, $secondParam, $thirdParam = "isOptional" ) |
| { |
| // Implementation. |
| |
| return "string"; |
| } |
| } |
| |
| |
| The custom parameters specified in the definition block should also be present |
| in the *customFunction* implementation. Three parameters are specified, so the |
| customFunction implementation should have three parameters. The last parameter |
| in the parameter definition is specified as optional, so should the last |
| parameter in customFunction be optional. |
| |
| The interface of the ezcTemplateCustomFunction requires to implement the |
| getCustomFunctionDefinition() method:: |
| |
| interface ezcTemplateCustomFunction |
| { |
| public static function getCustomFunctionDefinition( $name ); |
| } |
| |
| |
| Named parameters |
| ```````````````` |
| New in version 1.2 of the Template engine are named parameters. The advantage |
| of named parameters is that the order of the parameters are no longer important |
| and that parameters can be omitted that otherwise was not possible. The next |
| example shows a common custom function retrieving items from the database:: |
| |
| // fetch_item ( select = "*", start = 0, limit = false, orderBy = "id", reverseOrder = false ) |
| { fetch_item("*", 0, false, "name") } // Fetch everything but order by 'name' |
| |
| This example fetches everything from the items table and sorts it on "name". |
| Without named parameters the problem is that only the second last parameter |
| needs to be changed and therefore all the previous parameters need to be given. |
| |
| Named parameters are written in the form *"keyword = value"*. The keyword is |
| the name of the parameter. The equal sign is used as separator because it is not |
| possible to do any assignments within expressions. |
| |
| Using named parameters the code from the previous example is reduced to:: |
| |
| // fetch_item ( select = "*", start = 0, limit = false, orderBy = "id", reverseOrder = false ) |
| { fetch_item( orderBy = "name") } // Fetch everything but order by 'name' |
| |
| Besides that the code is shorter, it is also more descriptive. |
| |
| |
| Sending template objects |
| ```````````````````````` |
| In a few cases the template object is needed in the custom function |
| implementation. With access to the template object, the configuration and other |
| template settings could be retrieved and used. |
| |
| If the variable *sendTemplateObject* is set to *true*, the first parameter in |
| the function contains the template object. The following |
| |
| The next example adds the custom function *templatePath*:: |
| |
| class MyClass implements ezcTemplateCustomFunction |
| { |
| public static function getCustomFunctionDefinition( $name ) |
| { |
| switch ($name ) |
| { |
| case "templatePath": |
| $def = new ezcTemplateCustomFunctionDefinition; |
| $def->class = "MyClass"; |
| $def->method = "templatePath"; |
| $def->sendTemplateObject = true; |
| |
| return $def; |
| } |
| |
| return false; |
| } |
| |
| |
| public static function templatePath( $templateObj ) |
| { |
| return $templateObj->configuration->templatePath; |
| } |
| } |
| |
| |
| Caching |
| ======= |
| The purpose of the template cache is to speed up the processing time of a |
| template by storing its output to a file. This file is known as the |
| *cache file*. When the same template is requested later on, the cached contents |
| are displayed without processing the template first. The time consuming |
| instructions, like computations and requests to a database, can then be reduced |
| or omitted. |
| |
| Caching can truly reduce the processing time of the templates, but caching needs |
| to be handled with care. The developer needs to: |
| |
| - Add caching at the correct, time consuming, spots in the template. |
| - Make sure that the cache is expired and renewed in time. |
| - Clean up the unused cache files. |
| |
| Each cached template has a bit of overhead in comparison with an uncached |
| template. The extra work is to check if the cache file exists and if it's |
| valid, optionally regenerate the cache, and execute the cache. If the cache |
| file needs to be regenerated too often, the template is probably processed |
| quicker without caching at all. The same applies for small, non-time consuming |
| templates. |
| |
| Another issue the developer should keep in mind is that the cache needs to be |
| expired and renewed in time. Usually a template cache is valid for a limited |
| time. This can be a timeout (e.g. after 2 hours) or a trigger (an object |
| changes) that expires the cache. The triggers and timeouts need to be |
| available in the template. |
| |
| The last issue is that unused cache files need to be discarded. Without a |
| proper cache clean up mechanism the system will eventually flood with unused |
| cache files. It is the developer's responsibility to remove those files. |
| |
| |
| Configuration |
| ------------- |
| The template cache is enabled by default and activated when cache blocks are |
| present in the templates. The template configuration, |
| *ezcTemplateConfiguration* controls the locations where the cache files |
| are stored and the mechanism that cleans up the unused cache files. |
| The configuration has the following properties relevant to caching: |
| |
| - *cachedTemplatesPath*: The location where the cached templates should be |
| stored. The *compiledPath* and the *cachedTemplatePath* properties together |
| form the complete cache path. |
| |
| - *cacheManager*: This property is assigned to a cache manager object that |
| keeps track of the generated cache files and is responsible for its clean up. |
| |
| - *disableCache*: Disables all caching, useful during development. |
| |
| |
| The next code demonstrates an example configuration: :: |
| |
| $config = ezcTemplateConfiguration::getInstance(); |
| $config->templatePath = '/mydir/templates/'; |
| $config->compilePath = '/mydir/templates_bin/'; |
| $config->cachedTemplatesPath = "CACHE"; |
| $config->disableCache = false; |
| |
| $config->cacheManager = new DatabaseCacheManager(); |
| |
| $template = new ezcTemplate(); |
| $template->process( "hello_world.ezt" ); |
| |
| |
| The engine will process the following template: :: |
| |
| "/mydir/templates/hello_world.ezt" |
| |
| The compiled template and the cached template will then be stored in: :: |
| |
| "/mydir/templates_bin/compiled_templates/" |
| "/mydir/templates_bin/CACHE/" |
| |
| The 'compiled_templates' is a default setting. The cache manager that will be |
| used is the *DatabaseCacheManager*. Details about the cache manager are |
| explained later. |
| |
| |
| Cache tags |
| ---------- |
| There are two methods to enable caching: *cache_block* and *cache_template*. |
| The *cache_block* enables caching between the open and close tag:: |
| |
| {"dynamic"} |
| |
| {cache_block} |
| {foreach 1..10 as $i} |
| {$i} |
| {/foreach} |
| {/cache_block} |
| |
| {"dynamic"} |
| |
| |
| This example caches the *foreach*-loop. The strings that contains *"dynamic"* |
| are outside the cache block; thus not cached. |
| |
| The *cache_template* starts caching after this tag until the end of the |
| template. In the next example everything is cached except the string that |
| contains *"dynamic"*:: |
| |
| {"dynamic"} |
| |
| {cache_template} |
| |
| {foreach 1..10 as $i} |
| {$i} |
| {/foreach} |
| |
| {"cached"} |
| |
| |
| Sometimes a large block needs to be cached with the exception of a small block |
| of template code. Take for instance a relatively static page with the |
| current time in one corner. The *dynamic* block is a block that can only be |
| used inside a *cache_block* or after the *cache_template*. The code inside the |
| *dynamic* block is not cached and will always be executed. The next example |
| uses the *dynamic* block to display the current time: :: |
| |
| {cache_template} |
| |
| The current time is: |
| |
| {dynamic} |
| {date_format_timestamp("H:i:s")} |
| {/dynamic} |
| |
| |
| Note that the example above is only for demonstration purposes. The template is |
| so simple that it is probably quicker to use no caching at all. |
| |
| |
| Cache renewal |
| ------------- |
| Usually cached templates are valid for a limited time. A certain page is known |
| to be valid for some hours or until a value changes in the database. The |
| Template engine supports three mechanisms to expire the cache: |
| *cache-keys*, *time-to-live* (TTL), and a *cache manager*. |
| |
| The cache-keys and TTL are both parameters of the cache syntax. These |
| parameters check whether the cache is still valid and if needed create a |
| new version. |
| |
| The cache manager needs to be programmed manually. It gives a |
| better control over the cache and can also remove old cache files. |
| |
| |
| Cache keys |
| `````````` |
| Both *cache_block* and *cache_template* have a *keys* parameter. This |
| parameter can be used to define the uniqueness of a cache block. For every |
| combination of different values of the parameter, a separate file is stored on |
| the disk, containing the output of the cache block. The *keys* parameter can be |
| an expression but is usually limited to a variable or function call. The next |
| example creates new cache files when the user ID changes: :: |
| |
| {use $user_id} |
| {cache_block keys $user_id} |
| Show user information. |
| {/cache_block} |
| |
| {cache_block keys getUserId()} |
| Show user information, again. |
| {/cache_block} |
| |
| |
| The first cache_block relies on the imported *$user_id*. The second |
| *cache_block* uses a custom function that returns the ID. |
| |
| The given cache key can be of any type. If the type is a scalar (boolean, |
| integer, float, or string) then the value is compared as a string. |
| For arrays, it's compared with the checksum of the dumped structure. |
| For objects, the comparison consists of two steps. First will be checked if |
| the object has the *cacheKey* method. If this method exists on the object then |
| this value will be used. Otherwise the checksum of the object dump will be |
| used. |
| |
| The example below uses an user object as cache key. The name property of this |
| object will be shown: :: |
| |
| {use $userObj} |
| {cache_template keys $userObj} |
| |
| {$userObj->name} |
| |
| |
| The user object can be implemented like: :: |
| |
| class User |
| { |
| public $firstName; |
| public $lastName; |
| public $name; |
| public $id; |
| |
| public function cacheKey() |
| { |
| return $this->id; |
| } |
| |
| public function __construct( $firstName, $lastName, $id = 1 ) |
| { |
| $this->firstName = $firstName; |
| $this->lastName = $lastName; |
| $this->name = $firstName . " " . $lastName; |
| $this->id = $id; |
| } |
| } |
| |
| |
| And the application calling the template is done like this: :: |
| |
| $t = new ezcTemplate(); |
| $t->send->userObj = new User( "Bernard", "Black" ); |
| echo $t->process( "my_template.ezt" ); |
| |
| |
| Time-to-live |
| ```````````` |
| The *ttl* parameter makes it possible to specify how long a cache block should |
| live in number of seconds. The cache is removed after the timeout. Note that |
| this behavior is slightly different than the *cache-key*. The *cache-key* |
| creates a new version of the cache but does not remove any cache files. |
| |
| The next example creates a cache block that is valid for two hours:: |
| |
| {cache_block ttl 2*60*60} |
| News that changes not too often. |
| {/cache_block} |
| |
| |
| Via a custom function the TTL can be used to renew the cache at certain |
| predefined timestamps: :: |
| |
| {cache_block ttl getRemainingTime(minute=0, hour=6)} |
| Updated each morning at 6 o'clock |
| {/cache_block} |
| |
| |
| The custom function *getRemainingTime* calculates the remaining seconds until |
| it is 6 o'clock in the morning. |
| |
| |
| Cache manager |
| ------------- |
| In the previous sections it's already hinted about the cache manager. The cache |
| manager is a slightly complex but powerful mechanism to control the cached |
| pages. The cache manager is an interface that needs to be implemented and |
| assigned to the Template engine. The implementation gives the application the |
| possibilities to: |
| |
| - Mark expired cache files based on application criteria. |
| - Remove old cache files. |
| - Keep track of the cache dependencies. |
| |
| The solutions above need to be implemented from the cache manager interface. |
| This implementation allows the developer to make an application-dependent |
| solution. |
| |
| The cache manager interface |
| ``````````````````````````` |
| The user application and the Template engine communicate via method calls on |
| the cache manager implementation. The cache manager interface has the following |
| methods: :: |
| |
| interface ezcTemplateCacheManager |
| { |
| public function startCaching( $template, $templatePath, $cachePath, $cacheKeys ); |
| public function stopCaching(); |
| public function isValid( $template, $templateName, $cacheName ); |
| public function register( $name, $value ); |
| public function update( $name, $value ); |
| public function includeTemplate( $template, $templatePath ); |
| public function cleanExpired(); |
| } |
| |
| |
| The Template engine calls the following methods on the interface. Usually those |
| methods are not called from the user application. |
| |
| - *startCaching*: When a cache file is going to be created. |
| - *stopCaching*: After the cache file is created. |
| - *isValid*: To check whether the given cache file is still valid. |
| - *includeTemplate*: Notify the cache manager that a sub template is included. |
| |
| The remaining methods from the interface are called from the user application: |
| |
| - *register*: Register a value that is related to the cache file currently |
| created. |
| - *update*: A registered value is updated. This **may** indicate that a cache |
| file is outdated. |
| - *cleanExpired*: Removes the expired cache files. |
| |
| |
| Typically the cache creation procedure is as follows. This procedure gives |
| insight how the cache manager can be used: |
| |
| 1. The user application calls the method: *$t->process("my_template.ezt")*. |
| |
| 2. The template *"my_template.ezt"* caches parts of the page. |
| |
| 3. If a cache file exists for the requested template, the Template component |
| calls *CacheManager::isValid()* to see whether the cache file is still |
| correct. If it is then the cache contents can be returned. Otherwise a new |
| cache file will be created and returned. |
| |
| 4. When a cache file is going to be created, the *CacheManager::startCaching()* |
| method is called. The Cache Manager is now informed that all following |
| function calls in the application are used inside the cache. |
| |
| 5. Application code returning data which may be modified in the future should |
| be registered to the cache manager. This is done via the |
| *CacheManager::register()* method. |
| |
| 6. The *CacheManager::includeTemplate()* is called when another template is |
| included. |
| |
| 7. The *CacheManager::stopCaching()* is called when the cache file is created. |
| |
| 8. The user application should call the *CacheManager::update()* method when a |
| change in the database or application may affect any of the caches. |
| |
| |
| Keeping track of the values used in the caches is probably best stored in a |
| database. Using the file system is also possible but makes things more |
| complicated. |
| |
| |
| Database storage |
| ```````````````` |
| The database is a good medium to keep track of all the generated caches. It can |
| quickly mark lots of cache files as expired. The real removal of the cache files |
| from the file system can then be done when the server load is low. |
| |
| In which database tables the cache information is stored depends on the |
| implementation of the cache manager. In our example we will use two tables: |
| *cache_files* and *cache_values*. The table *cache_files* has at least the |
| following fields: |
| |
| +---------------+------------------+------+-----+---------+----------------+ |
| | Field | Type | Null | Key | Default | Extra | |
| +===============+==================+======+=====+=========+================+ |
| | id | int(10) unsigned | NO | PRI | NULL | auto_increment | |
| +---------------+------------------+------+-----+---------+----------------+ |
| | cache | varchar(255) | NO | MUL | | | |
| +---------------+------------------+------+-----+---------+----------------+ |
| | expired | tinyint(4) | NO | | 0 | | |
| +---------------+------------------+------+-----+---------+----------------+ |
| |
| The fields store: |
| |
| :id: Is the unique cache identifier. |
| :cache: The relative path to the cache file. |
| :expired: Has the value 0 if the cache is valid, otherwise 1. |
| |
| |
| The table *cache_values* has the following fields: |
| |
| +-------------+------------------+------+-----+---------+-------+ |
| | **Field** | Type | Null | Key | Default | Extra | |
| +=============+==================+======+=====+=========+=======+ |
| | cache_id | int(10) unsigned | NO | PRI | | | |
| +-------------+------------------+------+-----+---------+-------+ |
| | name | varchar(50) | NO | PRI | | | |
| +-------------+------------------+------+-----+---------+-------+ |
| | value | varchar(255) | NO | PRI | | | |
| +-------------+------------------+------+-----+---------+-------+ |
| |
| The fields store: |
| |
| :cache_id: The relation to *cache_files.id*. |
| :name: Name of the value that is stored. |
| :value: The value that belongs to the name. |
| |
| Another table can also store the cache keys that belong to the cache. The |
| structure of this table is similar to the table *cache_values*. |
| |
| |
| Database fetch |
| `````````````` |
| Often a database result needs to be shown in a template. Two techniques are |
| commonly used: |
| |
| - Do the database queries inside the application. Send the result to the |
| template. |
| - Implement a custom function or block that can retrieve database information |
| inside the template. |
| |
| The first solution has arguably a better separation between application |
| and layout code. The second solution has the main advantage that it is easier |
| to optimize. In this section we will continue with the second form. |
| |
| |
| The following template code shows the user information of a single user. The |
| template uses a custom function *db_fetch* that retrieves the user information |
| as an object: :: |
| |
| {use $userID} |
| {cache_template keys $userID} |
| {var $userObj = db_fetch(object="user", id=$userID)} |
| |
| Name: {$userObj->name} <br/> |
| Name: {$userObj->address} <br/> |
| Email:{$userObj->email}<br/> |
| |
| |
| The caching system creates a separate cache file for each *userID*. This |
| cache file is valid, until information changes. If *userID* 1 changes |
| its e-mail address, the Template engine will still use the old cache file. The |
| solution for this problem is that the application informs the Template engine |
| via the Cache Manager about this information update. |
| |
| |
| When the template is run for the first time, it calls the following methods in |
| order: |
| |
| 1. *startCaching( $template, $templatePath, $cachePath, $cacheKeys )*. The |
| current template will be cached. The $cachePath should be stored in the |
| *cache_files* database. The following code could be an implementation of |
| the *startCaching* method: :: |
| |
| public function startCaching( $template, $templatePath, $cachePath, $cacheKeys ) |
| { |
| // Get the current database handler. |
| $db = ezcDbInstance::get(); |
| |
| // Get the current cache ID, if it does exist. |
| $q = $db->prepare( "SELECT id FROM cache_files WHERE cache = :cache" ); |
| $q->bindValue( ":cache", $cachePath ); |
| $q->execute(); |
| |
| // One result and make sure the query is terminated. |
| $r = $q->fetchAll(); |
| |
| if ( sizeof( $r ) > 0 ) // Do we have any results? |
| { |
| $id = $r[0]["id"]; |
| |
| // Renew the cache_file. |
| $s = $db->prepare( "UPDATE cache_files SET expired=0 WHERE id = :id" ); |
| $s->bindValue( ":id", $id ); |
| $s->execute(); |
| } |
| else |
| { |
| // Insert the new cache file |
| $q = $db->prepare( "INSERT INTO cache_files VALUES( '', :cache, '', 0)" ); |
| $q->bindValue( ":cache", $cachePath ); |
| $q->execute(); |
| $id = $db->lastInsertId(); |
| } |
| |
| // Mark that the template is currently creating a cache. |
| $this->isCaching = true; |
| $this->template_id = $id; |
| } |
| |
| |
| The code checks whether the cache file is already registered. If the cache file |
| is available then it sets the *expired* status to 0. Otherwise it adds the |
| cache to the table, with a new id and *expired* set to 0. |
| |
| The *cache_files* table contains something like: |
| |
| == ================================== ======= |
| id cache expired |
| == ================================== ======= |
| 01 compiles/cache/user.ezt-9dsafa0 0 |
| 02 compiles/cache/user.ezt-84fdvj2 0 |
| == ================================== ======= |
| |
| |
| 2. *register( $name, $value )*. This function is called by the user |
| application **during** cache creation. In our example the fetch function |
| which returns the user object should call the *register* function. :: |
| |
| public static function fetch( $object, $id ) |
| { |
| $db = ezcDbInstance::get(); |
| $s = $db->createSelectQuery(); |
| $s->select( "*" )->from( $object )->where( $s->expr->eq( "id", $id ) ); |
| |
| $statement = $s->prepare(); |
| $statement->execute(); |
| |
| $result = $statement->fetchAll(); |
| |
| // Inform the cache manager |
| ezcTemplateConfiguration::getInstance()->cacheManager->register( $object, $result[0]["id"] ); |
| } |
| |
| |
| An example implementation of the *register* method is as follows: :: |
| |
| public function register( $name, $value ) |
| { |
| if ( $this->isCaching ) |
| { |
| $db = ezcDbInstance::get(); |
| $s = $db->prepare( "REPLACE INTO cache_values VALUES ( :id, :name, :value )" ); |
| $s->bindValue( ":id", $this->template_id ); |
| $s->bindValue( ":name", $name ); |
| $s->bindValue( ":value", $value ); |
| $s->execute(); |
| } |
| } |
| |
| |
| After registration the *cache_values* table contains something like: |
| |
| == ============= ======= |
| id name value |
| == ============= ======= |
| 01 user 1 |
| 02 user 2 |
| == ============= ======= |
| |
| Via the *cache_files* table, we know that the user ID 1 is bound to the |
| cache file 'compiles/cache/user.ezt-9dsafa0' and it is not expired. |
| |
| |
| 3. *stopCaching()*. The method is called when the caching is done. The |
| only thing that needs to be done, is to set *isCaching* to *false*. :: |
| |
| public function stopCaching() |
| { |
| $this->isCaching = false; |
| } |
| |
| |
| Right now, the cache file is created. The database contains the user IDs |
| requested during the cache creation. Since the cache file is available, the |
| Template engine will also call the *isValid()* method on the next request. If |
| this method returns *true* then the values used in the cache are unaltered. |
| Let's continue with the example and assume that the user application does |
| change the data of one user. |
| |
| |
| 4. *update( $name, $value )*. The user application calls this method when a |
| value changes that is possibly used inside the templates. The snippet below |
| modifies the user name. :: |
| |
| public static function updateUser( $id ) |
| { |
| $db = ezcDbInstance::get(); |
| $q = $db->createUpdateQuery(); |
| |
| $q->update( "user" )->set( "email", $q->bindValue( "bernard@example.com" ) )->where( $q->expr->eq( 'id', $id ) ); |
| $st = $q->prepare(); |
| $st->execute(); |
| |
| // Update the users. |
| ezcTemplateConfiguration::getInstance()->cacheManager->update( "user", $id ); |
| } |
| |
| |
| Most important is the last line which updates the user with the ID $id. The |
| *CacheManager::update* method can be implemented like: :: |
| |
| public function update( $name, $value ) |
| { |
| $db = ezcDbInstance::get(); |
| |
| $qry = "UPDATE cache_files, cache_values SET cache_files.expired=1 ". |
| "WHERE cache_files.id = cache_values.cache_id AND |
| cache_values.name = :name AND cache_values.value = :value"; |
| |
| $s = $db->prepare( $qry ); |
| $s->bindValue( ":name", $name ); |
| $s->bindValue( ":value", $value ); |
| $s->execute(); |
| } |
| |
| This method expires all the cache files that have the matching cache |
| values: $name and $value. If we assume that user with ID 1 changes the e-mail |
| address, the *cache_files* table is: |
| |
| == ================================== ======= |
| id cache expired |
| == ================================== ======= |
| 01 compiles/cache/user.ezt-9dsafa0 1 |
| 02 compiles/cache/user.ezt-84fdvj2 0 |
| == ================================== ======= |
| |
| And the *cache_values* table remains the same: |
| |
| == ============= ======= |
| id name value |
| == ============= ======= |
| 01 user 1 |
| 02 user 2 |
| == ============= ======= |
| |
| |
| 5. *isValid( $template, $templateName, $cacheName )*. The Template engine calls |
| this method to check whether the cache is still valid. See an example |
| implementation below:: |
| |
| public function isValid( $template, $templateName, $cacheName ) |
| { |
| $db = ezcDbInstance::get(); |
| |
| // Check whether the cache is registered and if it's expired. |
| $q = $db->prepare( "SELECT id, expired FROM cache_files WHERE cache = :cache" ); |
| $q->bindValue( ":cache", $cacheName ); |
| $q->execute(); |
| |
| $r = $q->fetchAll(); // Expect 0 or 1 result |
| |
| if ( count( $r ) == 0 || $r[0]["expired"] == 1 ) |
| { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| |
| When the cache file does not exist or when the cache file is marked as |
| *expired* the function returns *false*, otherwise *true*. The Template |
| engine regenerates the cache if this method returns *false*. Otherwise the |
| cache is displayed. |
| |
| |
| In this section we have discussed how to expire the cache when values in the |
| database change. The implementation of the cache manager is limited to this |
| problem for now. The following sections explain other problems that can be solved |
| using the cache manager. |
| |
| |
| Loose coupling |
| `````````````` |
| In the previous section we explained that the cache manager should be informed |
| when data used in the templates is requested or altered. This requirement |
| enforces strong dependencies, everywhere in the application code are function |
| calls to the cache manager. |
| |
| The previous section uses the following two example functions inside the user |
| application to update the cache manager:: |
| |
| public static function fetch( $object, $id ) |
| { |
| $db = ezcDbInstance::get(); |
| $s = $db->createSelectQuery(); |
| $s->select( "*" )->from( $object )->where( $s->expr->eq( "id", $id ) ); |
| |
| $statement = $s->prepare(); |
| $statement->execute(); |
| |
| $result = $statement->fetchAll(); |
| |
| // Inform the cache manager |
| ezcTemplateConfiguration::getInstance()->cacheManager->register( $object, $result[0]["id"] ); |
| } |
| |
| public static function updateUser( $id ) |
| { |
| $db = ezcDbInstance::get(); |
| $q = $db->createUpdateQuery(); |
| |
| $q->update( "user" )->set( "email", $q->bindValue( "bernard@example.com" ) )->where( $q->expr->eq( 'id', $id ) ); |
| $st = $q->prepare(); |
| $st->execute(); |
| |
| // Update the users. |
| ezcTemplateConfiguration::getInstance()->cacheManager->update( "user", $id ); |
| } |
| |
| |
| The call to the *register* and *update* methods are making dependencies with |
| the cache manager. These method calls can be replaced with a signal from the |
| SignalSlot component. See the following example code:: |
| |
| public static function fetch( $object, $id ) |
| { |
| $db = ezcDbInstance::get(); |
| // ... |
| $result = $statement->fetchAll(); |
| |
| if( $object == "user") |
| { |
| User::signals()->emit( "fetched", "user", $results[0]["id"] ); |
| } |
| } |
| |
| public static function updateUser( $id ) |
| { |
| $db = ezcDbInstance::get(); |
| // ... |
| $st->execute(); |
| |
| User::signals()->emit( "updated", "user", $id ); |
| } |
| |
| |
| The emitted signal describes what just has happened. E.g. There is a user |
| updated with ID number $id. This signal can be used not only for the cache |
| manager but also for e.g. logging. |
| |
| The *User::signals()* method returns an ezcSignalCollection that belongs to the |
| User objects. A signal is sent everytime a user is read or changed. The |
| *signals* method can be implemented as follows:: |
| |
| public static function signals() |
| { |
| if( self::$signals == null ) |
| { |
| self::$signals = new ezcSignalCollection( __CLASS__ ); |
| } |
| |
| return self::$signals; |
| } |
| |
| |
| The next step is to connect the signals to the cache manager. The connection |
| should be done at a place before the Template is processed. For example in the |
| *index.php* file. Creating the connections can be done like:: |
| |
| $tc = ezcTemplateConfiguration::getInstance(); |
| User::signals()->connect( "fetched", array( $tc->cacheManager, "register" ) ); |
| User::signals()->connect( "updated", array( $tc->cacheManager, "update" ) ); |
| |
| |
| The signal *fetched* from the *User* object is connected to the *register* |
| method from the cache manager. And the *update* signal is connected to the |
| *update* method from the cache manager. |
| |
| |
| Including templates |
| ``````````````````` |
| Assume there are two templates: A and B. Template A is cached and includes |
| template B. Below is the code of template A: :: |
| |
| {cache_template} |
| {include "B"} |
| |
| |
| Template B prints only: :: |
| |
| Hello world |
| |
| |
| After template A is executed a cache file is created. This cache file contains |
| the same data as template B. Everything will work fine, until the developer |
| changes template B. |
| |
| Template B is altered to: :: |
| |
| Goodbye world |
| |
| |
| Template A uses the cache and therefore the modification of template B is not |
| checked. Template A will still print "Hello world". |
| |
| The cache manager can solve the issue described above with the cost of some |
| overhead. |
| |
| |
| The cache manager implemented in the section `Database fetch`_ should be |
| modified at three points: |
| |
| 1. The method *includeTemplate* should be implemented. The *includeTemplate* |
| is called everytime a cached template includes another template. The |
| following code stores the include template in the *cache_values* table. :: |
| |
| public function includeTemplate( $template, $templatePath ) |
| { |
| if ( $this->depth >= 0 ) |
| { |
| $db = ezcDbInstance::get(); |
| $id = $this->keys[$this->depth]["cache_id"]; |
| |
| $q = $db->prepare( "REPLACE INTO cache_values VALUES(:id, :name, :value)" ); |
| $q->bindValue( ":id", $id ); |
| $q->bindValue( ":name", "include" ); |
| $q->bindValue( ":value", $templatePath ); |
| $q->execute(); |
| } |
| } |
| |
| |
| 2. The *startCaching* method should also store the template currently |
| processed. The following code should be added in the body of the 'else' |
| statement: :: |
| |
| $q = $db->prepare( "REPLACE INTO cache_values VALUES(:id, :name, :value)" ); |
| $q->bindValue( ":id", $id ); |
| $q->bindValue( ":name", "include" ); |
| $q->bindValue( ":value", $templatePath ); |
| $q->execute(); |
| |
| |
| The current template includes 'itself'. This makes it easier to expire the |
| cache. |
| |
| |
| 3. The *isValid* method should be extended that it also checks all the |
| modification times of the included cache files: :: |
| |
| $q = $db->prepare( "SELECT * FROM cache_values WHERE name = 'include' AND cache_id = :id" ); |
| $q->bindValue( ":id", $r[0]["id"] ); |
| $q->execute(); |
| |
| $r = $q->fetchAll(); |
| foreach ( $r as $a ) |
| { |
| if ( filemtime( $a["value"] ) > filemtime( $cacheName ) ) |
| { |
| return false; |
| } |
| } |
| return true; |
| |
| |
| The code retrieves all the included cache files and checks if an included |
| cache file is newer than the requested cache file. |
| |
| The complete code of the include mechanism is documented in the cache manager |
| interface. |
| |
| Translations |
| ============ |
| |
| With the `tr_context`_ and tr_ template constructs you can add translatable |
| strings to you application. For them to work you have to take a few steps. |
| |
| First of all, you need to make sure that you have the TemplateTranslationTiein |
| and Translation_ components installed as well. The TranslationTemplate |
| component provides the glue between the Template component and the Translation |
| component. |
| |
| Then you have to configure the template system with the correct configuration for |
| translations:: |
| |
| <?php |
| // Create a normal template configuration and create the translation configuration |
| $tc = new ezcTemplateConfiguration; |
| $tc->translation = ezcTemplateTranslationConfiguration::getInstance(); |
| |
| // Create a translation manager, and assign it to the template translation |
| // configuration |
| $backend = new ezcTranslationTsBackend( dirname( __FILE__ ). '/translations' ); |
| $backend->setOptions( array( 'format' => '[LOCALE].xml' ) ); |
| $manager = new ezcTranslationManager( $backend ); |
| $tc->translation->manager = $manager; |
| |
| // Set the locale to use |
| $tc->translation->locale = $locale; |
| ?> |
| |
| .. _Translation: introduction_Translation.html |
| |
| More information on how to configure the ezcTranslationManager can be found in |
| the documentation of the Translation_ component. Of course, the template configuration |
| can also be made through `Lazy initialization`_. |
| |
| After the template system knows about the translations, it will use the |
| Translation component's mechanism to fetch translations. |
| |
| |
| More information |
| ================ |
| |
| For more information, see the: |
| |
| * `Template functions`_ |
| * `EBNF`_ |
| * `API documentation`_ |
| |
| .. _`Template functions`: ../Template/functions.html |
| .. _`EBNF`: ../Template/EBNF.html |
| .. _`API documentation`: ../Template/phpdoc/classtrees.html |
| |
| |
| |
| |
| |
| .. |
| Local Variables: |
| mode: rst |
| fill-column: 79 |
| End: |
| vim: et syn=rst tw=79 |