Gestion des Erreurs & Exceptions

Un grand nombre de méthodes internes à PHP utilisent les erreurs pour communiquer les échecs. Ces erreurs doivent être récupérées et traitées. CakePHP fournit un récupérateur d’erreurs qui les affiche et/ou les écrit dans des fichiers de log par défaut lorsqu’elles se produisent. Ce gestionnaire d’erreurs est utilisé pour capturer les exceptions non interceptées par les controllers et par les autres parties de votre application.

Configuration des Erreurs et des Exceptions

La configuration des Erreurs est faite à l’intérieur du fichier config/app.php de votre application. Par défaut CakePHP utilise la classe ErrorHandler ou ConsoleErrorHandler pour capturer et afficher/mettre les erreurs dans des fichiers de log. Vous pouvez remplacer ce comportement en changeant le gestionnaire d’erreurs par défaut. Le gestionnaire d’erreurs par défaut gère également les exceptions non interceptées.

La gestion des erreurs accepte quelques options qui vous permettent de personnaliser la gestion des erreurs pour votre application:

  • errorLevel - int - Le niveau d’erreurs que vous souhaitez pour la capture. Utilisez les constantes d’erreur intégrées à PHP et les bitmasks pour sélectionner le niveau d’erreur qui vous intéresse.
  • trace - bool - Inclut les stack traces (contexte de débuggage) pour les erreurs dans les fichiers de log. Les Stack traces seront inclus dans le log après chaque erreur. Ceci est utile pour trouver où/quand des erreurs sont générées.
  • exceptionRenderer - string - La classe responsable de rendre les exceptions non interceptées. Si vous choisissez une classe personnalisée, vous devrez placer le fichier de cette classe dans le dossier src/Error. Cette classe doit implémenter une méthode render().
  • log - bool - Si true, les exceptions et leur stack traces seront loguées vers Cake\Log\Log.
  • skipLog - array - Un tableau des noms de classe d’exception qui ne doivent pas être mises dans des fichiers de log. C’est utile pour supprimer les NotFoundExceptions ou toute autre message de log sans intérêt.
  • extraFatalErrorMemory - int - Définit le nombre de megaoctets duquel doit être augmenté la limite de mémoire en cas d’erreur fatale. Cela permet d’allouer un petit espace mémoire supplémentaire pour la journalisation (logging) ainsi que la gestion d’erreur.

ErrorHandler affiche par défaut les erreurs quand debug est true et les erreurs de logs quand debug est false. Le type d’erreurs capté dans les deux cas est contrôlé par errorLevel. Le gestionnaire d’erreurs fatales va être appelé indépendamment de debug ou de la configuration de errorLevel, mais le résultat va être différent, basé sur le niveau de debug. Le comportement par défaut pour les erreurs fatales est d’afficher une page avec une erreur interne du serveur (debug désactivé) ou une page avec le message, le fichier et la ligne (debug activé).

Note

Si vous utilisez un gestionnaire d’erreurs personnalisé, les options supportées dépendent de votre gestionnaire.

Créer vos Propres Gestionnaires d’Erreurs

Vous pouvez créer un gestionnaire d’erreurs à partir de n’importe quel type de callback. Par exemple, vous pouvez utiliser une classe appelée AppError pour gérer vos erreurs. En étendant BaseErrorHandler, vous pouvez fournir une logique de gestion des erreurs personnalisée. Un exemple serait:

// Dans config/bootstrap.php
use App\Error\AppError;

$errorHandler = new AppError();
$errorHandler->register();

// Dans src/Error/AppError.php
namespace App\Error;

use Cake\Error\BaseErrorHandler;

class AppError extends BaseErrorHandler
{
    public function _displayError($error, $debug)
    {
        echo 'Il y a eu une erreur!';
    }
    public function _displayException($exception)
    {
        echo 'Il y a eu un exception';
    }
}

BaseErrorHandler définit deux méthodes abstraites. _displayError() est utilisée lorsque les erreurs sont déclenchées. La méthode _displayException() est appelée lorsqu’il y a une exception non interceptée.

Changer le Comportement des Erreurs Fatales

