web/lib/Zend/Controller/Plugin/ErrorHandler.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     7  * This source file is subject to the new BSD license that is bundled
       
     8  * with this package in the file LICENSE.txt.
       
     9  * It is also available through the world-wide-web at this URL:
       
    10  * http://framework.zend.com/license/new-bsd
       
    11  * If you did not receive a copy of the license and are unable to
       
    12  * obtain it through the world-wide-web, please send an email
       
    13  * to license@zend.com so we can send you a copy immediately.
       
    14  *
       
    15  * @category   Zend
       
    16  * @package    Zend_Controller
       
    17  * @subpackage Plugins
       
    18  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    19  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    20  */
       
    21 
       
    22 /** Zend_Controller_Plugin_Abstract */
       
    23 require_once 'Zend/Controller/Plugin/Abstract.php';
       
    24 
       
    25 /**
       
    26  * Handle exceptions that bubble up based on missing controllers, actions, or
       
    27  * application errors, and forward to an error handler.
       
    28  *
       
    29  * @uses       Zend_Controller_Plugin_Abstract
       
    30  * @category   Zend
       
    31  * @package    Zend_Controller
       
    32  * @subpackage Plugins
       
    33  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    34  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    35  * @version    $Id: ErrorHandler.php 20246 2010-01-12 21:36:08Z dasprid $
       
    36  */
       
    37 class Zend_Controller_Plugin_ErrorHandler extends Zend_Controller_Plugin_Abstract
       
    38 {
       
    39     /**
       
    40      * Const - No controller exception; controller does not exist
       
    41      */
       
    42     const EXCEPTION_NO_CONTROLLER = 'EXCEPTION_NO_CONTROLLER';
       
    43 
       
    44     /**
       
    45      * Const - No action exception; controller exists, but action does not
       
    46      */
       
    47     const EXCEPTION_NO_ACTION = 'EXCEPTION_NO_ACTION';
       
    48 
       
    49     /**
       
    50      * Const - No route exception; no routing was possible
       
    51      */
       
    52     const EXCEPTION_NO_ROUTE = 'EXCEPTION_NO_ROUTE';
       
    53 
       
    54     /**
       
    55      * Const - Other Exception; exceptions thrown by application controllers
       
    56      */
       
    57     const EXCEPTION_OTHER = 'EXCEPTION_OTHER';
       
    58 
       
    59     /**
       
    60      * Module to use for errors; defaults to default module in dispatcher
       
    61      * @var string
       
    62      */
       
    63     protected $_errorModule;
       
    64 
       
    65     /**
       
    66      * Controller to use for errors; defaults to 'error'
       
    67      * @var string
       
    68      */
       
    69     protected $_errorController = 'error';
       
    70 
       
    71     /**
       
    72      * Action to use for errors; defaults to 'error'
       
    73      * @var string
       
    74      */
       
    75     protected $_errorAction = 'error';
       
    76 
       
    77     /**
       
    78      * Flag; are we already inside the error handler loop?
       
    79      * @var bool
       
    80      */
       
    81     protected $_isInsideErrorHandlerLoop = false;
       
    82 
       
    83     /**
       
    84      * Exception count logged at first invocation of plugin
       
    85      * @var int
       
    86      */
       
    87     protected $_exceptionCountAtFirstEncounter = 0;
       
    88 
       
    89     /**
       
    90      * Constructor
       
    91      *
       
    92      * Options may include:
       
    93      * - module
       
    94      * - controller
       
    95      * - action
       
    96      *
       
    97      * @param  Array $options
       
    98      * @return void
       
    99      */
       
   100     public function __construct(Array $options = array())
       
   101     {
       
   102         $this->setErrorHandler($options);
       
   103     }
       
   104 
       
   105     /**
       
   106      * setErrorHandler() - setup the error handling options
       
   107      *
       
   108      * @param  array $options
       
   109      * @return Zend_Controller_Plugin_ErrorHandler
       
   110      */
       
   111     public function setErrorHandler(Array $options = array())
       
   112     {
       
   113         if (isset($options['module'])) {
       
   114             $this->setErrorHandlerModule($options['module']);
       
   115         }
       
   116         if (isset($options['controller'])) {
       
   117             $this->setErrorHandlerController($options['controller']);
       
   118         }
       
   119         if (isset($options['action'])) {
       
   120             $this->setErrorHandlerAction($options['action']);
       
   121         }
       
   122         return $this;
       
   123     }
       
   124 
       
   125     /**
       
   126      * Set the module name for the error handler
       
   127      *
       
   128      * @param  string $module
       
   129      * @return Zend_Controller_Plugin_ErrorHandler
       
   130      */
       
   131     public function setErrorHandlerModule($module)
       
   132     {
       
   133         $this->_errorModule = (string) $module;
       
   134         return $this;
       
   135     }
       
   136 
       
   137     /**
       
   138      * Retrieve the current error handler module
       
   139      *
       
   140      * @return string
       
   141      */
       
   142     public function getErrorHandlerModule()
       
   143     {
       
   144         if (null === $this->_errorModule) {
       
   145             $this->_errorModule = Zend_Controller_Front::getInstance()->getDispatcher()->getDefaultModule();
       
   146         }
       
   147         return $this->_errorModule;
       
   148     }
       
   149 
       
   150     /**
       
   151      * Set the controller name for the error handler
       
   152      *
       
   153      * @param  string $controller
       
   154      * @return Zend_Controller_Plugin_ErrorHandler
       
   155      */
       
   156     public function setErrorHandlerController($controller)
       
   157     {
       
   158         $this->_errorController = (string) $controller;
       
   159         return $this;
       
   160     }
       
   161 
       
   162     /**
       
   163      * Retrieve the current error handler controller
       
   164      *
       
   165      * @return string
       
   166      */
       
   167     public function getErrorHandlerController()
       
   168     {
       
   169         return $this->_errorController;
       
   170     }
       
   171 
       
   172     /**
       
   173      * Set the action name for the error handler
       
   174      *
       
   175      * @param  string $action
       
   176      * @return Zend_Controller_Plugin_ErrorHandler
       
   177      */
       
   178     public function setErrorHandlerAction($action)
       
   179     {
       
   180         $this->_errorAction = (string) $action;
       
   181         return $this;
       
   182     }
       
   183 
       
   184     /**
       
   185      * Retrieve the current error handler action
       
   186      *
       
   187      * @return string
       
   188      */
       
   189     public function getErrorHandlerAction()
       
   190     {
       
   191         return $this->_errorAction;
       
   192     }
       
   193 
       
   194     /**
       
   195      * Route shutdown hook -- Ccheck for router exceptions
       
   196      * 
       
   197      * @param Zend_Controller_Request_Abstract $request 
       
   198      */
       
   199     public function routeShutdown(Zend_Controller_Request_Abstract $request)
       
   200     {
       
   201         $this->_handleError($request);
       
   202     }
       
   203 
       
   204     /**
       
   205      * Post dispatch hook -- check for exceptions and dispatch error handler if
       
   206      * necessary
       
   207      *
       
   208      * @param Zend_Controller_Request_Abstract $request
       
   209      */
       
   210     public function postDispatch(Zend_Controller_Request_Abstract $request)
       
   211     {
       
   212         $this->_handleError($request);
       
   213     }
       
   214 
       
   215     /**
       
   216      * Handle errors and exceptions
       
   217      *
       
   218      * If the 'noErrorHandler' front controller flag has been set,
       
   219      * returns early.
       
   220      *
       
   221      * @param  Zend_Controller_Request_Abstract $request
       
   222      * @return void
       
   223      */
       
   224     protected function _handleError(Zend_Controller_Request_Abstract $request)
       
   225     {
       
   226         $frontController = Zend_Controller_Front::getInstance();
       
   227         if ($frontController->getParam('noErrorHandler')) {
       
   228             return;
       
   229         }
       
   230 
       
   231         $response = $this->getResponse();
       
   232 
       
   233         if ($this->_isInsideErrorHandlerLoop) {
       
   234             $exceptions = $response->getException();
       
   235             if (count($exceptions) > $this->_exceptionCountAtFirstEncounter) {
       
   236                 // Exception thrown by error handler; tell the front controller to throw it
       
   237                 $frontController->throwExceptions(true);
       
   238                 throw array_pop($exceptions);
       
   239             }
       
   240         }
       
   241 
       
   242         // check for an exception AND allow the error handler controller the option to forward
       
   243         if (($response->isException()) && (!$this->_isInsideErrorHandlerLoop)) {
       
   244             $this->_isInsideErrorHandlerLoop = true;
       
   245 
       
   246             // Get exception information
       
   247             $error            = new ArrayObject(array(), ArrayObject::ARRAY_AS_PROPS);
       
   248             $exceptions       = $response->getException();
       
   249             $exception        = $exceptions[0];
       
   250             $exceptionType    = get_class($exception);
       
   251             $error->exception = $exception;
       
   252             switch ($exceptionType) {
       
   253                 case 'Zend_Controller_Router_Exception':
       
   254                     if (404 == $exception->getCode()) {
       
   255                         $error->type = self::EXCEPTION_NO_ROUTE;
       
   256                     } else {
       
   257                         $error->type = self::EXCEPTION_OTHER;
       
   258                     }
       
   259                     break;
       
   260                 case 'Zend_Controller_Dispatcher_Exception':
       
   261                     $error->type = self::EXCEPTION_NO_CONTROLLER;
       
   262                     break;
       
   263                 case 'Zend_Controller_Action_Exception':
       
   264                     if (404 == $exception->getCode()) {
       
   265                         $error->type = self::EXCEPTION_NO_ACTION;
       
   266                     } else {
       
   267                         $error->type = self::EXCEPTION_OTHER;
       
   268                     }
       
   269                     break;
       
   270                 default:
       
   271                     $error->type = self::EXCEPTION_OTHER;
       
   272                     break;
       
   273             }
       
   274 
       
   275             // Keep a copy of the original request
       
   276             $error->request = clone $request;
       
   277 
       
   278             // get a count of the number of exceptions encountered
       
   279             $this->_exceptionCountAtFirstEncounter = count($exceptions);
       
   280 
       
   281             // Forward to the error handler
       
   282             $request->setParam('error_handler', $error)
       
   283                     ->setModuleName($this->getErrorHandlerModule())
       
   284                     ->setControllerName($this->getErrorHandlerController())
       
   285                     ->setActionName($this->getErrorHandlerAction())
       
   286                     ->setDispatched(false);
       
   287         }
       
   288     }
       
   289 }