1 <?xml version="1.0" encoding="UTF-8"?>
3 <!-- EN-Revision: 20765 -->
4 <sect1 id="zend.controller.action">
5 <title>アクションコントローラ</title>
7 <sect2 id="zend.controller.action.introduction">
11 <classname>Zend_Controller_Action</classname> は、
12 モデル - ビュー - コントローラ (<acronym>MVC</acronym>)
13 パターンにもとづいたウェブアプリケーションを作成する際に、
14 フロントコントローラで使用するアクションコントローラを実装するための抽象クラスです。
18 <classname>Zend_Controller_Action</classname> を使用するには、
19 実際のアクションコントローラクラス内でこのクラスのサブクラスを作成する必要があります
20 (あるいは、作成したサブクラスをもとにしてアクションコントローラを作成します)。
21 基本的な使い方としては、まずサブクラスを作成し、
22 そしてあなたのサイト上で処理したいさまざまなアクションに対応する
23 アクションメソッドを作成するという流れになります。
24 <classname>Zend_Controller</classname> は、このクラス内のメソッドで 'Action'
26 ルーティングやディスパッチの際にそれらを自動的にアクションとして扱います。
30 たとえば、次のようなクラスを見てみましょう。
33 <programlisting language="php"><![CDATA[
34 class FooController extends Zend_Controller_Action
36 public function barAction()
41 public function bazAction()
49 この <emphasis>FooController</emphasis> クラス (<emphasis>foo</emphasis> コントローラ)
50 では、ふたつのアクション <emphasis>bar</emphasis> および <emphasis>baz</emphasis>
55 もちろんこれ以外にもたくさんの機能があります。
56 たとえば初期化アクションを独自に作成したり、
57 アクションを指定しなかった (あるいは無効なアクションを指定した)
58 際にコールされるデフォルトのアクションを指定したり、
59 ディスパッチの前後に実行されるフックを指定したり、
60 さまざまなヘルパーメソッドを使用したりといったことができます。
61 この章では、アクションコントローラの機能の概要を説明します。
65 <title>デフォルトの挙動</title>
68 デフォルトでは、<link linkend="zend.controller.front">フロントコントローラ
69 </link> は <link linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>
70 アクションヘルパーを有効にします。このヘルパーは、
73 アクションコントローラでこれを無効にするには、
77 <programlisting language="php"><![CDATA[
78 class FooController extends Zend_Controller_Action
80 public function init()
83 // 初期化時に読み込まれるので、全アクションに影響を及ぼします
84 $this->_helper->viewRenderer->setNoRender(true);
87 $this->_helper->removeHelper('viewRenderer');
89 // これも全体で無効にしますが、同時にローカルでも無効にしておく必要があります。
90 // これは、ローカルの設定を全体に伝播させる方法です。
91 Zend_Controller_Front::getInstance()
92 ->setParam('noViewRenderer', true);
98 <methodname>initView()</methodname>、<methodname>getViewScript()</methodname>、
99 <methodname>render()</methodname> および <methodname>renderScript()</methodname>
100 は、それぞれ <emphasis>ViewRenderer</emphasis> へのプロキシとなります。
101 ただしヘルパーブローカ内にこのヘルパーが登録されていない場合や
102 <emphasis>noViewRenderer</emphasis> フラグが設定されている場合は除きます。
106 個々のビューのレンダリングを無効にするには、単純に
107 <emphasis>ViewRenderer</emphasis> の <emphasis>noRender</emphasis>
111 <programlisting language="php"><![CDATA[
112 class FooController extends Zend_Controller_Action
114 public function barAction()
116 // このアクションでのみ自動レンダリングを無効にします
117 $this->_helper->viewRenderer->setNoRender();
123 <emphasis>ViewRenderer</emphasis> を無効にする場面として考えられるのは、
125 ビュースクリプト経由でのレンダリングを行わない場合
126 (たとえば、アクションコントローラを使用して <acronym>SOAP</acronym> や
127 <acronym>XML-RPC</acronym>、<acronym>REST</acronym>
128 といったウェブサービスプロトコルを扱う場合)
129 です。<emphasis>ViewRenderer</emphasis> をグローバルで無効にすることはまずないでしょう。
130 無効にするとすれば、個々のコントローラやアクション単位で行うことになります。
135 <sect2 id="zend.controller.action.initialization">
136 <title>オブジェクトの初期化</title>
139 アクションコントローラのコンストラクタをオーバーライドすることもできますが、
140 お勧めしません。<methodname>Zend_Controller_Action::__construct()</methodname>
141 は、リクエストオブジェクトやレスポンスオブジェクトを登録するなどの重要な作業を行います。
142 また、フロントコントローラから渡された起動時引数の処理も行います。
143 コンストラクタをオーバーライドする場合は、必ずその中で
144 <methodname>parent::__construct($request, $response, $invokeArgs)</methodname>
149 初期化作業をカスタマイズするには、コンストラクタをオーバーライドするよりも
150 <methodname>init()</methodname> メソッドを使うほうがお勧めです。
151 これは、<methodname>__construct()</methodname>
153 初期化時にデータベースに接続したいなら次のようにします。
156 <programlisting language="php"><![CDATA[
157 class FooController extends Zend_Controller_Action
159 public function init()
161 $this->db = Zend_Db::factory('Pdo_Mysql', array(
163 'username' => 'user',
164 'password' => 'XXXXXXX',
165 'dbname' => 'website'
172 <sect2 id="zend.controller.action.prepostdispatch">
173 <title>ディスパッチ前後のフック</title>
176 <classname>Zend_Controller_Action</classname> には、
177 リクエストされたアクションの前後にコールされるふたつのメソッドがあります。それが
178 <methodname>preDispatch()</methodname> と <methodname>postDispatch()</methodname> です。
180 たとえばアクションを実行する前に認証情報や <acronym>ACL</acronym>
181 を調べたり (<methodname>preDispatch()</methodname> の中で
182 <methodname>_forward()</methodname> をコールすると、
184 作成したコンテンツを (<methodname>postDispatch()</methodname> で)
185 全サイト共通のテンプレートに配置したりといったことが考えられます。
189 <title>init() 対 preDispatch() の使用法</title>
192 <link linkend="zend.controller.action.initialization">前述のセクション</link>では、
193 <methodname>init()</methodname> メソッドを紹介しましたが、
194 このセクションでは <methodname>preDispatch()</methodname> メソッドを紹介します。
195 それらの違いは何で、それぞれどのような動作をさせるでしょう?
199 <methodname>init()</methodname> メソッドは、主にコンストラクタを拡張することが目的です。
200 一般的に、コンストラクタはオブジェクトの状態を単純に設定しなければならなくて、
202 これは、コントローラで使用されるリソース(例えばモデル、オブジェクトの構成、その他)を初期化すること、
203 またはフロントコントローラ、ブートストラップ、
204 またはレジストリから取得される値をアサインすることを含むかもしれません。
208 <methodname>preDispatch()</methodname> メソッドは、
209 オブジェクトまたは環境(例えば、ビュー、アクション・ヘルパー、その他)
210 の状態を設定するために使うこともできます。
211 しかし、その主な目的は、リクエストされたアクションをディスパッチしなければいけないかどうか
213 もししないのならば、別のアクションに <methodname>_forward()</methodname> するか、
218 注意: <methodname>init()</methodname> から実行されると、
219 実は <methodname>_forward()</methodname> は正しく動作しません。
220 それは、2つのメソッドの意図が形になったものです。
225 <sect2 id="zend.controller.action.accessors">
226 <title>アクセス用メソッド</title>
229 さまざまなオブジェクトや変数がオブジェクトに登録されており、
230 それぞれにアクセス用メソッドが用意されています。
236 <emphasis>リクエストオブジェクト</emphasis>:
237 <methodname>getRequest()</methodname> を使用してリクエストオブジェクトを取得し、
244 <emphasis>レスポンスオブジェクト</emphasis>:
245 <methodname>getResponse()</methodname> を使用して、最終的なレスポンスの内容を取得します。
249 <programlisting language="php"><![CDATA[
250 $this->getResponse()->setHeader('Content-Type', 'text/xml');
251 $this->getResponse()->appendBody($content);
257 <emphasis>起動時引数</emphasis>:
259 ルータやディスパッチャそしてアクションコントローラに送ります。
261 <methodname>getInvokeArg($key)</methodname> を使用します。あるいは、
263 <methodname>getInvokeArgs()</methodname> を使用します。
269 <emphasis>リクエストパラメータ</emphasis>:
270 リクエストオブジェクトは、<constant>_GET</constant> や <constant>_POST</constant>
272 <acronym>URL</acronym> のパスで指定したパラメータも収集します。
273 これらを取得するには、<methodname>_getParam($key)</methodname> あるいは
274 <methodname>_getAllParams()</methodname> を使用します。
275 <methodname>_setParam()</methodname> を使用して、
276 リクエストパラメータを設定することもできます。
277 これは、さらに別のアクションに転送する際などに有用です。
283 <methodname>_hasParam($key)</methodname> を使用します。
288 <methodname>_getParam()</methodname> は、オプションの二番目の引数でデフォルト値を指定できます。
289 もしパラメータが設定されていなかったり空だったりした場合は、このデフォルト値を使用するようになります。
290 これを用いることで、値を取得する前にいちいち
291 <methodname>_hasParam()</methodname> をコールする必要がなくなります。
294 <programlisting language="php"><![CDATA[
295 // id が設定されていない場合のデフォルト値を 1 とします
296 $id = $this->_getParam('id', 1);
298 // わざわざこのようにする必要はありません
299 if ($this->_hasParam('id') {
300 $id = $this->_getParam('id');
310 <sect2 id="zend.controller.action.viewintegration">
311 <title>ビューの統合</title>
313 <note id="zend.controller.action.viewintegration.viewrenderer">
314 <title>Default view integration is via the ViewRenderer</title>
318 <link linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>
319 を明示的に無効にしている場合にのみ有効です。
320 それ以外の場合はこの節を読み飛ばしてください。
325 <classname>Zend_Controller_Action</classname> では、
326 ビューの統合のためのちょっとした柔軟な仕組みを提供しています。
327 これを行うのは <methodname>initView()</methodname> と <methodname>render()</methodname>
328 のふたつのメソッドです。前者のメソッドはパブリックプロパティ
329 <varname>$view</varname> の遅延読み込みを行い、
330 後者のメソッドはアクションの要求にもとづいてビューをレンダリングします。
331 その際に、ディレクトリ階層をもとにスクリプトのパスを決定します。
334 <sect3 id="zend.controller.action.viewintegration.initview">
335 <title>ビューの初期化</title>
338 <methodname>initView()</methodname> はビューオブジェクトを初期化します。
339 <methodname>render()</methodname> は <methodname>initView()</methodname>
340 をコールしてビューオブジェクトを取得しますが、
341 その初期化はいつでも好きなときに行うことができます。
342 デフォルトでは、取得した結果は <classname>Zend_View</classname>
343 オブジェクトのプロパティ <varname>$view</varname> に格納されますが、
344 <classname>Zend_View_Interface</classname> を実装したクラスなら何でも好きなものを使用できます。
345 <varname>$view</varname> がすでに初期化されている場合は、そのプロパティの内容を返します。
349 デフォルトの実装は、以下のようなディレクトリ階層を前提としています。
352 <programlisting language="php"><![CDATA[
366 <filename>/views/scripts/</filename> ディレクトリ内にあり、かつ
367 <filename>/views/</filename> ディレクトリ内の同一階層に各機能
368 (ヘルパー、フィルタ)のディレクトリがあるということです。
369 ビュースクリプトの名前とパスを決定する際の基底ディレクトリとして
370 <filename>/views/scripts/</filename> が用いられます。
371 その中に、ビュースクリプトを実行するコントローラ名に基づいた名前のディレクトリが作成されます。
375 <sect3 id="zend.controller.action.viewintegration.render">
376 <title>ビューのレンダリング</title>
379 <methodname>render()</methodname> のシグネチャは次のとおりです。
382 <programlisting language="php"><![CDATA[
383 string render(string $action = null,
385 bool $noController = false);
389 <methodname>render()</methodname> はビュースクリプトをレンダリングします。
390 引数を省略した場合は、<filename>[controller]/[action].phtml</filename>
391 が指定されたものとみなします(<filename>.phtml</filename>
392 は <varname>$viewSuffix</varname> プロパティの値です)。
393 <varname>$action</varname> を指定すると、<filename>/[controller]/</filename>
394 ディレクトリにあるその名前のテンプレートをレンダリングします。
395 <filename>/[controller]/</filename> ディレクトリを使用しないようにするには、
396 <varname>$noController</varname> に <constant>TRUE</constant> を指定します。
397 テンプレートをレンダリングした結果はレスポンスオブジェクトに格納されます。
399 <link linkend="zend.controller.response.namedsegments">
400 特定の名前をつけた部分</link> に格納したい場合は、
401 <varname>$name</varname> の値を指定します。
406 コントローラやアクションの名前には区切り文字
407 ('_' や '.'、'-') を含めることができるので、
408 <methodname>render()</methodname> はスクリプト名を決定する際にこれらの文字を
410 ディスパッチャで設定されている単語やパスの区切り文字を正規化時に用います。
411 したがって、<filename>/foo.bar/baz-bat</filename> へのリクエストの際に
412 レンダリングされるスクリプトは <filename>foo-bar/baz-bat.phtml</filename> です。
413 アクションメソッド名が camelCase 方式の場合、
414 ビュースクリプトのファイル名では単語が '-' で区切られることに注意しましょう。
422 <programlisting language="php"><![CDATA[
423 class MyController extends Zend_Controller_Action
425 public function fooAction()
427 // my/foo.phtml をレンダリングします
430 // my/bar.phtml をレンダリングします
431 $this->render('bar');
433 // baz.phtml をレンダリングします
434 $this->render('baz', null, true);
436 // my/login.phtml をレンダリングし、
437 // レスポンスオブジェクトの 'form' の部分に返します
438 $this->render('login', 'form');
440 // site.phtml をレンダリングし、レスポンスオブジェクトの
442 // 'my/' ディレクトリは使用しません
443 $this->render('site', 'page', true);
446 public function bazBatAction()
448 // my/baz-bat.phtml をレンダリングします
456 <sect2 id="zend.controller.action.utilmethods">
457 <title>ユーティリティメソッド</title>
460 アクセス用メソッドやビューの統合用メソッド以外にも、<classname>Zend_Controller_Action</classname>
461 にはいくつかのユーティリティメソッドが用意されています。
463 (あるいはディスパッチ前後のフックメソッド)
470 <methodname>_forward($action, $controller = null, $module =
471 null, array $params = null)</methodname>:
472 別のアクションを実行します。<methodname>preDispatch()</methodname> の中でコールすると、
473 リクエストされていたアクションは飛ばされ、
474 新しいアクションを実行します。それ以外の場合は、
476 <methodname>_forward()</methodname> で指定したアクションを実行します。
482 <methodname>_redirect($url, array $options =
483 array())</methodname>:
484 別の場所にリダイレクトします。このメソッドには、<acronym>URL</acronym>
486 デフォルトでは、<acronym>HTTP</acronym> 302 リダイレクトを行います。
490 オプションは、以下のうちのひとつあるいは複数の組み合わせとなります。
496 <emphasis>exit:</emphasis> 即時に終了するかしないか。
497 これを指定すると、オープンしたいるセッションをすべて閉じた後にリダイレクトします。
501 このオプションをコントローラ全体で有効にするには、
502 アクセスメソッド <methodname>setRedirectExit()</methodname> を使用します。
508 <emphasis>prependBase:</emphasis>
509 リクエストオブジェクトに登録されている基底 <acronym>URL</acronym> を
510 この <acronym>URL</acronym> の先頭に付加するかどうか。
514 このオプションをコントローラ全体で有効にするには、
515 アクセスメソッド <methodname>setRedirectPrependBase()</methodname> を使用します。
521 <emphasis>code:</emphasis> リダイレクトの際にどの <acronym>HTTP</acronym> コードを使用するか。
522 デフォルトでは <acronym>HTTP</acronym> 302 を使用しますが、
523 301 から 306 までの任意の値を使用できます。
527 このオプションをコントローラ全体で有効にするには、
528 アクセスメソッド <methodname>setRedirectCode()</methodname> を使用します。
536 <sect2 id="zend.controller.action.subclassing">
537 <title>アクションコントローラのサブクラスの作成</title>
540 アクションコントローラを作成するには、必ず
541 <classname>Zend_Controller_Action</classname> のサブクラスを作成しなければならないようになっています。
542 最低限、コントローラがコールするアクションメソッドを定義しなければなりません。
546 自分のウェブアプリケーション用に便利な機能を実装していく一方で、
547 同じような前処理やちょっとした処理をあちこちのコントローラで書いているといったことはありませんか?
548 そのような場合は、<classname>Zend_Controller_Action</classname>
549 を継承した共通基底コントローラクラスを作成し、
550 共通処理をそこにまとめていくようにしましょう。
553 <example id="zend.controller.action.subclassing.example-call">
554 <title>存在しないアクションの処理</title>
557 コントローラへのリクエストの際に未定義のアクションメソッドが指定された場合は、
558 <methodname>Zend_Controller_Action::__call()</methodname> を実行します。
559 <methodname>__call()</methodname> とはもちろん、<acronym>PHP</acronym>
560 のマジックメソッドで、メソッドのオーバーロード用に使用するものです。
565 <classname>Zend_Controller_Action_Exception</classname>
566 をスローして、コントローラの中にアクションが見つからなかったことを示します。
567 メソッド名の最後が 'Action' であった場合は、
568 おそらく存在しないアクションをリクエストしたのであろうとみなします。
569 そして、コード 404 で例外を返します。その他のメソッドの場合は
571 これにより、単にページが見つからないだけなのか
572 アプリケーションエラーなのかをエラーハンドラで区別できるようになります。
576 もし別の動作をさせたい場合は、これをオーバーライドしましょう。
577 たとえば、エラーメッセージを表示させたい場合は次のようになります。
580 <programlisting language="php"><![CDATA[
581 class MyController extends Zend_Controller_Action
583 public function __call($method, $args)
585 if ('Action' == substr($method, -6)) {
586 // アクションメソッドが見つからなかった場合は、
587 // エラー用のテンプレートをレンダリングします
588 return $this->render('error');
591 // その他のメソッドの場合は例外をスローします
592 throw new Exception('Invalid method "'
601 もうひとつの例として、デフォルトコントローラに転送する処理を見てみましょう。
605 <programlisting language="php"><![CDATA[
606 class MyController extends Zend_Controller_Action
608 public function indexAction()
613 public function __call($method, $args)
615 if ('Action' == substr($method, -6)) {
616 // アクションメソッドが見つからなかった場合は、
618 return $this->_forward('index');
621 // その他のメソッドの場合は例外をスローします
622 throw new Exception('Invalid method "'
632 <methodname>__call()</methodname> をオーバーライドするかわりに、
633 これまで説明してきた各種フックメソッドをオーバーライドしてコントローラをカスタマイズすることもできます。
634 たとえば、ビューオブジェクトをレジストリに保存したい場合は、
635 <methodname>initView()</methodname> メソッドを次のように書き換えることになるでしょう。
638 <programlisting language="php"><![CDATA[
639 abstract class My_Base_Controller extends Zend_Controller_Action
641 public function initView()
643 if (null === $this->view) {
644 if (Zend_Registry::isRegistered('view')) {
645 $this->view = Zend_Registry::get('view');
647 $this->view = new Zend_View();
648 $this->view->setBasePath(dirname(__FILE__) . '/../views');
658 この章の情報をもとに、それぞれの機能の柔軟性をもとにして
659 アプリケーションやサイトの要求に応じたコントローラを作成していくとよいでしょう。