Le gestionnaire d’erreurs par défaut convertit les erreurs fatales en exceptions et réutilise la logique de traitement d’exception pour afficher une page d’erreur. Si vous ne voulez pas montrer la page d’erreur standard, vous pouvez la surcharger comme ceci:

// Dans config/bootstrap.php
use App\Error\AppError;

$errorHandler = new AppError();
$errorHandler->register();

// Dans src/Error/AppError.php
namespace App\Error;

use Cake\Error\BaseErrorHandler;

class AppError extends BaseErrorHandler
{
    // Autre méthode.

    public function handleFatalError($code, $description, $file, $line)
    {
        return 'Une erreur fatale est survenue';
    }
}

Classes des Exceptions

Il y a de nombreuses classes d’exception dans CakePHP. Le gestionnaire d’exception intégré va capturer les exceptions levées et rendre une page utile. Les exceptions qui n’utilisent pas spécialement un code dans la plage 400 seront traitées comme une erreur interne au serveur.

Exceptions Intégrées de CakePHP

Il existe plusieurs exceptions intégrées à l’intérieur de CakePHP, en plus des exceptions d’infrastructure internes, et il existe plusieurs exceptions pour les méthodes HTTP.

Exceptions HTTP

exception Cake\Http\Exception\BadRequestException

Utilisée pour faire une erreur 400 de Mauvaise Requête.

exception Cake\Http\Exception\UnauthorizedException

Utilisée pour faire une erreur 401 Non Autorisé.

exception Cake\Http\Exception\ForbiddenException

Utilisée pour faire une erreur 403 Interdite.

Nouveau dans la version 3.1: InvalidCsrfTokenException a été ajoutée.

exception Cake\Http\Exception\InvalidCsrfTokenException

Utilisée pour faire une erreur 403 causée par un token CSRF invalide.

exception Cake\Http\Exception\NotFoundException

Utilisée pour faire une erreur 404 Non Trouvé.

exception Cake\Http\Exception\MethodNotAllowedException

Utilisée pour faire une erreur 405 pour les Méthodes Non Autorisées.

exception Cake\Http\Exception\NotAcceptableException

Utilisée pour faire une erreur 406 Not Acceptable.

Nouveau dans la version 3.1.7: NotAcceptableException a été ajoutée.

exception Cake\Http\Exception\ConflictException

Utilisée pour faire une erreur 409 Conflict.

Nouveau dans la version 3.1.7: ConflictException a été ajoutée.

exception Cake\Http\Exception\GoneException

Utilisée pour faire une erreur 410 Gone.

Nouveau dans la version 3.1.7: GoneException a été ajoutée.

Pour plus de détails sur les codes de statut d’erreur HTTP 4xx, regardez RFC 2616#section-10.4.

exception Cake\Http\Exception\InternalErrorException

Utilisée pour faire une erreur 500 du Serveur Interne.

exception Cake\Http\Exception\NotImplementedException

Utilisée pour faire une erreur 501 Non Implémentée.

exception Cake\Http\Exception\ServiceUnavailableException

Utilisée pour faire une erreur 503 Service Unavailable.

Nouveau dans la version 3.1.7: Service Unavailable a été ajoutée.

Pour plus de détails sur les codes de statut d’erreur HTTP 5xx, regardez RFC 2616#section-10.5.

Vous pouvez lancer ces exceptions à partir de vos controllers pour indiquer les états d’échecs, ou les erreurs HTTP. Un exemple d’utilisation des exceptions HTTP pourrait être le rendu de pages 404 pour les items qui n’ont pas été trouvés:

// Prior to 3.6 use Cake\Network\Exception\NotFoundException
use Cake\Http\Exception\NotFoundException;

public function view($id = null)
{
    $article = $this->Articles->findById($id)->first();
    if (empty($article)) {
        throw new NotFoundException(__('Article not found'));
    }
    $this->set('article', $article);
    $this->set('_serialize', ['article']);
}

En utilisant les exceptions pour les erreurs HTTP, vous pouvez garder à la fois votre code propre, et donner les réponses RESTful aux applications clientes et aux utilisateurs.

De plus, les exceptions de couche du framework suivantes sont disponibles, et seront lancées à partir de certains components du cœur de CakePHP:

