Great Templates

FEATURED WEB TEMPLATES

Amazon Books

Learn PHP

PHP Training
Zend Cert Training Zend Certified Engineer Zend PHP Pro

Smarty: Extending Smarty With Plugins

Chapter 16. Extending Smarty With Plugins

Version 2.0 introduced the plugin architecture that is used for almost all the customizable functionality of Smarty. This includes:

  • functions
  • modifiers
  • block functions
  • compiler functions
  • prefilters
  • postfilters
  • outputfilters
  • resources
  • inserts

With the exception of resources, backwards compatibility with the old way of registering handler functions via register_* API is preserved. If you did not use the API but instead modified the class variables $custom_funcs, $custom_mods, and other ones directly, then you will need to adjust your scripts to either use the API or convert your custom functionality into plugins.

How Plugins Work

Plugins are always loaded on demand. Only the specific modifiers, functions, resources, etc invoked in the templates scripts will be loaded. Moreover, each plugin is loaded only once, even if you have several different instances of Smarty running within the same request.

Pre/postfilters and output filters are a bit of a special case. Since they are not mentioned in the templates, they must be registered or loaded explicitly via API functions before the template is processed. The order in which multiple filters of the same type are executed depends on the order in which they are registered or loaded.

The plugins directory can be a string containing a path or an array containing multiple paths. To install a plugin, simply place it in one of the directories and Smarty will use it automatically.

Naming Conventions

Plugin files and functions must follow a very specific naming convention in order to be located by Smarty.

The plugin files must be named as follows:

type.name.php

Where type is one of these plugin types:

  • function
  • modifier
  • block
  • compiler
  • prefilter
  • postfilter
  • outputfilter
  • resource
  • insert

And name should be a valid identifier (letters, numbers, and underscores only).

Some examples: function.html_select_date.php, resource.db.php, modifier.spacify.php.

The plugin functions inside the plugin files must be named as follows:

smarty_type_name()

The meanings of type and name are the same as before.

Smarty will output appropriate error messages if the plugin file it needs is not found, or if the file or the plugin function are named improperly.

Writing Plugins

Plugins can be either loaded by Smarty automatically from the filesystem or they can be registered at runtime via one of the register_* API functions. They can also be unregistered by using unregister_* API functions.

For the plugins that are registered at runtime, the name of the plugin function(s) does not have to follow the naming convention.

If a plugin depends on some functionality provided by another plugin (as is the case with some plugins bundled with Smarty), then the proper way to load the needed plugin is this:

<?php
require_once $smarty->_get_plugin_filepath('function', 'html_options');
?>

As a general rule, Smarty object is always passed to the plugins as the last parameter (with two exceptions: modifiers do not get passed the Smarty object at all and blocks get passed &$repeat after the Smarty object to keep backwards compatibility to older versions of Smarty)

Template Functions

void smarty_function_name (array $params, object &$smarty)

All attributes passed to template functions from the template are contained in the $params as an associative array.

The output (return value) of the function will be substituted in place of the function tag in the template (fetch() function, for example). Alternatively, the function can simply perform some other task without any output (assign() function).

If the function needs to assign some variables to the template or use some other Smarty-provided functionality, it can use the supplied $smarty object to do so.

See also: register_function(), unregister_function().

Example 16-1. function plugin with output
<?php
/*
* Smarty plugin
* -------------------------------------------------------------
* File:     function.eightball.php
* Type:     function
* Name:     eightball
* Purpose:  outputs a random magic answer
* -------------------------------------------------------------
*/
function smarty_function_eightball($params, &$smarty)
{
    
$answers = array('Yes',
                     
'No',
                     
'No way',
                     
'Outlook not so good',
                     
'Ask again soon',
                     
'Maybe in your reality');

    
$result = array_rand($answers);
    return
$answers[$result];
}
?>

which can be used in the template as:

