エラーと例外処理

cakePHPでは、エラー処理と例外処理が用意されている。PHPエラーはトラップされ、表示またはログに記録される。キャッチされなかった例外はエラーページに自動的にレンダリングされる。

例外処理の設定

例外処理の設定はconfig/app.phpで行われる。デフォルトではCake\Error\ErrorHandlerを使う。

例外処理のカスタマイズ

例外の処理方法を調整するいくつかの方法が用意されている。

エラーテンプレートのカスタマイズ

エラーページのビューはApp/Template/Errorに配置される。
すべての 4xx エラーは error400.ctp テンプレートを使い、 すべての 5xx エラーは error500.ctp を使う。
エラーテンプレートの変数は次の通り。

  • message: 例外メッセージ
  • code: 例外コード
  • url: リクエストURL
  • error: 例外オブジェクト
<?php
// src/Template/Error/error400.ctp の中で
$this->layout = 'my_error';
?>

上記は、エラーページのレイアウトとして src/Template/Layout/my_error.ctp を使用する。

ErrorControllerのカスタマイズ

App\Controller\ErrorController クラスは CakePHP の例外レンダリングでエラーページビューを 描画するために使われ、すべての標準リクエストライフサイクルイベントを受け取る。

<?php
namespace App\Controller\Admin;

use App\Controller\AppController;
use Cake\Event\EventInterface;

class ErrorController extends AppController
{
    /**
     * Initialization hook method.
     *
     * @return void
     */
    public function initialize(): void
    {
        $this->loadComponent('RequestHandler');
    }

    /**
     * beforeRender callback.
     *
     * @param \Cake\Event\EventInterface $event Event.
     * @return void
     */
    public function beforeRender(EventInterface $event)
    {
        $this->viewBuilder()->setTemplatePath('Error');
    }
}
?>

どのコンポーネントが使用され、どのテンプレートが描画されるかを制御する。

独自アプリケーション例外の作成

組み込みの SPL の例外 、 Exception そのもの、または Cake\Core\Exception\Exception のいずれかを使って、独自のアプリケーション例外を作ることができる。

<?php
use Cake\Core\Exception\Exception;

class MissingWidgetException extends Exception
{
    // コンテキストデータはこのフォーマット文字列に差し込まれます。
    protected $_messageTemplate = '%s が見当たらないようです。';

    // デフォルトの例外コードも設定できます。
    protected $_defaultCode = 404;
}

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

上記の例ではMissingWidgetExceptionという例外を作成している。このときテンプレートはsrc/Template/Error/missing_widget.ctpになる。

ExceptionRendererのカスタマイズ

アプリケーション固有の例外クラスに対してカスタムエラーページを提供する。カスタム例外レンダラークラスは src/Error に配置する。

<?php
// src/Error/AppExceptionRenderer.php の中で
namespace App\Error;

use Cake\Error\ExceptionRenderer;

class AppExceptionRenderer extends ExceptionRenderer
{
    public function missingWidget($error)
    {
        $response = $this->controller->response;
        return $response->withStringBody('おっとウィジェットが見つからない!');
    }
}
?>
// config/app.php の中で
'Error' => [
    'exceptionRenderer' => 'App\Error\AppExceptionRenderer',
    // ...
],
// ...
?>

上記の例では、カスタム例外レンダラークラスの中でMissingWidgetExceptionに対して missingWidgetというメソッドを作成している。

cakePHP用の組み込みの例外

  • Cake\Http\Exception\BadRequestException: 400 Bad Request
  • Cake\Http\Exception\UnauthorizedException: 401 Unauthorized
  • Cake\Http\Exception\ForbiddenException: 403 Forbidden
  • Cake\Http\Exception\InvalidCsrfTokenException: (無効なCSRFトークンによる)403 Forbidden
  • Cake\Http\Exception\NotFoundException: 404 Not Found
  • Cake\Http\Exception\MethodNotAllowedException: 405 Method Not Allowed
  • Cake\Http\Exception\NotAcceptableException: 406 Not Acceptable
  • Cake\Http\Exception\NotAcceptableException: 406 Not Acceptable
  • Cake\Http\Exception\ConflictException: 409 Conflict
  • Cake\Http\Exception\GoneException: 410 Gone
  • Cake\Http\Exception\InternalErrorException: 500 Internal Server Error
  • Cake\Http\Exception\NotImplementedException: 501 Not Implemented
  • Cake\Http\Exception\ServiceUnavailableException: 503 Service Unavailable などなど
<?php
use Cake\Http\Exception\NotFoundException;

public function view($id = null)
{
    $article = $this->Articles->findById($id)->first();
    if (empty($article)) {
        throw new NotFoundException(__('記事が見つかりません'));
    }
    $this->set('article', $article);
    $this->set('_serialize', ['article']);
}
?>