Autres Exceptions Intégrées

exception Cake\View\Exception\MissingViewException

La classe View choisie n’a pas pu être trouvée.

exception Cake\View\Exception\MissingTemplateException

Le fichier de template choisi n’a pas pu être trouvé.

exception Cake\View\Exception\MissingLayoutException

Le layout choisi n’a pas pu être trouvé.

exception Cake\View\Exception\MissingHelperException

Un helper n’a pas pu être trouvé.

exception Cake\View\Exception\MissingElementException

L’element n’a pas pu être trouvé.

exception Cake\View\Exception\MissingCellException

La classe Cell choisie n’a pas pu être trouvée.

exception Cake\View\Exception\MissingCellViewException

La vue de Cell choisie n’a pas pu être trouvée.

exception Cake\Controller\Exception\MissingComponentException

Un component configuré n’a pas pu être trouvé.

exception Cake\Controller\Exception\MissingActionException

L’action demandée du controller n’a pas pu être trouvé.

exception Cake\Controller\Exception\PrivateActionException

Accès à une action préfixée par _, privée ou protégée.

exception Cake\Console\Exception\ConsoleException

Une classe de la librairie console a rencontré une erreur

exception Cake\Console\Exception\MissingTaskException

Une tâche configurée n’a pas pu être trouvée.

exception Cake\Console\Exception\MissingShellException

Une classe de shell n’a pas pu être trouvée.

exception Cake\Console\Exception\MissingShellMethodException

Une classe de shell choisie n’a pas de méthode de ce nom.

exception Cake\Database\Exception\MissingConnectionException

Une connexion à un model n’existe pas.

exception Cake\Database\Exception\MissingDriverException

Un driver de base de donnée de n’a pas pu être trouvé.

exception Cake\Database\Exception\MissingExtensionException

Une extension PHP est manquante pour le driver de la base de données.

exception Cake\ORM\Exception\MissingTableException

Une table du model n’a pas pu être trouvé.

exception Cake\ORM\Exception\MissingEntityException

Une entity du model n’a pas pu être trouvé.

exception Cake\ORM\Exception\MissingBehaviorException

Une behavior du model n’a pas pu être trouvé.

exception Cake\ORM\Exception\PersistenceFailedException

Une entity n’a pas pu être sauvegardée / supprimée en utilisant Cake\ORM\Table::saveOrFail() ou Cake\ORM\Table::deleteOrFail()

Nouveau dans la version 3.4.1: PersistenceFailedException a été ajoutée.

exception Cake\Datasource\Exception\RecordNotFoundException

L’enregistrement demandé n’a pas pu être trouvé. Génère une réponse avec une entête 404.

exception Cake\Routing\Exception\MissingControllerException

Le controller requêté n’a pas pu être trouvé.

exception Cake\Routing\Exception\MissingRouteException

L’URL demandée ne pas peut pas être inversée ou ne peut pas être parsée.

exception Cake\Routing\Exception\MissingDispatcherFilterException

Le filtre du dispatcher n’a pas pu être trouvé.

exception Cake\Core\Exception\Exception

Classe de base des exceptions dans CakePHP. Toutes les exceptions lancées par CakePHP étendent cette classe.

Ces classes d’exception étendent toutes Exception. En étendant Exception, vous pouvez créer vos propres erreurs “framework”. Toutes les Exceptions standards que CakePHP va lancer étendent également Exception.

Cake\Core\Exception\Exception::responseHeader($header = null, $value = null)

See Cake\Network\Request::header()

Toutes les exceptions Http et CakePHP étendent la classe Exception, qui a une méthode pour ajouter les en-têtes à la réponse. Par exemple quand vous lancez une MethodNotAllowedException 405, le rfc2616 dit:

"La réponse DOIT inclure un en-tête contenant une liste de méthodes valides
pour la ressource requêtée."

Utiliser les Exceptions HTTP dans vos Controllers

Vous pouvez envoyer n’importe quelle exception HTTP liée à partir des actions de votre controller pour indiquer les états d’échec. Par exemple:

// Prior to 3.6 use Cake\Http\Exception\NotFoundException
use Cake\Http\Exception\NotFoundException;

