Excepciones MVCIntroducción
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.
Manejando las Excepciones
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
perdidasErrores 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:
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()
y
Zend_Controller_Response_Abstract::isException()
.
Pasando un valor booleano
TRUE
a
Zend_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étodo
isException()
, y recuperando
las excepciones a través del método
getException()
. Como ejemplo:
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.
Excepciones MVC que Usted Pueda Encontrar
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: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 una
Zend_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á una
Zend_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:
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étodo
getAction()
para
verificar si la acción existe. Como ejemplo:
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()
o
Zend_Controller_Plugin_Abstract::preDispatch()
para identificar acciones inválidas.
Subclaseando
Zend_Controller_Action
y
modificando
preDispatch()
,
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: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.