Question: Will we ever have time travel?
Answer: {eightball}.
Example 16-2. function plugin without output
<?php
/*
* Smarty plugin
* -------------------------------------------------------------
* File:     function.assign.php
* Type:     function
* Name:     assign
* Purpose:  assign a value to a template variable
* -------------------------------------------------------------
*/
function smarty_function_assign($params, &$smarty)
{
    if (empty(
$params['var'])) {
        
$smarty->trigger_error("assign: missing 'var' parameter");
        return;
    }

    if (!
in_array('value', array_keys($params))) {
        
$smarty->trigger_error("assign: missing 'value' parameter");
        return;
    }

    
$smarty->assign($params['var'], $params['value']);
}
?>

Modifiers

Modifiers are little functions that are applied to a variable in the template before it is displayed or used in some other context. Modifiers can be chained together.

mixed smarty_modifier_name (mixed $value, [mixed $param1, ...])

The first parameter to the modifier plugin is the value on which the modifier is supposed to operate. The rest of the parameters can be optional, depending on what kind of operation is supposed to be performed.

The modifier has to return the result of its processing.

See also register_modifier(), unregister_modifier().

Example 16-3. simple modifier plugin

This plugin basically aliases one of the built-in PHP functions. It does not have any additional parameters.

<?php
/*
* Smarty plugin
* -------------------------------------------------------------
* File:     modifier.capitalize.php
* Type:     modifier
* Name:     capitalize
* Purpose:  capitalize words in the string
* -------------------------------------------------------------
*/
function smarty_modifier_capitalize($string)
{
    return
ucwords($string);
}
?>
Example 16-4. more complex modifier plugin
<?php
/*
* Smarty plugin
* -------------------------------------------------------------
* File:     modifier.truncate.php
* Type:     modifier
* Name:     truncate
* Purpose:  Truncate a string to a certain length if necessary,
*           optionally splitting in the middle of a word, and
*           appending the $etc string.
* -------------------------------------------------------------
*/
function smarty_modifier_truncate($string, $length = 80, $etc = '...',
                                  
$break_words = false)
{
    if (
$length == 0)
        return
'';

    if (
strlen($string) > $length) {
        
$length -= strlen($etc);
        
$fragment = substr($string, 0, $length+1);
        if (
$break_words)
            
$fragment = substr($fragment, 0, -1);
        else
            
$fragment = preg_replace('/\s+(\S+)?$/', '', $fragment);
        return
$fragment.$etc;
    } else
        return
$string;
}
?>

Block Functions

void smarty_block_name (array $params, mixed $content, object &$smarty, boolean &$repeat)

Block functions are functions of the form: {func} .. {/func}. In other words, they enclose a template block and operate on the contents of this block. Block functions take precedence over custom functions of the same name, that is, you cannot have both custom function {func} and block function {func} .. {/func}.

By default your function implementation is called twice by Smarty: once for the opening tag, and once for the closing tag (see &$repeat below how to change this).

Only the opening tag of the block function may have attributes. All attributes passed to template functions from the template are contained in the $params as an associative array. You can access those values as e.g. $params['start']. The opening tag attributes are also accessible to your function when processing the closing tag.

The value of $content variable depends on whether your function is called for the opening or closing tag. In case of the opening tag, it will be null, and in case of the closing tag it will be the contents of the template block. Note that the template block will have already been processed by Smarty, so all you will receive is the template output, not the template source.