public function view($id = null)
{
    $article = $this->Articles->findById($id)->first();
    if (empty($article)) {
        throw new NotFoundException(__('Article not found'));
    }
    $this->set('article', $article);
    $this->set('_serialize', ['article']);
}

Ce qui précède va faire que le gestionnaire d’exception attrape et traite la NotFoundException. Par défaut, cela va créer une page d’erreur et enregistrer l’exception.

Exception Renderer

class Cake\Core\Exception\ExceptionRenderer(Exception $exception)

La classe ExceptionRenderer avec l’aide de ErrorController s’occupe du rendu des pages d’erreur pour toutes les exceptions lancées par votre application.

Les vues de la page d’erreur sont localisées dans src/Template/Error/. Pour toutes les erreurs 4xx et 5xx, les fichiers de template error400.ctp et error500.ctp sont utilisées respectivement. Vous pouvez les personnaliser selon vos besoins. Par défaut, votre src/Template/Layout/error.ctp est également utilisé pour les pages d’erreur. Si par exemple, vous voulez utiliser un autre layout src/Template/Layout/my_error.ctp pour vos pages d’erreur, modifiez simplement les vues d’erreur et ajoutez la ligne $this->layout = 'my_error'; dans error400.ctp et error500.ctp.

Chaque exception au niveau du framework a son propre fichier de vue localisé dans les templates du cœur mais vous n’avez pas besoin de les personnaliser puisqu’ils sont utilisés seulement pendant le développement. Avec debug éteint, toutes les exceptions au niveau du framework sont converties en InternalErrorException.

Créer vos Propres Exceptions dans votre Application

Vous pouvez créer vos propres exceptions d’application en utilisant toute exception SPL intégrée, Exception lui-même ou :Cake\Core\Exception\Exception.

Si votre application contenait l’exception suivante:

use Cake\Core\Exception\Exception;

class MissingWidgetException extends Exception
{};

Vous pourriez fournir de jolies erreurs de développement, en créant src/Template/Error/missing_widget.ctp. Quand on est en mode production, l’erreur du dessus serait traitée comme une erreur 500. Le constructeur pour Cake\Core\Exception\Exception a été étendu, vous autorisant à lui passer des données hashées. Ces hashs sont interpolés dans le messageTemplate, ainsi que dans la vue qui est utilisée pour représenter l’erreur dans le mode développement. Cela vous permet de créer des exceptions riches en données, en fournissant plus de contexte pour vos erreurs. Vous pouvez aussi fournir un template de message qui permet aux méthodes natives __toString() de fonctionner normalement:

use Cake\Core\Exception\Exception;

class MissingWidgetException extends Exception
{
    protected $_messageTemplate = 'Il semblerait que %s soit manquant.';
}

throw new MissingWidgetException(['widget' => 'Pointy']);

Lorsque le gestionnaire d’exception intégré attrapera l’exception, vous obtiendriez une variable $widget dans votre template de vue d’erreur. De plus, si vous attrapez l’exception en chaîne ou utilisez sa méthode getMessage(), vous aurez Il semblerait que Pointy soit manquant.. Cela vous permet de créer rapidement vos propres erreurs de développement riches, exactement comme CakePHP le fait en interne.

Créer des Codes de Statut Personnalisés

Vous pouvez créer des codes de statut HTTP personnalisés en changeant le code utilisé quand vous créez une exception:

throw new MissingWidgetHelperException('Widget manquant', 501);

Va créer un code de réponse 501, vous pouvez utiliser le code de statut HTTP que vous souhaitez. En développement, si votre exception n’a pas de template spécifique, et que vous utilisez un code supérieur ou égal à 500, vous verrez le template error500.ctp. Pour tout autre code d’erreur, vous aurez le template error400.ctp. Si vous avez défini un template d’erreur pour votre exception personnalisée, ce template sera utilisé en mode développement. Si vous souhaitez votre propre logique de gestionnaire d’exception même en production, regardez la section suivante.

Etendre et Implémenter vos Propres Gestionnaires d’Exceptions

