PhpRiot
Become Zend Certified

Prepare for the ZCE exam using our quizzes (web or iPad/iPhone). More info...


When you're ready get 7.5% off your exam voucher using voucher CJQNOV23 at the Zend Store
Related Articles

Application Logic Versus Template Logic

This article takes a look at separating application logic from template logic. We will use the Smarty Template Engine as the basis for the article and its examples.

What this is basically saying is that anything relating to the final output should be determined in the template, while any data handling or processing should be done in your PHP files and classes. There’s a little more to it than though, which we’ll soon see.

An important aspect of this is that it works both ways. Often people focus on making sure their templates don’t do anything application related, but then make the mistake of making their PHP scripts (or classes) doing work that their templates should be doing. We will look at both situations and common issues that arise.

Application logic (also called business logic) is any code that deals with processing of data. That is, the processing behind the scenes. Common examples of this include:

  • Processing the input from a web form
  • Saving data to a database
  • Debiting money from a credit card
  • Reading or writing cookies on the client’s computer

This even includes instantiating the Smarty class and displaying a template:

Listing 1 listing-1.php
<?php
    $smarty = new Smarty();
    $smarty->display('index.tpl');
?>

It also includes generating data that may be used in your template logic, but we’ll look at that in a little while.

Template logic (also called display logic) is any code in your templates that determines how things are displayed. For instance, if you output a certain message if a string is empty, or the string if it isn’t empty, then this is template logic. Here’s an example:

Listing 2 listing-2.tpl
{if $name|strlen == 0)
    <p>
        You didn't enter your name!
    <p>
{else}
    <p>
        Hello {$name}
    </p>
{/if}

Formatting of a string is also template logic (although there may be exceptions, depending on the data). For example:

Listing 3 listing-3.tpl
<p>
    Title: {$title|strtoupper}
    Summary: {$summary|truncate}
</p>

We’ll look at some more examples of application logic and template logic shortly, for now, we’ll look at things that aren’t application logic and aren’t template logic.

Smarty allows developers to directly embed PHP code by using the {php} {/php} tag. Personally, while it’s good to have the functionality available, I think it’s almost always a bad idea to ever use this. It is also possible to use any declared PHP function (builtin or user defined) as a modifier (unless you have template security turned on).

An example would be to directly access some data from a form and sanitize it in the template:

Listing 4 listing-4.tpl
<p>
    This is bad, but you entered {$smarty.get.name|strip_tags|trim}.
</p>

The way this should be done is done in the PHP file, and then passing the sanitized value to the template:

Listing 5 listing-5.php
<?php
    require_once('Smarty.class.php');
 
    $name = trim(strip_tags($_GET['name']));
 
    $smarty = new Smarty();
    $smarty->assign('name', $name);
    $smarty->display('example.tpl');
?>

And then the template would look like:

Listing 6 listing-6.tpl
<p>
    This is good. You entered {$name}.
</p>

So now that I’ve covered a few bad things, what kinds of things are acceptable? Here are some examples.

Checking a String Value or Boolean Flag to Determine Output:

Listing 7 listing-7.tpl
{if $name|strlen > 8}
    <p>
        Your name is long!
    </p>
{/if}
 
{if $male}
    <img src="male.gif" />
{else}
    <img src="female.gif" />
{/if}

Alternating Background Colours

Actually, this is made easy in Smarty with the {cycle} function:

Listing 8 listing-8.tpl
<table>
    <tr>
        <th>Field 1</th>
        <th>Field 2</th>
    </tr>
    {foreach from=$data item=row}
        <tr style="background: {cycle values='#ccc,#ddd'}">
            <td>{$row.field1}</td>
            <td>{$row.field2}</td>
        </tr>
    {/foreach}
</table>

Displaying a Running Count

This is also made easy in Smarty, using the {counter} function.

Listing 9 listing-9.tpl
{foreach from=$items row=item}
    <p>
        Item number {counter}. {$item}
    </p>
{/foreach}

Including Another Template

This will be required frequently, and as we point out next, the alternative to doing this is quite bad!

Listing 10 listing-10.tpl
{include file='header.tpl'}
 
<p>
    Example of including a header and a footer.
</p>
 
{include file='footer.tpl'}

There are several situations where you may incorrectly end up using template logic in your application without even realising.

Case 1: Displaying Multiple Template Files

Take a look at this PHP code to output a single page:

Listing 11 listing-11.php
<?php
    require_once('Smarty.class.php');
 
    $smarty = new Smarty();
    $smarty->display('header.tpl');
    $smarty->display('example.tpl');
    $smarty->display('footer.tpl');
?>

