7.5. アクションコントローラ

7.5.1. 導入

Zend_Controller_Action は、 モデル - ビュー - コントローラ (MVC) パターンにもとづいたウェブアプリケーションを作成する際に、 フロントコントローラで使用するアクションコントローラを実装するための抽象クラスです。

Zend_Controller_Action を使用するには、 実際のアクションコントローラ内でこのクラスのサブクラスを作成する必要があります (あるいは、作成したサブクラスをもとにしてアクションコントローラを作成します)。 基本的な使い方としては、まずサブクラスを作成し、 そしてあなたのサイト上で処理したいさまざまなアクションに対応する アクションメソッドを作成するという流れになります。 Zend_Controller は、このクラス内のメソッドで 'Action' という名前で終わるものを見つけると、 ルーティングやディスパッチの際にそれらを自動的にアクションとして扱います。

たとえば、次のようなクラスを見てみましょう。

class FooController extends Zend_Controller_Action
{
    public function barAction()
    {
        // 何かをします
    }

    public function bazAction()
    {
        // 何かをします
    }
}

この FooController クラス ('foo' コントローラ) では、ふたつのアクション 'bar' および 'baz' が定義されています。

もちろんこれ以外にもたくさんの機能があります。 たとえば初期化アクションを独自に作成したり、 アクションを指定しなかった (あるいは無効なアクションを指定した) 際にコールされるデフォルトのアクションを指定したり、 ディスパッチの前後に実行されるフックを指定したり、 さまざまなヘルパーメソッドを使用したりといったことができます。 この章では、アクションコントローラの機能の概要を説明します。

7.5.2. オブジェクトの初期化

アクションコントローラのコンストラクタをオーバーライドすることもできますが、 お勧めしません。Zend_Controller_Action::__construct() は、リクエストオブジェクトやレスポンスオブジェクトを登録するなどの重要な作業を行います。 また、フロントコントローラから渡された起動時引数の処理も行います。 コンストラクタをオーバーライドする場合は、必ずその中で parent::__construct($request, $response, $invokeArgs) をコールするようにしましょう。

初期化作業をカスタマイズするには、コンストラクタをオーバーライドするよりも init() メソッドを使うほうがお勧めです。これは、__construct() の中で最後にコールされます。たとえば、 初期化時にデータベースに接続したいなら次のようにします。

class FooController extends Zend_Controller_Action
{
    public function init()
    {
        $this->db = Zend_Db::factory('Pdo_Mysql', array(
            'host'     => 'myhost',
            'username' => 'user',
            'password' => 'XXXXXXX',
            'dbname'   => 'website'
        ));
    }
}

7.5.3. ディスパッチ前後のフック

Zend_Controller_Action には、 リクエストされたアクションの前後にコールされるふたつのメソッドがあります。それが preDispatch() と postDispatch() です。 これらはさまざまな場面で活用できます。 たとえばアクションを実行する前に認証情報や ACL を調べたり (preDispatch() の中で _forward() をコールすると、 そのアクションの処理は飛ばされます)、 作成したコンテンツを (postDispatch() で) 全サイト共通のテンプレートに配置したりといったことが考えられます。

7.5.4. アクセス用メソッド

さまざまなオブジェクトや変数がオブジェクトに登録されており、 それぞれにアクセス用メソッドが用意されています。

  • リクエストオブジェクト: getRequest() を使用してリクエストオブジェクトを取得し、 それを用いてアクションをコールします。

  • レスポンスオブジェクト: getResponse() を使用して、最終的なレスポンスの内容を取得します。 典型的な使用法は、このようになります。

    $this->getResponse()->setHeader('Content-Type', 'text/xml');
    $this->getResponse()->appendBody($content);
    
  • 起動時引数: フロントコントローラは、パラメータを ルータやディスパッチャそしてアクションコントローラに送ります。 これらのパラメータを取得するには、 getInvokeArg($key) を使用します。あるいは、 すべてのパラメータを取得するには getInvokeArgs() を使用します。

  • リクエストパラメータ: リクエストオブジェクトは、_GET や _POST のようなリクエストパラメータのほかに URL のパスで指定したパラメータも収集します。 これらを取得するには、_getParam($key) あるいは _getAllParams() を使用します。 _setParam() を使用して、リクエストパラメータを設定することもできます。 これは、さらに別のアクションに転送する際などに有用です。

    パラメータが存在するかどうかを調べる (条件分岐の際に使用します) には、 _hasParam($key) を使用します。

7.5.5. ユーティリティメソッド

