Documentation officielle du framework PHP Symfony 3

Comment faire pour personnaliser les pages retournées en cas d'erreur ?

La gestion des erreurs est un élément important dans une application Web. Avoir des messages suffisamment explicatifs sur vos pages d'erreur peut apporter une plus-value à votre application, et à l'expérience utilisateur. Symfony propose des pages d'erreur par défaut, selon les événements, mais il est possible de les personnaliser.

Dans ce tutoriel, vous apprendre à personnaliser les pages d'erreur dans votre application Web Symfony.

Un espace vous est proposé sur le forum pour apporter vos avis sur ce tutoriel.

2 commentaires Donner une note à l'article (5)

Article lu   fois.

Les deux auteur et traducteur

Traducteur : Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

Dans les applications Symfony, toutes les erreurs sont traitées comme des exceptions. Peu importe si ce sont juste des erreurs « 404 Objet non trouvé » ou une erreur fatale déclenchée par une exception dans votre code.

Dans l'environnement de programmation, Symfony détecte toutes les erreurs et affiche une page d'exception spéciale avec plusieurs informations de débogage pour vous aider à retrouver rapidement le problème racine.

Image non disponible
Image non disponible

Et comme ces pages contiennent plusieurs informations internes sensibles, Symfony ne les affiche pas dans un environnement de production. En lieu et place de cela, il va afficher une simple page d'erreur générique.

Les pages d'erreur en environnement de production peuvent être personnalisées de plusieurs façons selon vos besoins :

  1. Si vous voulez juste modifier le contenu et le style de vos pages d'erreur pour correspondre avec le reste de votre application, il suffit de remplacer les templates d'erreur par défautRemplacement des templates d'erreur par défaut ;
  2. Si vous souhaitez également modifier la logique utilisée par Symfony pour générer des pages d'erreur, remplacer le contrôleur de gestion des exceptions par défautRemplacement du ExceptionController par défaut ;
  3. Si vous avez besoin d'un contrôle total de la gestion des exceptions pour exécuter votre propre logique, utiliser l'événement kernel.exceptionProgrammer avec l'événement kernel.exception.

II. Remplacement des templates d'erreur par défaut

II-A. Présentation générale

Quand une page d'erreur est en train d'être chargée, un contrôleur interne ExceptionController est utilisé pour retourner un template Twig présenté à l'utilisateur.

Ce contrôleur utilise un statut de code HTTP et un format de requête dans la logique suivante pour déterminer le nom du template :

  1. Retrouver un template pour le format indiqué et le code du statut (par exemple error404.json.twig ou error500.html.twig) ;
  2. Si le précédent template n'existe pas, il faut ignorer le code de statut pour retrouver un template générique selon le format indiqué (par exemple error.json.twig ou error.xml.twig) ;
  3. Si aucun des templates précédents n'existe, il faut revenir au template générique HTML (error.html.twig).

Pour remplacer ces templates, il suffit d'utiliser la méthode standard de Symfony pour remplacer les templates contenus dans un bundle : les mettre dans le répertoire app/Resources/TwigBundle/views/Exception.

Un projet typique qui retourne des pages JSON et HTML ressemble à peu près à ceci :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
app/
└─ Resources/
   └─ TwigBundle/
      └─ views/
         └─ Exception/
            ├─ error404.html.twig
            ├─ error403.html.twig
            ├─ error.html.twig      # All other HTML errors (including 500)
            ├─ error404.json.twig
            ├─ error403.json.twig
            └─ error.json.twig      # All other JSON errors (including 500)

II-B. Exemple avec le template du code d'erreur 404

