Jake N
Jake N

Reputation: 10583

Set a different errorhandler depending on module - Zend Framework

I have a few modules, one is an API. I want to set a different ErrorHandler for this API module.

Because when the default ErrorHandler is fired it uses the default module with the default layout, which contains HTML. Which is something I do not want my API to be returning.

I have looked on here and at the Zend Docs and have not come up with anything that allows me to do this.

Thanks for any help.

Upvotes: 0

Views: 3178

Answers (3)

Robb
Robb

Reputation: 417

@takeshin: Thank you for sharing your plugin, this is great! And just the thing I was looking for on the google machine.

I made some changes, respectfully, to the logic that determines the request to be an "error request," since I found that the full plugin callback was running on every request, regardless of whether or not an error had occured.

I just changed the plugin hook to "postDispatch" and tested that an exception had actually occurred during dispatch. The rest of the code functions exactly the same as yours.

Now, you can put a die statement in the middle of the plugin, and you will only see it after an exception has occurred during the request.

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

        // true if response has any exception
        $isError = $front->getResponse()->hasExceptionOfType('Exception');

        // if there was no error during dispatch
        if (!$isError) {
            return false;
        }

        // standard error handler plugin class name
        $errorHandlerClass = 'Zend_Controller_Plugin_ErrorHandler';

        // if the error handler plugin is not registered, do not continue.
        if (!$front->hasPlugin($errorHandlerClass)) {
            return false;
        }

        $plugin = $front->getPlugin($errorHandlerClass);

        // the module that was requested and threw error
        $module = $request->getModuleName();

        // the controller & action name that error handler will dispatch
        $errorController = $plugin->getErrorHandlerController();
        $errorAction = $plugin->getErrorHandlerAction();

        // create a dummy request to test for dispatchablility
        $testRequest = new Zend_Controller_Request_Http();
        $testRequest->setModuleName($module)
            ->setControllerName($errorController)
            ->setActionName($errorAction);

        // verify that the current module has defined an ErrorController::errorAction
        if ($front->getDispatcher()->isDispatchable($testRequest)) {
            // tell error controller plugin to use the module's error controller
            $plugin->setErrorHandlerModule($module);
        } else {
            return false;
        }

        return true;
    }
}

Upvotes: 1

takeshin
takeshin

Reputation: 50658

Here is the one I use:

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

        // Front controller has error handler plugin
        // if the request is an error request.
        // If the error handler plugin is not registered,
        // we will be unable which MCA to run, so do not continue.
        $errorHandlerClass = 'Zend_Controller_Plugin_ErrorHandler';
        if (!$front->hasPlugin($errorHandlerClass)) {

            return false;
        }

        // Determine new error controller module_ErrorController_ErrorAction
        $plugin = $front->getPlugin($errorHandlerClass);
        $errorController = $plugin->getErrorHandlerController();
        $errorAaction = $plugin->getErrorHandlerAction();
        $module = $request->getModuleName();

        // Create test request module_ErrorController_ErrorAction...
        $testRequest = new Zend_Controller_Request_Http();
        $testRequest->setModuleName($module)
            ->setControllerName($errorController)
            ->setActionName($errorAaction);

        // Set new error controller if available
        if ($front->getDispatcher()->isDispatchable($testRequest)) {
            $plugin->setErrorHandlerModule($module);
        } else {

            return false;
        }

        return true;
    }
}

(BTW, This issue already was discussed here, look carefully.)

Upvotes: 4

smack0007
smack0007

Reputation: 11356

Just off the top of my head, you could store a copy of the original request object in the registry from a controller plugin. In the preDispatch() of your controller you could then forward to another error controller based on the requested module.

// Plugin
public function routeStartup(Zend_Controller_Request_Abstract $request)
{
    $clonedRequest = clone $request;
    Zend_Registry::set('originalRequest', $clonedRequest);
}

// ErrorController
public function preDispatch()
{
    $request = Zend_Registry::get('originalRequest');
    $this->_forward('error', 'error', $request->getModuleName());
}

Upvotes: 0

Related Questions