The parameter &$repeat is passed by reference to the function implementation and provides a possibility for it to control how many times the block is displayed. By default $repeat is true at the first call of the block-function (the block opening tag) and false on all subsequent calls to the block function (the block's closing tag). Each time the function implementation returns with &$repeat being true, the contents between {func} .. {/func} are evaluated and the function implementation is called again with the new block contents in the parameter $content.

If you have nested block functions, it's possible to find out what the parent block function is by accessing $smarty->_tag_stack variable. Just do a var_dump() on it and the structure should be apparent.

See also: register_block(), unregister_block().

Example 16-5. block function
<?php
/*
* Smarty plugin
* -------------------------------------------------------------
* File:     block.translate.php
* Type:     block
* Name:     translate
* Purpose:  translate a block of text
* -------------------------------------------------------------
*/
function smarty_block_translate($params, $content, &$smarty, &$repeat)
{
    if (isset(
$content)) {
        
$lang = $params['lang'];
        
// do some intelligent translation thing here with $content
        
return $translation;
    }
}
?>

Compiler Functions

Compiler functions are called only during compilation of the template. They are useful for injecting PHP code or time-sensitive static content into the template. If there is both a compiler function and a custom function registered under the same name, the compiler function has precedence.

mixed smarty_compiler_name (string $tag_arg, object &$smarty)

The compiler function is passed two parameters: the tag argument string - basically, everything from the function name until the ending delimiter, and the Smarty object. It's supposed to return the PHP code to be injected into the compiled template.

See also register_compiler_function(), unregister_compiler_function().

Example 16-6. simple compiler function
<?php
/*
* Smarty plugin
* -------------------------------------------------------------
* File:     compiler.tplheader.php
* Type:     compiler
* Name:     tplheader
* Purpose:  Output header containing the source file name and
*           the time it was compiled.
* -------------------------------------------------------------
*/
function smarty_compiler_tplheader($tag_arg, &$smarty)
{
    return
"\necho '" . $smarty->_current_file . " compiled at " . date('Y-m-d H:M'). "';";
}
?>

This function can be called from the template as:

{* this function gets executed at compile time only *}
{tplheader}

The resulting PHP code in the compiled template would be something like this:

<?php
echo 'index.tpl compiled at 2002-02-20 20:02';
?>

Prefilters/Postfilters

Prefilter and postfilter plugins are very similar in concept; where they differ is in the execution -- more precisely the time of their execution.

string smarty_prefilter_name (string $source, object &$smarty)

Prefilters are used to process the source of the template immediately before compilation. The first parameter to the prefilter function is the template source, possibly modified by some other prefilters. The plugin is supposed to return the modified source. Note that this source is not saved anywhere, it is only used for compilation.

string smarty_postfilter_name (string $compiled, object &$smarty)

Postfilters are used to process the compiled output of the template (the PHP code) immediately after the compilation is done but before the compiled template is saved to the filesystem. The first parameter to the postfilter function is the compiled template code, possibly modified by other postfilters. The plugin is supposed to return the modified version of this code.

Example 16-7. prefilter plugin
<?php
/*
* Smarty plugin
* -------------------------------------------------------------
* File:     prefilter.pre01.php
* Type:     prefilter
* Name:     pre01
* Purpose:  Convert html tags to be lowercase.
* -------------------------------------------------------------
*/
function smarty_prefilter_pre01($source, &$smarty)
{
     return
preg_replace('!<(\w+)[^>]+>!e', 'strtolower("")', $source);
}
?>
Example 16-8. postfilter plugin
<?php
/*
* Smarty plugin
* -------------------------------------------------------------
* File:     postfilter.post01.php
* Type:     postfilter
* Name:     post01
* Purpose:  Output code that lists all current template vars.
* -------------------------------------------------------------
*/
function smarty_postfilter_post01($compiled, &$smarty)
{
     
$compiled = "<pre>\n<?php print_r($this->get_template_vars()); ?>\n</pre>" . $compiled;
     return
$compiled;
}
?>

Output Filters

Output filter plugins operate on a template's output, after the template is loaded and executed, but before the output is displayed.

string smarty_outputfilter_name (string $template_output, object &$smarty)

The first parameter to the output filter function is the template output that needs to be processed, and the second parameter is the instance of Smarty invoking the plugin. The plugin is supposed to do the processing and return the results.

Example 16-9. output filter plugin
<?php
/*
* Smarty plugin
* -------------------------------------------------------------
* File:     outputfilter.protect_email.php
* Type:     outputfilter
* Name:     protect_email
* Purpose:  Converts @ sign in email addresses to %40 as
*           a simple protection against spambots
* -------------------------------------------------------------
*/
function smarty_outputfilter_protect_email($output, &$smarty)
{
     return
preg_replace('!(\S+)@([a-zA-Z0-9\.\-]+\.([a-zA-Z]{2,3}|[0-9]{1,3}))!',
                         
'%40', $output);
}
?>

Resources

Resource plugins are meant as a generic way of providing template sources or PHP script components to Smarty. Some examples of resources: databases, LDAP, shared memory, sockets, and so on.

There are a total of 4 functions that need to be registered for each type of resource. Every function will receive the requested resource as the first parameter and the Smarty object as the last parameter. The rest of parameters depend on the function.

bool smarty_resource_name_source (string $rsrc_name, string &$source, object &$smarty)

bool smarty_resource_name_timestamp (string $rsrc_name, int &$timestamp, object &$smarty)

bool smarty_resource_name_secure (string $rsrc_name, object &$smarty)

bool smarty_resource_name_trusted (string $rsrc_name, object &$smarty)

The first function is supposed to retrieve the resource. Its second parameter is a variable passed by reference where the result should be stored. The function is supposed to return true if it was able to successfully retrieve the resource and false otherwise.

The second function is supposed to retrieve the last modification time of the requested resource (as a UNIX timestamp). The second parameter is a variable passed by reference where the timestamp should be stored. The function is supposed to return true if the timestamp could be succesfully determined, and false otherwise.

The third function is supposed to return true or false, depending on whether the requested resource is secure or not. This function is used only for template resources but should still be defined.

The fourth function is supposed to return true or false, depending on whether the requested resource is trusted or not. This function is used for only for PHP script components requested by include_php tag or insert tag with src attribute. However, it should still be defined even for template resources.

See also register_resource(), unregister_resource().

Example 16-10. resource plugin
<?php
/*
* Smarty plugin
* -------------------------------------------------------------
* File:     resource.db.php
* Type:     resource
* Name:     db
* Purpose:  Fetches templates from a database
* -------------------------------------------------------------
*/
function smarty_resource_db_source($tpl_name, &$tpl_source, &$smarty)
{
    
// do database call here to fetch your template,
    // populating $tpl_source
    
$sql = new SQL;
    
$sql->query("select tpl_source
                   from my_table
                  where tpl_name='$tpl_name'"
);
    if (
$sql->num_rows) {
        
$tpl_source = $sql->record['tpl_source'];
        return
true;
    } else {
        return
false;
    }
}

function
smarty_resource_db_timestamp($tpl_name, &$tpl_timestamp, &$smarty)
{
    
// do database call here to populate $tpl_timestamp.
    
$sql = new SQL;
    
$sql->query("select tpl_timestamp
                   from my_table
                  where tpl_name='$tpl_name'"
);
    if (
$sql->num_rows) {
        
$tpl_timestamp = $sql->record['tpl_timestamp'];
        return
true;
    } else {
        return
false;
    }
}

function
smarty_resource_db_secure($tpl_name, &$smarty)
{
    
// assume all templates are secure
    
return true;
}

function
smarty_resource_db_trusted($tpl_name, &$smarty)
{
    
// not used for templates
}
?>

Inserts

Insert plugins are used to implement functions that are invoked by insert tags in the template.

string smarty_insert_name (array $params, object &$smarty

The first parameter to the function is an associative array of attributes passed to the insert.

The insert function is supposed to return the result which will be substituted in place of the insert tag in the template.

Example 16-11. insert plugin
<?php
/*
* Smarty plugin
* -------------------------------------------------------------
* File:     insert.time.php
* Type:     time
* Name:     time
* Purpose:  Inserts current date/time according to format
* -------------------------------------------------------------
*/
function smarty_insert_time($params, &$smarty)
{
    if (empty(
$params['format'])) {
        
$smarty->trigger_error("insert time: missing 'format' parameter");
        return;
    }

    
$datetime = strftime($params['format']);
    return
$datetime;
}
?>

 


Learn PHP | Zend Certified Engineer | Zend PHP Pro | PHP Web Apps | Web Hosting Service | Low Cost Domain Names | Great Templates | Great Books | Testimonials | Tech.Articles | TOS | AUS | Home | Linux Apache MySQL PHP