Pour remplacer un template d'erreur 404 dans les pages HTML, créer un nouveau template error404.html.twig dans le répertoire app/Resources/TwigBundle/views/Exception/.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
{# app/Resources/TwigBundle/views/Exception/error404.html.twig #}
{% extends 'base.html.twig' %}

{% block body %}
    <h1>Page not found</h1>

    {% if is_granted('IS_AUTHENTICATED_FULLY') %}
        {# ... #}
    {% endif %}

    <p>
        The requested page couldn't be located. Checkout for any URL
        misspelling or <a href="{{ path('homepage') }}">return to the homepage</a>.
    </p>
{% endblock %}

Dans le cas où vous avez besoin d'eux, le ExceptionController passe certaines informations au template d'erreur via les variables status_code et status_text qui stockent respectivement le code et le message du statut HTTP.

Vous pouvez personnaliser le code du statut en implémentant l'interface HttpExceptionInterface et sa méthode getStatusCode() requise. Sinon le status_code est par défaut à 500.

Les pages d'exception présentées dans l'environnement de programmation peuvent être personnalisées de la même manière que les pages d'erreur. Il faut créer un nouveau template exception.html.twig pour la page standard de l'exception HTML ou exception.json.twig pour la page de l'exception JSON.

II-C. Tests des pages d'erreur pendant la programmation

Tant que vous êtes dans l'environnement de programmation, Symfony vous montre une grande page d'exception au lieu de votre nouvelle brillante page d'erreur personnalisée. Donc, comment voir à quoi elle ressemble et comment la déboguer ?

Heureusement, le contrôleur, par défaut, ExceptionController vous permet de prévisualiser vos pages d'erreur pendant la phase de développement.

Pour utiliser cette fonction, vous avez besoin d'une définition semblable à celle-ci dans le fichier routing_dev.yml :

Script YAML
Sélectionnez
1.
2.
3.
4.
# app/config/routing_dev.yml
_errors:
    resource: "@TwigBundle/Resources/config/routing/errors.xml"
    prefix:   /_error
Script XML
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
<!-- app/config/routing_dev.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">

    <import resource="@TwigBundle/Resources/config/routing/errors.xml"
        prefix="/_error" />
</routes>
Script PHP
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
// app/config/routing_dev.php
use Symfony\Component\Routing\RouteCollection;

$collection = new RouteCollection();
$collection->addCollection(
    $loader->import('@TwigBundle/Resources/config/routing/errors.xml')
);
$collection->addPrefix("/_error");

return $collection;

Si vous venez d'une ancienne version de Symfony, vous auriez besoin d'ajouter cela dans votre fichier routing_dev.yml. Si vous démarrez de zéro, l'édition standard de Symfony contient déjà cela pour vous.

Avec cette route ajoutée, vous pouvez utiliser les URL comme ceci :

 
Sélectionnez
1.
2.
http://localhost/app_dev.php/_error/{statusCode}
http://localhost/app_dev.php/_error/{statusCode}.{format}

Ces URL vous permettent de prévisualiser la page d'erreur relative au code de statut donné en HTML ou dans le code du statut et du format donné.

III. Remplacement du ExceptionController par défaut

Si vous avez besoin d'un peu plus de flexibilité, au-delà d'un simple remplacement de template, alors vous pouvez changer le contrôleur qui retourne la page d'erreur. Par exemple, vous pourriez avoir besoin de passer certaines variables à votre template.

Pour le faire, il suffit de créer simplement un nouveau contrôleur à n'importe quel emplacement de votre application, et paramétrer l'option de configuration twig.exception_controller pour pointer dessus :

Script YAML
Sélectionnez
1.
2.
3.
# app/config/config.yml
twig:
    exception_controller:  AppBundle:Exception:showException
Script XML
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:twig="http://symfony.com/schema/dic/twig"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/twig
        http://symfony.com/schema/dic/twig/twig-1.0.xsd">

    <twig:config>
        <twig:exception-controller>AppBundle:Exception:showException</twig:exception-controller>
    </twig:config>
</container>
Script PHP
Sélectionnez
1.
2.
3.
4.
5.
// app/config/config.php
$container->loadFromExtension('twig', array(
    'exception_controller' => 'AppBundle:Exception:showException',
    // ...
));

La classe ExceptionListener utilisée par le TwigBundle comme listener de l'événement kernel.exception crée la requête qui sera envoyée à votre contrôleur. En plus, deux paramètres seront passés à votre contrôleur :

  1. exception : une instance FlattenException créée par l'exception gérée ;
  2. logger : une instance DebugLoggerInterface qui peut être null dans certaines circonstances.

Au lieu de créer une nouvelle exception de contrôleur à partir de zéro, vous pouvez tout simplement étendre le contrôleur par défaut ExceptionController. Dans ce cas, vous pouvez remplacer l'une ou les deux méthodes suivantes : showAction() et findTemplate(). Cette dernière permet de retrouver le template qui sera utilisé.

Dans le cas où il s'agit d'étendre le contrôleur ExceptionController, vous devez configurer un service pour lui passer l'environnement Twig et le flag debug au constructeur.

Script YAML
Sélectionnez
1.
2.
3.
4.
5.
# app/config/services.yml
services:
    app.exception_controller:
        class: AppBundle\Controller\CustomExceptionController
        arguments: ['@twig', '%kernel.debug%']
Script XML
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
<!-- app/config/services.xml -->
<?xml version="1.0" encoding="utf-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"
>
    <services>
        <service id="app.exception_controller"
            class="AppBundle\Controller\CustomExceptionController"
        >
            <argument type="service" id="twig"/>
            <argument>%kernel.debug%</argument>
        </service>
    </services>
</container>
Script PHP
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
// app/config/services.php
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Definition;

$definition = new Definition('AppBundle\Controller\CustomExceptionController', array(
    new Reference('twig'),
    '%kernel.debug%'
));
$container->setDefinition('app.exception_controller', $definition);

Et maintenant, configurez twig.exception_controller en utilisant le contrôleur comme syntaxe des services (par exemple : app.exception_controller:showAction).

La prévisualisation de la page d'erreurTests des pages d'erreur pendant la programmation fonctionne aussi pour vos propres contrôleurs configurés de cette façon.

IV. Programmer avec l'événement kernel.exception

Quand une exception est détectée, la classe HttpKernel la récupère et envoie un événement kernel.exception. Cela vous donne la possibilité de convertir l'exception dans un objet « Response » de peu de manières différentes.

Travailler avec cet événement est en fait beaucoup plus puissant que ce qui a été expliqué plus haut, mais requiert une connaissance plus approfondie du fonctionnement interne de Symfony. Cela peut être utile dans un cas où votre code a besoin de lancer des exceptions spécialisées ayant une signification particulière pour votre domaine d'application.

Écrire votre propre listener d'événements pour l'événement kernel.exception vous permettra d'examiner, de plus près, l'exception et exécuter plusieurs actions en dépendant. Ces actions peuvent porter sur la journalisation de l'exception, la redirection des utilisateurs vers une autre page, ou encore le rendu de pages d'erreur spécialisées.

Si votre listener appelle la méthode setResponse() dans l'événement GetResponseForExceptionEvent, la propagation va s'arrêter et l'objet « Response » sera envoyé au client.

Cette approche vous permet de créer une couche de gestion centralisée des erreurs : au lieu de capturer (et gérer) les mêmes exceptions dans divers contrôleurs à plusieurs reprises, vous pouvez juste avoir un (ou seulement très peu) de listeners pour les traiter.

Observez le code de la classe ExceptionListener comme exemple réel de listener avancé de ce type. Ce listener permet de gérer plusieurs exceptions relatives à la sécurité, qui sont intégrées dans votre application (comme AccessDeniedException) et prendre des mesures telles que rediriger l'utilisateur à la page de login, les journaliser et bien d'autres choses encore.

Notes de la rédaction de Developpez.com

Nous remercions Guillaume Sigui pour la traduction de ce tutoriel et f-leb pour la relecture orthographique.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Licence Creative Commons
Le contenu de cet article est rédigé par Symfony et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 3.0 non transposé.
Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright © 2013 Developpez.com.