Creating Template-Based Applications with HTML_Template_Flexy

Welcome To The Jungle

If you’ve been programming for a while, you probably already know the basic function of a template engine: to separate presentation and layout information from program code in an application. This separation lets designers and developers work independently on the form and function of an application, and it can substantially reduce the time and effort required in the maintenance phase of a project.

There’s no shortage of PHP-based template engines out there: Smarty, Template_IT, Xipe and patTemplate are just some of the names that spring to mind. In that sense, the template engine discussed in this article, Flexy, should just be considered one of many. But it isn’t – as you’ll shortly see, although Flexy isn’t as feature-rich or as well-documented as some of the other options available, it’s lightweight, fast and comes with some unique features that will endear it to most developers.

Over the course of this article, I’ll introduce you to some of these features, in the hope that it will encourage you to use Flexy in your next development effort. So come on in, and let’s get cracking!

Knock, Knock

This tutorial makes a couple of assumptions. First, it assumes that you know the basics of PHP and database programming, and you have at least a passing familiarity with using objects and object methods in PHP. Second, it assumes that you have an Apache/PHP/MySQL development environment already set up, and that you’ve managed to successfully install the Flexy package, as well as its dependencies. For your reference, the Flexy package is freely available from http://pear.php.net/package/HTML_Template_Flexy, and is currently maintained by Alan Knowles.

I should also mention at this point that the Flexy package was originally written for PHP 4.x. As a result, you might need to set PHP’s error reporting level to ignore warnings and notices thrown by the package under PHP 5.x. Don’t worry too much about this; in my usage, I found the code stable under both PHP 4.x and PHP 5.x.

With the caveats out of the way, let’s get started with the basics. In Flexy-lingo, a “template” is simply a text file, typically containing both static HTML elements and template variables. Flexy works by replacing these variables with actual values before rendering the HTML page. The values for these variables are dynamically set inside your PHP script or page controller, from a database or other data source.

To see how this works, create a simple, illustrative HTML page, as below, and save it as templates/question.tmpl in your working directory:

And here’s the output:

There’s a fairly standard sequence to rendering a template using Flexy:

  • Create an instance of the HTML_Template_Flexy object, and configure it. Typically, this configuration consists of an associative array of option-value pairs, which is passed to the object constructor. Flexy supports many different options; the two most important ones are ‘templateDir’, which defines the disk path to the template files, and ‘compileDir’, which defines the path to the compiled templates. In most cases, if these directories don’t already exist, Flexy will create them for you.
  • Assign values to the template variables. There are various ways to do this; the script above uses the simplest, the setData() method, which accepts two arguments: the name of the template variable, and the value it should be assigned.
  • Compile the template and display the output. Once values have been assigned to the template variables, the final step is to compile the template, replace the variables within it with actual values, and display the output. This is accomplished via the compile() and output() methods; notice that the compile() method is passed the name of the template file to use.

An alternative here is to use the toString() method instead the output() method; this retrieves the interpolated version of the template and assigns it to a variable instead of displaying it, and comes in handy if you’re working with complex template trees or simply want to perform further processing on the output page before displaying it. Try it for yourself and see.

Joking Around

The previous example demonstrated the simplest way to use Flexy. However, one of Flexy’s unique features is that it can directly map an object’s properties to template variables, without requiring setData() to be manually invoked for each variable. This approach comes in handy when your application is built on OOP principles, as in the following revision of the previous example:

This listing creates a Joke object, passing the object constructor a question and answer; these values can be accessed using the $Joke->question and $Joke->answer properties respectively. This object is then passed to the Page object’s display() method, which internally calls HTML_Template_Flexy object’s outputObject() method to read the object’s properties and map them directly to template variables. As a result, the template variables $question and $answer are populated with the values of $Joke->question and $Joke->answer, with no manual assignment needed.

The output of this script is equivalent to the previous one:

[image]image1.gif[/image]

Fortune Favours The Brave

Flexy templates also support the if conditional test, via {if} and {end} blocks. This test makes it easy to display different output depending on how a particular, user-defined condition is evaluated. To illustrate this feature, consider the following template, which displays a different fortune cookie depending on the day of the week:

And here’s the PHP script that sets one of these variables to true, depending on the current day of the week:

In this script, the date() function is used to return the current day of the week and this, in turn, becomes a property of the object passed to the outputObject() method. So, if today happens to be a Monday, the property $object->monday will be set, and will be used by the conditional tests within the template to display the fortune cookie corresponding to Monday. As before, the fortune cookies in the template can be updated independently of the PHP code.

