Confessions of an apprentice: Setting up template operators in eZ Publish

By Tomislav Buljević -

Welcome to the first article in a series of articles concerning development in the eZ Publish CMS. In this, the first article of a new series concerning the intermediate developers we take a look at the creation and usability of template operators. First, we will get an overview of template operators in general, after that, I will explain the creation of a custom template operator. So, read on!

This series of articles is targeted at developers who already possess a basic knowledge of eZ Publish, especially those who went through all of the articles in my previous tutorial series, Confessions of a n00b, originally posted on the escapestudio.net site. Now, let's get to the matter at hand: setting up custom template operators.

Template operators setup in eZ Publish

Difference between template operators and template functions

If you have any knowledge of working with templates in eZ Publish, you will know that the template operators make a base of all the magic you can do in your templates, from simple mathematics to more complex issues such as array manipulation and logical operations. Now, what makes template operators so different from template functions? Well, template functions work under the assumption that the developer has a knowledge of all the names of parameters required to make it work. The best example for this is the node_view_gui function. Let's take a look at how it works:

{node_view_gui content_node=$node view='full'}

So, in this example you see the basic usage of the node_view_gui function. In the line above, node_view_gui is the function we want to use in the template, content_node is the name of the first parameter in which we put the $node value, and view is the name of the second parameter in which we put value 'full'. Now, in this particular example, $node is a variable in which the node we want to display is stored, and the 'full' is a string depicting which view we want to use for that node. As you can see, we are aware of everything we need to pass to a function in order for it to work. Fail in one parameter, nothing will come out.

On the other hand, template operators use a set of unnamed parameters, which means that you only need to know what kind of a datatype you need to pass to a parameter (be it an integer, string, array, etc.), and what kind of an operator you need in a given situation. So, for example, if you have a timestamp you wish to display in a human-readable fashion, like so: mm/dd/yyyy, you will use the datetime operator which is already a built in feature of eZ Publish:

{$timestamp|datetime('custom', '%m/%d/%Y')}

Now, what did we do here? We have taken a variable $timestamp in which our original timestamp was stored, and we have passed it as an input parameter to the datetime operator using a pipe sign ( | ). Now, the datetime operator uses two more parameters, the first one defines which preset time format we will be using. Since none of the formats in the datetime.ini wasn't good for us, we have defined it as 'custom' which only means that we determine how this particular date and time will be displayed. The second parameter defines how the actual display is going to take place. So, since the display possibilities are already set in the datetime operator, we just use those available to us.

As you can see, the difference isn't great, but it's crucial. Using operators actually gives you greater manipulation of the results you get from various variables used in your templates. Also, template operators use PHP as their main engine for variable manipulation as opposed to variable manipulation through the template, and that really speeds up caching of the system. For all of you who have previous knowledge of PHP, you can see that the usage of functions vs. operators is no different than the basic usage of functions and operators in PHP.

Creating a template operator in eZ Publish

Now you're probably wondering, why would anyone work on creating his/her own template operator since there is so many of them already defined and working perfectly. Well, the plain and simple answer is: Sometimes you just have to. Sometimes you need a functionality on your site you previously never had to use, and as such it isn't defined in the existing set of operators. That's where custom operators kick in, and you'll see that they're really easy to create.

So, basically, what is a template operator? It's a PHP class defining a functionality which allows you to manipulate the variable values in your code. Why do we use it? Mostly to create your own PHP instead of the template compiler translating the template language to PHP. It looks cleaner, loads faster, and is a good practice. How do we create it? Through our extension, of course!

Let’s say that you have a web-page called mypage set up, and you have created your own extension called mypage in it. It probably has only two basic folders in it called design and settings. What you need to do before you set up your template operator is enable it through your extension’s ini settings. So, go to /extension/mypage/settings/ folder and in it, create a site.ini.append.php file if it’s not already created. We won’t be putting any settings of this manner into any of the siteaccesses because we want our template operator to be available in all siteaccesses throughout the page. In the site.ini.append.php file, enter the following lines of code:

[TemplateSettings]
ExtensionAutoloadPath[]=mypage

This means that we want our extension to be available on the autoload path of eZ Publish. Autoloads are, as you have probably already guessed, a set of scripts used to automatically load all PHP files we want to be preloaded so we can use them later. Operators need to be on the autoload path so they can be easily accessible all the time.

Now, since we’ve designated our extension to be on the autoload path, the next course of action is to actually put in some code which will enable the creation of our template operator. So, go one file up into the extension/mypage folder. In it, create a new folder called autoloads. Yup, you guessed it, autoloads is the folder which will handle the loading of our template operator script. So, inside this new folder, create a PHP file called eztemplateautoload.php in which you’ll input the following lines of code:

