# Zend_Controller_Plugin_ErrorHandler(日本語)

`Zend_Controller_Plugin_ErrorHandler` は、アプリケーションからスローされた例外を処理するためのプラグインです。 たとえば、指定したコントローラやアクションが見つからないといったエラーを処理します。 これは、MVC の例外についてのセクション で説明したメソッド群の代わりとして使用できます。

このプラグインが主に対象としているのは、次のような例外です。

- 一致したルートが見つからない場合に発生する例外

- コントローラやアクションメソッドが見つからない場合に発生する例外

- アクションコントローラ内で発生する例外

言い換えると、ErrorHandler プラグインが想定しているのは、HTTP 404 型のエラー (ページが存在しない) と 500 型のエラー (内部エラー) ということになります。 他のプラグインで発生した例外の処理は、想定していません。

デフォルトでは、`Zend_Controller_Plugin_ErrorHandler` はデフォルトモジュールの `ErrorController::errorAction()` に処理を転送します。これを変更するには、以下のようなアクセス用メソッドを使用します。

- `setErrorHandlerModule()` は、 使用するコントローラモジュール名を設定します。

- `setErrorHandlerController()` は、 使用するコントローラを設定します。

- `setErrorHandlerAction()` は、 使用するコントローラアクションを設定します。

- `setErrorHandler()` は連想配列を受け取ります。 この連想配列のキーには 'module'、'controller' あるいは 'action' を指定することができ、 それぞれ対応する値を設定します。

さらに、コンストラクタの引数として連想配列を渡すこともできます。 この場合、その配列がそのまま `setErrorHandler()` に渡されます。

`Zend_Controller_Plugin_ErrorHandler` は `postDispatch()` フックとして登録され、 レスポンスオブジェクト に格納された例外を確認します。もし何かの例外が見つかったら、 事前に登録されているエラーハンドラアクションに処理を転送します。

エラーハンドラへのディスパッチ中に例外が発生した場合は、 このプラグインはフロントコントローラに例外をスローします。 その際に、レスポンスオブジェクトに格納された直近の例外を再度スローします。

## 404 ハンドラとしての ErrorHandler の使用

ErrorHandler プラグインが捕捉するのは、 アプリケーションのエラーだけではありません。 コントローラチェインが次のコントローラクラスやアクションメソッドを 見つけられなかった場合に、404 ハンドラとして動作させることもできます。 そのためには、エラーコントローラ内で例外の型を調べる必要があります。

捕捉した例外は、リクエストで登録したオブジェクトの中に記録されます。 これを取得するには、 `Zend_Controller_Action::_getParam('error_handler')` を使用します。

    class ErrorController extends Zend_Controller_Action
    {
        public function errorAction()
        {
            $errors = $this->_getParam('error_handler');
        }
    }

エラーオブジェクトを取得したら、次に `$errors->type` でその型を調べます。 これは、次のいずれかとなります。

- `Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE` は、一致したルートが見つからなかったことを表します。

- `Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER` は、コントローラが見つからなかったことを表します。

- `Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION` は、アクションが見つからなかったことを表します。

- `Zend_Controller_Plugin_ErrorHandler::EXCEPTION_OTHER` は、その他の例外を表します。

最初の３つの型であった場合に、404 ページを返せばいいわけです。

    class ErrorController extends Zend_Controller_Action
    {
        public function errorAction()
        {
            $errors = $this->_getParam('error_handler');

            switch ($errors->type) {
                case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
                case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
                case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
                    // 404 エラー -- コントローラあるいはアクションが見つかりません
                    $this->getResponse()
                         ->setRawHeader('HTTP/1.1 404 Not Found');

                    // ... 何か、表示する内容を作成します ...
                    break;
                default:
                    // アプリケーションのエラー。エラーページを表示しますが、
                    // ステータスコードは変更しません
                    break;
            }
        }
    }

エラーハンドラで発生した礼儀を取得するには、 error_handler オブジェクトのプロパティ exception を使用します。

    public function errorAction()
    {
            $errors = $this->_getParam('error_handler');

            switch ($errors->type) {
                case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
                case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
                case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
                    // 404 エラー -- コントローラあるいはアクションが見つかりません
                    $this->getResponse()
                         ->setRawHeader('HTTP/1.1 404 Not Found');

                    // ... 何か、表示する内容を作成します ...
                    break;
                default:
                    // アプリケーションのエラー。エラーページを表示しますが、
                    // ステータスコードは変更しません

                    // ...

                    // 例外をログに記録します
                    $exception = $errors->exception;
                    $log = new Zend_Log(
                        new Zend_Log_Writer_Stream(
                            '/tmp/applicationException.log'
                        )
                    );
                    $log->debug($exception->getMessage() . "\n" .
                                $exception->getTraceAsString());
                    break;
            }
    }

## 前回のレンダリング結果の扱い

ひとつのリクエストで複数のアクションにディスパッチする場合、 あるいはアクション内で `render()` を複数回コールする場合などは、 レスポンスオブジェクト内にすでに内容が格納されていることがあります。 これをうまく処理しないと、本当に必要な内容と それ以外の内容が混じってしまう恐れがあります。

そのような場合にページの中でエラー処理をしたい場合は、 特に何も手を加える必要はありません。 そのような内容をレンダリングしたくないという場合は、 ビューのレンダリング前に以前の内容を消去しておく必要があります。

    $this->getResponse()->clearBody();

## プラグインの使用例

### 標準的な使用法

    $front = Zend_Controller_Front::getInstance();
    $front->registerPlugin(new Zend_Controller_Plugin_ErrorHandler());

### 別のエラーハンドラの設定

    $front = Zend_Controller_Front::getInstance();
    $front->registerPlugin(new Zend_Controller_Plugin_ErrorHandler(array(
        'module'     => 'mystuff',
        'controller' => 'static',
        'action'     => 'error'
    )));

### アクセス用メソッドの使用

    $plugin = new Zend_Controller_Plugin_ErrorHandler();
    $plugin->setErrorHandlerModule('mystuff')
           ->setErrorHandlerController('static')
           ->setErrorHandlerAction('error');

    $front = Zend_Controller_Front::getInstance();
    $front->registerPlugin($plugin);

## エラーコントローラの例

エラーハンドラプラグインを使用するには、 エラーコントローラが必要です。以下にシンプルな例を示します。

    class ErrorController extends Zend_Controller_Action
    {
        public function errorAction()
        {
            $errors = $this->_getParam('error_handler');

            switch ($errors->type) {
                case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
                case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
                case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
                    // 404 エラー -- コントローラあるいはアクションが見つかりません
                    $this->getResponse()->setRawHeader('HTTP/1.1 404 Not Found');

                    $content =<<<EOH
    <h1>エラー!</h1>
    <p>そのページは存在しません。</p>
    EOH;
                    break;
                default:
                    // アプリケーションのエラー
                    $content =<<<EOH
    <h1>エラー!</h1>
    <p>予期せぬエラーが発生しました。後でもう一度お試しください。</p>
    EOH;
                    break;
            }

            // 前回の内容を消去します
            $this->getResponse()->clearBody();

            $this->view->content = $content;
        }
    }