アクセス用メソッド以外にも、Zend_Controller_Action にはいくつかのユーティリティメソッドが用意されています。 これらを使用して、アクションメソッド (あるいはディスパッチ前後のフックメソッド) でのさまざまな作業を行います。

  • _forward($action, $controller = null, $module = null, array $params = null): 別のアクションを実行します。preDispatch() の中でコールすると、 リクエストされていたアクションは飛ばされ、 新しいアクションを実行します。それ以外の場合は、 現在のアクションの処理を済ませた後で _forward() で指定したアクションを実行します。

  • _redirect($url, array $options = array()): 別の場所にリダイレクトします。このメソッドには、URL のほかに任意でオプション群を指定します。 デフォルトでは、HTTP 302 リダイレクトを行います。

    オプションは、以下のうちのひとつあるいは複数の組み合わせとなります。

    • exit: 即時に終了するかしないか。 これを指定すると、オープンしたいるセッションをすべて閉じた後にリダイレクトします。

      このオプションをコントローラ全体で有効にするには、 アクセスメソッド setRedirectExit() を使用します。

    • prependBase: リクエストオブジェクトに登録されている基底 URL を この URL の先頭に付加するかどうか。

      このオプションをコントローラ全体で有効にするには、 アクセスメソッド setRedirectPrependBase() を使用します。

    • code: リダイレクトの際にどの HTTP コードを使用するか。 デフォルトでは HTTP 302 を使用しますが、 301 から 306 までの任意の値を使用できます。

      You may set this option globally within the このオプションをコントローラ全体で有効にするには、 アクセスメソッド setRedirectCode() を使用します。

  • render($action = null, $name = null, $noController = false): ビュースクリプトをレンダリングします。 引数を省略した場合は、[コントローラ名]/[アクション名].phtml (.phtml はプロパティ $viewSuffix の値です) が要求されたものとみなします。 $action の値を指定すると、 [controller] サブディレクトリ内のテンプレートをレンダリングします。 [controller] サブディレクトリを無視させるには、 $noController に true を渡します。 最後にひとつ。レンダリングされたテンプレートは、レスポンスオブジェクトに出力されます。 もしレスポンスオブジェクト内の特定の部分に出力したい場合は、その値を $name に渡してください。

    例を見てみましょう。

    <?php
    class MyController extends Zend_Controller_Action
    {
        public function fooAction()
        {
            // my/foo.phtml を出力します
            $this->render();
    
            // my/bar.phtml を出力します
            $this->render('bar');
    
            // baz.phtml を出力します
            $this->render('baz', null, true);
    
            // foo/login.phtml を、レスポンスオブジェクトの 'form' 部に出力します
            $this->render('login', 'form');
            
            // site.phtml を、レスポンスオブジェクトの 'page' 部に出力します
            $this->render('site', 'page', true);
        }
    }
    
  • initView(): ビューオブジェクトを初期化します。 render()initView() をコールしてビューオブジェクトを取得しますが、 この初期化はいつでも行うことができます。デフォルトでは、 プロパティ $view を作成します。 デフォルトで使用するのは Zend_View ですが、 Zend_View_Interface を実装したクラスならなんでも使用可能です。

    デフォルトの実装は、次のようなディレクトリ構造を想定しています。

    applicationOrModule/
        controllers/
            IndexController.php
        views/
            scripts/
                index/
                    index.phtml
            helpers/
            filters/
    

    言い換えると、ビュースクリプトが views/scripts/ の配下にあること、そして views ディレクトリが controllers ディレクトリと同一階層にあることを想定しているということです。

    変数の代入やフィルタの登録が必要になった場合などに、 initView()init() あるいはアクションメソッドからコールします。たとえば次のようになります。

    <?php
    class MyController extends Zend_Controller_Action
    {
        public function init()
        {
            // ビューオブジェクトをすぐに初期化します
            $this->initView();
        }
    
        public function fooAction()
        {
            // いくつかの変数を初期化します
            $this->view->foo = 'bar';
            $this->view->bar = 'baz';
    
            // ビューをレンダリングします。変数 'foo' および 'bar' には値が代入されています
            $this->render();
        }
    }
    
    class FooController extends Zend_Controller_Action
    {
        public function barAction()
        {
            // アクション単位でビューを初期化します
            $view = $this->initView();
    
            // いくつかの変数を初期化します
            $view->foo = 'bar';
            $view->bar = 'baz';
    
            // ビューをレンダリングします。変数 'foo' および 'bar' には値が代入されています
            $this->render();
        }
    }
    
  • getViewScript($action = null, $noController = false): ビュースクリプトのパスを取得します。 主に render() から使用しますが、 ビュースクリプトのパスを取得したい場面ではいつでも使用できます。 あるいは、このメソッドをオーバーライドすることで、 コントローラがビュースクリプトのパスを決定する方法を変更することもできます。

    上の render() で詳しく説明したように、デフォルトの機能は [コントローラ名]/[アクション名].phtml というビュースクリプトを探すというものです。 $action を指定すると、ビュースクリプトのファイル名をオーバーライドします。 また $noController に true を渡すと controller サブディレクトリを探さないようにします。 プロパティ $viewSuffix をオーバーライドして、 ファイルの拡張子 (デフォルトは .phtml) を変更することもできます。

    このメソッドをオーバーライドすることで、 ビュースクリプトの名前とパスを決定する機能を変更できます。