| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 15103 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.controller.exceptions">
- <title>Excepciones MVC</title>
- <sect2 id="zend.controller.exceptions.introduction">
- <title>Introducción</title>
- <para>
- 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.
- </para>
- <para>
- 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
- <classname>Zend_Controller_Front</classname> 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.
- </para>
- </sect2>
- <sect2 id="zend.controller.exceptions.handling">
- <title>Manejando las Excepciones</title>
- <para>
- Ya hay varios mecanismos construidos en los componentes de MVC,
- que le permiten manejar excepciones.
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Por defecto, el <link
- linkend="zend.controller.plugins.standard.errorhandler">error
- handler plugin</link> está registrado y activo.
- Este plugin fue diseñado para manejar:
- </para>
- <itemizedlist>
- <listitem><para>Errores debido a controladores o acciones perdidas</para></listitem>
- <listitem><para>Errores ocurriendo dentro de controladores de acción</para></listitem>
- </itemizedlist>
- <para>
- Operan como un plugin de <methodname>postDispatch()</methodname>,
- 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.
- </para>
- <para>
- Este manejador abarcará la mayoría de las situaciones
- excepcionales, y maneja airosamente controladores y acciones
- perdidos.
- </para>
- </listitem>
- <listitem>
- <para><classname>Zend_Controller_Front::throwExceptions()</classname></para>
- <para>
- Pasando a este método un valor booleano verdadero,
- 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:
- </para>
- <programlisting language="php"><![CDATA[
- $front->throwExceptions(true);
- try {
- $front->dispatch();
- } catch (Exception $e) {
- // usted mismo maneja las excepciones
- }
- ]]></programlisting>
- <para>
- 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.
- </para>
- </listitem>
- <listitem>
- <para><classname>Zend_Controller_Response_Abstract::renderExceptions()</classname></para>
- <para>
- Al pasar a este método un valor booleano verdadero,
- 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.
- </para>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Controller_Front::returnResponse()</classname> y
- <classname>Zend_Controller_Response_Abstract::isException()</classname>.
- </para>
- <para>
- Pasando un valor booleano verdadero a
- <classname>Zend_Controller_Front::returnResponse()</classname>,
- <classname>Zend_Controller_Front::dispatch()</classname>
- 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
- <methodname>isException()</methodname>, y recuperando las excepciones
- a través del método <methodname>getException()</methodname>.
- Como ejemplo:
- </para>
- <programlisting language="php"><![CDATA[
- $front->returnResponse(true);
- $response = $front->dispatch();
- if ($response->isException()) {
- $exceptions = $response->getException();
- // maneje las excepciones ...
- } else {
- $response->sendHeaders();
- $response->outputBody();
- }
- ]]></programlisting>
- <para>
- La principal ventaja que este método ofrece por sobre
- <classname>Zend_Controller_Front::throwExceptions()</classname>
- 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.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.controller.exceptions.internal">
- <title>Excepciones MVC que Usted Pueda Encontrar</title>
- <para>
- 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.
- </para>
- <para>Como algunos ejemplos:</para>
- <itemizedlist>
- <listitem>
- <para>
- <classname>Zend_Controller_Dispatcher::dispatch()</classname>
- 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.
- </para>
- <itemizedlist>
- <listitem>
- <para>Establecer el parámetro
- <methodname>useDefaultControllerAlways</methodname>.
- </para>
- <para>
- En su front controller, o en su despachador,
- añada la siguiente directiva:
- </para>
- <programlisting language="php"><![CDATA[
- $front->setParam('useDefaultControllerAlways', true);
- // o
- $dispatcher->setParam('useDefaultControllerAlways', true);
- ]]></programlisting>
- <para>
- 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.
- </para>
- </listitem>
- <listitem>
- <para>
- La excepción arrojada por <methodname>dispatch()</methodname> es
- una <classname>Zend_Controller_Dispatcher_Exception</classname>
- conteniendo el texto 'Invalid controller specified'.
- Use uno de los métodos descriptos de <link
- linkend="zend.controller.exceptions.handling">la
- sección anterior</link> para atrapar la
- excepción, y luego redireccionar a una página
- genérica de error o a la página de inicio.
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Controller_Action::__call()</classname>
- arrojará una
- <classname>Zend_Controller_Action_Exception</classname>
- 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:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Subclasear <classname>Zend_Controller_Action</classname> y
- anular el método <methodname>__call()</methodname>.
- Como ejemplo:
- </para>
- <programlisting language="php"><![CDATA[
- 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');
- }
- }
- ]]></programlisting>
- <para>
- El ejemplo anterior intercepta cualquier llamada a
- un método de acción indefinido y redirecciona a la
- acción predeterminada en el controlador.
- </para>
- </listitem>
- <listitem>
- <para>
- Subclasea a <classname>Zend_Controller_Dispatcher</classname>
- y anula el método <methodname>getAction()</methodname>
- para verificar si la acción existe.
- Como ejemplo:
- </para>
- <programlisting language="php"><![CDATA[
- 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;
- }
- }
- ]]></programlisting>
- <para>
- 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.
- </para>
- <para>
- 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.
- </para>
- </listitem>
- <listitem>
- <para>
- Use
- <classname>Zend_Controller_Action::preDispatch()</classname>
- o
- <classname>Zend_Controller_Plugin_Abstract::preDispatch()</classname>
- para identificar acciones inválidas.
- </para>
- <para>
- Subclaseando <classname>Zend_Controller_Action</classname>
- y modificando <methodname>preDispatch()</methodname>,
- 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
- <methodname>__call()</methodname>.
- </para>
- <para>
- 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.
- </para>
- <para>
- Como ejemplo:
- </para>
- <programlisting language="php"><![CDATA[
- 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;
- }
- }
- }
- ]]></programlisting>
- <para>
- 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.
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|