Laravelではexceptionのハンドリングを app/Exceptions/Handler.php
で指定できます。
このクラスの実装は大半が親クラスのIlluminate\Foundation\Exceptions\Handler
にあるので、
参考にしながらメソッドをオーバーライドしていきます。
app/Exception/Hander.php
/**
* Prepare a response for the given exception.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $e
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function prepareResponse($request, Exception $e)
{
if (! $this->isHttpException($e) && config('app.debug')) {
return $this->toIlluminateResponse(
$this->convertExceptionToResponse($e), $e
);
}
if (! $this->isHttpException($e)) {
$e = new HttpException(500, $e->getMessage());
}
// パスごとにエラーのviewを分岐する
return $this->toIlluminateResponse(
$this->customRenderHttpException($request, $e), $e // ここがparentのものと差し替わっている
);
}
/**
* parentのrenderHttpExceptionを改変してrequestパスごとに分岐するようにしたもの
* @param Request $request
* @param \Symfony\Component\HttpKernel\Exception\HttpException $e
* @return \Symfony\Component\HttpFoundation\Response
*/
private function customRenderHttpException(Request $request, HttpException $e)
{
$status = $e->getStatusCode();
$paths = collect(config('view.paths'));
view()->replaceNamespace('errors', $paths->map(function ($path) use ($request) {
return $request->is('admin/*') ? "{$path}/admin/errors" : "{$path}/service/errors"; // viewを分岐
})->push(__DIR__ . '/views')->all());
if (view()->exists($view = "errors::{$status}")) {
return response()->view($view, ['exception' => $e], $status, $e->getHeaders());
}
return $this->convertExceptionToResponse($e);
}
今回はadmin/
以下にアクセスが来たときは/views/admin/errors
にそれ以外のときは/views/service/errors
に振り分けます。
親クラスにconvertExceptionToResponse
というメソッドがあってそこだけ書き換えられればよかったのですが、パスで分岐するためには\Illuminate\Http\Request
が引数に必要で、それが無かったので、prepareResponse
メソッドから書き換えています。