Los componentes MVC en Zend Framework utilizan un Front Controller, lo que significa que todas las solicitudes de un determinado sitio pasarán por un solo punto de entrada. Como resultado, todas las excepciones burbujearán eventualmente hacia arriba hasta el Front Controller, permitiendo al desarrollador manejarlos en un solo lugar.
Sin embargo, los mensajes de excepción y la información de
backtrace contienen a menudo
información sensible del sistema, como
declaraciones
SQL
, ubicaciones de archivos y
otras cosas más. Para ayudar a proteger su sitio, por defecto
Zend_Controller_Front
captura todas las
excepciones y las registra con el objeto respuesta; a su vez, y por
defecto, el objeto respuesta no muestra mensajes de excepción.
Ya hay varios mecanismos construidos en los componentes de MVC , que le permiten manejar excepciones.
-
Por defecto, el error handler plugin está registrado y activo. Este plugin fue diseñado para manejar:
-
Errores debido a controladores o acciones perdidas
-
Errores ocurriendo dentro de controladores de acción
Operan como un plugin de
postDispatch()
, y comprueban para ver si un despachador, controlador de acción, o de otra excepción ha ocurrido. Si así fuera, lo remite a un controlador de manejo de errores.Este manejador abarcará la mayoría de las situaciones excepcionales, y maneja airosamente controladores y acciones perdidos.
-
-
Zend_Controller_Front::throwExceptions()
Pasando a este método un valor booleano
TRUE
, puede decirle al front controller que, en lugar de sumar excepciones en el objeto respuesta o utilizando el plugin de manejo de errores, prefiere manejarlos usted mismo. Como ejemplo:$front->throwExceptions(true); try { $front->dispatch(); } catch (Exception $e) { // usted mismo maneja las excepciones }
Este método es probablemente la forma más fácil de añadir un manejo de excepciones personalizado que abarque toda la gama de posibles excepciones a su aplicación de front controller.
-
Zend_Controller_Response_Abstract::renderExceptions()
Al pasar a este método un valor booleano
TRUE
, le esta diciendo al objeto respuesta que debe emitir un mensaje de excepción y backtrace cuando se renderiza a sí mismo. En este escenario, se mostrará cualquier excepción planteada por su aplicación. Esto no es recomendable para entornos de producción, pero sí en desarrollo. -
Zend_Controller_Front::returnResponse()
yZend_Controller_Response_Abstract::isException()
.Pasando un valor booleano
TRUE
aZend_Controller_Front::returnResponse()
,Zend_Controller_Front::dispatch()
no renderizará la respuesta, sino que la devolverá. Una vez que tiene la respuesta, entonces puede probar ver si todas las excepciones fueron atrapadas usando su métodoisException()
, y recuperando las excepciones a través del métodogetException()
. Como ejemplo:$front->returnResponse(true); $response = $front->dispatch(); if ($response->isException()) { $exceptions = $response->getException(); // maneje las excepciones ... } else { $response->sendHeaders(); $response->outputBody(); }
La principal ventaja que este método ofrece por sobre
Zend_Controller_Front::throwExceptions()
es que le permite renderizar condicionalmente la respuesta después de manejar la excepción. Esta capturará cualquier excepción en la cadena de controladores, a diferencia del plugin de manejo de errores.
Los diversos componentes de MVC -- solicitud, router, despachador, controlador de acción, y los objetos respuesta -- pueden arrojar excepciones en ocasiones. Algunas excepciones puede ser condicionalmente anuladas, y otras se usan para indicar al desarrollador que puede necesitar re-considerar la estructura de su aplicación.
Como algunos ejemplos:
-
Zend_Controller_Dispatcher::dispatch()
hará, por defecto, arrojar una excepción si se hace un requerimiento a un controlador no válido. Hay dos maneras recomendadas para lidiar con esto.-
Establecer el parámetro useDefaultControllerAlways .
En su front controller, o en su despachador, añada la siguiente directiva:
$front->setParam('useDefaultControllerAlways', true); // o $dispatcher->setParam('useDefaultControllerAlways', true);
Cuando este flag está establecido, el despachador utilizará el controlador y la acción por defecto en lugar de lanzar una excepción. La desventaja de este método es que cualquier error ortográfico que un usuario haga cuando acceda a su sitio lo resolverá y mostrará su página de inicio, y que puede causar estragos con la optimización para los motores de búsqueda.
-
La excepción arrojada por
dispatch()
es unaZend_Controller_Dispatcher_Exception
conteniendo el texto 'Invalid controller specified'. Use uno de los métodos descriptos de la sección anterior para atrapar la excepción, y luego redireccionar a una página genérica de error o a la página de inicio.
-
-
Zend_Controller_Action::__call()
arrojará unaZend_Controller_Action_Exception
si no puede despachar una acción inexistente a un método. Es probable que desee utilizar alguna acción por defecto en el controlador en casos como este. Formas de lograr esto incluyen:-
Subclasear
Zend_Controller_Action
y anular el método__call()
. Como ejemplo:class My_Controller_Action extends Zend_Controller_Action { public function __call($method, $args) { if ('Action' == substr($method, -6)) { $controller = $this->getRequest()->getControllerName(); $url = '/' . $controller . '/index'; return $this->_redirect($url); } throw new Exception('Invalid method'); } }
El ejemplo anterior intercepta cualquier llamada a un método de acción indefinido y redirecciona a la acción predeterminada en el controlador.
-
Subclasea a
Zend_Controller_Dispatcher
y anula el métodogetAction()
para verificar si la acción existe. Como ejemplo:class My_Controller_Dispatcher extends Zend_Controller_Dispatcher { public function getAction($request) { $action = $request->getActionName(); if (empty($action)) { $action = $this->getDefaultAction(); $request->setActionName($action); $action = $this->formatActionName($action); } else { $controller = $this->getController(); $action = $this->formatActionName($action); if (!method_exists($controller, $action)) { $action = $this->getDefaultAction(); $request->setActionName($action); $action = $this->formatActionName($action); } } return $action; } }
El código anterior comprueba para ver que las acciones solicitadas existan en la clase del controlador; si no, se restablece la acción a la acción por defecto.
Este método es agradable porque puede alterar transparentemente la acción antes del último despacho. Sin embargo, también significa que errores ortográficos en la URL todavía pueden despacharse correctamente, lo que no es muy bueno para la optimización en un motor de búsqueda.
-
Use
Zend_Controller_Action::preDispatch()
oZend_Controller_Plugin_Abstract::preDispatch()
para identificar acciones inválidas.Subclaseando
Zend_Controller_Action
y modificandopreDispatch()
, puede modificar todos sus controladores que transmitan a otra acción o redireccionar antes de despachar la acción. El código para hacer esto se verá parecido al código de sustitución de arriba__call()
.Alternativamente, puede verificar esta información en un plugin global. Esto tiene la ventaja de ser independiente del controlador de acción; si su aplicación consiste en una variedad de controladores de acción, y no todos ellos heredan de la misma clase, este método puede añadir coherencia a su manejo de clases diferentes.
Como ejemplo:
class My_Controller_PreDispatchPlugin extends Zend_Controller_Plugin_Abstract { public function preDispatch(Zend_Controller_Request_Abstract $request) { $front = Zend_Controller_Front::getInstance(); $dispatcher = $front->getDispatcher(); $class = $dispatcher->getControllerClass($request); if (!$controller) { $class = $dispatcher->getDefaultControllerClass($request); } $r = new ReflectionClass($class); $action = $dispatcher->getActionMethod($request); if (!$r->hasMethod($action)) { $defaultAction = $dispatcher->getDefaultAction(); $controllerName = $request->getControllerName(); $response = $front->getResponse(); $response->setRedirect('/' . $controllerName . '/' . $defaultAction); $response->sendHeaders(); exit; } } }
En este ejemplo, vamos a consultar para ver si la acción solicitada está disponible en el controlador. Si no, redireccionamos a la acción predeterminada en el controlador, y salimos inmediatamente de la ejecución del script.
-