Smarty and the Zend Framework

by Naneau

Like I’ve mentioned in previous posts, I’m a great fan of using “decent” template engines, and try to avoid writing views in php. I don’t want to discuss the reasons behind this in detail right now. I just believe that limiting yourself to a small set of template tags makes you think more about structuring your output and separating logic from design. Which is a good thing.

When I started using the Zend Framework a while ago now, I read this article on the zend developer zone. While it describes a decent implementation, I have some problems with it. First of all it breaks standard Zend_View behavior. Like mentioned in the comments somewhere, if you were to decide you want to use Zend_View again for some reason you would have to rewrite large parts of your application, apart from editing your templates. Especially the caching functions annoy me, as they add a set of behavior not even remotely present in the parent class. Zend_Cache is there for a reason.

Also, you can’t use view helpers with his approach. So I decided to come up with my own implementation. It follows Zend_View as closely as possible, while still retaining standard Smarty behavior. That means that I have overwritten as little as possible, and added nothing.

You can assign variables to your view and access them directly from your Smarty template, with {$variableName}. However, I have made sure that you can also use $this (like you would in a regular view) in your templates. Have a look at the _run method to see how it works:

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
 /**
 * fetch a template, echos the result,
 *
 * @see Zend_View_Abstract::render()
 * @param string $name the template
 * @return void
 */

protected function _run()
{
    $vars = get_object_vars($this);
    foreach ($vars as $key => $value) {
        if ('_' != substr($key, 0, 1)) {
            $this->_smarty->assign($key, $value);
        }
    }
    //assign variables to the template engine

    $this->_smarty->assign_by_ref('this', $this);
    //why 'this'?
    //to emulate standard zend view functionality
    //doesn't mess up smarty in any way

    $path = $this->getScriptPaths();
    $file = substr(func_get_arg(0), strlen($path[0]));
    //smarty needs a template_dir, and can only use templates,
    //found in that directory, so we have to strip it from the filename

    echo $this->_smarty->fetch($file);
    //process the template (and filter the output)
}

As you can see I use get_object_vars() in _run(). Therefore I didn’t have to overwrite the __get() and __set() methods of the parent class. The only functionality I really did have to overwrite was the way the view handles script paths. Because Smarty expects a single path from which it gets it’s templates, I had to change the setScriptPath() and addScriptPath() methods.

Examples

Check out these examples, to see what I mean:

1
2
3
4
5
6
{$test}
{$this->test}
{* will output the same variable 'test' *}

{$this->formButton('but', 'button!')}
{*will create a button, using the standard zend view helper *}

There’s one little catch you may want to think about, though. Let’s assume you have a controller script that does the following:

1
2
//create $view
$view->test = array(1,2,3,4,5);

and a template like:

1
2
3
4
5
6
7
8
9
10
{$test}
{*
    note that $test is the same as $this->test before the loop,
    but not inside it (and afterwards for that matter).
*}

{foreach from=$this->test item="test"}
    {$test}
{/foreach}

{$test}

will output:

1
Array 1 2 3 4 5 5

As you can see, {$test} is an array at first, but the foreach statement puts a new value in it on every loop. After the loop is complete {$test} is set to 5. Please pick one way of accessing your variables and stick to it. Personally I would choose {$this->varName} over {$varName}, even though it’s longer. It’s just closer to the normal Zend_View implementation.

At any rate, download Naneau View Smarty and check it out for yourself! It is well documented. Just put it in your library. Make sure to create a directory for your templates and compiled templates. My playground uses it, and I’ve been more than happy with how it works.

Update – May 29, 2007

Because of the new viewRenderer action helper in the framework snapshot version, you will get exceptions complainingg about somecontroller/someaction.phtml not being present, if you use Naneau_View_Smarty. The action helper tries to automate the process of initiating/rendering views. I suggest you disable the viewRenderer action helper for now:

1
$frontController->setParam('noViewRenderer', true);

Update 2 – May 31, 2007

I have a solution for those that want to use Naneau_View_Smarty with Zend Framework 1.0.0RC1.