Quickie: Module-specific Error Controllers in Zend Framework (1.5)

In my quest to do some alterations on ZF error handling (in particular, render the view if the action or controller is not found, makes it real easy for my designer to prototype) I had the desire to be able to allow modules to have their own ErrorControllers. Unfortunately, the Zend_Controller_Plugin_ErrorHandler() default does not allow for this and I didn’t really want to extend that class (I planned on handling the rendering in the ErrorControllers) so I wrote up a quick plugin. Doing random stuff like this has really helped me get to know the Zend Framework (I was developing my own internal framework architectured somewhat similarly that I have abandoned due to time constraints and the large community behind ZF).

The plugin hooks into the routeShutdown as this is the first place I have access to the ZF-determined module name. I need the current module name to make sure I override the ErrorHandler’s module, and while I could determine that for myself, problems would arise if I decided to start overriding the routers and URL structure.

<?php
class MyApp_ControllerPlugin_ErrorControllerSelector extends Zend_Controller_Plugin_Abstract
{
	public function routeShutdown(Zend_Controller_Request_Abstract $request)
	{
		$front = Zend_Controller_Front::getInstance();

		//If the ErrorHandler plugin is not registered, bail out
		if( !($front->getPlugin('Zend_Controller_Plugin_ErrorHandler') instanceOf Zend_Controller_Plugin_ErrorHandler) )
			return;

		$error = $front->getPlugin('Zend_Controller_Plugin_ErrorHandler');

		//Generate a test request to use to determine if the error controller in our module exists
		$testRequest = new Zend_Controller_Request_HTTP();
		$testRequest->setModuleName($request->getModuleName())
		            ->setControllerName($error->getErrorHandlerController())
		            ->setActionName($error->getErrorHandlerAction());

		//Does the controller even exist?
		if( $front->getDispatcher()->isDispatchable($testRequest) )
		{
			$error->setErrorHandlerModule($request->getModuleName());
		}
	}
}

$front = Zend_Controller_Front::getInstance();
$front->registerPlugin( new MyApp_ControllerPlugin_ErrorControllerSelector() );
?>

You’ll notice I generated a Zend_Controller_Request_HTTP() object and filled it with the ErrorController’s set controller name and action name (again if I decided to change how the error controllers are named, this plug in will still work) then use the dispatcher to check if this controller exists (basically, can we dispatch this controller’s action from this module). If so, go ahead and set the ErrorHandler’s module name to the current module name.

I’ll bring more later once I finish making the Zend Framework my bitch.

Comments

  1. Cel says:

    Is perfect!! :)

  2. Keith Miller says:

    Your post was incredibly helpful! Thanks!

  3. Edson Hilios says:

    Man I love you! really, that was the only thing that was missing in my CMS.

    Thanks a lot!

  4. Edson Hilios says:

    Wowww I love you man, that was the only thing that was missing on my CMS system, thank you

  5. D3N says:

    Oh man das hab ich gesucht :)
    Thank you, wunderful plugin

  6. Joe Devon says:

    Could have used this in the past; bookmarked for the future ;) Good job.

  7. Jeremy Hoke says:

    Worked perfectly – thanks for this, exactly what I was looking for.

  8. Leandro says:

    My solution:

    application/Bootstrap.php: _initAutoLoad()
    {…}
    $modules = explode(‘/’,$_SERVER['REQUEST_URI']);

    //Seta os modulos que fazem parte do sistema
    $iterator = new DirectoryIterator( APPLICATION_PATH . ‘/your_name_module’);
    foreach ($iterator as $fileinfo) {
    if ($fileinfo->isDir() && $fileinfo->getFilename()!=’.’ && $fileinfo->getFilename()!=’..’) {
    $directories[$fileinfo->getFilename()] = APPLICATION_PATH . DIRECTORY_SEPARATOR . ‘your_name_module’ . DIRECTORY_SEPARATOR . $fileinfo->getFilename() . DIRECTORY_SEPARATOR . ‘controllers’;
    }
    }

    //Se nao existir modulo, o modulo padrao é assumido
    //senao pega o valor que esta chegando e seta como modulo
    if(!array_key_exists($modules[1], $directories))
    {
    $module = DEFAULT_MODULE;
    } else {
    $module = $modules[1];
    }
    $front = Zend_Controller_Front::getInstance();
    $front->setControllerDirectory($directories);
    $front->setParam(‘module_request’,$module);

    application/Bootstrap.php: _initError()

    $front = Zend_Controller_Front::getInstance();
    $plugin = new Zend_Controller_Plugin_ErrorHandler();
    $plugin->setErrorHandlerModule($front->getParam(‘module_request’))
    ->setErrorHandlerController(‘error’)
    ->setErrorHandlerAction(‘error’);
    $front->registerPlugin($plugin);

  9. alex says:

    Good Job! Great Article – that fits my needs exactly!

    But..one thing
    use new Zend_Controller_Request_Http() instead of new Zend_Controller_Request_HTTP()

    on linux systems it won’t work cause of caseSensitive ;)

    Thanks for this article!

  10. Bungee says:

    Thank you !

  11. Rafael Dohms says:

    Thanks dude, just saved me a few minutes of senseless coding! I owe you a beer at #tek11.

  12. Ben Crosthwaite says:

    Brilliant, thanks very much

  1. [...] a work around online (credit to Daniel Cousineau). Apparently the ZF does not allow for multiple error controllers by default – God knows why not – [...]

  2. [...] the help of Daniel Cousineau’s Blog Post I was able to come up with the following Layout [...]

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>