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
が定義されています。
もちろんこれ以外にもたくさんの機能があります。 たとえば初期化アクションを独自に作成したり、 アクションを指定しなかった (あるいは無効なアクションを指定した) 際にコールされるデフォルトのアクションを指定したり、 ディスパッチの前後に実行されるフックを指定したり、 さまざまなヘルパーメソッドを使用したりといったことができます。 この章では、アクションコントローラの機能の概要を説明します。
デフォルトの挙動 | |
---|---|
デフォルトでは、フロントコントローラ は ViewRenderer アクションヘルパーを有効にします。このヘルパーは、 ビューオブジェクトをコントローラに注入し、 ビューを自動的にレンダリングします。 アクションコントローラでこれを無効にするには、 以下のいずれかの方法を使用します。 <?php class FooController extends Zend_Controller_Action { public function init() { // このコントローラでのみ無効にします $this->_invokeArgs['noViewRenderer'] = true; // 全体で無効にします $this->_helper->removeHelper('viewRenderer'); // これも全体で無効にしますが、同時にローカルでも無効にしておく必要があります。 // これは、ローカルの設定を全体に伝播させる方法です。 Zend_Controller_Front::getInstance()->setParam('noViewRenderer', true); } }
個々のビューのレンダリングを無効にするには、単純に
<?php class FooController extends Zend_Controller_Action { public function barAction() { // このアクションでの自動レンダリングを無効にします $this->_helper->viewRenderer->setNoRender(); } }
|
アクションコントローラのコンストラクタをオーバーライドすることもできますが、
お勧めしません。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' )); } }
Zend_Controller_Action
には、
リクエストされたアクションの前後にコールされるふたつのメソッドがあります。それが
preDispatch()
と postDispatch()
です。
これらはさまざまな場面で活用できます。
たとえばアクションを実行する前に認証情報や ACL
を調べたり (preDispatch()
の中で _forward()
をコールすると、
そのアクションの処理は飛ばされます)、
作成したコンテンツを (postDispatch()
で)
全サイト共通のテンプレートに配置したりといったことが考えられます。
さまざまなオブジェクトや変数がオブジェクトに登録されており、 それぞれにアクセス用メソッドが用意されています。
リクエストオブジェクト:
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)
を使用します。
注意 | |
---|---|
<?php // id が設定されていない場合のデフォルト値を 1 とします $id = $this->_getParam('id', 1); // わざわざこのようにする必要はありません if ($this->_hasParam('id') { $id = $this->_getParam('id'); } else { $id = 1; } ?> |
Zend_Controller_Action
では、
ビューの統合のためのちょっとした柔軟な仕組みを提供しています。
これを行うのは initView()
と render()
のふたつのメソッドです。前者のメソッドはパブリックプロパティ
$view
の遅延読み込みを行い、
後者のメソッドはアクションの要求にもとづいてビューをレンダリングします。
その際に、ディレクトリ階層をもとにスクリプトのパスを決定します。
initView()
はビューオブジェクトを初期化します。
render()
は initView()
をコールしてビューオブジェクトを取得しますが、
その初期化はいつでも好きなときに行うことができます。
デフォルトでは、取得した結果は Zend_View
オブジェクトのプロパティ $view
に格納されますが、
Zend_View_Interface
を実装したクラスなら何でも好きなものを使用することができます。
$view
がすでに初期化されている場合は、そのプロパティの内容を返します。
デフォルトの実装は、以下のようなディレクトリ階層を前提としています。
applicationOrModule/ controllers/ IndexController.php views/ scripts/ index/ index.phtml helpers/ filters/
言い換えると、ビュースクリプトが
views/scripts/
ディレクトリ内にあり、かつ
views
ディレクトリ内の同一階層に各機能
(ヘルパー、フィルタ)のディレクトリがあるということです。
ビュースクリプトの名前とパスを決定する際の基底ディレクトリとして
views/scripts/
が用いられます。
その中に、ビュースクリプトを実行するコントローラ名に基づいた名前のディレクトリが作成されます。
render()
のシグネチャは次のとおりです。
<?php string render(string $action = null, string $name = null, bool $noController = false); ?>
render()
はビュースクリプトをレンダリングします。
引数を省略した場合は、[controller]/[action].phtml
が指定されたものとみなします(.phtml
は $viewSuffix
プロパティの値です)。
$action
を指定すると、[controller]
ディレクトリにあるその名前のテンプレートをレンダリングします。
[controller]
ディレクトリを使用しないようにするには、
$noController
に true を指定します。
テンプレートをレンダリングした結果はレスポンスオブジェクトに格納されます。
レスポンスオブジェクトの中の、
特定の名前をつけた部分 に格納したい場合は、
$name
の値を指定します。
注意 | |
---|---|
コントローラやアクションの名前には区切り文字
('_' や '.'、'-') を含めることができるので、
render() はスクリプト名を決定する際にこれらの文字を
'-' に正規化します。内部的には、
ディスパッチャで設定されている単語やパスの区切り文字を正規化時に用います。
したがって、 |
例を見てみましょう。
<?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); // my/login.phtml をレンダリングし、レスポンスオブジェクトの 'form' の部分に返します $this->render('login', 'form'); // site.phtml をレンダリングし、レスポンスオブジェクトの 'page' の部分に返します // 'my/' ディレクトリは使用しません $this->render('site', 'page', true); } public function bazBatAction() { // my/baz-bat.phtml をレンダリングします $this->render(); } }
アクセス用メソッドやビューの統合用メソッド以外にも、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 までの任意の値を使用できます。
このオプションをコントローラ全体で有効にするには、
アクセスメソッド setRedirectCode()
を使用します。
アクションコントローラを作成するには、必ず
Zend_Controller_Action
のサブクラスを作成しなければならないようになっています。
最低限、コントローラがコールするアクションメソッドを定義しなければなりません。
自分のウェブアプリケーション用に便利な機能を実装していく一方で、
同じような前処理やちょっとした処理をあちこちのコントローラで書いているといったことはありませんか?
そのような場合は、Zend_Controller_Action
を継承した共通基底コントローラクラスを作成し、
共通処理をそこにまとめていくようにしましょう。
コントローラへのリクエストの際に未定義のアクションメソッドが指定された場合は、
Zend_Controller_Action::__call()
を実行します。
__call()
とはもちろん、PHP
のマジックメソッドで、メソッドのオーバーロード用に使用するものです。
デフォルトでは、このメソッドは
Zend_Controller_Action_Exception
をスローして、コントローラの中にアクションが見つからなかったことを示します。
もし別の動作をさせたい場合は、これをオーバーライドしましょう。
たとえば、エラーメッセージを表示させたい場合は次のようになります。
<?php class MyController extends Zend_Controller_Action { public function __call($method, $args) { if ('Action' == substr($method, -6)) { // アクションメソッドが見つからなかった場合は、エラー用のテンプレートをレンダリングします return $this->render('error'); } // その他のメソッドの場合は例外をスローします throw new Exception('Invalid method "' . $method . '" called'); } } ?>
もうひとつの例として、デフォルトコントローラに転送する処理を見てみましょう。
<?php class MyController extends Zend_Controller_Action { public function indexAction() { $this->render(); } public function __call($method, $args) { if ('Action' == substr($method, -6)) { // アクションメソッドが見つからなかった場合は、index アクションに転送します return $this->_forward('index'); } // その他のメソッドの場合は例外をスローします throw new Exception('Invalid method "' . $method . '" called'); } } ?>
__call()
をオーバーライドするかわりに、
これまで説明してきた各種フックメソッドをオーバーライドしてコントローラをカスタマイズすることもできます。
たとえば、ビューオブジェクトをレジストリに保存したい場合は、
initView()
メソッドを次のように書き換えることになるでしょう。
<?php abstract class My_Base_Controller extends Zend_Controller_Action { public function initView() { if (null === $this->view) { if (Zend_Registry::isRegistered('view')) { $this->view = Zend_Registry::get('view'); } else { $this->view = new Zend_View(); $this->view->setBasePath(dirname(__FILE__) . '/../views'); } } return $this->view; } } ?>
この章の情報をもとに、それぞれの機能の柔軟性をもとにして アプリケーションやサイトの要求に応じたコントローラを作成していくとよいでしょう。