Vous pouvez implémenter un gestionnaire d’exception spécifique pour votre application de plusieurs façons. Chaque approche vous donne différents niveaux de contrôle sur le processus de gestion d’exception.

  • Créer et enregistrer votre propre gestionnaire d’erreurs.
  • Etendre le BaseErrorHandler fourni par CakePHP.
  • Configurer l’option exceptionRenderer dans le gestionnaire d’erreurs par défaut.

Dans les prochaines sections, nous allons détailler les différentes approches et les bénéfices de chacune.

Créer votre Propre Gestionnaire d’Exceptions

Créer votre propre gestionnaire d’exception vous donne le contrôle total sur le processus de gestion des exceptions. Dans ce cas, vous devrez vous-même appeler set_exception_handler.

Etendre le BaseErrorHandler

La section Configurer les erreurs comporte un exemple.

Utiliser l’Option exceptionRenderer dans le Gestionnaire par Défaut

Si vous ne voulez pas prendre le contrôle sur le gestionnaire d’exception, mais que vous voulez changer la manière dont les exceptions sont rendues, vous pouvez utiliser l’option exceptionRenderer dans config`/app.php pour choisir la classe qui affichera les pages d’exception. Par défaut Cake\Core\Exception\ExceptionRenderer est utilisée. Votre gestionnaire d’exceptions doit être placé dans src/Error. Dans une classe de rendu personnalisé d’exception vous pouvez fournir un traitement particulier pour les erreurs spécifique à votre application:

// Dans src/Error/AppExceptionRenderer.php
namespace App\Error;

use Cake\Error\ExceptionRenderer;

class AppExceptionRenderer extends ExceptionRenderer
{
    public function missingWidget($error)
    {
        return 'Oups ce widget est manquant!';
    }
}

// Dans config/app.php
'Error' => [
    'exceptionRenderer' => 'App\Error\AppExceptionRenderer',
    // ...
],
// ...

Le code ci-dessus gérerait toutes les exceptions de type MissingWidgetException, et vous permettrait un affichage et/ou une logique de gestion personnalisée pour ces exceptions de l’application. Les méthodes de gestion d’exceptions obtiennent l’exception étant traitée en argument. Votre gestionnaire de rendu personnalisé peut retourner une chaîne ou un objet Response. Retourner une Response vous donnera le contrôle total de la réponse.

Note

Votre gestionnaire de rendu doit attendre une exception dans son constructeur et implémenter une méthode de rendu. Ne pas le faire entraînera des erreurs supplémentaires.

Si vous utilisez un gestionnaire d’exception personnalisé, configurer le moteur de rendu n’aura aucun effet. A moins que vous le référenciez à l’intérieur de votre implémentation.

Créer un Controller Personnalisé pour Gérer les Exceptions

Par convention CakePHP utilisera App\Controller\ErrorController s’il existe. Implémenter cette classe vous offrira une voie pour personnaliser les pages d’erreur sans aucune configuration supplémentaire.

Si vous utilisez un moteur de rendu d’exceptions personnalisé, vous pouvez utiliser la méthode _getController() pour rendre un controller personnalisé. En implémentant _getController() dans votre moteur de rendu d’exceptions, vous pouvez utiliser n’importe quel controller de votre choix:

// Dans src/Error/AppExceptionRenderer
namespace App\Error;

use App\Controller\SuperCustomErrorController;
use Cake\Error\ExceptionRenderer;

class AppExceptionRenderer extends ExceptionRenderer
{
    protected function _getController($exception)
    {
        return new SuperCustomErrorController();
    }
}

// Dans config/app.php
'Error' => [
    'exceptionRenderer' => 'App\Error\AppExceptionRenderer',
    // ...
],
// ...

Le controller d’erreur, qu’il soit conventionnel ou personnalisé, est utilisé pour rendre la vue de page d’erreurs et reçoit tous les événements standards du cycle de vie des requêtes.

Logger les Exceptions

En Utilisant la gestion d’exception intégrée, vous pouvez logger toutes les exceptions qui sont gérées par ErrorHandler en configurant l’option log à true dans votre config/app.php. Activer cela va logger chaque exception vers Cake\Log\Log et les loggers configurés.

Note

Si vous utilisez un gestionnaire personnalisé, cette configuration n’aura aucun effet. A moins que vous ne le référenciez à l’intérieur de votre implémentation.