コントローラは MVC アーキテクチャの一部を構成するものです。 それは yii\base\Controller を拡張したクラスのオブジェクトであり、リクエストの処理とレスポンスの生成について責任を負います。 具体的には、コントローラは、アプリケーション から制御を引き継いだ後、 入ってきたリクエストのデータを分析し、それを モデル に引き渡して、 モデルが生成した結果を ビュー に投入し、最終的に外に出て行くレスポンスを生成します。
コントローラは、エンド・ユーザがアドレスを指定して実行をリクエストできる最も基本的なユニットである アクション から構成されます。 コントローラは一つまたは複数のアクションを持つことが出来ます。
次の例は、view
と create
という二つのアクションを持つ post
コントローラを示すものです。
namespace app\controllers;
use Yii;
use app\models\Post;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
class PostController extends Controller
{
public function actionView($id)
{
$model = Post::findOne($id);
if ($model === null) {
throw new NotFoundHttpException;
}
return $this->render('view', [
'model' => $model,
]);
}
public function actionCreate()
{
$model = new Post;
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
}
view
アクション (actionView()
メソッドで定義されます) において、コードは最初に、リクエストされたモデルの ID に従って モデル を読み出します。
モデルの読み出しが成功したときは、view
という名前の ビュー を使ってモデルを表示します。
失敗したときは例外を投げます。
create
アクション (actionCreate()
メソッドで定義されます) においても、コードは似たようなものです。
最初に、リクエスト・データを使って モデル の新しいインスタンスにデータを投入することを試み、そして、モデルを保存することを試みます。
両方が成功したときは、新しく作成されたモデルの ID を使って view
アクションにブラウザをリダイレクトします。
どちらかが失敗したときは、ユーザが必要なデータを入力できるようにするための create
ビューを表示します。
エンド・ユーザは、いわゆる ルート によって、アクションを指定します。ルートは、次の部分からなる文字列です。
ルートは次の形式を取ります。
ControllerID/ActionID
または、コントローラがモジュールに属する場合は、次の形式を取ります。
ModuleID/ControllerID/ActionID
ですから、ユーザが https://hostname/index.php?r=site/index
という URL でリクエストをした場合は、
site
コントローラの中の index
アクションが実行されます。
ルートがどのようにしてアクションとして解決されるかについての詳細は、ルーティングと URL 生成 のセクションを参照してください。
ウェブ・アプリケーション では、コントローラは yii\web\Controller またはその子クラスから派生させなければなりません。
同様に、コンソール・アプリケーション では、コントローラは yii\console\Controller またはその子クラスから派生させなければなりません。
次のコードは site
コントローラを定義するものです。
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
}
通常、コントローラは特定のタイプのリソースに関するリクエストを処理するように設計されます。
この理由により、たいていは、処理するリソースのタイプを示す名詞をコントローラの ID として使います。
例えば、記事データを処理するコントローラの ID としては、article
を使うことが出来ます。
デフォルトでは、コントローラ ID は、小文字の英字、数字、アンダースコア、ダッシュ、および、フォワード・スラッシュのみを含むべきものです。
例えば、article
と post-comment
はともに有効なコントローラ ID ですが、
article?
、PostComment
、admin\post
はそうではありません。
コントローラ ID は、サブ・ディレクトリの接頭辞を含んでも構いません。
例えば、admin/article
は、コントローラ名前空間 の下の admin
サブ・ディレクトリにある article
コントローラを表します。
サブ・ディレクトリの接頭辞として有効な文字は、小文字または大文字の英字、数字、アンダースコア、そして、フォワード・スラッシュです。
フォワード・スラッシュは、複数レベルのサブ・ディレクトリの区切り文字として使われます (例えば、panels/admin
)。
コントローラ・クラスの名前は下記の手順に従ってコントローラ ID から導出することが出来ます。
Controller
を追加する。以下は、コントローラ名前空間 がデフォルト値 app\controllers
を取っていると仮定したときの、いくつかの例です。
article
は app\controllers\ArticleController
になる。post-comment
は app\controllers\PostCommentController
になる。admin/post-comment
は app\controllers\admin\PostCommentController
になる。adminPanels/post-comment
は app\controllers\adminPanels\PostCommentController
になる。コントローラ・クラスは オートロード可能 でなければなりません。
この理由により、上記の例の aritcle
コントローラ・クラスは エイリアス が
@app/controllers/ArticleController.php
であるファイルに保存されるべきものとなります。
一方、admin/post-comment
コントローラは @app/controllers/admin/PostCommentController.php
というエイリアスのファイルに保存されるべきものとなります。
情報: 最後の例である
admin/post-comment
は、どうすれば コントローラ名前空間 のサブ・ディレクトリにコントローラを置くことが出来るかを示しています。 この方法は、コントローラをいくつかのカテゴリに分けて編成したい、けれども モジュール は使いたくない、という場合に役立ちます。
コントローラ・マップ を構成すると、上で述べたコントローラ ID とクラス名の制約を乗り越えることが出来ます。 これは、主として、クラス名に対する制御が及ばないサード・パーティのコントローラを使おうとする場合に有用です。
コントローラ・マップ は アプリケーションの構成情報 の中で、次のように構成することが出来ます。
[
'controllerMap' => [
// クラス名を使って "account" コントローラを宣言する
'account' => 'app\controllers\UserController',
// 構成情報配列を使って "article" コントローラを宣言する
'article' => [
'class' => 'app\controllers\PostController',
'enableCsrfValidation' => false,
],
],
]
全てのアプリケーションは、それぞれ、yii\base\Application::$defaultRoute プロパティによって指定されるデフォルト・コントローラを持ちます。
リクエストが ルート を指定していない場合、このプロパティによって指定されたルートが使われます。
ウェブ・アプリケーション では、この値は 'site'
であり、一方、コンソール・アプリケーション では、help
です。
従って、URL が https://hostname/index.php
である場合は、site
コントローラがリクエストを処理することになります。
次のように アプリケーションの構成情報 を構成して、デフォルト・コントローラを変更することが出来ます。
[
'defaultRoute' => 'main',
]
アクションは、コントローラ・クラスの中にいわゆる アクション・メソッド を定義するだけで簡単に作成することが出来ます。
アクション・メソッドとは、action
という語で始まる名前を持つ public メソッドのことです。
アクション・メソッドの返り値がエンド・ユーザに送信されるレスポンス・データを表します。次のコードは、index
と hello-world
という二つのアクションを定義するものです。
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public function actionIndex()
{
return $this->render('index');
}
public function actionHelloWorld()
{
return 'Hello World';
}
}
アクションは、たいてい、あるリソースについて特定の操作を実行するように設計されます。
この理由により、アクション ID は、通常、view
、update
などのような動詞になります。
デフォルトでは、アクション ID は、小文字の英字、数字、アンダースコア、そして、ハイフンのみを含むべきものです。
アクション ID の中のハイフンは単語を分けるために使われます。
例えば、view
、update2
、comment-post
は全て有効なアクション ID ですが、view?
、Update
はそうではありません。
アクションは二つの方法、すなわち、インライン・アクションまたはスタンドアロン・アクションとして作成することが出来ます。 インライン・アクションはコントローラ・クラスのメソッドとして定義されるものであり、 一方、スタンドアロン・アクションは yii\base\Action またはその子クラスを拡張するクラスです。 インライン・アクションは作成するのにより少ない労力を要するため、通常は、アクションを再利用する意図がない場合に推奨されます。 もう一方のスタンドアロン・アクションは、主として、さまざまなコントローラの中で使われることや、エクステンション として再配布されることを目的として作成されます。
インライン・アクションは、たった今説明したように、アクション・メソッドの形で定義されるアクションを指します。
アクション・メソッドの名前は、次の手順に従って、アクション ID から導出されます。
action
を付ける。例えば、index
は actionIndex
となり、hello-world
は actionHelloWorld
となります。
補足: アクション・メソッドの名前は、大文字と小文字を区別 します。
ActionIndex
という名前のメソッドがあっても、それはアクション・メソッドとは見なされず、結果として、index
アクションに対するリクエストは例外に帰結します。 アクション・メソッドが public でなければならない事にも注意してください。 private や protected なメソッドがインライン・アクションを定義することはありません。
インライン・アクションは作成するのにほとんど労力を要さないため、たいていのアクションはインライン・アクションとして定義されます。 しかし、同じアクションを別の場所で再利用する計画を持っていたり、また、アクションを再配布したいと思っていたりする場合は、 アクションを スタンドアロン・アクション として定義することを検討すべきです。
スタンドアロン・アクションは、yii\base\Action またはその子クラスを拡張するアクション・クラスの形で定義されるものです。 例えば、Yii のリリースに yii\web\ViewAction と yii\web\ErrorAction が含まれていますが、 これらは両方ともスタンドアロン・アクションです。
スタンドアロン・アクションを使用するためには、下記のように、コントローラの yii\base\Controller::actions() メソッドをオーバーライドして、 アクション・マップ の中でスタンドアロン・アクションを宣言しなければなりません。
public function actions()
{
return [
// クラス名を使って "error" アクションを宣言する
'error' => 'yii\web\ErrorAction',
// 構成情報配列を使って "view" アクションを宣言する
'view' => [
'class' => 'yii\web\ViewAction',
'viewPrefix' => '',
],
];
}
ご覧のように、actions()
メソッドは、キーがアクション ID であり、値が対応するアクションのクラス名または
構成情報 である配列を返さなければなりません。
インライン・アクションと違って、スタンドアロン・アクションのアクション ID は、actions()
メソッドにおいて宣言される限りにおいて、任意の文字を含むことが出来ます。
スタンドアロン・アクション・クラスを作成するためには、yii\base\Action またはその子クラスを拡張して、run()
という名前の public メソッドを実装しなければなりません。
run()
メソッドの役割はアクション・メソッドの役割と同じです。例えば、
<?php
namespace app\components;
use yii\base\Action;
class HelloWorldAction extends Action
{
public function run()
{
return "Hello World";
}
}
アクション・メソッド、または、スタンドアロン・アクションの run()
メソッドの返り値は、重要な意味を持ちます。
それは、対応するアクションの結果を表すものです。
返り値は、エンド・ユーザにレスポンスとして送信される レスポンス オブジェクトとすることが出来ます。
これまでに示した例においては、アクションの結果はすべて文字列であり、エンド・ユーザに送信されるレスポンス・ボディとして扱われるものでした。 次の例では、アクションがレスポンス・オブジェクトを返すことによって、ユーザのブラウザを 新しい URL にリダイレクトすることが出来る様子が示されています (redirect() メソッドの返り値はレスポンス・オブジェクトです)。
public function actionForward()
{
// ユーザのブラウザを https://example.com にリダイレクトする
return $this->redirect('https://example.com');
}
インライン・アクションのアクション・メソッドと、スタンドアロン・アクションの run()
メソッドは、アクション・パラメータ と呼ばれるパラメータを取ることが出来ます。
パラメータの値はリクエストから取得されます。
ウェブ・アプリケーション では、各アクション・パラメータの値は $_GET
からパラメータ名をキーとして読み出されます。
コンソール・アプリケーション では、アクション・パラメータはコマンドライン引数に対応します。
次の例では、view
アクション (インライン・アクションです) は、二つのパラメータ、すなわち、$id
と $version
を宣言しています。
namespace app\controllers;
use yii\web\Controller;
class PostController extends Controller
{
public function actionView($id, $version = null)
{
// ...
}
}
アクション・パラメータには、次のように、さまざまなリクエストに応じて異なる値が投入されます。
https://hostname/index.php?r=post/view&id=123
: $id
パラメータには '123'
という値が入れられます。
一方、version
というクエリ・パラメータは無いので、$version
は null
のままになります。https://hostname/index.php?r=post/view&id=123&version=2
: $id
および $version
パラメータに、
それぞれ、'123'
と '2'
が入ります。https://hostname/index.php?r=post/view
: 必須の $id
パラメータがリクエストで提供されていないため、
yii\web\BadRequestHttpException 例外が投げられます。https://hostname/index.php?r=post/view&id[]=123
: $id
パラメータが予期しない配列値 ['123']
を受け取ろうとするため、
yii\web\BadRequestHttpException 例外が投げられます。アクション・パラメータに配列値を受け取らせたい場合は、次のように、パラメータに array
の型ヒントを付けなければなりません。
public function actionView(array $id, $version = null)
{
// ...
}
このようにすると、リクエストが https://hostname/index.php?r=post/view&id[]=123
である場合は、$id
パラメータは ['123']
という値を受け取ります。
リクエストが https://hostname/index.php?r=post/view&id=123
である場合も、スカラ値 '123'
が自動的に配列に変換されるため、
$id
パラメータは引き続き同じ配列値を受け取ります。
上記の例は主としてウェブ・アプリケーションでのアクション・パラメータの動作を示すものです。 コンソール・アプリケーションについては、コンソール・コマンド のセクションで詳細を参照してください。
すべてのコントローラは、それぞれ、yii\base\Controller::$defaultAction によって指定されるデフォルト・アクションを持ちます。 ルート がコントローラ ID のみを含む場合は、 指定されたコントローラのデフォルト・アクションがリクエストされたことを意味します。
デフォルトでは、デフォルト・アクションは index
と設定されます。
このデフォルト値を変更したい場合は、以下のように、コントローラ・クラスでこのプロパティをオーバーライドするだけです。
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public $defaultAction = 'home';
public function actionHome()
{
return $this->render('home');
}
}
リクエストを処理するときに、アプリケーション はリクエストされた ルート に基いてコントローラを作成します。 そして、次に、コントローラはリクエストに応じるために以下のライフサイクルを経過します。
beforeAction()
メソッドをこの順で呼び出す。false
を返した場合は、残りのまだ呼ばれていない beforeAction()
メソッドはスキップされ、
アクションの実行はキャンセルされる。beforeAction()
メソッドは、ハンドラをアタッチすることが可能な beforeAction
イベントをトリガする。afterAction()
メソッドをこの順で呼び出す。afterAction()
メソッドは、ハンドラをアタッチすることが可能な afterAction
イベントをトリガする。良く設計されたアプリケーションでは、コントローラはたいてい非常に軽いものになり、 それぞれのアクションは数行のコードしか含まないものになります。 あなたのコントローラが少々複雑になっている場合、そのことは、通常、コントローラをリファクタして、コードの一部を他のクラスに移動すべきことを示すものです。
いくつかのベスト・プラクティスを特に挙げるなら、コントローラは、
Found a typo or you think this page needs improvement?
Edit it on github !
Signup or Login in order to comment.