File: Zend_Controller-Exceptions.xml

package info (click to toggle)
zendframework 1.12.9%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: jessie-kfreebsd
  • size: 133,584 kB
  • sloc: xml: 1,311,829; php: 570,173; sh: 170; makefile: 125; sql: 121
file content (319 lines) | stat: -rw-r--r-- 15,274 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: 24249 -->
<!-- Reviewed: no -->
<sect1 id="zend.controller.exceptions">
    <title>Exceptions avec MVC</title>

    <sect2 id="zend.controller.exceptions.introduction">
        <title>Introduction</title>

        <para>
            Les composants <acronym>MVC</acronym> de Zend Framework utilisent un contrôleur frontal, ce qui veut
            dire que toute requête envoyée à l'application entre par ce point unique. Ainsi, toutes
            les exceptions sont encapsulées dans le contrôleur frontal, ceci vous permet de toutes
            les traiter dans un seul endroit.
        </para>

        <para>
            Cependant, les exceptions peuvent contenir des messages ou des traces plutôt
            sensibles pour le système, comme des requêtes <acronym>SQL</acronym>, l'emplacement de certains fichiers
            ... Pour vous aider à protéger votre site, par défaut,
            <classname>Zend_Controller_Front</classname> attrape toutes les exceptions et les
            enregistre dans l'objet de réponse ; et bien entendu, par défaut, cet objet de réponse
            n'affiche pas ces exceptions.
        </para>
    </sect2>

    <sect2 id="zend.controller.exceptions.handling">
        <title>Gestion des exceptions</title>

        <para>
            Plusieurs mécanismes vont vous permettre de traiter les exceptions dans le modèle
            <acronym>MVC</acronym> de Zend Framework.
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    Par défaut, le plugin
                    <link linkend="zend.controller.plugins.standard.errorhandler">error
                    handler</link>est présent, et activé. Ce plugin a été conçu pour gérer&#160;:
                </para>
                <itemizedlist>
                    <listitem>
                        <para>Les erreurs d'absence de contrôleurs ou d'actions</para>
                    </listitem>
                    <listitem>
                        <para>Erreurs survenant dans un contrôleur</para>
                    </listitem>
                </itemizedlist>
                <para>
                    <code>ErrorHandler</code> agit dans le <methodname>postDispatch()</methodname>, et
                    analyse si une exception a été levée (en gérant son type). Si c'est le cas,
                    alors le plugin renvoie un jeton vers un contrôleur de gestion des
                    erreurs.
                </para>
                <para>
                    Ce contrôleur couvrira la majorité des cas d'utilisation. Il parvient à
                    gérer les cas "contrôleur absent", "action absente", ou "autre cas".
                </para>
            </listitem>
            <listitem>
                <para><methodname>Zend_Controller_Front::throwExceptions()</methodname></para>
                <para>
                    En passant la valeur <constant>TRUE</constant> à cette méthode, vous indiquez au
                    contrôleur frontal que vous souhaitez qu'il vous retourne les exceptions qu'il
                    rencontre. Ainsi, il ne les ajoutera pas à la réponse, et il ne fera pas
                    intervenir le plugin "<code>Error handler</code>". Exemple&#160;:
                </para>
                <programlisting language="php"><![CDATA[
$front->throwExceptions(true);
try {
    $front->dispatch();
} catch (Exception $e) {
    // A vous de gérer ici
}
]]></programlisting>
                <para>
                    Cette méthode vous permet d'utiliser une gestion personnalisée des
                    exceptions dans votre application, de manière simple.
                </para>
            </listitem>
            <listitem>
                <para>

                    <methodname>Zend_Controller_Response_Abstract::renderExceptions()</methodname>
                </para>
                <para>
                    En passant un paramètre <constant>TRUE</constant> à cette méthode, vous indiquez
                    à la réponse d'afficher les exceptions qu'elle reçoit (du contrôleur frontal,
                    ou du plugin "<code>Error handler</code>", par exemple), lorsque son rendu est
                    appelé. Ceci ne devrait être activé qu'en environnement de développement.
                </para>
            </listitem>
            <listitem>
                <para>
                    <methodname>Zend_Controller_Front::returnResponse()</methodname> et
                    <methodname>Zend_Controller_Response_Abstract::isException()</methodname>.
                </para>
                <para>
                    En passant le booléen <constant>TRUE</constant> à
                    <methodname>Zend_Controller_Front::returnResponse()</methodname>,
                    <methodname>Zend_Controller_Front::dispatch()</methodname> ne commandera pas
                    l'affichage de la réponse automatiquement. Au lieu de cela, l'objet de réponse
                    sera retourné. Vous pouvez alors tester celui-ci pour voir s'il contient des
                    exceptions, ceci grâce à <methodname>isException()</methodname> et
                    <methodname>getException()</methodname>. Voyez&#160;:
                </para>
                <programlisting language="php"><![CDATA[
$front->returnResponse(true);
$response = $front->dispatch();
if ($response->isException()) {
    $exceptions = $response->getException();
    // Gestion des exceptions ici
} else {
    $response->sendHeaders();
    $response->outputBody();
}
]]></programlisting>
                <para>
                    Par rapport à
                    <methodname>Zend_Controller_Front::throwExceptions()</methodname>, cette
                    utilisation vous permet de ne rendre la réponse que lorsque vous le décidez,
                    selon la présence de telle ou telle exception, ou pas.
                </para>
            </listitem>
        </itemizedlist>
    </sect2>

    <sect2 id="zend.controller.exceptions.internal">
        <title>Différents types d'exceptions que vous pouvez rencontrer</title>

        <para>
            Les composants <acronym>MVC</acronym> sont nombreux, - requête, routeur, distributeur, contrôleur,
            et réponse - chaque objet risque de renvoyer une exception qui lui est propre.
            Certaines peuvent être créées ou dérivées, d'autres par défaut indiquent un problème de
            l'application.
        </para>

        <para>Comme exemples :</para>

        <itemizedlist>
            <listitem>
                <para>
                    <methodname>Zend_Controller_Dispatcher::dispatch()</methodname> va envoyer
                    une exception, par défaut, si un contrôleur invalide est demandé. Vous pouvez
                    jouer sur ce paramètre&#160;:
                </para>
                <itemizedlist>
                    <listitem>
                        <para>
                            Initialisez le paramètre
                            <code>useDefaultControllerAlways</code>
                        </para>
                        <para>
                            Dans votre contrôleur frontal, ou distributeur, ajoutez la
                            directive suivante&#160;:
                        </para>
                        <programlisting language="php"><![CDATA[
$front->setParam('useDefaultControllerAlways', true);
// ou
$dispatcher->setParam('useDefaultControllerAlways', true);
]]></programlisting>
                        <para>
                            Lorsque ceci est injecté, le distributeur utilisera le contrôleur
                            par défaut s'il s'aperçoit qu'il ne peut distribuer un contrôleur
                            spécifique, plutôt que de renvoyer une exception. Méfiez vous des
                            moteurs de recherche qui n'aiment pas que plusieurs <acronym>URI</acronym> pointent sur un
                            même contenu. En effet, avec ce paramètre activé, les utilisateurs
                            orthographiant mal votre site, seront redirigés vers la page d'accueil
                            de celui-ci, ce qui peut aboutir à du "duplicate content" (contenu
                            dupliqué).
                        </para>
                    </listitem>
                    <listitem>
                        <para>
                            L'exception envoyée par <methodname>dispatch()</methodname> est de type
                            <classname>Zend_Controller_Dispatcher_Exception</classname> et contient
                            le message "Invalid controller specified". Utilisez une méthode comme
                            vu dans la
                            <link linkend="zend.controller.exceptions.handling">section
                            précédente</link>pour attraper celle-ci et rediriger vers une page
                            d'erreur générique.
                        </para>
                    </listitem>
                </itemizedlist>
            </listitem>
            <listitem>
                <para>
                    <methodname>Zend_Controller_Action::__call()</methodname> enverra une
                    <classname>Zend_Controller_Action_Exception</classname> s'il n'est pas possible
                    de distribuer l'action demandée. Il est facile de changer ce
                    comportement&#160;:
                </para>
                <itemizedlist>
                    <listitem>
                        <para>
                            Dérivez la classe <classname>Zend_Controller_Action</classname>
                            en redéfinissant sa méthode <methodname>__call()</methodname>, voyez plutôt&#160;:
                        </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>
                            Cet exemple intercepte les actions non existantes, et redirige
                            vers l'action principale du contrôleur actuel.
                        </para>
                    </listitem>
                    <listitem>
                        <para>
                            Dérivez <classname>Zend_Controller_Dispatcher</classname> et
                            redéfinissez <methodname>getAction()</methodname> pour vérifier si l'action existe
                            bien&#160;:
                        </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>
                            L'exemple précédant vérifie si l'action existe dans le contrôleur
                            demandé. Si ce n'est pas le cas, il redéfinit l'action en spécifiant
                            celle par défaut.
                        </para>
                        <para>
                            Cette méthode permet de changer l'action avant la distribution.
                            Attention une fois encore aux erreurs de syntaxes dans l'URL, qui
                            devraient mener vers une page d'erreur quelconque.
                        </para>
                    </listitem>
                    <listitem>
                        <para>
                            Utilisez
                            <methodname>Zend_Controller_Action::preDispatch()</methodname> ou
                            <methodname>Zend_Controller_Plugin_Abstract::preDispatch()</methodname>
                            pour identifier les actions invalides.
                        </para>
                        <para>
                            En dérivant <classname>Zend_Controller_Action</classname> pour y
                            modifier <methodname>preDispatch()</methodname>, vous agissez sur la globalité de
                            vos contrôleurs, avant même la distribution de l'action
                            demandée.
                        </para>
                        <para>
                            L'utilisation d'un plugin offre une flexibilité supplémentaire :
                            Si tous vos contrôleurs n'héritent pas de la même classe, plutôt que de
                            dupliquer du code, un plugin va agir indépendamment de vos contrôleurs.
                            En <methodname>preDispatch()</methodname>, il agit avant ceux-ci.
                        </para>
                        <para>Par exemple :</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 (!$class) {
            $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>
                            Dans cet exemple, nous vérifions si l'action demandée existe dans
                            le contrôleur distribué. Si ce n'est pas le cas, nous exécutons une
                            redirection immédiate.
                        </para>
                    </listitem>
                </itemizedlist>
            </listitem>
        </itemizedlist>
    </sect2>
</sect1>