さまざまなパターンに対応させたエラーレンダラクラス
前節でエラー画面表示のカスタマイズが一通り完了しました。ここからは、さらにさまざまなパターンに対応させたカスタマイズの方法を紹介していきます。
デフォルトのレンダラクラスとの組み合わせ
前節で用意したerror.htmlはあくまでサンプルですが、これをきっちりデザインした画面とすることで、アプリのユーザーに対して失礼のないエラー表示となります。一方で、アプリの開発段階では、デザインされた本番向けエラー画面よりも、エラー内容が詳細に表示された図2の方が助かります。そこで、本運用環境では独自のエラー画面を表示させ、開発段階ではSlimデフォルトのエラー画面を表示させるようにCustomErrorRendererクラスを改造します。
その際、考え方の中心となるのは、__invoke()メソッドの第2引数の$displayErrorDetailsの値です。この値は先述の通り、addErrorMiddleware()の第1引数の値がそのまま渡ってくることになっており、この値こそ、開発環境と本運用環境の切り替えのための値でした。そこで、リスト5のように、__invoke()メソッド内で$displayErrorDetailsの値で分岐を行います。
<?php
〜省略〜
use Slim\Error\Renderers\HtmlErrorRenderer; // (1)
class CustomErrorRenderer implements ErrorRendererInterface
{
〜省略〜
public function __invoke(Throwable $exception, bool $displayErrorDetails): string
{
if($displayErrorDetails) { // (2)
$htmlErrorRenderer = new HtmlErrorRenderer(); //(3)
$returnHtml = $htmlErrorRenderer($exception, $displayErrorDetails); // (4)
}
else {
$twig = $this->container->get("view");
$assign["errorMsg"] = "もう一度初めから操作してください。";
$returnHtml = $twig->fetch("error.html", $assign);
}
return $returnHtml;
}
}
$displayErrorDetailsの値で分岐を行っているのがリスト5の(2)です。ifブロック内に詳細エラーを表示させる処理を記述し、elseブロック内に本運用環境の独自エラー画面を表示させる処理を記述します。そのため、elseブロック内のコードはリスト2と同じです。
一方、ifブロック内の(3)と(4)がSlimのデフォルトエラーレンダラクラスを利用した処理です。Slimのデフォルトエラーレンダラクラスというのは、\Slim\Error\Renderers\HtmlErrorRendererです。このインスタンスを生成しているのが(3)です。ただし、このクラスを利用するために(1)のように事前にuseしておく必要があります。
HtmlErrorRendererクラスも、そのレンダリング処理は__invoke()メソッドに記述されているので、newしたインスタンス$htmlErrorRendererに対して関数のように呼び出すだけで、デフォルトのエラー画面HTML文字列を生成してくれます。それが(4)です。引数は、__invoke()の引数と同じなので、そのまま渡します。
この状態でエラーを発生させると、無事、図2の画面が表示されます。一方、addErrorMiddleware()の第1引数をfalseとすると図4が表示され、開発環境用、本運用環境用独自エラー画面の2種のエラー画面を、addErrorMiddleware()の第1引数の値で切り替えられるようになりました。
例外ごとに表示画面を切り替える
今度は、__invoke()メソッドの第1引数を利用してエラー画面を切り替える方法を紹介します。現状で、addErrorMiddleware()の第1引数がtrueの状態で存在しないURLにアクセスした場合、図5の画面が表示されます。
存在しないURLなので、いわゆる404エラーです。これが、addErrorMiddleware()の第1引数がfalse、つまり、本運用環境の場合、図4が表示されてしまいます。この場合、障害とは言いにくく、エラー画面もそれ専用に変えるべきです。その画面用テンプレートファイルを404.htmlとするならば、404エラーではこの404.htmlを表示させるようにCustomErrorRendererを改造する必要があります。それは、リスト6の通りになります。
<?php
〜省略〜
use Slim\Exception\HttpNotFoundException; // (1)
class CustomErrorRenderer implements ErrorRendererInterface
{
〜省略〜
else {
$twig = $this->container->get("view");
if($exception instanceof HttpNotFoundException) { // (2)
$returnHtml = $twig->fetch("404.html");
}
else {
$assign["errorMsg"] = "もう一度初めから操作してください。";
$returnHtml = $twig->fetch("error.html", $assign);
}
}
return $returnHtml;
}
}
図5にもあるように、404エラーは、\Slim\Exception\HttpNotFoundExceptionが発生していることになります。したがって、$displayErrorDetailsの分岐のelseブロック内で、__invoke()の第1引数である$exceptionの型で分岐を行います。先述のように、この$exceptionには、発生した例外インスタンスが渡ってくるので、そのインスタンスの型がHttpNotFoundExceptionと一致するかの判定を行います。それがリスト6の(2)です。そして、一致する場合は、fetch()するテンプレートファイルを404.htmlにします。ただし、そのためには(1)の通り、事前にこのHttpNotFoundExceptionクラスをuseしておいてください。
この方式を応用して、例えば、以下のようにelseifブロックを積み重ねることで、発生するさまざまな例外に合わせて、表示するエラー画面を適宜切り替えることが可能となります。
if($exception instanceof HttpNotFoundException) {
:
}
elseif($exception instanceof FileIOException) {
:
}
:
まとめ
今回は、本運用では欠かすことのできないSlimのエラーハンドラを扱いました。
これで、連載終了となります。ここまで全9回に渡り、お付き合いいただき、ありがとうございました。Slimは、マイクロフレームワークとうたうだけあって、作りが非常にシンプルにできているうえ、実際のアプリケーション開発には必要十分な機能が備わっています。フルスタックフレームワークに比べて、プログラマーがコーディングしなければならない部分も増えますが、これは逆にプログラマーが自由にコーディングできるようになっているということでもあります。ややこしいところだけをフレームワークに任せて、自由にコーディングできる、それがSlimの魅力だと思います。この連載で、その魅力の一端でも分かっていただけたら、こんなにうれしいことはありません。
