エラーハンドリングの実装例

Naifyのエラーハンドリングの実装例を紹介します。Router層の想定エラーをErrorControllerへ流し、予期しない例外はApplication層で最終的に受けます。

このページでは追加する処理を紹介します。ファイル配置と公開入口、BaseController、NaifyViewの初期化とgetView()を先に用意します。Controllerとテンプレートを追加したら、対応するURLを routes/routes.php に登録します。

ルートの書き方

$router->error() にエラー用Controllerを登録します。個別コードと共通ハンドラを分けることもできます。

use Naify\Router\Router;

return static function (Router $router): void
{
    $to = $router->createRouteFactory('App\\Controllers\\');

    $router->any('/', $to('IndexController::index'));

    $router->error([404], $to('ErrorController::notFound'));
    $router->error('*', $to('ErrorController::index'));
};

ErrorController

Router層で発生した RouteException は RequestContext から取得できます。HTTPステータスを設定し、Viewへ値を渡します。

namespace App\Controllers;

final class ErrorController extends BaseController
{
    public function indexAction(): void
    {
        $error = $this->context->getRoutingError();
        $code = $error?->getStatusCode() ?? 500;
        $message = $error?->getMessage() ?? 'Internal Server Error';

        http_response_code($code);

        $view = $this->getView();
        $view->assign('code', $code);
        $view->assign('message', $message);
        $view->setTemplate('error.html');
    }

    public function notFoundAction(): void
    {
        http_response_code(404);

        $view = $this->getView();
        $view->assign('code', 404);
        $view->assign('message', 'ページが見つかりません');
        $view->setTemplate('error.html');
    }
}

Viewテンプレート

エラーページも通常のNaifyView Nativeテンプレートとして扱います。

<h1>{{ code }}</h1>
<p>{{ message }}</p>
<p><a href="/">トップへ戻る</a></p>

Application層の最終catch

想定外の例外はブートストラップ側で最終的に受け、ログへ残します。本番環境ではスタックトレースを画面へ出しません。

// SampleAppBootstrap.php のApp生成以降を置き換える
// $config は Naify::createConfig() で設定済み
try {
    $app = Naify::createWebApp($config);
    $app->loadRoute('routes/routes.php');
    $app->run();
} catch (Throwable $e) {
    error_log($e->getMessage() . PHP_EOL . $e->getTraceAsString());
    http_response_code(500);
    echo '<h1>500 Internal Server Error</h1>';
}