Skip to end of metadata
Go to start of metadata

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

Zend Framework: Zend_Controller_Plugin_ErrorHandler Component Proposal

Proposed Component Name Zend_Controller_Plugin_ErrorHandler
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/Zend_Controller_Plugin_ErrorHandler
Proposers Ralph Schindler
Revision 1.1 - 29 April 2007 (wiki revision: 10)

Table of Contents

1. Overview

This component is an option easy to use error handler. Only available to ZF > 9.2 since postDispatch() hooks can now run even after an action controller exception.

2. References

3. Component Requirements, Constraints, and Acceptance Criteria

Simple component, see code below.

4. Dependencies on Other Framework Components

  • Zend_Exception

5. Theory of Operation

6. Milestones / Tasks

7. Class Index

8. Use Cases

UC-01

9. Class Skeletons

]]></ac:plain-text-body></ac:macro>

]]></ac:plain-text-body></ac:macro>

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Apr 29, 2007

    <p>I think including something like this by default will greatly simplify the lives of community members--a one-line solution rather than repeatedly pasting code or directing people to URLs. It could be included in the documentation to preemptively catch this kind of case.</p>

    <p>Some small typos in your use cases, Ralph:</p>

    <blockquote><p>DVLabs_Controller_Plugin_ErrorHandler()</p></blockquote>

    <p>and</p>

    <blockquote><p>class ErrorController extends Zend_Controller_Action</p></blockquote>

  2. Apr 29, 2007

    <p>Matthew,<br />
    I fixed the copy/paste error i had, as well as combined the code into UC1 as its really just a single use case.. again, bad copy paste <ac:emoticon ac:name="wink" /></p>

    <p>Thanks for the input.. I think this optional component does indeed simplify the lives of people looking for an out-of-the-box solution whereas all they need to do is write an error controller, which arguably is part of the stack of components needed in error/exception handling anyway.</p>

    1. Apr 30, 2007

      <p>Oh, it looks like I was confused about the purpose of the <code>ErrorController</code>. <ac:emoticon ac:name="smile" /></p>

  3. Apr 29, 2007

    <p>Hi Ralph</p>

    <p>Indeed, it would make life a lot easier.</p>

    <p>The only real issue I have with the constants is that it seems to add more complexity/abstraction to the error handling. If an exception of type 'Zend_Controller_Dispatcher_Exception' has been thrown, then why not use that in the switch case of the error handler?</p>

    <p>Could I suggest that the exception is passed to the error handler, and then in the preDispatch() method of the ErrorController that the pre-processing is done? E.g.</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    class ErrorController extends Zend_Controller_Action
    {
    public function preDispatch()
    {
    $request = $this->getRequest();
    $error = $request->getParam('error');
    switch (get_class($error))

    Unknown macro: { case 'Zend_Controller_Dispatcher_Exception'}


    }

    public function notfoundAction()

    Unknown macro: { // Page not found error }

    public function applicationAction()

    Unknown macro: { // Application error }

    }
    ]]></ac:plain-text-body></ac:macro>

    <p>The advantage in this would be that application/logic errors can also be handled here as well as routing errors (privilege errors, timeout errors, etc...) without too much trouble and no subclassing needed.</p>

  4. Apr 30, 2007

    <p>Hey Simon,<br />
    Your above code is indeed possible as is.. One of the conveniences of this proposal is that the topmost exception in the stack is returned by defining it as a request parameter 'error_exception'.</p>

    <p>My only argument for the abstraction is that currently, if you use Zend_Controller out the box, there is a good chance that you will never actually see a class with the name 'Dispatcher' in it. That being said, by throwing Zend_Controller_Dispatcher_Exception, we are implying that users must know whats going on inside the controller.</p>

    <p>This layer of simple abstraction creates a facade for those who wish not to know whats really going on under the hood, but allows them to concentrate on the two most common exceptions that might be thrown from the controller stack.</p>

    <p>But like I said, you can do it either way <ac:emoticon ac:name="wink" /></p>

    <p>Thoughts?<br />
    -Ralph</p>

    <p>BTW, I really do like your way of handling the ErrorController in the Users Action Controller by modifying the request in preDispatch(), I dont use that hook nearly enough. Thanks.</p>

    1. May 02, 2007

      <p>I don't see that exposing developers to this kind of exception is a bad thing. But then again I'm also mindful that simplicity is also to be encouraged... Ouch, you get splinters sitting on the fence! LOL. Anyway, I'm sticking with using exceptions as-is for the sake of less 'overhead'.</p>

      <p>BTW, the preDispatch() method is a no-go. I just tried it in development on a site and it ended in an infinite loop. I'll have to work out why, but using the init() method ends up being just as good.</p>

  5. May 01, 2007

    <p>I have tried this but if you use a bad controller name the handler is not called as postDispatch is not called in this case but dispatchLoopShutdown() is.</p>

  6. May 01, 2007

    <p>Douglas, what version of the Zend Framework are you using? If you are not using the absolute most recent .9.2 (i think) then this will not work. This type of error handler was only possible since the change Matthew made to the dispatcher that allows postDispatch() to be notified even if an exception was thrown elsewhere. (see the first note in overview)</p>

    <p>dispatchLoopShutdown() does not give you the opportunity to forward to new actions, which is exactly why I pushed to allow postDispatch() notifications to happen even when exceptions where thrown elsewhere... so we could have an error handler like this <ac:emoticon ac:name="smile" /></p>

    <p>-ralph</p>

  7. May 08, 2007

    <p>I have updated the above code to account for missing error handlers. After it reaches three passes of the loop after being non-dispatchable (file exists, but no action), then it will turn exceptions on and throw a major exception.</p>

    <p>I have this code in a working environment.</p>

    <p>In the example error handler, APPLICTION_STATE is something that is defined in my bootstrap file. It gets set by the SetEnv apache directive. This allows me to be able to deploy the same exact code setup from development to production, where the production machine does not have the</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    SetEnv APPLICTION_STATE development
    ]]></ac:plain-text-body></ac:macro>

    <p>and in my bootstrap:</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    // STATE OF APPLICATION
    define('APPLICATION_STATE', (getenv('APPLICATION_STATE') == 'development') ? 'development' : 'production');

    /* ... */
    // sample config setup:

    $config = new Zend_Config(new Zend_Config_Ini('../application/config/config.ini', APPLICATION_STATE));

    ]]></ac:plain-text-body></ac:macro>

    <p>Those are some pointers from how I do things.</p>

  8. May 08, 2007

    <ul>
    <li>APPLICATION_STATE is misspelled in part of the example.</li>
    </ul>

  9. May 15, 2007

    <ac:macro ac:name="unmigrated-wiki-markup"><ac:plain-text-body><![CDATA[

    Unknown macro: {note title="Zend Framework Comments}

    This proposal is accepted for incubator development. We strongly urge testing and documenting this plugin thoroughly prior to the 1.0.0RC1 release so that it may be included in the standard 1.0.0 distribution.

    Matthew (Zend team) will assist in preparing this for inclusion.

    ]]></ac:plain-text-body></ac:macro>

  10. May 15, 2007

    <p>I would like to bring to the attention that the code from proposal is not compatible with the applications that do not use modules.</p>

    <p>First problem is that in ErrorHandler::postDispatch() the $request->setModuleName($this->_errorModule) method gets called even if not using modules.</p>

    <p>The other, dependent on the previous is that if calling, for example: <a class="external-link" href="http://application/controller/nonExistantAction/">http://application/controller/nonExistantAction/</a><br />
    the ErrorHandler class checks for the $exceptionType but the exception returned by the response object for nonexistant action when not using modules is "Zend_Controller_Exception" and not the "Zend_Controller_Action_Exception" as is expected by ErrorHandler.</p>

    <p>This results in all non existing actions generating EXCEPTION_OTHER which is erroneous in my opinion.</p>

    1. May 16, 2007

      <p>Evidently a change I'd made to __call() to throw Zend_Controller_Action_Exception did not merge. I've updated the code in r4817 to do so.</p>

      <p>Thanks for the report!</p>

  11. May 15, 2007

    <p>I see a few problems with this plugin.</p>

    <p>As I understand the current dispatch process, any exception thrown in routeStartup, routeShutdown, dispatchLoopStartup, preDispatch will not be caught with this plugin. Only exceptions from within the action controller will be processed. If an exception is thrown in postDispatch, in a plugin that is executed before ErrorHandler, then ErrorHandler won't run. </p>

    <p>I've accomplished a similar exception handler using dispatchLoopShutdown. I examine the top most exception and redirect based on that. If there are any 500 level exceptions they are emailed to staff and logged. I then wrap $frontController->dispatch() in a try block in my bootstrap for dispatchLoopShutdown exceptions. </p>

    <p>Can we extend this proposal to support catching exceptions from routeStartup through postDispatch?</p>

    <p>Can this plugin support </p>

    1. May 16, 2007

      <p>As I wrote on the fw-mvc list:</p>

      <p>Not in this iteration.</p>

      <p>The specific errors/exceptions this plugin was intended to catch were:</p>

      <ul>
      <li>Inability to dispatch a request (missing controller or action)</li>
      <li>Application errors (within action controllers)</li>
      </ul>

      <p>These situations basically indicate that a recoverable error occurred, and content should be displayed to the user still; the dispatch process is still intact and may continue.</p>

      <p>In the situations you describe, the errors actually <strong>break</strong> the dispatch process, and the only way to recover gracefully is to redirect or throw back static content to the user.</p>

      <p>I'm not averse to adding a dispatchLoopShutdown() segment to this plugin, but feel that this needs a lot of additional thought. There are several actions such a plugin could trigger:</p>

      <ul>
      <li>Log the exception</li>
      <li>Mail a report to an administrator</li>
      <li>Send an SMS to an administrator</li>
      </ul>

      <p>and after one or more of the above actions has been performed, we still need to<br />
      get something to the user:</p>

      <ul>
      <li>Do we provide a static page?</li>
      <li>Do we redirect to a known good error page?</li>
      <li>Do we simply display the exception?</li>
      <li>Do we redispatch the front controller?</li>
      </ul>

      <p>These are very different questions than the ErrorHandler plugin proposal set out to address. </p>

      <p>I'd suggest creating a new proposal to either extend the ErrorHandler, or create a new plugin, to address these issues. However, work on it will not begin until post-1.0.0.</p>