| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 17593 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.controller.exceptions">
- <title>Excepciones MVC</title>
- <sect2 id="zend.controller.exceptions.introduction">
- <title>Introducción</title>
- <para>
- Los componentes
- <acronym>MVC</acronym>
- 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
- <acronym>SQL</acronym>
- , 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
- <acronym>MVC</acronym>
- , 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>
- <methodname>Zend_Controller_Front::throwExceptions()</methodname>
- </para>
- <para>
- Pasando a este método un valor booleano
- <constant>TRUE</constant>
- , 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>
- <methodname>Zend_Controller_Response_Abstract::renderExceptions()</methodname>
- </para>
- <para>
- Al pasar a este método un valor booleano
- <constant>TRUE</constant>
- , 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>
- <methodname>Zend_Controller_Front::returnResponse()</methodname>
- y
- <methodname>Zend_Controller_Response_Abstract::isException()</methodname>
- .
- </para>
- <para>
- Pasando un valor booleano
- <constant>TRUE</constant>
- a
- <methodname>Zend_Controller_Front::returnResponse()</methodname>
- ,
- <methodname>Zend_Controller_Front::dispatch()</methodname>
- 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
- <methodname>Zend_Controller_Front::throwExceptions()</methodname>
- 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
- <acronym>MVC</acronym>
- -- 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>
- <methodname>Zend_Controller_Dispatcher::dispatch()</methodname>
- 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
- <emphasis>useDefaultControllerAlways</emphasis>
- .
- </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>
- <methodname>Zend_Controller_Action::__call()</methodname>
- 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
- <acronym>URL</acronym>
- 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
- <methodname>Zend_Controller_Action::preDispatch()</methodname>
- o
- <methodname>Zend_Controller_Plugin_Abstract::preDispatch()</methodname>
- 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>
|