<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<!-- EN-Revision: 16674 -->
<sect1 id="zend.controller.front">
    <title>フロントコントローラ</title>

    <sect2 id="zend.controller.front.overview">
        <title>概要</title>

        <para>
            <classname>Zend_Controller_Front</classname> は
            <ulink url="http://en.wikipedia.org/wiki/Model-view-controller">Model-View-Controller
            (MVC)</ulink> アプリケーションで用いられる
            <ulink url="http://www.martinfowler.com/eaaCatalog/frontController.html">
            フロントコントローラパターン</ulink> を実装したものです。
            その役割は、リクエスト環境を初期化してリクエストの配送先を決定し、
            見つかった配送先に処理を引き渡すことです。また、
            レスポンスの内容を取得してそれをコール元に返します。
        </para>

        <para>
            <classname>Zend_Controller_Front</classname> は <ulink
            url="http://en.wikipedia.org/wiki/Singleton_pattern">シングルトンパターン</ulink>
            も実装しています。つまり、どんな場合でもひとつのインスタンスしか存在しないことになります。
            これを利用すると、コントローラをレジストリとして扱えるようになります。
        </para>

        <para>
            <classname>Zend_Controller_Front</classname> は <link
                linkend="zend.controller.plugins">プラグインブローカ</link>
            を持っています。これにより、さまざまなイベントをプラグインで処理できるようになります。
            開発者は、ディスパッチ処理をカスタマイズして機能を追加する際に
            フロントコントローラ自体を継承したクラスを作成する必要がなくなります。
        </para>

        <para>
            <link linkend="zend.controller.action">アクションコントローラ</link>
            へのパスを含むディレクトリを最低ひとつは指定しないと、
            フロントコントローラは動作しません。
            フロントコントローラの動作環境やそのヘルパークラスを変更するために、
            さまざまな手法が用意されています。
        </para>

        <note>
            <title>デフォルトの挙動</title>
            <para>
                デフォルトでは、フロントコントローラは
                <link linkend="zend.controller.plugins.standard.errorhandler">ErrorHandler</link>
                プラグインと
                <link linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>
                アクションヘルパープラグインを読み込みます。
                これらにより、コントローラ内でのエラー処理やビューのレンダリングがシンプルに行えるようになります。
            </para>

            <para>
                <emphasis>ErrorHandler</emphasis> を無効にするには、
                <methodname>dispatch()</methodname> をコールする前のどこかで以下のようにします。
            </para>

            <programlisting language="php"><![CDATA[
// ErrorHandler プラグインを無効にします
$front->setParam('noErrorHandler', true);
]]></programlisting>

            <para>
                <emphasis>ViewRenderer</emphasis> を無効にするには、
                <methodname>dispatch()</methodname> をコールする前に以下を実行します。
            </para>

            <programlisting language="php"><![CDATA[
// ViewRenderer ヘルパーを無効にします
$front->setParam('noViewRenderer', true);
]]></programlisting>
        </note>
    </sect2>

    <sect2 id="zend.controller.front.methods.primary">
        <title>主要なメソッド</title>

        <para>
            フロントコントローラには、その環境設定用のメソッドがいくつか用意されています。
            そのうち、フロントコントローラの機能の鍵となる主要なメソッドは、以下の3つです。
        </para>

        <sect3 id="zend.controller.front.methods.primary.getinstance">
            <title>getInstance()</title>

            <para>
                <methodname>getInstance()</methodname> は、フロントコントローラのインスタンスを取得します。
                フロントコントローラはシングルトンパターンを実装しているので、
                フロントコントローラのインスタンスを作成する唯一の方法はこのメソッドをコールすることとなります。
            </para>

            <programlisting language="php"><![CDATA[
$front = Zend_Controller_Front::getInstance();
]]></programlisting>
        </sect3>

        <sect3 id="zend.controller.front.methods.primary.setcontrollerdirectory">
            <title>setControllerDirectory() および addControllerDirectory</title>

            <para>
                <methodname>setControllerDirectory()</methodname> は、<link
                    linkend="zend.controller.dispatcher">ディスパッチャ</link>
                が <link
                    linkend="zend.controller.action">アクションコントローラ</link>
                クラスファイルをどこから探せばよいのかを指定するメソッドです。
                単一のパスを指定することもできますし、複数のパスを連想配列で指定することもできます。
            </para>

            <para>
                いくつか例を示します。
            </para>

            <programlisting language="php"><![CDATA[
// デフォルトのコントローラディレクトリを設定します
$front->setControllerDirectory('../application/controllers');

// 複数のモジュールのディレクトリを一度に指定します
$front->setControllerDirectory(array(
    'default' => '../application/controllers',
    'blog'    => '../modules/blog/controllers',
    'news'    => '../modules/news/controllers',
));

// 'foo' モジュールのディレクトリを追加します
$front->addControllerDirectory('../modules/foo/controllers', 'foo');
]]></programlisting>

            <note>
                <para>
                    <methodname>addControllerDirectory()</methodname>
                    でモジュール名を省略すると、<emphasis>default</emphasis>
                    モジュールが指定されたものとみなします。
                    もしすでに存在する場合は、それを上書きします。
                </para>
            </note>

            <para>
                コントローラディレクトリの現在の設定を取得するには
                <methodname>getControllerDirectory()</methodname> を使用します。
                これは、モジュールとディレクトリの組を配列で返します。
            </para>
        </sect3>

        <sect3 id="zend.controller.front.methods.primary.addmoduledirectory">
            <title>addModuleDirectory() および getModuleDirectory()</title>

            <para>
                フロントコントローラのひとつの側面として、<link
                    linkend="zend.controller.modular">モジュラーディレクトリ構造を定義
                </link> して単体のコンポーネントを作成するということがあります。
                これは "モジュール" と呼ばれます。
            </para>

            <para>
                書くモジュールは個別のディレクトリになければならず、
                またデフォルトモジュールと同じディレクトリ構成でなければなりません。
                すなわち、すくなくともサブディレクトリ <filename>/controllers/</filename> がなければならず、
                またたいていは <filename>/views/</filename> などの他のサブディレクトリもあるということです。
            </para>

            <para>
                <methodname>addModuleDirectory()</methodname>
                には、ひとつあるいは複数のモジュールディレクトリの名前を渡します。
                渡された内容を調べ、それをフロントコントローラのコントローラディレクトリに追加します。
            </para>

            <para>
                その後、特定のモジュールや現在のモジュールへのパスを知りたい場合に
                <methodname>getModuleDirectory()</methodname> をコールします。
                モジュール名を渡すと、指定したモジュールのディレクトリを取得することができます。
            </para>
        </sect3>

        <sect3 id="zend.controller.front.methods.primary.dispatch">
            <title>dispatch()</title>

            <para>
                <methodname>dispatch(Zend_Controller_Request_Abstract $request = null,
                    Zend_Controller_Response_Abstract $response = null)</methodname>
                は、フロントコントローラでもっとも重要な仕事を担当します。
                オプションで <link linkend="zend.controller.request">リクエストオブジェクト</link>
                や <link linkend="zend.controller.response">レスポンスオブジェクト</link>
                を受け取り、それぞれ独自のオブジェクトを指定することができます。
            </para>

            <para>
                リクエストオブジェクトやレスポンスオブジェクトを省略すると、
                <methodname>dispatch()</methodname> は事前にオブジェクトが登録されているかどうかを確認します。
                もし登録されていればそれを使用し、登録されていなければデフォルトのオブジェクトを作成して使用します
                (どちらの場合についても、<acronym>HTTP</acronym> リクエスト/レスポンス オブジェクトをデフォルトで使用します)。
            </para>

            <para>
                同様に、<methodname>dispatch()</methodname> は <link
                    linkend="zend.controller.router">ルータ</link> や <link
                    linkend="zend.controller.dispatcher">ディスパッチャ</link>
                オブジェクトについても登録済みのものがあるかどうかを確認します。
                もしあればそれを使用し、なければデフォルトのオブジェクトを作成して使用します。
            </para>

            <para>
                ディスパッチ処理は、次の三段階に分けられます。
            </para>

            <itemizedlist>
                <listitem><para>ルーティング</para></listitem>
                <listitem><para>ディスパッチ</para></listitem>
                <listitem><para>レスポンス</para></listitem>
            </itemizedlist>

            <para>
                ルーティングは一度だけ発生します。これは、<methodname>dispatch()</methodname>
                がコールされた際のリクエストオブジェクトの内容を使用して行います。
                ディスパッチは繰り返し行われます。
                ひとつのリクエストが複数のアクションを指定している場合や、
                コントローラまたはプラグインがリクエストオブジェクトを設定しなおして
                別のアクションへディスパッチさせた場合などです。
                すべてが終了したら、フロントコントローラはレスポンスを返します。
            </para>
        </sect3>

        <sect3 id="zend.controller.front.methods.primary.run">
            <title>run()</title>

            <para>
                <methodname>Zend_Controller_Front::run($path)</methodname>
                は静的メソッドで、コントローラを含むディレクトリへのパスを指定します。
                このメソッドは
                <link linkend="zend.controller.front.methods.primary.getinstance">getInstance()</link>
                を使用してフロントコントローラのインスタンスを取得し、
                <link linkend="zend.controller.front.methods.primary.setcontrollerdirectory">setControllerDirectory()</link>
                を使用してパスを登録し、最後に
                <link linkend="zend.controller.front.methods.primary.dispatch">ディスパッチ</link>
                します。
            </para>

            <para>
                <methodname>run()</methodname> は、サイト単位の設定などで
                フロントコントローラのカスタマイズが不要な場合に便利なメソッドです。
            </para>

            <programlisting language="php"><![CDATA[
// フロントコントローラを作成してコントローラディレクトリを設定し、
// ディスパッチするまでをいちどでお手軽に行います
Zend_Controller_Front::run('../application/controllers');
]]></programlisting>
        </sect3>
    </sect2>

    <sect2 id="zend.controller.front.methods.environment">
        <title>環境へのアクセス用メソッド群</title>

        <para>
            これまでに説明したメソッド以外にもさまざまなアクセス用メソッドが用意されており、
            これらを使用してフロンとコントローラの環境にアクセスすることができます。
            つまり、フロントコントローラが処理を委譲しているクラスの環境にもアクセスできるということです。
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    <methodname>resetInstance()</methodname> は、現在の設定をすべて消去します。
                    主にテスト目的で使用しますが、
                    複数のフロントコントローラを連結させたい場合などに使用することもあります。
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>setDefaultControllerName()</methodname> および
                    <methodname>getDefaultControllerName()</methodname>
                    で、デフォルトのコントローラとして使用する名前を指定したり
                    (指定しなければ 'index' となります) 現在の設定を取得したりできます。
                    これらメソッドは、<link linkend="zend.controller.dispatcher">
                    ディスパッチャ</link> へのプロキシです。
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>setDefaultAction()</methodname> および
                    <methodname>getDefaultAction()</methodname>
                    で、デフォルトのアクションとして使用する名前を指定したり
                    (指定しなければ 'index' となります) 現在の設定を取得したりできます。
                    これらのメソッドは <link linkend="zend.controller.dispatcher">
                    ディスパッチャ</link> へのプロキシです。
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>setRequest()</methodname> および
                    <methodname>getRequest()</methodname> は、ディスパッチ処理で使用する
                    <link linkend="zend.controller.request">リクエスト</link>
                    クラスやオブジェクトを指定したり、現在のオブジェクトを取得したりします。
                    リクエストオブジェクトを指定するときに、クラス名を指定することができます。
                    この場合、このメソッドは指定したクラスファイルを読み込んでインスタンスを作成します。
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>setRouter()</methodname> および
                    <methodname>getRouter()</methodname> は、ディスパッチ処理で使用する
                    <link linkend="zend.controller.router">ルータ</link>
                    クラスやオブジェクトを指定したり、現在のオブジェクトを取得したりします。
                    ルータオブジェクトを指定するときに、クラス名を指定することができます。
                    この場合、このメソッドは指定したクラスファイルを読み込んでインスタンスを作成します。
                </para>

                <para>
                    ルータオブジェクトを取得する際には、まずルータが存在するかどうかを調べ、
                    存在しない場合にはデフォルトのルータ (rewrite ルータ) のインスタンスを作成します。
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>setBaseUrl()</methodname> および
                    <methodname>getBaseUrl()</methodname> は、リクエストのルーティング時に URL から取り除く
                    <link linkend="zend.controller.request.http.baseurl">基底 URL</link>
                    を指定したり、現在の値を取得したりします。
                    この値は、ルーティングの直前にリクエストオブジェクトに渡されます。
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>setDispatcher()</methodname> および
                    <methodname>getDispatcher()</methodname> は、ディスパッチ処理で使用する
                    <link linkend="zend.controller.dispatcher">ディスパッチャ</link>
                    クラスやオブジェクトを指定したり、現在のオブジェクトを取得したりします。
                    ディスパッチャオブジェクトを指定するときに、クラス名を指定することができます。
                    この場合、このメソッドは指定したクラスファイルを読み込んでインスタンスを作成します。
                </para>

                <para>
                    ディスパッチャオブジェクトを取得する際には、まずディスパッチャが存在するかどうかを調べ、
                    存在しない場合にはデフォルトのディスパッチャのインスタンスを作成します。
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>setResponse()</methodname> および
                    <methodname>getResponse()</methodname> は、ディスパッチ処理で使用する
                    <link linkend="zend.controller.response">レスポンス</link>
                    クラスやオブジェクトを指定したり、現在のオブジェクトを取得したりします。
                    レスポンスオブジェクトを指定するときに、クラス名を指定することができます。
                    この場合、このメソッドは指定したクラスファイルを読み込んでインスタンスを作成します。
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>registerPlugin(Zend_Controller_Plugin_Abstract $plugin, $stackIndex = null)</methodname>
                    は、<link linkend="zend.controller.plugins">プラグインオブジェクト</link>
                    を登録します。オプションの <varname>$stackIndex</varname>
                    を設定すると、プラグインの実行順を制御することができます。
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>unregisterPlugin($plugin)</methodname> は、
                    <link linkend="zend.controller.plugins">プラグインオブジェクト</link>
                    の登録を解除します。<varname>$plugin</varname>
                    にはプラグインオブジェクトそのものか、あるいはプラグインのクラス名を表す文字列を指定します。
                    ここで指定したプラグインの登録を解除します。
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>throwExceptions($flag)</methodname> で、ディスパッチの際に発生した例外をスローするかどうかを切り替えます。
                    デフォルトでは、例外はスローされず、
                    <link linkend="zend.controller.response">レスポンスオブジェクト</link>
                    に保存されます。<methodname>throwExceptions()</methodname>
                    をオンにすると、この挙動を変更できます。
                </para>

                <para>
                    詳細は <link linkend="zend.controller.exceptions">MVC
                    例外</link> を参照ください。
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>returnResponse($flag)</methodname> は、フロントコントローラが
                    <methodname>dispatch()</methodname> からのレスポンスを返す (<constant>TRUE</constant>)
                    かレスポンスを自動的に発行する (<constant>FALSE</constant>)
                    かを切り替えます。デフォルトでは、レスポンスは
                    (<methodname>Zend_Controller_Response_Abstract::sendResponse()</methodname> によって)
                    自動的に発行されます。<methodname>returnResponse()</methodname>
                    をオンにすると、この挙動を変更できます。
                    behaviour.
                </para>

                <para>
                    レスポンスを返すようにする理由としては、
                    実際に発行する前に例外のチェックを行いたり
                    レスポンスの情報 (ヘッダなど) をログに記録したりなどが考えられます。
                </para>
            </listitem>
        </itemizedlist>
    </sect2>

    <sect2 id="zend.controller.front.methods.params">
        <title>フロントコントローラのパラメータ</title>

        <para>
            最初のほうで、フロントコントローラはレジストリとしても使用できると説明しました。
            その際に使用するのが "param" 系のメソッド群です。
            これらのメソッドを使用すると、任意のデータ (オブジェクトや変数)
            をフロントコントローラに登録することができます。
            登録したデータは、ディスパッチチェイン内のどこででも使用できます。
            これらの値は、ルータやディスパッチャそしてアクションコントローラにも渡されます。
            各メソッドについて、以下にまとめます。
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    <methodname>setParam($name, $value)</methodname> は、
                    パラメータ <varname>$name</varname> の値を
                    <varname>$value</varname> に設定します。
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>setParams(array $params)</methodname> は、
                    連想配列を使用して複数のパラメータを一度に設定します。
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>getParam($name)</methodname> は、
                    <varname>$name</varname> で指定した名前のパラメータの値を取得します。
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>getParams()</methodname> は、
                    すべてのパラメータの一覧を一度に取得します。
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>clearParams()</methodname> は、
                    単一のパラメータ (文字列で指定した場合) か
                    複数のパラメータ (文字列の配列で指定した場合)、
                    またはすべてのパラメータ (何も指定しなかった場合)
                    を消去します。
                </para>
            </listitem>
        </itemizedlist>

        <para>
            ディスパッチチェイン内で特定の目的で使用するために、
            いくつかのパラメータが事前に定義されています。
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    <emphasis>useDefaultControllerAlways</emphasis> は、
                    ディスパッチできない
                    (モジュール、コントローラ、アクションのいずれかが存在しない)
                    リクエストに対して、
                    デフォルトモジュールのデフォルトコントローラにディスパッチするよう
                    <link linkend="zend.controller.dispatcher">ディスパッチャ</link>
                    に指示します。デフォルトではこの機能は無効になっています。
                </para>

                <para>
                    この設定の使用法についての詳細は
                    <link linkend="zend.controller.exceptions.internal">
                    遭遇するであろう MVC 例外</link>
                    を参照ください。
                </para>
            </listitem>

            <listitem>
                <para>
                    <emphasis>disableOutputBuffering</emphasis> は、
                    アクションコントローラの出力をバッファリングしないよう
                    <link linkend="zend.controller.dispatcher">ディスパッチャ</link>
                    に指示します。デフォルトでは、
                    ディスパッチャがいったんすべての出力をキャプチャして、
                    レスポンスオブジェクトに追加しています。
                </para>
            </listitem>

            <listitem>
                <para>
                    <emphasis>noViewRenderer</emphasis> を使用して、<link
                        linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>
                    を無効にします。このパラメータを true に設定すると、無効となります。
                </para>
            </listitem>

            <listitem>
                <para>
                    <emphasis>noErrorHandler</emphasis> を使用して、<link
                        linkend="zend.controller.plugins.standard.errorhandler">
                    エラーハンドラプラグイン</link> を無効にします。
                    このパラメータを true に設定すると、無効となります。
                </para>
            </listitem>
        </itemizedlist>
    </sect2>

    <sect2 id="zend.controller.front.subclassing">
        <title>フロントコントローラの継承</title>

        <para>
            フロントコントローラを継承する際には、
            最低限 <methodname>getInstance()</methodname> メソッドをオーバーライドしなければなりません。
        </para>

        <programlisting language="php"><![CDATA[
class My_Controller_Front extends Zend_Controller_Front
{
    public static function getInstance()
    {
        if (null === self::$_instance) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }
}
]]></programlisting>

        <para>
            <methodname>getInstance()</methodname> メソッドをオーバーライドすることで、それ以降の
            <methodname>Zend_Controller_Front::getInstance()</methodname> のコールが
            <classname>Zend_Controller_Front</classname> ではなく新しいサブクラスのインスタンスを返すようになります。
            これは、デフォルト以外のルータやビューヘルパーを使用する場合などに便利です。
        </para>

        <para>
            何か新しい機能 (たとえばプラグインの自動ローダーや、
            アクションヘルパーのパスの指定方法)
            を追加したいというのでもない限り、
            ふつうはフロントコントローラのサブクラスを作成する必要はありません。
            ほかに変更したくなるような箇所としては、
            コントローラディレクトリの保存方法や
            デフォルトルータ/デフォルトディスパッチャを使用するかどうかなどがあるでしょう。
        </para>
    </sect2>
</sect1>
<!--
vim:se ts=4 sw=4 et:
-->
