コントローラーはMVCアーキテクチャの一部です。yii\base\Controllerから拡張したクラスのオブジェクトであり、リクエストの処理とレスポンスの生成を担当します。特に、アプリケーションから制御を引き継いだ後、コントローラーは着信リクエストデータの分析を行い、それをモデルに渡し、モデルの結果をビューに挿入し、最終的に発信レスポンスを生成します。
コントローラーは、エンドユーザーがアドレス指定して実行をリクエストできる最も基本的な単位であるアクションで構成されています。コントローラーには、1つまたは複数のアクションを含めることができます。
次の例は、`view`と`create`の2つのアクションを持つ`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
そのため、ユーザーがURL `https://hostname/index.php?r=site/index` でリクエストした場合、`site`コントローラーの`index`アクションが実行されます。ルートがどのようにアクションに解決されるかについては、ルーティングとURLの作成セクションを参照してください。
ウェブアプリケーションにおいては(Webアプリケーション)、コントローラーは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
になります。コントローラークラスは自動ロード可能である必要があります。このため、上記の例では、article
コントローラークラスは、エイリアスが@app/controllers/ArticleController.php
であるファイルに保存する必要があります。一方、admin/post-comment
コントローラーは@app/controllers/admin/PostCommentController.php
に保存する必要があります。
情報:最後の例
admin/post-comment
は、コントローラー名前空間のサブディレクトリにコントローラーを配置する方法を示しています。これは、コントローラーをいくつかのカテゴリに整理したい場合に、モジュールを使用したくない場合に役立ちます。
コントローラーマップを構成することで、上記のコントローラーIDとクラス名の制約を克服できます。これは主に、サードパーティのコントローラーを使用しており、そのクラス名を制御できない場合に役立ちます。
コントローラーマップは、アプリケーション構成で構成できます。例:
[
'controllerMap' => [
// declares "account" controller using a class name
'account' => 'app\controllers\UserController',
// declares "article" controller using a configuration array
'article' => [
'class' => 'app\controllers\PostController',
'enableCsrfValidation' => false,
],
],
]
各アプリケーションには、yii\base\Application::$defaultRouteプロパティで指定されたデフォルトコントローラーがあります。リクエストがルートを指定していない場合、このプロパティで指定されたルートが使用されます。ウェブアプリケーション(Webアプリケーション)では、その値は'site'
であり、コンソールアプリケーション(コンソールアプリケーション)ではhelp
です。そのため、URLがhttps://hostname/index.php
の場合、site
コントローラーがリクエストを処理します。
次のアプリケーション構成でデフォルトコントローラーを変更できます。
[
'defaultRoute' => 'main',
]
アクションの作成は、コントローラークラスにいわゆる「アクションメソッド」を定義するほど簡単です。アクションメソッドとは、名前がaction
という単語で始まる「public」メソッドです。アクションメソッドの戻り値は、エンドユーザーに送信されるレスポンスデータを表します。次のコードは、index
とhello-world
の2つのアクションを定義しています。
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には、小文字の英字、数字、アンダースコア、ハイフンのみを含める必要があります(ハイフンを使用して単語を区切ることができます)。たとえば、view
、update2
、comment-post
はすべて有効なアクションIDですが、view?
とUpdate
は無効です。
アクションは、インラインアクションとスタンドアロンアクションの2つの方法で作成できます。インラインアクションはコントローラークラスのメソッドとして定義され、スタンドアロンアクションは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 [
// declares "error" action using a class name
'error' => 'yii\web\ErrorAction',
// declares "view" action using a configuration array
'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()
メソッドの戻り値は重要です。それは、対応するアクションの結果を表します。
戻り値は、エンドユーザーにレスポンスとして送信されるレスポンスオブジェクトにすることができます。
上記の例では、アクションの結果はすべて文字列であり、エンドユーザーに送信されるレスポンスボディとして扱われます。次の例は、レスポンスオブジェクトを返すことによって(redirect()メソッドはレスポンスオブジェクトを返すため)、アクションがユーザーのブラウザーを新しいURLにリダイレクトする方法を示しています。
public function actionForward()
{
// redirect the user browser to https://example.com
return $this->redirect('https://example.com');
}
インラインアクションのアクションメソッドとスタンドアロンアクションのrun()
メソッドは、「アクションパラメーター」と呼ばれるパラメーターを受け取ることができます。それらの値はリクエストから取得されます。ウェブアプリケーション(Webアプリケーション)では、各アクションパラメーターの値は、パラメーター名をキーとして$_GET
から取得されます。コンソールアプリケーション(コンソールアプリケーション)では、コマンドライン引数に対応します。
次の例では、view
アクション(インラインアクション)は、$id
と$version
の2つのパラメーターを宣言しています。
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
イベントをトリガーし、ハンドラをアタッチできます。適切に設計されたアプリケーションでは、コントローラは多くの場合非常に薄く、各アクションには数行のコードしか含まれていません。コントローラが非常に複雑な場合は、通常、リファクタリングして他のクラスにコードを移動する必要があることを示しています。
具体的なベストプラクティスをいくつか示します。コントローラ
タイプミスを見つけた場合、またはこのページの改善が必要だと考える場合は、
Githubで編集してください !
サインアップまたはログインしてコメントしてください。