This is extremely bad! You have essentially hardcoded in your application that your templates are built by displaying a header, then the main content, and then the footer. The fact that your templates are split into 3 templates like this is a function of the templates, not of the application.

The correct way to do this is:

Listing 12 listing-12.php
<?php
    require_once('Smarty.class.php');
 
    $smarty = new Smarty();
    $smarty->display('example.tpl');
?>

And then the example.tpl file would like:

Listing 13 listing-13.tpl
{include file='header.tpl'}
 
<p>
    Example of including a header and a footer.
</p>
 
{include file='footer.tpl'}

Case 2: Determining a style or an image in code and then assigning it to a template

Let’s assume you’re outputting a document and you want to show an image that says new if it was submitted today, or an image that says old if it was submitted earlier.

It would be bad to specify this image in the code like so:

Listing 14 listing-14.php
<?php
    require_once('Smarty.class.php');
 
    if ($article->isNew)
        $image = 'new.gif';
    else
        $image = 'old.gif';
 
    $smarty = new Smarty();
    $smarty->assign('image', $image);
    $smarty->display('example.tpl');
?>

Even worse would be:

Listing 15 listing-15.php
<?php
    if ($article->isNew)
        $image = '<img src="new.gif" alt="New" />';
    else
        $image = '<img src="old.gif" alt="Old" />';
?>

It seems obvious, but I have seen it done. The correct way would be to pass the flag to the template and in the template determine which image to use:

Listing 16 listing-16.php
<?php
    require_once('Smarty.class.php');
 
    $smarty = new Smarty();
    $smarty->assign('isNew', $article->isNew);
    $smarty->display('example.tpl');
?>

And the template:

Listing 17 listing-17.tpl
{if $isNew}
    <img src="new.gif" alt="New" />
{else}
    <img src="old.gif" alt="New" />
{/if}

Afterall, the image is tied to display. You might change template sets or image sets, resulting a new filename. You should only have to change your templates, not your application code.

There are always going to be exceptions where you may need to put application logic in a template, or some circumstances that sit right on the fence. Here’s an example:

Listing 18 listing-18.tpl
<input type="text" name="title" value="{$title|escape}" />

In this situation, to deal with the fact a user might enter a quotation mark ("), we must escape the data. You could argue that this is application logic, but personally, I think this is directly related to the output of your HTML document, and so should be escaped when it is output.

Another exception I can think of would be if you wanted to list news articles in your template, but you’re not sure how many. That is, the number of articles shown is a function of the template. In one layout you might have room to fit three articles, but if you change templates, you might have room for five. So how many articles do you assign?

The only way to cover all bases would be to get every single article and assign them all to the template. This seems somewhat excessive. The way I have dealt with this in the past is to use a function call with the number of articles. This function directly calls the database, which as we have said is therefore application logic, but sometimes there’s no easier way around things:

Listing 19 listing-19.tpl
{foreach from=$news->getArticles(5) item=article}
    <h2>{$article.headline}</h2>
{/foreach}

You must use your own judgement when determining what should be in code and what should be in template. Take a look at this example of checking for an empty array:

Listing 20 listing-20.tpl
{assign var='numElements' value=$myArray|@count}
{if $numElements == 0}
    <p>
        The array is empty.
    </p>
{else}
    <p>
        There are {$numElements} elements.
    </p>
{/if}

Strictly speaking, you should determine the count in PHP, and perhaps even a flag to check if it’s empty:

Listing 21 listing-21.php
<?php
    require_once('Smarty.class.php');
 
    $myArray = array(1, 2, 3);
    $numElements = count($myArray);
    $isEmpty = $numElements == 0;
 
    $smarty = new Smarty();
    $smarty->assign('myArray', $myArray);
    $smarty->assign('numElements', $numElements);
    $smarty->assign('isEmpty', $isEmpty);
    $smarty->display('example.tpl');
?>

And the example.tpl file:

Listing 22 listing-22.tpl
{if $isEmpty}
    <p>
        The array is empty.
    </p>
{else}
    <p>
        There are {$numElements} elements.
    </p>
{/if}

Personally, I think the second method is overkill and I would always use the first method. The additional problem is that we don’t necessarily know in the script what data the template requires.

The fact that we do something in the template for an empty array is display specific, not something that needs to be known in the application.

In this article I explained the difference between application logic and template logic when using Smarty. Hopefully you found some simple ways to improve your template design, but also recognised that some complexities can arise when doing this and sometimes comprimises must be made.

One (simplified) way to look at it is like this:

You should be able to completely change templates, including all image files and CSS files, without having to touch any of your PHP files.

All fundamental data required in your templates should be fetched or determined ahead of time and assigned to your templates (this doesn’t include meta data, such as the length of a string, etc.).

Further reading

Other Options

Application Logic Versus Template Logic