Ransford Okpoti's Dev Notes

August 24, 2009

Building Modifiers and Functions In Smarty

Filed under: PHP,Smarty — Tags: , , — admin @ 10:17 am

In this article, we will be looking at how to build modifiers and functions in Smarty, a very popular templating engine in PHP. If you don’t know how to setup Smarty up in your project, you can refer to my earlier post on Smarty Templating Overview which is accompanied by a screencast.

A quick look into the Smarty plugins directory should give you an idea of what’s under the hood, the obvious thing you would notice is the file naming convention adopted:
type.function_name.php
where type could be modifier, function, etc.
So, you will typically end up with file names of this structure:

  • modifier.[modifier name goes here].php
  • function.[function name goes here].php
  • etc

MODIFIERS

To be a little curious, lets open modifier.lower.php

<?php
// Comments removed for brevity
function smarty_modifier_lower($string)
{
    return strtolower($string);
}
?>

The above file only shows you that a Smarty plugin is just a normal PHP function, as you may be aware functions are first class citizens in PHP, which accepts arguments and returns a value that would be placed at the location it was called in the template file it self. So, {'Hmm, Interesting Discovery' | lower} in a template file would result in hmm, interesting discovery being substituted in the place of {'Hmm, Interesting Discovery' | lower} in the generated file from that template.
General usage:
{ argument_to_pass_to_the_modifier | modifier_name_goes_here}

The modifier always appears at the right, and there is a pipe | separating it and the argument it will work on.

Ok, so now what? Do you have a website with funny, and uninteresting URLs like
http://mysite.com/article.php?id=2,
where 2 may refer to an article with the title “All You Need To Know To Build Smarty Plugins”.
Let’s try and create a Search Engine Optimization or pretty URL for that article which would result in us having a new friendly URL like

http://mysite.com/article/all-you-need-to-know-to-build-smarty-plugins-2*

* To show the article, you will need to use apache mod_rewrite, but that is not the topic for discussion now, we just want to transform or slugify All You Need To Know To Build Smarty Plugins to all-you-need-to-know-to-build-smarty-plugins. And as a personal preference, i always append the unique id at the end of the generated URL so I do not run into problems when the title of the article is changed.

STEPS

Go into the plugins directory and create a file with the name modifier.seourl.php
Open the file and place the content below into it.

<?php
/**
 * Smarty seourl modifier plugin
 *
 * Type:     modifier<br>
 * Name:     seourl<br>
 * Purpose:  creates a Search Engine Optimized string
 *
 * @author   Ransford Okpoti <ranskills at yahoo dot co dot uk>
 * @param string
 * @return string
 */
function smarty_modifier_seourl($string) {
    $notAcceptableCharactersRegex = '#[^-a-zA-Z0-9_ ]#';
    $string = trim(preg_replace($notAcceptableCharactersRegex, '', strtolower($string)));
    return preg_replace('#[-_ ]+#', '-', $string);
}
 
?>

Once the file is saved, you can go to your template and use it like any normal modifier. E.g.
{$articleTitle | seourl}, {'Just what to see it working' | seourl}.
That’s it for modifiers, so just feel at home and create one if you see the need to.

FUNCTIONS

Smarty functions are similar in nature to their modifiers counterpart,but there is substantial difference in the way they are used within templates.

Usage:
{function_name optional_arguments}
where optional_arguments is in the form key1=value [, key2=value2]*

Lets create a very useful function which would enable us to dynamically include javascript files into our template.
This is extremely helpful if you want to stick to the generally accepted standard of adding javascript files to the tail end of your application or site to improve the performance of the site in terms of how long it takes the site to be loaded.


If you are interested in improving the performance of your site, you can follow the Best Practices for Speeding Up Your Web Site on yahoo which is an interesting and revealing information for any serious web developer.

A practical usage would be to include our little function we are about to develop in the main template of the site and to dynamically add the javascript files depending on which template(s) needs them.

Within the plugins directory, create a file named function.javascript.php with the content below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php 
/**
 * Smarty plugin
 * @package Smarty
 * @subpackage plugins
 */
 
/**
 * Smarty {javascript} function plugin
 *
 * Type:     function<br>
 * Name:     javascript<br>
 * Purpose:  outputs javascript tags for the provided srcs
 * @author Ransford Okpoti <ranskills at yahoo dot co dot uk>
 * @version 1.0
 * @example {javascript srcs='/script location'}
 *          {javascript srcs=$scripts}
 * @param array parameters
 * @return string
 */
