Laravel4、カスタムエラーページ

タグ: Laravel4  

自分でカスタマイズしたエラーページを表示する方法の一例の紹介です。

一番簡単なのは、app/start/global.phpの中の、例外ハンドラーを以下のように変更します。

<?php

if( !Config::get( 'app.debug' ) )
{    
    App::error( function( Exception $e, $code )
    {
        $message = $e->getMessage() == '' ? $code.'エラーです。' : $e->getMessage();

        if( File::exists( app_path().'/views/errors/'.$code.'.blade.php' ) )
        {
            return Response::view( 'errors.'.$code, array( 'reason' => $message ), $code );
        }
        else
        {
            Log::error($e);
            return Response::view( 'errors.500', array( 'reason' => $message ), '500' );
        }
    } );

}

続いて、app/view/errosにレスポンスコードに対応するビューを用意します。500.phpもしくは500.blade.phpは必ず用意してください。

もうちょっと、丁寧な方法です。

方針

app/views下にerrorsディレクトリーを作成し、その下に"レスポンスコード.blade.php"か"レスポンスコード.php"を用意しておきます。

発生したレスポンスコードに対応するbladeファイルが存在するかチェックし、存在していなければ500.blade.phpを表示します。存在していれば、そのbladeファイルを表示します。

そのため、必ず500.blade.phpを用意しておく必要があります。

この方法は、Laravel3で採用されていた方法で、いまだに人気のある実装方法です。一度作成しておけば、処理するレスポンスコードを変更したい場合にコードの変更は必要なく、ビューファイルだけを作成/削除すれば済みます。

エラービュー

エラービューも表示に統一感を持たせるために、親のレイアウト(app/view/layout.blade.php)を使用すると仮定しましょう。titleはページタイトル、contentがコンテンツ本体のセクションです。

500.blade.php

@extends('layout')

@section('title')
500 内部エラーが発生しました。
@stop

@section('content')
<h2>内部エラーが発生しました。</h2>
<p>{{ $reason }}</p>
<p>時間を置いて、お試しください。</p>
<p>長時間続いている場合はお手数ですが、adimin@exmaple.comまでご連絡ください。</p>
@stop

404.blade.php

@extends('layout')

@section('title')
404 ページが見つかりません
@stop

@section('content')
<h2>ページが見つかりません。</h2>
<p>{{ $reason }}</p>
<p>古いページは削除されている可能性があります。</p>
<p>URLに間違いはありませんか?確認をお願いします。</p>
@stop

その他、お好みで対応するページを作成しましょう。

例外のハンドリング

以下の内容でファイルを作成し、app/start/global.phpもしくはサービスプロバイダーなどから、読み込みます。(もしくは、先の例のようにapp/start/global.phpの例外ハンドラーを書き換えます。)

<?php

if( !Config::get( 'app.debug' ) )
{
    // 全例外の処理(主にPHPエラー)
    App::error( function( Exception $e )
    {
        Log::error($e);

        return Response::view( 'errors.500', array( 'reason' => '内部でエラーが発生しました。' ), '500' );
    } );

    // HTTPエラー
    App::error( function (Symfony\Component\HttpKernel\Exception\HttpException $e, $code)
    {
        $message = $e->getMessage() == '' ? $code.'エラーです。' : $e->getMessage();

        if( File::exists( app_path().'/views/errors/'.$code.'.blade.php' ) )
        {
            return Response::view( 'errors.'.$code, array( 'reason' => $message ), $code );
        }
        else
        {
            return Response::view( 'errors.500', array( 'reason' => '内部でエラーが発生しました。' ), '500' );
        }
    } );

}

例外ハンドラーは全般的なものから、個別のものへと順番に宣言します。HTTPエラーは2つ目のハンドラーで処理され、それ以外のエラーは全部最初のハンドラーで処理されます。

ポイントとなるのは、ルートからならViewを返しても自動的にレスポンスクラスに変換されますが、例外の処理から返せるのは、レスポンスクラスだけであることです。(この仕組みは変更されているかも知れません。)Response::view()メソッドがありますので、簡単に特定ビューとレスポンスコードを持ったレスポンスオブジェクトをリターンできます。

後は、お好みに合わせて、ご自由にどうぞ。