例外発生時のテンプレートの変更

symfonyのアプリケーション内部で例外が発生した場合、デバッグモードが有効になっていればデバッグトレースを、無効になっている場合はOops!の画面を出すようにデフォルトではなっています。

デバッグモードが有効になっている場合は後に説明しますが、重要なのはデバッグが無効、つまり本番環境の場合です。

symfony1.0の場合は web/error/error500.php を作成すればそれが読み込まれるようになっています。アプリケーションごとに変更することはできません。

symfony1.2ではここが変更されています。アプリケーションのconfigもしくはプロジェクトのconfigディレクトリ内に error/error.html.php というファイルを作成すればそれが読み込まれるような仕様になっています。htmlはフォーマットです。リクエストのフォーマットがrssならerror.rss.phpというファイルが読み込まれます。

symfony1.2からはアプリケーションごとに設定できるようになり、ルーティングにあわせてフォーマットの指定もできるようになりました。基本的にはこのあたりの仕様はsfException::outputStackTraceメソッドを見てもらえればわかると思います。

また、デバッグモードが有効になっている場合に表示されるデバッグトレース画面も、symfony1.2では変更可能です。先ほどはerror.html.phpでしたが、exception.html.phpという名前にすれば変更することができます。ここらへんはまあ詳しくみたければソースをみてください。エラーのテンプレートファイル名を取得しているのがsfException::getTemplatePathForErrorになります。

<?php
static public function getTemplatePathForError($format, $debug)
{
  $templatePaths = array(
    sfConfig::get('sf_app_config_dir').'/error',
    sfConfig::get('sf_config_dir').'/error',
    dirname(__FILE__).'/data',
  );

  $template = sprintf('%s.%s.php', $debug ? 'exception' : 'error', $format);
  foreach ($templatePaths as $path)
  {
    if (!is_null($path) && is_readable($file = $path.'/'.$template))
    {
      return $file;
    }
  }

  return false;
}


念のために言っておくと、上記が適応されるのはsfFrontWebController#dispatchの内部になります。後でまとめるとかいってまとめていないのですが、dispatchする前にApplicationConfigurationの生成やらsfContextの生成やらが行われます。その処理はdispatchの前の処理なのでそこで起きた例外については内部的に捕捉は行いませんので上記の適応外です。投げっぱなしです。ちょっと間違っていたので追記しました。

     *      *
  *     +  うそです
     n ∧_∧ n
 + (ヨ(* ´∀`)E)
      Y     Y    * 

まとめるっていってまとめていない記事ですが、流れを書くのはいいけどそれにうまくコメントをつけて解説するのがすげー面倒くさいなーと思って止まってます。そもそもまだ全部見ているわけではないので、口でも説明できない場所があるのですが。。。書き終わるまでもうちょっとかかりそうです。

追記:うそついた

sfContext#initializeでloadFactoriesメソッドを呼び出すときも同じように例外の捕捉とスタックトレースの出力を行ってました。ですので、

  • sfContext#initialize()
  • sfFrontWebController#dispatch()

上記のメソッドの外側で実行されているものに関しては例外を出力したりはしていないようです。細かいところはあんまりみてませんが、上記に当てはまらない場所で例外が発生することは普通に使っていればないんじゃないでしょうか。