Ever since discovering Zend Framework’s ContextSwitch and AjaxContext action helpers, I’ve been hooked. What’s not to love about writing one controller action and having the request dictate the response format.

Whilst this generally does the job for XML, JSON and AJAX HTML snippets where any layout is disabled, sometimes you just need to wrap that content in something.

I often find myself writing small configuration screens that work nicely in modal style dialogs as opposed to a devoted web page. Generally I’ll render these screens as inline frames using my favourite JavaScript library and DOM Window (a ThickBox successor). The problem with iframes is they require a complete HTML document. ContextSwitch just wasn’t cutting it as I needed some kind of layout but obviously not the full blown, menus and all default.

The solution was to implement my own custom context, complete with a post-processing callback function to alter the layout script. Here’s how I’ve done it.

First, I added a static method to my Bootstrap class to add a suffix to the layout script name should a context be present.

public static function setLayoutContext()
{
    $layout = Zend_Layout::getMvcInstance();
    if (null !== $layout && $layout->isEnabled()) {
        $context = Zend_Controller_Action_HelperBroker::getStaticHelper('ContextSwitch')->getCurrentContext();
        if (null !== $context) {
            $layout->setLayout($layout->getLayout() . '.' . $context);
        }
    }
}

For example, given the default layout script layout.phtml and context iframe, this method will set the layout script to layout.iframe.phtml

Now I just need to add the context to the action helper. Again, in my Bootstrap class.

public static function setupActionHelpers()
{
    // This method is called during application bootstrapping
 
    // Add "iframe" context
    $iframeContext = array(
        'suffix'    => 'iframe',
        'callbacks' => array(
            'post' => array(__CLASS__, 'setLayoutContext')
        )
    );
 
    $contextSwitch = Zend_Controller_Action_HelperBroker::getStaticHelper('ContextSwitch');
 
    $contextSwitch->addContext('iframe', $iframeContext);
}

Ok, that’s all the preparation work out of the way. To add this context to a controller action, you simply, well, add it.

class MyController extends Zend_Controller_Action
{
    public function init()
    {
        $this->_helper->contextSwitch->addActionContext('config', 'iframe')
                                     ->setAutoDisableLayout(false)
                                     ->initContext();
    }
 
    public function configAction()
    {
        // Controller tasks here
    }
}

All that’s left to do is ensure your links to the context enabled controller action include the correct format parameter, for example /my/config/format/iframe or /my/config?format=iframe.

One thing I’ve noticed is that the ContextSwitch helper should be configured after your view and layout are initialised.

Thanks to Jeff Carouth for the inspiration for this post.