<?php
$eZTemplateOperatorArray = array();
$eZTemplateOperatorArray[] = array(
                'script' => 'extension/mypage/classes/my_operator.php',
                'class' => 'MyOperator',
                'operator_names' => array('my_operator')
);
?>

In this file we’ve instantiated a variable called $eZTemplateOperatorArray and determined to be an array, of course. After that, we’ve put in an associative array in our variable as the first element, and defined the path to our operator’s script, the class we’ll be using and the operator name(s). Of course, since we’ve designated the extension/mypage/classes/my_operator.php as the path to our script, we need to create it. So let’s do just that.

Create a new folder in your extension/mypage folder called classes. In the extension/mypage/classes folder, create a new PHP file called my_operator.php and fill it with code like so:

<?php
class MyOperator
{ 

function __construct()
{
    $this->Operators = array('my_operator');
}

function operatorList()
{
    return $this->Operators;
}

function namedParameterPerOperator()
{
    return true;
}

function namedParameterList()
{
    return array(
            'my_operator' => array(
                    'display_string' => array(
                            'type' => 'string',
                            'required' => true,
                            'default' => ''
                    )
            )
    );
}

function modify( $tpl, $operatorName, $operatorParameters, $rootNamespace,$currentNamespace, &$operatorValue, $namedParameters )
{
    if ($operatorName == 'my_operator')
    {
        $operatorValue = $this->my_operator($namedParameters['display_string']);
    }
}

function my_operator( $args )
{
    return ('My operator displays any string I want, for example: '.$args);
}

private $Operators;
}
?>

As you can see, this is a pretty big chunk of code. Let’s break it down to its defining elements.

So, the first thing we see here is that we have defined our class called MyOperator(). At the end of it, we can see that there is a private variable called $Operators defined. In the constructor, which is the function __construct(), we have set this variable to be an array in which we’ve put only one element, and that’s the template operator identifier ‘my_operator’. After that, we have a function called operatorList() which returns the value of the operators in our class (that very same array defined in the constructor). The function namedParameterPerOperator() which returns true to tell the template engine that the parameter list exists per operator type, this is needed for operator classes that have multiple operators. After that, we have the namedParameterList() function which returns every argument (or parameter, if you will) for every defined operator in the class, in the type of an associative array. You can see that we define the kind of parameters we will pass onto out template operator here. After that, we have a modify() function which tells the engine which parameters to use if it stumbles upon my_operator in the code. And, last but not least, the my_operator() function which defines the actions you want your operator to achieve. In this example, we’ve passed one argument to our operator, and displayed it on the screen.

After you’ve defined your operator in such a manner, the last task you need to do is regenerate the autoload arrays in your administration (under the section Setup/Extensions just select Regenerate autoload arrays) and clear the cache. And you’re all set!

Usage of a template operator

Usage of a template operator is pretty straightforward. Just open any template you wish your operator to be used in, and type in the following:

{my_operator('some string or param I want to display')}

After that, you will see that the information on the display page looks like this:

My operator displays any string I want, for example: some string or param I want to display

If you want to make the use of a pipe (|), you need to change the namedParameterList() and modify() functions accordingly, for example:

function namedParameterList()
{
    return array( 'my_operator' => array('display_string' => array('type'=> 'string', 'required' => false, 'default' => '' )));
}

function modify($tpl, $operatorName, $operatorParameters, $rootNamespace, $currentNamespace, &$operatorValue, $namedParameters)
{
    if ($operatorName !== null) {
        $operatorValue = $this->my_operator($operatorValue);
    }
else if ( !empty( $namedParameters['display_string'] ) )
{
    $operatorValue =$this->my_operator($namedParameters['display_string']);
}
else
{
    $operatorValue = "";
}
}

As you can see, we have designated the first parameter of our operator to be false in the namedParameterList() function, because we want the input parameter of the operator to serve the same function. And of course, if you write the following in your template:

{'some string or param I want to display'|my_operator}

you will get the same result as before but handled in a different way.

And that’s pretty much it! As you can see, the creation and usage of a template operator in eZ Publish is really easy enough for any programmer to accomplish, and it helps you out in situations where: a) the basic template operators just don’t cut it, and b) you need to get performance by custom PHP. That being said, if you ever find yourself staring at large number of lines in your template, remember the template operators, they can be a life-saver in such cases.

I truly hope that you’ve gained some knowledge and new vision concerning the creation and usage of template operators out of this article, and that it will help you in your future projects.

Until next time, I wish you happy coding,
Tomislav

Comments

This site uses cookies. Some of these cookies are essential, while others help us improve your experience by providing insights into how the site is being used. For more detailed information on the cookies we use, please check our Privacy Policy.