Smarty Plugin To Replace Zend Framework View Helper “Url”

We made a Smarty plugin to replace Zend Framework’s Zend_Controller_Action_Helper_Url functionality that was lost by doing a full integration of Smarty and Zend.

Sometimes, Integrations Come with Setbacks

In a previous post here at engfers.com, we talked about how to fully integrate the PHP templating engine, Smarty, with the Zend Framework by replacing the implementation of the viewRenderer’s Zend_View_Interface with a Zend_View_Smarty implementation.

Unfortunately, by using this solution, any reference to the $this pointer in the template land references the Smarty object instead of Zend_View.

Well, the Smarty object doesn’t contain the nice “url-ifier” ($this->url()). With the “url-ifier” (Zend_Controller_Action_Helper_Url), one could specify the module, controller, action and request parameters as an associative array parameter, and it would generate a nice and pretty url for you.

Well, we wanted that functionality back!

Hacks

At first thought, one might be tempted to use the {php}...{/php} template tags in Smarty. Don’t do it! It’ll totally invalidate the whole point of using Smarty and it’s ugly as snot.

Another creative way to accomplish this is to do some sort of fancy template variable assignment that gives you access to some method, object or whatever; don’t do this either.

The correct way to accomplish the task at hand is to make a Smarty plugin that emulates the functionality of whatever Zend_Controller_Action_Helper_Url did.

The Smarty Plugin

Read the comments section in the code and see the examples section for template implementations.

The Code: function.zend_url.php

Just copy this and plop it in your $smarty->plugins_dir and call it function.zend_url.php

// @depends Zend_Controller_Front from Zend Framework

/**
 * Type:     function
 * Name:     zend_url
 * Purpose:  Generate a url based on the default front
 *  controller's router rules. It's just a proxy method to
 *  the router's assemble() method. This was meant to
 *  replace view calls to $this->url();
 *
 * Parameters:
 *  module (optional)
 *    - module name
 *  controller (optional)
 *    - controlle name
 *  action (optional)
 *    - action name
 *  zend_url_name (optional)
 *    - see Zend_Controller_Router_Interface::assemble()
 *  zend_url_reset (optional)
 *    - see Zend_Controller_Router_Interface::assemble()
 *  zend_url_encode (optional)
 *    - see Zend_Controller_Router_Interface::assemble()
 *
 * Other url parameters can be passed via 'key="value"'
 *
 * Example:
 * {zend_url module="myapp" controller="blog"
 *    action="edit" postId="232" user="admin"}
 *
 * @author David Engfer
 *
 * @param array containg attrubtes
 * @param Smarty
 */
function smarty_function_zend_url($params, &$smarty) {
    // Defaults as specified by assemble()
    $urlParams = array();
    $name = null;
    $reset = false;
    $encode = true;

    // Capture the module
    if (isset($params['module'])) {
        $urlParams['module'] = $params['module'];
        unset($params['module']);
    }

    // Capture the controller
    if (isset($params['controller'])) {
        $urlParams['controller'] = $params['controller'];
        unset($params['controller']);
    }

    // Capture the action
    if (isset($params['action'])) {
        $urlParams['action'] = $params['action'];
        unset($params['action']);
    }

    // Capture if a route name is specified
    if (isset($params['zend_url_name'])) {
        print_r ($params['zend_url_name']);
        $name = $params['zend_url_name'];
        unset($params['zend_url_name']);
    }

    // Capture if resetting the route is specified
    if (isset($params['zend_url_reset'])) {
        $reset = $params['zend_url_reset'] == "true"
        ? true
        : false;
        unset($params['zend_url_reset']);
    }

    // Capture if encoding parameters is specified
    if (isset($params['zend_url_encode'])) {
        $encode = $params['zend_url_encode'] == "false"
            ? false
            : true;
        unset($params['zend_url_encode']);
    }

    // Grab rest of the params and add them to urlParams
    foreach ( $params as $key => $val ) {
        $urlParams[ $key ] = $val;
        unset( $params[ $key ] );
    }

    // Assemble the url and pass it back
    return Zend_Controller_Front::getInstance()
        ->getRouter()->assemble(
            $urlParams,
            $name,
            $reset,
            $encode );
}

Example Usage:

If we were on the page http://servername/blog/post/index/231 (post/index.tpl), the following would generate:

{zend_url}
  • http://servername/blog/post/index
{zend_url action="edit" id="231"}
  • http://servername/blog/post/edit/id/231
{zend_url module="blog2" controller="user" action="edit"
   name="john"}
  • http://servername/blog2/user/edit/name/john

8 thoughts on “Smarty Plugin To Replace Zend Framework View Helper “Url”

  1. Ugh… so you propose that we (re)write every view helper as a smarty plugin? There has got to be a better way.

  2. @Jake. I know it seems bad or ugly; however, it does follow a pattern that designers can follow. If you are just working on the project yourself.

    You can accomplish this through other means.

    You could create a true Zend_View object and assign it as a variable in your Smarty object and use the {php}...{/php} fashion to grab the view and use the view helpers. It still is very ugly, but it will work

    Which ones do you use that you want someone to write a Smarty plugin for?

  3. OK, just a short look at the code would take much less time than writing those comments=)

    The code for my previous comment should be:

    {zend_url action=”add” zend_url_reset=true}

  4. Works great, just what I needed right now.

    Do you have an idea how to get rid of the default module in the link? With IndexController and IndexAction it worked right by the way, but I do not like a link like /en/default/login

  5. Awesome! This works great. Thanks David. Are you guys planning on doing something similar for forms to create something like Zend_View_Smarty::formText()?

  6. Easily, your post is actually the freshest on this laudable topic. I concur with your conclusions and anxiously await your upcoming updates. Saying thank you will not be sufficient, for the great lucidity in your writing. I will immediately grab your rss feed to stay abreast of any updates. Good work and much success in your business dealings!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>