<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<!-- EN-Revision: 24249 -->
<sect3 id="zend.controller.plugins.standard.errorhandler">
    <title>Zend_Controller_Plugin_ErrorHandler(日本語)</title>

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

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

    <itemizedlist>
        <listitem>
            <para>一致したルートが見つからない場合に発生する例外</para>
        </listitem>

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

        <listitem>
            <para>アクションコントローラ内で発生する例外</para>
        </listitem>
    </itemizedlist>

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

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

    <itemizedlist>
        <listitem>
            <para>
                <methodname>setErrorHandlerModule()</methodname> は、
                使用するコントローラモジュール名を設定します。
            </para>
        </listitem>

        <listitem>
            <para>
                <methodname>setErrorHandlerController()</methodname> は、
                使用するコントローラを設定します。
            </para>
        </listitem>

        <listitem>
            <para>
                <methodname>setErrorHandlerAction()</methodname> は、
                使用するコントローラアクションを設定します。
            </para>
        </listitem>

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

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

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

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

    <sect4 id="zend.controller.plugins.standard.errorhandler.fourohfour">
        <title>404 ハンドラとしての ErrorHandler の使用</title>

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

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

        <programlisting language="php"><![CDATA[
class ErrorController extends Zend_Controller_Action
{
    public function errorAction()
    {
        $errors = $this->_getParam('error_handler');
    }
}
]]></programlisting>

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

        <itemizedlist>
            <listitem>
                <para>
                    <constant>Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE</constant>
                    は、一致したルートが見つからなかったことを表します。
                </para>
            </listitem>

            <listitem>
                <para>
                    <constant>Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER</constant>
                    は、コントローラが見つからなかったことを表します。
                </para>
            </listitem>

            <listitem>
                <para>
                    <constant>Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION</constant>
                    は、アクションが見つからなかったことを表します。
                </para>
            </listitem>

            <listitem>
                <para>
                    <constant>Zend_Controller_Plugin_ErrorHandler::EXCEPTION_OTHER</constant>
                    は、その他の例外を表します。
                </para>
            </listitem>
        </itemizedlist>

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

        <programlisting language="php"><![CDATA[
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;
        }
    }
}
]]></programlisting>

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

        <programlisting language="php"><![CDATA[
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;
        }
}
]]></programlisting>
    </sect4>

    <sect4 id="zend.controller.plugins.standard.errorhandler.buffer">
        <title>前回のレンダリング結果の扱い</title>

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

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

        <programlisting language="php"><![CDATA[
$this->getResponse()->clearBody();
]]></programlisting>
    </sect4>

    <sect4 id="zend.controller.plugins.standard.errorhandler.examples">
        <title>プラグインの使用例</title>

        <example id="zend.controller.plugins.standard.errorhandler.examples.example-1">
            <title>標準的な使用法</title>

            <programlisting language="php"><![CDATA[
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new Zend_Controller_Plugin_ErrorHandler());
]]></programlisting>
        </example>

        <example id="zend.controller.plugins.standard.errorhandler.examples.example-2">
            <title>別のエラーハンドラの設定</title>

            <programlisting language="php"><![CDATA[
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new Zend_Controller_Plugin_ErrorHandler(array(
    'module'     => 'mystuff',
    'controller' => 'static',
    'action'     => 'error'
)));
]]></programlisting>
        </example>

        <example id="zend.controller.plugins.standard.errorhandler.examples.example-3">
            <title>アクセス用メソッドの使用</title>

            <programlisting language="php"><![CDATA[
$plugin = new Zend_Controller_Plugin_ErrorHandler();
$plugin->setErrorHandlerModule('mystuff')
       ->setErrorHandlerController('static')
       ->setErrorHandlerAction('error');

$front = Zend_Controller_Front::getInstance();
$front->registerPlugin($plugin);
]]></programlisting>
        </example>
    </sect4>

    <sect4 id="zend.controller.plugins.standard.errorhandler.controllerexamples">
        <title>エラーコントローラの例</title>

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

        <programlisting language="php"><![CDATA[
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;
    }
}
]]></programlisting>
    </sect4>
</sect3>
<!--
vim:se ts=4 sw=4 et:
-->