function smarty_function_javascript($params) {
	$retval = '';
 
	if(isset($params['srcs'])){
		$scriptTemplate = '<script type="text/javascript" src="{0}"></script>';	
 
		$srcs = $params['srcs'];
	    if(is_array($srcs)){
	        foreach($srcs as $src){
	            $retval .= str_replace('{0}', $src, $scriptTemplate);
	        }
	    }
	    else{
	        $retval = str_replace('{0}', $params['srcs'], $scriptTemplate);
	    }			
	}
 
	return $retval;;
}
 
?>

Usage:
You could have this in your php file that is responsible for rendering the template.

...
// You could have some logic here to determine if a javascript file is required on a certain page
$scripts = array(
       '/public/js/contentslider.js',
       '/public/js/flash.js'
);
 
 
$this->smarty->assign('srcs', $scripts);
$this->smarty->display('template.xhtml');

The template showing just the line where our newly created Smarty function is used.

?View Code SMARTY
{javascript srcs=$srcs}

would result in this:

?View Code HTML4STRICT
<script type="text/javascript" src="/public/js/contentslider.js"></script>
<script type="text/javascript" src="/public/js/flash.js"></script>

This is just one approach of building Smarty plugins, the other approach is to use your existing classes or functions and register them using the function register_type*(…) on a Smarty instance/object.

*
Type could be any of the following:

  1. modifier
  2. function
  3. block
  4. outputfilter
  5. etc

Go! Go!! Go!!! Let Smarty work for you by developing your own plugins to provide extra functionalities.

[SCREEN CAST IS COMING SOON...]

October 23, 2008

Smarty Templating Overview

Filed under: PHP,Smarty — Tags: , , — admin @ 12:39 pm

Smarty is one of the most popular PHP templating engines. There are many other templating engines, based on similar principles, such as

  • PHPTemplate
  • PHPTAL (TAL Template Attribute Language), phptal.motion-twin.com/
  • Savant, http://phpsavant.com/
  • FastTemplate
  • PHPlib

Irrespective of the templating engine that one uses, one of the design goals is the separation of business logic from the presentation logic. A point of caution, you can still use Smarty, the wrong way, without the clear separation of the business and presentation logic since Smarty does not enforce the separation of the 2 logics.

Business logic basically has to deal with how you solve the problem at hand, such as the computation of an employee’s monthly salary using the various parameters required in a typical payroll application.

Presentation logic, as the name suggests, deals with the logic pertaining to the presentation of data/content only. Examples of presentation logic are: iterating through an array of data to be displayed, picking the first X number of characters to display such as displaying a news or an article summary, alternating row colours of tables, etc.

Simply put, a templating engine replaces placeholders with values you specify.
In a real world web development project, there are going to be 2 main teams working on the project namely:
The developers/programmers who uses the full power of the programming language to achieve the requirements of the system such as accessing data from a database or a web service, validating and process the data, and persisting or presenting the processed data if required.
Designer or user interface (UI) team which builds the interface the users of the application would interact with using xHTML and it’s various controls or any appropriate UI technology suitable for the project at hand without affecting the developers codes.

SMARTY INSTALLATION

  1. Grab a copy of the smarty templating engine from http://smarty.net/download.php, as at the time of writing this article the latest stable version is 2.6.19. Extracting the content of the downloaded compressed file gives you this structure:
    Smarty-2.6.19/
      demo/
      lib/
      misc/
      unit_test/
      …
  2. Create a lib folder in your site where all libraries will be kept.
  3. Within the lib folder create a folder with the name smarty and copy the libs folder of the extracted file here.
  4. Now, create these 4 folders
    • templates, all template files, normally with the extension .tpl, goes into this folder
    • templates_c, compiled versions of all the templates will automatically be place here for you by smarty
    • configs, configuration files goes here
    • cache, directory/folder for cache files

After the installation, the directory structure for your project/site must be something like this

root_of_site/
  cache/
  configs/
  lib/
  smarty/
  libs/
  templates/
  templates_c/

After the installation, it is recommended that you subclass the Smarty class itself as this gives you the chance to modify some of the default settings of smarty and apply project specific settings here. Now, lets create a file with the name CustomSmarty.class.php in the site’s root folder ie. /root_of_site/CustomSmarty.class.php