Here’s what the output looks like:

In addition to the standard {if} block, Flexy also supports an {else} block, which can be used if your template needs to make a logical decision between two branches. Here’s an example:

Here, depending on the values of $object->formSubmitted, Flexy will either display or hide the log-in form. Similarly, depending on the value of $object->loginSuccess, Flexy will either display a welcome message or a failure notification.

Here’s the PHP code that goes with the previous template:

And here’s the template, which generates an HTML list from the array using {foreach}:

Here’s the template, which iterates over the array of SalesRecord objects and prints each one’s location and amount:

And here’s what the output looks like:

Data Dump

Flexy’s support for loops and objects make it a snap to integrate the results of a database query into your output template. To illustrate, consider the following cutaway of a PHP class, which queries a MySQL database and retrieves a list of country records as a collection of objects:

Here, each record in the result set is retrieved as an object using PDO’s fetchObject() method. Field values are mapped to object properties, and the entire object is then placed in the Countries.records array. This Countries object can then be passed to the outputObject() method for interpolation into a template, as below:

Here’s how you’d use this class:

And here’s what the template contains:

This template uses {object.property} notation to iterate over the objects stored in the Countries.records array, and print each object’s ‘name’ and ‘pop’ properties. Here’s what the output page looks like:

Of Form And Function

Flexy also comes with additional features specifically for working with Web forms. With Flexy, it’s possible to programmatically define form and element attributes elements and set default values for form elements. This is accomplished by creating new instances of the HTML_Template_Flexy_Element class (one for each element), setting attributes and values for these objects, and passing an array of these objects to the outputObject() method as an additional argument.

To illustrate, consider the following form template, which sets up the base framework for a pizza order:

And here’s a PHP script, which uses Flexy to set default values for the elements in this form:

To work with form elements using Flexy, create instances of HTML_Template_Flexy_Element for each element you wish to modify. Each of these instances exposes an ‘attributes’ property, which can be used to set attributes of the corresponding form element, and a setValue() method, which can be used to set the element’s default value (note that when setting the value for checkboxes, the input argument to setValue() must be an array of checked items, rather than a single string).

The HTML_Template_Flexy_Element objects created in this manner are then placed in an associative array, with the array key in each case corresponding to the element’s ‘name’ in the output form. This array is then passed to Flexy’s outputObject() method as an additional argument. When the template is compiled and rendered, the HTML_Template_Flexy_Element objects will be automatically merged with the existing form elements in the template to produce a composite result.

Here’s what the form generated by the previous script looks like:

Adding Flexy-bility

In previous examples, you’ve seen two of the configuration options passed to Flexy: ‘templateDir’ and ‘compileDir’. However, Flexy is particularly versatile and comes with numerous other options as well. Here’s a brief list of the most useful ones:

Option Description
‘debug’ Prints debugging messages
‘allowPHP’ Process PHP code embedded in template
‘url_rewrite’ Automatically rewrite specified URLs
‘globals’ Allow usage of PHP super-global variables within template
‘strict’ Display PHP notices for undefined template variables
‘fatalError’ Die or return a PEAR_Error object on fatal errors

Here’s an example which demonstrates some of these options in action:

A common requirement when working with tabular data, such as that generated by the previous example, involves formatting odd- and even-numbered rows differently. Unfortunately, there’s no easy way to do this with Flexy, as the engine doesn’t natively support loop counters or arithmetic operators (both of which are required to determine if a particular row of a table is odd or even). However, there’s still a way out – consider the following template, which illustrates:

Here’s what the output looks like:

This template-and-PHP-script-combination has some points of note:

  • This template contains embedded PHP code to automatically count loop iterations and determine if a particular row is odd or even. The appropriate style is then applied to the corresponding table row, to format odd- and even-numbered rows differently. This is only possible because of the ‘allowPHP’ configuration option.
  • The particular styles to use for odd and even rows are imported from the $GLOBALS superglobal array. Flexy is able to read these values because of the ‘globals’ configuration option, set to true in this case.
  • The template constant HERE is automatically replaced by the path to the script on the Web server, using Flexy’s ‘url_rewrite’ configuration option.

And that’s about all we have time for. As these examples illustrate, although Flexy has a simple API, it is nevertheless a fairly powerful template engine, suitable for deployment in small-to-medium Web applications. And with its support for conditional tests, loops and object mapping, it can speed up development time and reduce the effort involved in maintaining a Web application. Take a look at it sometime, and see for yourself!

Copyright Melonfire 2008. All rights reserved.