Table des matières
Notre petite et simple application est en train de grandir ! Pour terminer cette section du livre, conçue pour vous familiariser avec Zend Framework et ses étapes de base lorsqu'il s'agit de mettre en place une application, jetons un coup d'oeil à la gestion d'erreurs.
Tel que nous l'avons
configuré au chapitre précédent,
Zend_Controller_Front
ne lévera d'exception que
pour les environnements de développement ou de tests. En production,
aucune erreur ni exception ne devrait être affichée aux utilisateurs. Cela
dit, lorsque quelque chose ne se passe pas comme attendu, nous ne pouvons
pas juste laisser l'utilisateur devant une fenêtre de navigateur vide, où
il se demanderait tout d'abord avec quelque sorte d'amusement ce qu'il se
passe... Jusqu'à ce que cet amusement se transforme peu à peu en agacement
! A la place, nous devrions informer l'utilisateur sur le fait qu'il y a
un problème, que nous en sommes réellement désolé, que nous torturerons le
développeur responsable aussi tôt que possible, et, espérons-le, que nous
résoudrons ce problème dès que la séance de torture aura eu les effets
désirés.
Pour permettre cela,
Zend_Controller_Front
suppose que nous créerons un
nouveau Contrôleur, nommé ErrorController
pour être
précis, pour gérer ce type de situation. Si vous ne créez pas
ErrorController
, votre application se plaindra de
son absence, en particulier lorsqu'une erreur sera causée par un accès via
une URL qui pointe sur un emplacement qui n'existe pas ; ce qui devrait
renvoyer une 404.
Cette gestion des
Exceptions est effectuée par un Plugin Front Controller nommé
Zend_Controller_Plugin_ErrorHandler
.
Nous ferons en sorte que nos rapports d'erreurs effectués auprès de l'utilisateur soient aussi simples que possibles, avec cette classe minimaliste :
<?php
class ErrorController extends Zend_Controller_Action
{
public function errorAction()
{
}
}
Comme nous l'avons vu
précédemment, toutes les Actions de Contrôleurs entraineront
automatiquement le rendering d'une Vue correspondante. Puisque nous avons
une méthode errorAction()
dans un
ErrorController
, c'est le script de Vue
/application/views/scripts/error/error.phtml
qui sera
rendu. Du moins, s'il existe ; créez le donc !
<?php echo $this->doctype() ?>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<?php echo $this->headMeta() ?>
<meta name="language" content="en" />
<title>Oops! There's Been A Problem!</title>
</head>
<body>
<h1>An Error Has Occurred</h1>
<p>We're truly sorry, but we cannot complete your request at this
time.</p>
<p>If it's any consolation, we have scheduled a new appointment
for our development team leader in Torture Chamber #7 to encourage
his colleagues to investigate this incident.</p>
</body>
</html>
Ah... Si seulement c'était aussi simple...
Retournez dans votre
navigateur, et essayez d'appeler l'URL http://helloworld.tld/route/does/not/exist
.
Du fait que cette URL ne correspond à aucune route (et donc, à aucun
Contrôleur), elle devrait entrainer l'apparition du message
d'erreur.
A la place de notre page d'erreur, nous avons le véritable message de l'Exception, et ses détails, qui sont tous envoyés au navigateur.
L'ErrorController
a été conçu de manière à n'être utilisé que si le Front Controller a été
configuré pour ne jamais lever d'exception - sauf pour les exceptions qui
doivent être levées parce que quelqu'un a oublié d'ajouter
ErrorController
! En fait, l'infameuse Exception à
propos du ErrorController
non trouvé vient
précisément de cette situation. Pour tester
l'ErrorController
, nous devons effectuer une
modification temporaire à /config/application.ini
,
pour désactiver la levée d'Exceptions par
Zend_Controller_Front
, en changeant la toute
dernière ligne "resources.frontController.throwExceptions", pour lui
affecter une valeur de 0 (ce qui signifie false). Cela permet de s'assurer
que le plugin ErrorHandler peut servir une page d'erreur libre
d'exception, telle que nous l'avons créée.
[production] phpSettings.display_startup_errors = 0 phpSettings.display_errors = 0 bootstrap.path = APPLICATION_ROOT "/library/ZFExt/Bootstrap.php" bootstrap.class = "ZFExt_Bootstrap" resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers" resources.view.encoding = "UTF-8" resources.view.doctype = "XHTML1_STRICT" resources.view.contentType = "text/html;charset=utf-8" resources.modifiedFrontController.contentType = "text/html;charset=utf-8" [staging : production] [testing : production] phpSettings.display_startup_errors = 1 phpSettings.display_errors = 1 resources.frontController.throwExceptions = 1 [development : production] phpSettings.display_startup_errors = 1 phpSettings.display_errors = 1 resources.frontController.throwExceptions = 0
Vous pourriez penser que nous pourrions nous arrêter là, et discrêtement échapper à la chambre de torture n°7, mais vous auriez tord. Si vous regardez sous le capot, notre gestionnaire d'erreur est extrêmement vague, et nous répondons toujours aux requêtes HTTP avec une en-tête HTTP/1.1 200 OK. Maintenant, traitez-moi d'idiot si vous en avez envie, mais est-ce que nous n'avons pas admis qu'un problème s'était produit en osant afficher un message d'erreur à l'utilisateur ? Si notre application rencontre une erreur, elle ne devrait absolument jamais retourner un tel code de statut ni un tel message.
Bien que cela puisse ne pas sembler très important, ça l'est. Toute notre application ne sera pas servie à Joe Bloggs via un navigateur. Des requêtes peuvent arriver d'autres applications, qui pourraient faire confiance au code de réponse HTTP, plutôt qu'à la cruauté évidente dont vous faites preuve envers vos développeurs pour qu'ils détectent toutes les erreurs. Dans tous les cas, vous devez penser à votre propre revue interne des applications. Serez-vous en mesure de traquer les problèmes, si toute requête semble réussir, d'après les logs de votre serveur Web ? Il y a aussi le gros problème nommé RFC 2616 "Hypertext Transfer Protocol -- HTTP/1.1", qui décrit la plage de code de statut 2xx en disant : "Cette classe de codes de status indique que la requête émise par le client a été correctement reçue, comprise, et acceptée". En d'autres mots, le W3C a une chambre de torture spéciale, appelée Chambre de Torture de l'Enfer n°1, pour ceux dont les applications croient tout savoir.
Une échec de routage
n'est pas une succès, puisqu'il signifie soit que notre fonctionnalité de
routage est cassée, soit, et c'est plus probable, que l'utilisateur a
requis l'utilisation d'une URL invalide. Puisque la mauvaise URL est une
erreur de l'utilisateur, nous ne devrions probablement pas expédier tout
de suite notre Team Leader vers la chambre de torture. A la place, nous
devrions expliquer (poliment) aux utilisateurs qu'ils ont tord, et inclure
une en-tête de statut 404 Not Found, pour le cas où l'utilisateur est une
machine. Pour accomplir cela, nous devons ajouter quelques vérifications à
notre ErrorController
.
<?php
class ErrorController extends Zend_Controller_Action
{
public function errorAction()
{
$error = $this->_getParam('error_handler');
switch ($error->type)
{
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
$this->getResponse()->setHttpResponseCode(404);
$this->view->statusCode = 404;
break;
default:
$this->getResponse()->setHttpResponseCode(500);
$this->view->statusCode = 500;
}
}
}
Ci-dessus, nous utilisons le Plugin ErrorHandler, et récupérons la valeur de son type d'erreur. Si l'erreur correspond à un problème de routage, nous utiliserons le code statut HTTP 404, qui indique que le problème n'est pas de notre faute, et que le chemin requis n'existe tout simplement pas pour notre application. Sinon, nous utiliserons le code statut HTTP 500, pour toutes les autres erreurs. Le code statut 500 est accompagné du message "Internal Server Error" dans les en-têtes. Maintenant, améliorons notre template d'erreur existant.
<?php echo $this->doctype() ?>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<?php echo $this->headMeta() ?>
<meta name="language" content="en" />
<title>Oops! There's Been A Problem!</title>
</head>
<body>
<h1>An Error Has Occurred</h1>
<?php if ($this->statusCode == 500): ?>
<p>We're truly sorry, but we cannot complete your request at this
time.</p>
<p>If it's any consolation, we have scheduled a new appointment
for our development team leader in Torture Chamber #7 to encourage
his colleagues to investigate this incident.</p>
<?php else: ?>
<p>We're truly sorry, but the page you are trying to locate
does not exist.</p>
<p>Please double check the requested URL or consult your local
Optometrist.</p>
<?php endif; ?>
</body>
</html>
De toute évidence, garder nos utilisateurs n'est pas un des premiers objectifs de ce chapitre.
Si vous essayez avec votre navigateur en utilisant une URL invalide, vous devriez obtenir le message d'erreur attendu, ainsi qu'un code statut de 404 dans les en-têtes. Si vous effectuez quelque chose qui entraine la levée d'une Exception différente, vous devriez recevoir en réponse le code status 500, et le message HTML correspondant.
Gérer les erreurs n'est
pas une tâche difficile, mais elle est nécessaire, en particulier quand
nos applications peuvent être visitées par d'autres clients, eux-même
intégrés à des applications, qui sont dépendant de la communication de
codes de statut et d'en-têtes appropriés, et non de pages HTML humainement
lisibles, pour déterminer si une requête HTTP a réussi ou non. Il est
fortement recommandé que vous vous assuriez que votre application retourne
toujours des en-têtes HTTP et codes de statut appropriés. Bien que notre
ErrorController
semble relativement simple, nous
voyons bien que nous pourrions l'améliorer, de manière à logger les
erreurs, ou même envoyer des notifications par email.