Posted at

laravelのApp\Exception\Handlerのrenderを安易に弄るな

laravel 5.0以降の話です。

laravelにはApp\Exception\Handler.phpがありますね

アプリケーション全体の例外を扱うクラスです。

https://github.com/laravel/laravel/blob/master/app/Exceptions/Handler.php#L47-L50

    /**

* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @return \Illuminate\Http\Response
*/

public function render($request, Exception $exception)
{
return parent::render($request, $exception);
}


結論

このrender関数を弄るときは、このparent::renderを握りつぶさないようにしましょう

ifを挟んでなにか特別な処理をするときは、自作の例外クラスを扱うなど、明らかにparent::render側に渡さなくていい処理を引っ掛けるにとどめましょう。

if( $exception instanceof SomeCustomExceptionYouDefined) {

// return view what you want to show when your exception happens
}

return parent::render($requext, $exception);

こんな感じで。

さもなくばフレームワークが行う処理が実行されません。


この関数で何が起きているのか

parent::renderを呼んでいるということは、このクラスの継承元のクラスを呼んでいるわけで、そこでフレームワーク側の処理を行っています。

具体的にはここですね。 https://github.com/laravel/framework/blob/6.x/src/Illuminate/Foundation/Exceptions/Handler.php#L165-L193

つまり、if文でこの関数に処理を書くならば、書き方を間違えればフレームワーク側の処理が実行されなくなることを意味します。

実は、


  • authの失敗

  • フォームのバリデーションエラー

  • 他にもRenderable例外の処理など

などもExceptionとしてthrowされ、このparent::renderでハンドリングされます。

つまり、フォームのバリデーションなどわりと日常的に使うの機能に関しても、このparent::renderの関数の中でその失敗時のリダイレクト処理を担っています。

たまたま私が関わっているプロジェクトで、ここにreturn response()->view('hoge/404')のように書いて、parent::renderを呼んでいないものがありました。

おそらく、なにかうまく行かなかったときは404の画面を出したかったのでしょう。


エラー画面を扱いたいときは

https://laravel.com/docs/master/errors#custom-http-error-pages

公式が述べています。

resources/views/errors/$status_code.balde.phpの形でファイルを置いて対処しましょう。

ドキュメントのみでの確認ですが、5.0以降はこれが使えます。

また、公式のドキュメントは、これ以外の方法は指示してくれていません。(見落としがあればぜひ教えて下さい!)

特定のステータスコードだけでではなくまとめて扱いたいなら、以下が参考になるでしょう。

https://qiita.com/M_Ishikawa/items/1f0d72fc93286109464e

しかし、親クラスをoverrideする際は、自分で何をしているのかを把握すべきです。

結局の所、公式のドキュメントが指示しないことをやるなら、フレームワークのソースコードを理解しないと手を付けるべきではありません。


まとめ

公式のドキュメントも読もう

https://laravel.com/docs/master/errors


ところで、フォームの失敗までもが例外としてthrowされて、このparent::render関数内で処理をするのはちょっとおかしい気がします。

アプリケーション全体の失敗と言えるようなものがここにまで到達すべきな気がしますが、みなさんはどう思われますか?