コントローラ
コントローラ
は CController か、CController を拡張したクラスのインスタンスです。
コントローラは、ユーザが要求した時にアプリケーションオブジェクトにより生成されます。
コントローラは、起動されると、要求されたアクションを実行するために、通常は、必要なモデルを取り込んで適切なビューを表示します。
アクション
は、最も単純化された形式としては、コントローラクラスの action
で始まる名前のメソッドです。
コントローラは既定のアクション (デフォルトアクション) を持っています。
どのアクションを実行するかをユーザが指定しない場合、デフォルトアクションが実行されます。
既定では、デフォルトアクション名は index
です。
これは、インスタンスのパブリック変数 CController::defaultAction を設定することで変更できます。
以下のコードは site
コントローラと index
アクション (デフォルトのアクション) と contact
アクションを定義します。
class SiteController extends CController { public function actionIndex() { // ... } public function actionContact() { // ... } }
ルート (経路)
コントローラとアクションは ID により識別されます。
コントローラ ID は path/to/xyz
の形式で、コントローラクラスファイル protected/controllers/path/to/XyzController.php
に対応します。
(xyz
を実際の名前に置き換えて考えてください。例えば、post
は protected/controllers/PostController.php
に対応します。)
また、アクション ID はアクションメソッド名からプレフィックス action
を除いたものです。
たとえば、コントローラクラスに actionEdit
という名前のメソッドがあれば、アクション ID は edit
になります。
ユーザはルート (経路) により、特定のコントローラとアクションをリクエストします。
ルートはスラッシュによりコントローラ ID とアクション ID を連結することで形成されます。
たとえば、ルート post/edit
は PostController
の edit
アクションを参照します。
そして、デフォルトでは http://hostname/index.php?r=post/edit
という URL が post コントローラと edit アクションをリクエストするものになります。
注意: デフォルトでは、ルートは大文字と小文字を区別します。 アプリケーション初期構成で CUrlManager::caseSensitive を false に設定することで、大文字と小文字を区別しないようすることも可能です。 大文字と小文字を区別しないモード (case-insensitive mode) の場合は、 コントローラクラスファイルを含むディレクトリ名が小文字であること、さらに、 controller map と action map の両方でキーが小文字であることという規約を必ず守って下さい。
アプリケーションは モジュール を含むことができます。
モジュール内のコントローラのアクションは moduleID/controllerID/actionID
のフォーマットで表されます。
より詳細には モジュール の章を見てください。
コントローラのインスタンス
コントローラのインスタンスは CWebApplication が入ってきたリクエストを処理する際に生成されます。 コントローラ ID が与えられると、アプリケーションは次のルールを用いて、コントローラクラスとクラスファイルを探し出します。
CWebApplication::catchAllRequest が指定されている場合、コントローラはこのプロパティを元に生成され、 ユーザの指定したコントローラ ID は無視されます。 これは主にアプリケーションをメンテナンスモードにし、通知のための静的ページを表示するために使用します。
ID が CWebApplication::controllerMap に指定されている場合、 対応するコントローラ設定に基づき、コントローラインスタンスが生成されます。
ID が
'path/to/xyz'
形式の場合、コントローラクラス名はXyzController
で、 対応するクラスファイルはprotected/controllers/path/to/XyzController.php
であると仮定されます。 たとえば、コントローラ ID がadmin/user
なら、コントローラクラス名がUserController
で、 クラスファイルがprotected/controllers/admin/UserController.php
になります。 もしクラスファイルがなければ、404 CHttpException が呼び出されます。
モジュール が使われる場合には、上記のプロセスは若干異ります。 具体的には、アプリケーションは ID がモジュール中のコントローラを参照しているかを調べ、 もしそうなら、モジュールインスタンスが最初に生成されコントローラインスタンスが次に生成されます。
アクション
前述したとおり、アクションは action
から始まる名前のメソッドにより定義できます。
より高度な方法は、アクションクラスを定義し、リクエスト時にインスタンス化するようにコントローラに要求する方法です。
この方法を用いる事で、アクションの再利用が可能になるため、より再利用性を高められます。
新しいアクションクラスを定義するためには、下記のように行います:
class UpdateAction extends CAction { public function run() { // ここにアクションロジックを記述 } }
コントローラがこのアクションを認識するように、このコントローラクラスの actions() メソッドを上書き定義します。
class PostController extends CController { public function actions() { return array( 'edit'=>'application.controllers.post.UpdateAction', ); } }
上記で使用されている、application.controllers.post.UpdateAction
というパスは、
アクションクラスファイル protected/controllers/post/UpdateAction.php
へのパスエイリアスです。
クラスベースのアクションを書く事で、モジュール方式でアプリケーションを構成出来ます。 たとえば、コントローラのためのコードを構成するために、次のようなディレクトリ構造を利用出来ます。:
protected/ controllers/ PostController.php UserController.php post/ CreateAction.php ReadAction.php UpdateAction.php user/ CreateAction.php ListAction.php ProfileAction.php UpdateAction.php
アクションパラメータ結合
バージョン 1.1.4 からは自動アクションパラメータ結合がサポートされました。 これは、コントローラアクションメソッドにおいて名前付きパラメータを定義し、その値が自動的に $_GET から代入されるものです。
これがどのように動作するかを説明するために、PostController
コントローラの create
アクションを記述することを考えてみましょう。
このアクションは二つのパラメータを必要とします。
category
: カテゴリ ID を意味する整数で、この元で新規ポストが作成されます。language
: 新規ポストが書かれる言語コードを意味する文字列です。
必要なパラメータ値を $_GET
から取得するために以下のようなつまらないコードを書くはめになるかもしれません。
class PostController extends CController { public function actionCreate() { if(isset($_GET['category'])) $category=(int)$_GET['category']; else throw new CHttpException(404,'invalid request'); if(isset($_GET['language'])) $language=$_GET['language']; else $language='en'; // ... 面白いコードはここから開始 ... } }
さて、アクションパラメータ機能を用いると、タスクがもっと楽しいものになります。
class PostController extends CController { public function actionCreate($category, $language='en') { $category=(int)$category; // ... 面白いコードはここから開始 ... } }
二つのパラメータをアクションメソッド actionCreate
に追加したことに注意してください。
パラメータの名前は $_GET
から得られるパラメータと全く同じにする必要があります。
$language
パラメータは、リクエストがそういうパラメータを含んでいない場合は、デフォルト値 en
を取ります。
一方 $category
はデフォルト値が無いため、もしリクエストが category
パラメータを含んでいない場合は、
CHttpException (error code 400) エラーが自動的に発行されます。
バージョン 1.1.5 からは、配列タイプのアクションパラメータをサポートします。 これは PHP のタイプヒンティングを利用しており、以下のような文法により行われます。
class PostController extends CController { public function actionCreate(array $categories) { // Yii は必ず $categories を配列にします } }
すなわち、メソッドのパラメータ宣言において、$categories
の直前に array
キーワードを置きます。
こうすることによって、$_GET['categories']
が単純な文字列である場合には、その文字列からなる配列に変換されます。
注意: もしパラメータが
array
タイプヒント無しに宣言された場合は、そのパラメータはスカラー (配列でない) でなくてはいけません。 この場合、$_GET
から配列パラメータが渡されると、HTTP 例外が発生します。
バージョン 1.1.7 からは、自動パラメータ結合はクラスベースのアクションにも適用されます。
もしアクションクラス run()
メソッドがパラメータ付きで定義された場合、それらのパラメータには
対応する名前のリクエストパラメータが代入されます。例えば、
class UpdateAction extends CAction { public function run($id) { // $id には $_GET['id'] が代入される } }
フィルタ
フィルタは、コントローラのアクション実行の前か後 (もしくはその両方) に実行されるように構成されるコードの断片です。 たとえば、アクセスコントロールフィルタは、ユーザがリクエストしたアクションを実行する前に、 認証済みである事を確実にするために使用されるかもしれません。 パフォーマンスフィルタは、アクションの実行所要時間を計測するために使用されるかもしれません。
一つのアクションは複数のフィルタを持つことが出来ます。 フィルタはフィルタリストに登場する順で順次実行されます。 フィルタは、アクションと残りの実行されていないフィルタの実行を防ぐことが出来ます。
フィルタはコントローラクラスメソッドで定義出来ます。
メソッド名は必ず filter
で始めます。
たとえば、filterAccessControl
メソッドは、accessControl
という名前のフィルタを定義します。
フィルタメソッドは正しいシグネチャを持っていなければなりません:
public function filterAccessControl($filterChain) { // フィルタリングとアクションの実行を継続するために、$filterChain->run() をコールします }
ここで、$filterChain
はリクエストされたアクションに結びついているフィルターリストを表した、CFilterChain のインスタンスです。
フィルタメソッド内で、フィルタリングとアクションの実行を継続するためには、$filterChain->run() をコールします。
フィルタもまた CFilter かその子クラスのインスタンスにする事が出来ます。 次のコードは新しいフィルタクラスを定義するものです:
class PerformanceFilter extends CFilter { protected function preFilter($filterChain) { // アクションが実行される前に実行されるコード return true; // アクションが実行されるべきでない場合は false } protected function postFilter($filterChain) { // アクションが実行された後に実行されるコード } }
アクションにフィルタを適用するために、CController::filters()
メソッドを上書きする必要があります。
このメソッドはフィルタ構成の配列を返さなくてはなりません。たとえば、
class PostController extends CController { ...... public function filters() { return array( 'postOnly + edit, create', array( 'application.filters.PerformanceFilter - edit, create', 'unit'=>'second', ), ); } }
上記のコードは postOnly
と PerformanceFilter
という、二つのフィルタを指定しています。
postOnly
フィルタは、メソッドベースのフィルタです (対応するフィルタメソッドは、既に CController に定義されています) 。
そして、PerformanceFilter
フィルタはオブジェクトベースです。
application.filters.PerformanceFilter
というパスは、フィルタークラスファイル protected/filters/PerformanceFilter
へのパスのエイリアスです。
フィルタオブジェクトのプロパティ値を初期化するために、配列を使用して PerformanceFilter
を構成しています。
ここでは、PerformanceFilter
の unit
プロパティを 'second'
に初期化しています。
プラスやマイナス演算子を使用すると、アクションに対してのフィルタ適用の有無を指定できます。
上記の場合、postOnly
は edit
と create
アクションに適用され、
PerformanceFilter
は edit
と create
アクション以外のすべてのアクションに適用されます。
もし、プラスとマイナスのどちらも使用されていない場合、フィルタはすべてのアクションに適用されます。