[ZF-10089] Zend_Log
[zend.git] / documentation / manual / es / module_specs / Zend_Controller-Exceptions.xml
blob2ad0ef2c78969a5dc88c6704550c98a31ed0c6e0
1 <?xml version="1.0" encoding="UTF-8"?>
2     <!-- EN-Revision: 17593 -->
3     <!-- Reviewed: no -->
4 <sect1 id="zend.controller.exceptions">
5     <title>Excepciones MVC</title>
7     <sect2 id="zend.controller.exceptions.introduction">
8         <title>Introducción</title>
10         <para>
11             Los componentes
12             <acronym>MVC</acronym>
13             en Zend Framework utilizan
14             un Front Controller, lo que significa que todas las
15             solicitudes de
16             un determinado sitio pasarán por un solo punto de entrada. Como
17             resultado,
18             todas las excepciones burbujearán eventualmente hacia
19             arriba hasta el Front Controller,
20             permitiendo al desarrollador
21             manejarlos en un solo lugar.
22         </para>
24         <para>
25             Sin embargo, los mensajes de excepción y la información de
26             backtrace contienen a menudo
27             información sensible del sistema, como
28             declaraciones
29             <acronym>SQL</acronym>
30             , ubicaciones de archivos y
31             otras cosas más. Para ayudar a proteger su sitio, por defecto
32             <classname>Zend_Controller_Front</classname>
33             captura todas las
34             excepciones y las registra con el objeto respuesta; a su vez, y por
35             defecto, el objeto respuesta no muestra mensajes de excepción.
36         </para>
37     </sect2>
39     <sect2 id="zend.controller.exceptions.handling">
40         <title>Manejando las Excepciones</title>
42         <para>
43             Ya hay varios mecanismos construidos en los componentes de
44             <acronym>MVC</acronym>
45             , que le permiten manejar excepciones.
46         </para>
48         <itemizedlist>
49             <listitem>
50                 <para>
51                     Por defecto, el
52                     <link linkend="zend.controller.plugins.standard.errorhandler">error handler
53                         plugin</link>
54                     está registrado y activo.
55                     Este plugin fue diseñado para manejar:
56                 </para>
58                 <itemizedlist>
59                     <listitem>
60                         <para>Errores debido a controladores o acciones
61                             perdidas</para>
62                     </listitem>
64                     <listitem>
65                         <para>Errores ocurriendo dentro de controladores de
66                             acción</para>
67                     </listitem>
68                 </itemizedlist>
70                 <para>
71                     Operan como un plugin de
72                     <methodname>postDispatch()</methodname>
73                     , y comprueban
74                     para ver si un despachador, controlador de acción, o de otra
75                     excepción ha ocurrido. Si así fuera, lo remite a un
76                     controlador de manejo de
77                     errores.
78                 </para>
80                 <para>Este manejador abarcará la mayoría de las situaciones
81                     excepcionales, y maneja
82                     airosamente controladores y acciones
83                     perdidos.</para>
84             </listitem>
86             <listitem>
87                 <para>
88                     <methodname>Zend_Controller_Front::throwExceptions()</methodname>
89                 </para>
91                 <para>
92                     Pasando a este método un valor booleano
93                     <constant>TRUE</constant>
94                     , puede decirle al front
95                     controller que, en lugar de sumar excepciones en el
96                     objeto
97                     respuesta o utilizando el plugin de manejo de errores,
98                     prefiere manejarlos
99                     usted mismo. Como ejemplo:
100                 </para>
102                 <programlisting language="php"><![CDATA[
103 $front->throwExceptions(true);
104 try {
105     $front->dispatch();
106 } catch (Exception $e) {
107     // usted mismo maneja las excepciones
109 ]]></programlisting>
111                 <para>Este método es probablemente la forma más fácil de añadir
112                     un manejo de
113                     excepciones personalizado que abarque toda la
114                     gama de posibles excepciones a su
115                     aplicación de front
116                     controller.</para>
117             </listitem>
119             <listitem>
120                 <para>
121                     <methodname>Zend_Controller_Response_Abstract::renderExceptions()</methodname>
122                 </para>
124                 <para>
125                     Al pasar a este método un valor booleano
126                     <constant>TRUE</constant>
127                     , le esta diciendo al objeto
128                     respuesta que debe emitir un mensaje de excepción y
129                     backtrace cuando se renderiza a sí mismo. En este escenario,
130                     se mostrará
131                     cualquier excepción planteada por su aplicación.
132                     Esto no es recomendable para
133                     entornos de producción, pero sí
134                     en desarrollo.
135                 </para>
136             </listitem>
138             <listitem>
139                 <para>
140                     <methodname>Zend_Controller_Front::returnResponse()</methodname>
141                     y
142                     <methodname>Zend_Controller_Response_Abstract::isException()</methodname>
143                     .
144                 </para>
146                 <para>
147                     Pasando un valor booleano
148                     <constant>TRUE</constant>
149                     a
150                     <methodname>Zend_Controller_Front::returnResponse()</methodname>
151                     ,
152                     <methodname>Zend_Controller_Front::dispatch()</methodname>
153                     no renderizará la respuesta, sino que la devolverá. Una vez
154                     que tiene la
155                     respuesta, entonces puede probar ver si todas
156                     las excepciones fueron atrapadas
157                     usando su método
158                     <methodname>isException()</methodname>
159                     , y recuperando
160                     las excepciones a través del método
161                     <methodname>getException()</methodname>
162                     . Como ejemplo:
163                 </para>
165                 <programlisting language="php"><![CDATA[
166 $front->returnResponse(true);
167 $response = $front->dispatch();
168 if ($response->isException()) {
169     $exceptions = $response->getException();
170     // maneje las excepciones ...
171 } else {
172     $response->sendHeaders();
173     $response->outputBody();
175 ]]></programlisting>
177                 <para>
178                     La principal ventaja que este método ofrece por sobre
179                     <methodname>Zend_Controller_Front::throwExceptions()</methodname>
180                     es que le permite renderizar condicionalmente la respuesta
181                     después de manejar la
182                     excepción. Esta capturará cualquier
183                     excepción en la cadena de controladores, a
184                     diferencia del
185                     plugin de manejo de errores.
186                 </para>
187             </listitem>
188         </itemizedlist>
189     </sect2>
191     <sect2 id="zend.controller.exceptions.internal">
192         <title>Excepciones MVC que Usted Pueda Encontrar</title>
194         <para>
195             Los diversos componentes de
196             <acronym>MVC</acronym>
197             -- solicitud,
198             router, despachador, controlador de acción, y los objetos respuesta
199             --
200             pueden arrojar excepciones en ocasiones. Algunas excepciones
201             puede ser condicionalmente
202             anuladas, y otras se usan para indicar al
203             desarrollador que puede necesitar re-considerar
204             la estructura de su
205             aplicación.
206         </para>
208         <para>Como algunos ejemplos:</para>
210         <itemizedlist>
211             <listitem>
212                 <para>
213                     <methodname>Zend_Controller_Dispatcher::dispatch()</methodname>
214                     hará, por defecto, arrojar una excepción si se hace un
215                     requerimiento a un
216                     controlador no válido. Hay dos maneras
217                     recomendadas para lidiar con esto.
218                 </para>
220                 <itemizedlist>
221                     <listitem>
222                         <para>
223                             Establecer el parámetro
224                             <emphasis>useDefaultControllerAlways</emphasis>
225                             .
226                         </para>
228                         <para>En su front controller, o en su despachador,
229                             añada la siguiente
230                             directiva:</para>
232                         <programlisting language="php"><![CDATA[
233 $front->setParam('useDefaultControllerAlways', true);
235 // o
237 $dispatcher->setParam('useDefaultControllerAlways', true);
238 ]]></programlisting>
240                         <para>Cuando este flag está establecido, el despachador
241                             utilizará el
242                             controlador y la acción por defecto en
243                             lugar de lanzar una excepción. La
244                             desventaja de este
245                             método es que cualquier error ortográfico que un
246                             usuario haga cuando acceda a su sitio lo resolverá y
247                             mostrará su página
248                             de inicio, y que puede causar
249                             estragos con la optimización para los
250                             motores de
251                             búsqueda.</para>
252                     </listitem>
254                     <listitem>
255                         <para>
256                             La excepción arrojada por
257                             <methodname>dispatch()</methodname>
258                             es una
259                             <classname>Zend_Controller_Dispatcher_Exception</classname>
260                             conteniendo el texto 'Invalid controller specified'.
261                             Use uno de los
262                             métodos descriptos de
263                             <link linkend="zend.controller.exceptions.handling">la
264                                 sección anterior</link>
265                             para atrapar la
266                             excepción, y luego redireccionar a una página
267                             genérica de
268                             error o a la página de inicio.
269                         </para>
270                     </listitem>
271                 </itemizedlist>
272             </listitem>
274             <listitem>
275                 <para>
276                     <methodname>Zend_Controller_Action::__call()</methodname>
277                     arrojará una
278                     <classname>Zend_Controller_Action_Exception</classname>
279                     si no puede despachar una acción inexistente a un método. Es
280                     probable que desee
281                     utilizar alguna acción por defecto en el
282                     controlador en casos como este. Formas
283                     de lograr esto
284                     incluyen:
285                 </para>
287                 <itemizedlist>
288                     <listitem>
289                         <para>
290                             Subclasear
291                             <classname>Zend_Controller_Action</classname>
292                             y
293                             anular el método
294                             <methodname>__call()</methodname>
295                             .
296                             Como ejemplo:
297                         </para>
299                         <programlisting language="php"><![CDATA[
300 class My_Controller_Action extends Zend_Controller_Action
302     public function __call($method, $args)
303     {
304         if ('Action' == substr($method, -6)) {
305             $controller = $this->getRequest()->getControllerName();
306             $url = '/' . $controller . '/index';
307             return $this->_redirect($url);
308         }
310         throw new Exception('Invalid method');
311     }
313 ]]></programlisting>
314                         <para>El ejemplo anterior intercepta cualquier llamada
315                             a un método de acción
316                             indefinido y redirecciona a la
317                             acción predeterminada en el controlador.</para>
318                     </listitem>
320                     <listitem>
321                         <para>
322                             Subclasea a
323                             <classname>Zend_Controller_Dispatcher</classname>
324                             y anula el método
325                             <methodname>getAction()</methodname>
326                             para
327                             verificar si la acción existe. Como ejemplo:
328                         </para>
330                         <programlisting language="php"><![CDATA[
331 class My_Controller_Dispatcher extends Zend_Controller_Dispatcher
333     public function getAction($request)
334     {
335         $action = $request->getActionName();
336         if (empty($action)) {
337             $action = $this->getDefaultAction();
338             $request->setActionName($action);
339             $action = $this->formatActionName($action);
340         } else {
341             $controller = $this->getController();
342             $action     = $this->formatActionName($action);
343             if (!method_exists($controller, $action)) {
344                 $action = $this->getDefaultAction();
345                 $request->setActionName($action);
346                 $action = $this->formatActionName($action);
347             }
348         }
350         return $action;
351     }
353 ]]></programlisting>
355                         <para>El código anterior comprueba para ver que las
356                             acciones solicitadas
357                             existan en la clase del
358                             controlador; si no, se restablece la acción a la
359                             acción por defecto.</para>
361                         <para>
362                             Este método es agradable porque puede alterar
363                             transparentemente la acción
364                             antes del último
365                             despacho. Sin embargo, también significa que errores
366                             ortográficos en la
367                             <acronym>URL</acronym>
368                             todavía
369                             pueden despacharse correctamente, lo que no es muy
370                             bueno para la
371                             optimización en un motor de búsqueda.
372                         </para>
373                     </listitem>
375                     <listitem>
376                         <para>
377                             Use
378                             <methodname>Zend_Controller_Action::preDispatch()</methodname>
379                             o
380                             <methodname>Zend_Controller_Plugin_Abstract::preDispatch()</methodname>
381                             para identificar acciones inválidas.
382                         </para>
384                         <para>
385                             Subclaseando
386                             <classname>Zend_Controller_Action</classname>
387                             y
388                             modificando
389                             <methodname>preDispatch()</methodname>
390                             ,
391                             puede modificar todos sus controladores que
392                             transmitan a otra acción o
393                             redireccionar antes de
394                             despachar la acción. El código para hacer esto se
395                             verá parecido al código de sustitución de arriba
396                             <methodname>__call()</methodname>
397                             .
398                         </para>
400                         <para>Alternativamente, puede verificar esta
401                             información en un plugin global.
402                             Esto tiene la
403                             ventaja de ser independiente del controlador de
404                             acción; si
405                             su aplicación consiste en una variedad de
406                             controladores de acción, y no
407                             todos ellos heredan de
408                             la misma clase, este método puede añadir
409                             coherencia
410                             a su manejo de clases diferentes.</para>
412                         <para>Como ejemplo:</para>
414                         <programlisting language="php"><![CDATA[
415 class My_Controller_PreDispatchPlugin extends Zend_Controller_Plugin_Abstract
417     public function preDispatch(Zend_Controller_Request_Abstract $request)
418     {
419         $front      = Zend_Controller_Front::getInstance();
420         $dispatcher = $front->getDispatcher();
421         $class      = $dispatcher->getControllerClass($request);
422         if (!$controller) {
423             $class = $dispatcher->getDefaultControllerClass($request);
424         }
426         $r      = new ReflectionClass($class);
427         $action = $dispatcher->getActionMethod($request);
429         if (!$r->hasMethod($action)) {
430             $defaultAction  = $dispatcher->getDefaultAction();
431             $controllerName = $request->getControllerName();
432             $response       = $front->getResponse();
433             $response->setRedirect('/' . $controllerName
434                                   . '/' . $defaultAction);
435             $response->sendHeaders();
436             exit;
437         }
438     }
440 ]]></programlisting>
442                         <para>En este ejemplo, vamos a consultar para ver si la
443                             acción solicitada
444                             está disponible en el controlador.
445                             Si no, redireccionamos a la acción
446                             predeterminada en
447                             el controlador, y salimos inmediatamente de la
448                             ejecución del script.</para>
449                     </listitem>
450                 </itemizedlist>
451             </listitem>
452         </itemizedlist>
453     </sect2>
454 </sect1>