<?php
    set_include_path( get_include_path().PATH_SEPARATOR.'./lib');
    require_once('Smarty/libs/Smarty.class.php');
    if(!defined('REQUIRED_SMARTY_DIR')) define('REQUIRED_SMARTY_DIR','./');	

    class CustomSmarty extends Smarty{

        function __construct(){
            $this->Smarty();

            /*
            You can remove this comment, if you prefer this JSP tag style
            instead of the default { and }
            $this->left_delimiter =  '<%';
            $this->right_delimiter = '%>';
            */

            $this->template_dir = REQUIRED_SMARTY_DIR.'templates';
            $this->compile_dir 	= REQUIRED_SMARTY_DIR.'templates_c';
            $this->config_dir  	= REQUIRED_SMARTY_DIR.'config';
            $this->cache_dir   	= REQUIRED_SMARTY_DIR.'cache';
        }
    }
?>

Now let’s create our template file with the name index.tpl into the templates folder.
Note that all the elements in the tag { } will be substituted in our code.
index.tpl

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <title>Smarty Demo</title>
  </head>

  <body>
    {$msg} <br/>
    <!-- Applying a modifier -->
    {$msg|upper} <br/>

    Select a country:
    <select name="select">
      {html_options options=$countries selected=$selectedCountry}
    </select>
    <p/>
    <!-- For dynamically generated options, it comes in handy -->
    {html_checkboxes values=$country_keys output=$countries
    selected=$selectedCountries separator='<br/>'}
    <p/>

    <!--
I wouldn't recommend you use the date component provided by Smarty since
it's not visually appealing and offers no validation whatsoever
    -->
    Day of departure: {html_select_date start_year="-10"} <br/>
    Time of departure: {html_select_time}

    <p/>
    <!--
{$flight->company} replaces <?php echo $flight->company; ?> you would have to use
if you weren't using Smarty
    -->
    <form id="form1" name="form1" method="post" action="">
      Flight: <input  type="text" id="company" value="{$flight->company}" />
      <br/>
      From: <input type="text" id="from" value="{$flight->from}" />
    </form>

    <p/>
    <table width="100%" cellpadding="0" cellspacing="0">
      <tr align="left">
        <th width="18%" scope="col">SSN</th>
        <th width="25%" scope="col">COURSES</th>
        <th width="14%" scope="col">CREDITS</th>
        <th width="21%" scope="col">SCORE</th>
        <th width="22%" scope="col">COMMENT</th>
      </tr>
      {section name=c loop=$courses }
      <tr bgcolor="{cycle values='#FFA, #FFF'}">
        <td>{$smarty.section.c.iteration}</td>
        <td>{$courses[c].name}</td>
        <td>{$courses[c].credit}</td>
        <td>{$courses[c].score}</td>
        <td>
          {if $courses[c].score gte 50}
          PASS
          {else}
          FAIL
          {/if}
        </td>
      </tr>
      {/section}
    </table>
    <p/>

    <!--
Modifiers can be used to change the output of the passed variable by
doing some processing on it first such as displaying a date in a specified
format.
    -->
    Created on: {$posted|date_format:"%A, %B %e, %Y"}
  </body>
</html>

Next, create a PHP file with the name index.php in the site’s root folder ie. /root_of_site/index.php

<?php
    include_once('CustomSmarty.class.php');

    class Flight{
        public $company;
        public $from;
        public $to;

        public function __construct(){
            $this->company = 'South African Airways';
            $this->from = 'Accra';
            $this->to = 'London';
        }
    }

    $lsCourses = array(
        array('name'=>'Programming using BASIC', 'credit'=>2, 'score'=>70),
        array('name'=>'XMLifying data', 'credit'=>1, 'score'=>40),
        array('name'=>'Web 2.0 Concept', 'credit'=>2, 'score'=>49)
    );

    $countries = array(
        'gh' => 'Ghana',
        'ng' => 'Nigeria',
        'lr' => 'Liberia',
        'ch' => 'China'
    );
    $smarty = new CustomSmarty();
    $smarty->debugging_ctrl = URL;

    $smarty->assign('msg', 'This is a demonstration of the Smarty templating engine.');
    $smarty->assign('countries', $countries);
    $smarty->assign('country_keys', array_keys($countries));
    $smarty->assign('selectedCountry', 'lr');
    $smarty->assign('selectedCountries', array('lr'));
    $smarty->assign('flight', new Flight());
    $smarty->assign('courses', $lsCourses);
    $smarty->assign('posted', '2008-08-27');

    $smarty->display('index.xhtml');
?>

I used smarty_demo as the site root.
Pointing your browser’s URL to http://localhost/smarty_demo, you should see the outcome displayed below.

Smarty demo screen capture

Smarty demo screen capture

Powered by WordPress