========================= The eZ Template Component ========================= :Author: Tobias Schlitt :Date: Monday 17 July 2006 11:50:00 am .. contents:: Table of Contents This article describes the template engine included in version 1.1 of eZ components. I analyze a simple application that, using the template engine, queries Google for specified keywords and then checks the rank of a website in the results. While I am not going to describe the entire application (which also uses the eZ PersistentObject component and some more classes), describing the template aspect of the application should give you a good idea of how the eZ Template can be used. The models ========== Site ---- * site: The site URI to look for in the search results. Search ------ * query: The query string to search for on Google. Result ------ * rank: Either the position of the site in the Google search results or 0 (if the site was not found). * timestamp: The time when the search was performed. * title: Either the title of the site or an empty string (if the site was not found). * url: Either the complete URL or an empty string (if the site was not found). * snippet: Either the text snippet Google displayed for the URL or an empty string (if the site was not found). Application architecture ======================== The application follows the MVC pattern, similar to the one described in the Image Gallery article (which described other aspects of the eZ components). There is a main controller that dispatches to several action controllers based on a URL parameter. Rather than analyzing this aspect in detail, we will look at the portion of the main controller that interacts with the template engine. Each action controller contains the models that are needed to fill in the template variables and tell the main controller which template file to load. Specifically, we will look at the action controller that displays the detailed view of the search containing a list of the results as they are collected. The PHP code ============ As mentioned above, we are only looking at the parts of the PHP code within the controller that deal with the eZ Template component and the action controller. The main controller ------------------- The template engine is called by two of the controller methods. In the constructor of the controller, we configure the template engine. The method display() loads a template, submits the current action controller to it and displays it. Here is the interesting part of the constructor:: class tsGrcController { // ... public function __construct() { // ... $eztConfig = ezcTemplateConfiguration::getInstance(); $eztConfig->templatePath = dirname( __FILE__ ) . "/templates"; $eztConfig->compilePath = dirname( __FILE__ ) . "/templatesc"; } I removed the code in this section that reads the selected action from a GET parameter and instantiates the necessary action controller, which is then stored in the private attribute $action. The code snippet above shows the configuration of the Template component. The call to ezcTemplateConfiguration::getInstance() is a singleton implementation for the template configuration. We tell the configuration object where our templates are stored and where compiled templates will be stored. The eZ Template component compiles its templates into pure PHP code and caches the compiled versions. Templates automatically get recompiled when they change. (Note that the directory where compiled templates are stored must be writable by the user account running the web server.) :: public function run() { $this->action->run(); $template = new ezcTemplate(); $template->send->action = $this->action; echo $template->process( $this->action->template . ".ezt" ); } This is the run() method of the main controller. It simply calls the run method of the action controller in the first line. (We will talk about this in greater detail below.) After that, a new template is instantiated. The third line of code sends the action controller to the template. Sending a variable to a template is necessary to make it available to the template code. You can send as many variables as you like to a template by simply assigning them to a child of the template's $send attribute. The name you choose for the child is the name under which the variable will be available in the template. The last line makes the template engine process the template (which is selected by the action controller) and prints the results. If the selected template is already compiled, the Template component runs the compiled version. If no compiled version is available or if the template has changed since the last compile, it is compiled and stored. The action controller --------------------- Now we will look at the action controller we mentioned above:: class ActionSearchdetails { private $searchId; public $template = "searchdetails"; public $title = "Search details"; public $site; public $search; public $results; public function __construct() { // ... } public function run() { $this->search = tsGrcController::getSession()->load( 'Search', $this->searchId ); $this->results = $this->search->getResults(); $this->site = $this->search->getSite(); } } The constructor, which I did not include here, processes the parameters needed by this action, specifically the ID of the search we want to display. The retrieved search ID is stored in the private member $searchId. In the first line of the run() method, you see how the Search object is loaded from the database and stored in the public member called $search. After that, we call several methods on this object to retrieve the related results and the site this search belongs to. Both are also stored in public attributes. Templating ========== Now we come to the interesting part of this article. We have all the basics in place to start looking at the template for our action. The main template ----------------- :: {use $action} {var $menu = array( "Back to site" => array( "action" => "sitedetails", "site" => $action->site-id ) ) } {include "header.ezt" send $action, $menu}

Search details for search "{$action->search->query}" about site "{$action->site->site}"

Results

{cycle $rowStyle = array( "light", "dark" )} {foreach $action->results as $result} {increment $rowStyle} {/foreach}
Query date Rank More details
{date_timestamp_format( "Y-m-d H:i", $result->timestamp )} {$result->rank} "resultdetails", "result" => $result->id ) )}">details
{include "footer.ezt"} If you are familiar with Smarty, you will find it easy to understand our template language, since it is very similar to the Smarty language. However, in contrast to Smarty, the eZ Template component is written only for PHP 5.1 or greater, while Smarty maintains compatibility with PHP 4. Each template instruction is wrapped in curly braces ("{", "}") and each of these instructions may output text (so you do not need to specify a command like echo for printing text). All printed text is automatically escaped using PHP's htmlentities() function (assuming that we did not change the context of the template, which is XHTML by default). If, for some reason, you need to print non-escaped text, you can use the raw command. The first template instruction is the use command, which retrieves the variables that have been sent to the template. (Remember that we did that in the main controller.) After that, the variable $action is available for use. Next we define a new variable called $menu. This is a multi-dimensional associative array that represents a menu structure. (In the context of the eZ Template component we talk about associative arrays as hashes, so I will use that term from now on.) As you can see, the hash is defined in exactly the same way that it is done in PHP. The menu structure defines a link named "Back to site". The link name is assigned to an array of parameters that needs to be sent to the main controller to show the site we want to link to. We will show how the menu is generated from this array in a moment. Next we include another template that is responsible for displaying the HTML header and the menu. Including a template works exactly like processing a template from PHP; you have to send it the variables that it will need. Here we send our $action and the newly generated $menu variables. But before we look at the included template, let's finish with the main template. In the next line (6), some HTML code gets generated. We print a first-level heading and, for the first time, echo some data. As already mentioned, this is quite easy - you just wrap the variable that will be output in curly braces. Access to object attributes works the same as with PHP. Note, though, that for now it is not possible to call methods on objects from a template. If you need to access methods, you can try to emulate this through overloading in your class. This is a very limited approach, but it may be sufficient in some cases. In line 14 we see a special feature of the eZ Template component - the "cycle". A cycle is a single-dimensional array (or a hash). It is special because you can iterate over it in an infinite loop. When the cycle reaches the end, it will start from the beginning again. Our cycle $rowStyle contains two elements: the strings "light" and "dark", which refer to CSS classes. Each time you use the cycle variable, it will return its currently selected value. To advance its internal pointer to the next value, call the increment statement (line 27). In line 15 we use a foreach loop to iterate over all results stored in our action. The foreach loop is closed in line 28, using the statement:: {/foreach} As you can see, ending blocks in the template language are similar to the HTML construct. Inside the foreach we use a template function for the first time. Line 18 refers to a function called date_timestamp_format(). This function works exactly like PHP's date() function: it takes a format string to determine how to display a date and an optional timestamp to format. If the latter is not specified, the current time will be used. In most cases, we named the functions in our template language differently from the PHP functions to provide a unique naming scheme. You will also see that with parameter orders. Where PHP is sometimes very inconsistent, the order is always the same for our functions. Line 24 contains another function call. The function url_parameters_build() wraps around PHP's http_build_query() function, which takes a hash and builds an HTTP-GET query string from it. The last line in this template includes another template, which simply closes the HTML constructs from the " header.ezt" template we included previously. There is nothing special in there. Included templates ================== On line 5 of the main template we included another template that prints the HTML header and the menu structure for each page. Remember that we sent the $action and $menu variables to this template.:: {use $action, $menu = array()} GoogleRankCheck - {$action->title} {include "menu.ezt" send $menu} Again we have a use statement on the first line. This is always necessary to make external variables available to a template. The reason for this mechanism is simple: in a complex system, you might have duplicate variable names, which can be avoided via a mechanism called aliasing. Aliasing is not done in the use statement but in the include statement. So, if you want to rename a variable for a template you include, you can write:: {include "test.ezt" send $foo as $bar} You can also send static values to a template using this method. In the use statement of the header template, we define a default value for the $menu variable. If no value is sent to the template, it will be an empty array. We are already familiar with the rest of the code in this template, so we will proceed to the menu template, which gets included in the last line. :: {use $menu} {var $menuStd = array( "Main page" => array( "action" => "sitelist" ), ) } { $menu = array_merge( $menuStd, $menu ) } {foreach $menu as $menuName => $menuParams} {/foreach}
[{$menuName}]
The menu template is responsible for generating a menu on each page of our application. The lines 2-6 define a hash of default links that should be available on every page. After that, on line 8, the received menu hash is merged with these default links. The array_merge() function works exactly as it does in PHP. Lines 12-14 iterate over the resulting menu hash and generate a table of menu items. Again we use the url_parameters_build() function on the GET parameter array that is defined for each menu item. Conclusion and resources ======================== The eZ Template component is a good choice if you need a template engine. It is built exclusively for PHP 5.1 and later, making use of new and powerful PHP functionality and usability. eZ Template has a very clean and slim API design and supports compiling templates for the sake of performance. Because the template language is similar to PHP's, it is easy for PHP developers to write template code. However, eZ Template removes some of PHP's oversized features, which makes it easy for HTML designers who might not be familiar with programming to use. eZ Template adds value for your template engineers like the cycle-statement, which makes tasks like generating alternating row colors simple. The consistency in the names and prototypes of the functions provide a very low learning curve for programming eZ templates. Resources ========= * `eZ components`__ __ http://ezcomponents.org