structure-views.md 42.8 KB
Newer Older
1 2
ビュー
======
3

4 5
ビューは [MVC](http://ja.wikipedia.org/wiki/Model_View_Controller) アーキテクチャの一部を成すものです。
ビューはエンドユーザにデータを表示することに責任を持つコードです。
6 7
ウェブアプリケーションにおいては、ビューは、通常、主として HTML コードと表示目的の PHP コードを含む PHP スクリプトファイルである、*ビューテンプレート* の形式で作成されます。
そして、ビューテンプレートを管理する [[yii\web\View|ビュー]] [アプリケーションコンポーネント](structure-application-components.md) が、
8 9
ビューの構築とレンダリングを助けるためによく使われるメソッドを提供します。
なお、簡潔さを重視して、ビューテンプレートまたはビューテンプレートファイルを単にビューと呼ぶことがよくあります。
10 11


12
## ビューを作成する <a name="creating-views"></a>
13

14 15 16
前述のように、ビューは HTML と PHP コードが混ざった単なる PHP スクリプトです。
次に示すのは、ログインフォームを表示するビューです。
見ると分るように、PHP コードがタイトルやフォームなど動的なコンテンツを生成するのに使われ、HTML コードがそれらを編成して表示可能な HTML ページを作っています。
17 18 19 20 21 22 23 24 25 26

```php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;

/* @var $this yii\web\View */
/* @var $form yii\widgets\ActiveForm */
/* @var $model app\models\LoginForm */

27
$this->title = 'ログイン';
28 29 30
?>
<h1><?= Html::encode($this->title) ?></h1>

31
<p>次の項目を入力してログインしてください:</p>
32 33 34 35

<?php $form = ActiveForm::begin(); ?>
    <?= $form->field($model, 'username') ?>
    <?= $form->field($model, 'password')->passwordInput() ?>
36
    <?= Html::submitButton('ログイン') ?>
37 38 39
<?php ActiveForm::end(); ?>
```

40
ビューの中でアクセスできる `$this` は、このビューテンプレートを管理しレンダリングしている [[yii\web\View|ビューコンポーネント]] を参照します。
41

42 43
`$this` 以外に、上記の例の `$model` のように、前もって定義された変数がビューの中にあることがあります。
このような変数は、[コントローラ](structure-controllers.md) または [ビューのレンダリング](#rendering-views) をトリガするオブジェクトによってビューに *プッシュ* されたデータを表します。
44

45 46
> Tip|ヒント: 上の例では、事前に定義された変数は、IDE に認識されるように、ビューの先頭のコメントブロックの中にリストされています。
  これは、ビューにドキュメントを付けるのにも良い方法です。
47 48


49
### セキュリティ <a name="security"></a>
50

51
HTML ページを生成するビューを作成するときは、エンドユーザから受け取るデータを表示する前にエンコード および/または フィルタすることが重要です。
52
そうしなければ、あなたのアプリケーションは [クロスサイトスクリプティング](http://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0) 攻撃をこうむるおそれがあります。
53

54
平文テキストを表示するためには、まず [[yii\helpers\Html::encode()]] を呼んでエンコードします。
55
例えば、次のコードはユーザの名前を表示する前にエンコードしています。
56 57 58 59 60 61 62 63 64 65 66

```php
<?php
use yii\helpers\Html;
?>

<div class="username">
    <?= Html::encode($user->name) ?>
</div>
```

67 68
HTML コンテンツを表示するためには、[[yii\helpers\HtmlPurifier]] を使って、最初にコンテンツをフィルタします。
例えば、次のコードは、投稿のコンテンツを表示する前にフィルタしています。
69 70 71 72 73 74 75 76 77 78 79

```php
<?php
use yii\helpers\HtmlPurifier;
?>

<div class="post">
    <?= HtmlPurifier::process($post->text) ?>
</div>
```

80 81
> Tip|ヒント: HTMLPurifier は、出力を安全なものにすることにおいては素晴らしい仕事をしますが、速くはありません。
  アプリケーションが高いパフォーマンスを要求する場合は、フィルター結果を [キャッシュ](caching-overview.md) することを考慮すべきです。
82 83


84
### ビューを整理する <a name="organizing-views"></a>
85

86
[コントローラ](structure-controllers.md)[モデル](structure-models.md) と同じように、ビューを整理するための規約があります。.
87

88
* コントローラによって表示されるビューは、既定では、ディレクトリ `@app/views/ControllerID` の下に置かれるべきものです。
89
  ここで、`ControllerID`[コントローラ ID](structure-controllers.md#routes) を指します。
90 91 92 93 94 95
  例えば、コントローラクラスが `PostController` である場合、ディレクトリは `@app/views/post` となります。
  `PostCommentController` の場合は、ディレクトリは `@app/views/post-comment` です。
  また、コントローラがモジュールに属する場合は、ディレクトリは [[yii\base\Module::basePath|モジュールディレクトリ]] の下の `views/ControllerID` です。
* [ウィジェット](structure-widgets.md) で表示されるビューは、既定では、`WidgetPath/views` ディレクトリの下に置かれるべきものです。
  ここで、`WidgetPath` は、ウィジェットのクラスファイルを含んでいるディレクトリを指します。
* 他のオブジェクトによって表示されるビューについても、ウィジェットの場合と同じ規約に従うことが推奨されます。
96

97 98
これらの既定のビューディレクトリは、コントローラやウィジェットの [[yii\base\ViewContextInterface::getViewPath()]]
メソッドをオーバーライドすることでカスタマイズすることが可能です。
99 100


101
## ビューをレンダリングする <a name="rendering-views"></a>
102

103 104
[コントローラ](structure-controllers.md) の中でも、[ウィジェット](structure-widgets.md) の中でも、または、その他のどんな場所でも、
ビューをレンダリングするメソッドを呼ぶことによってビューをレンダリングすることが出来ます。
105
これらのメソッドは、下記に示されるような類似のシグニチャを共有します。
106 107 108

```
/**
109
 * @param string $view ビュー名またはファイルパス (実際のレンダリングメソッドに依存する)
110 111
 * @param array $params ビューに引き渡されるデータ
 * @return string レンダリングの結果
112 113 114 115 116
 */
methodName($view, $params = [])
```


117
### コントローラでのレンダリング <a name="rendering-in-controllers"></a>
118

119
[コントローラ](structure-controllers.md) の中では、ビューをレンダリングするために次のコントローラメソッドを呼ぶことが出来ます。
120

121 122 123
* [[yii\base\Controller::render()|render()]]: [名前付きビュー](#named-views) をレンダリングし、その結果に [レイアウト](#layouts) を適用する。
* [[yii\base\Controller::renderPartial()|renderPartial()]]: [名前付きビュー](#named-views) をレイアウトなしでレンダリングする。
* [[yii\web\Controller::renderAjax()|renderAjax()]]: [名前付きビュー](#named-views) をレイアウトなしでレンダリングし、登録されている全ての JS/CSS スクリプトおよびファイルを注入する。
124
  通常、AJAX ウェブリクエストに対するレスポンスにおいて使用される。
125 126
* [[yii\base\Controller::renderFile()|renderFile()]]: ビューファイルのパスまたは [エイリアス](concept-aliases.md) の形式で指定されたビューをレンダリングする。
* [[yii\base\Controller::renderContent()|renderContent()]]: 静的な文字列をレンダリングして、現在適用可能な [レイアウト](#layouts) に埋め込む。このメソッドは バージョン 2.0.1 以降で使用可能。
127

128
例えば、
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146

```php
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;
        }

147
        // "view" という名前のビューをレンダリングし、レイアウトを適用する
148 149 150 151 152 153 154 155
        return $this->render('view', [
            'model' => $model,
        ]);
    }
}
```


156
### ウィジェットでのレンダリング <a name="rendering-in-widgets"></a>
157

158
[ウィジェット](structure-widgets.md) の中では、ビューをレンダリングするために、次のウィジェットメソッドを使用することが出来ます。
159

160
* [[yii\base\Widget::render()|render()]]: [名前付きのビュー](#named-views) をレンダリングする。
161
* [[yii\base\Widget::renderFile()|renderFile()]]: ビューファイルのパスまたは [エイリアス](concept-aliases.md) の形式で指定されたビューをレンダリングする。
162

163
例えば、
164 165 166 167 168 169 170 171 172 173 174 175 176

```php
namespace app\components;

use yii\base\Widget;
use yii\helpers\Html;

class ListWidget extends Widget
{
    public $items = [];

    public function run()
    {
177
        // "list" という名前のビューをレンダリングする
178 179 180 181 182 183 184 185
        return $this->render('list', [
            'items' => $this->items,
        ]);
    }
}
```


186
### ビューでのレンダリング <a name="rendering-in-views"></a>
187

188
[[yii\base\View|ビューコンポーネント]] によって提供される下記のメソッドのどれかを使うと、ビューの中で、別のビューをレンダリングすることが出来ます。
189

190
* [[yii\base\View::render()|render()]]: [名前付きのビュー](#named-views) をレンダリングする。
191
* [[yii\web\View::renderAjax()|renderAjax()]]: [名前付きビュー](#named-views) をレンダリングし、登録されている全ての JS/CSS スクリプトおよびファイルを注入する。
192
  通常、AJAX ウェブリクエストに対するレスポンスにおいて使用される。
193
* [[yii\base\View::renderFile()|renderFile()]]: ビューファイルのパスまたは [エイリアス](concept-aliases.md) の形式で指定されたビューをレンダリングする。
194

195 196
例えば、ビューの中の次のコードは、現在レンダリングされているビューと同じディレクトリにある `_overview.php` というビューファイルをレンダリングします。
ビューでは `$this`[[yii\base\View|ビュー]] コンポーネントを参照することを思い出してください。
197 198 199 200 201 202

```php
<?= $this->render('_overview') ?>
```


203
### 他の場所でのレンダリング <a name="rendering-in-other-places"></a>
204

205 206 207
場所がどこであれ、`Yii::$app->view` という式によって [[yii\base\View|ビュー]] アプリケーションコンポーネントにアクセスすることが出来ますから、
前述の [[yii\base\View|ビュー]] コンポーネントメソッドを使ってビューをレンダリングすることが出来ます。
例えば、
208 209

```php
210
// ビューファイル "@app/views/site/license.php" を表示
211 212 213 214
echo \Yii::$app->view->renderFile('@app/views/site/license.php');
```


215 216
### 名前付きビュー <a name="named-views"></a>

217
ビューをレンダリングするとき、ビューを指定するのには、ビューの名前か、ビューファイルのパス/エイリアスか、どちらかを使うことが出来ます。
218 219 220 221 222 223 224
たいていの場合は、より簡潔で柔軟な前者を使います。
名前を使って指定されるビューを *名前付きビュー* と呼びます。

ビューの名前は、以下の規則に従って、対応するビューファイルのパスに解決されます。

* ビュー名はファイル拡張子を省略することが出来ます。その場合、`.php` が拡張子として使われます。
  例えば、`about` というビュー名は `about.php` というファイル名に対応します。
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
* ビュー名が二つのスラッシュ (`//`) で始まる場合は、対応するビューファイルのパスは `@app/views/ViewName` となります。
  つまり、ビューファイルは [[yii\base\Application::viewPath|アプリケーションのビューパス]] の下で探されます。
  例えば、`//site/about``@app/views/site/about.php` へと解決されます。
* ビュー名が一つのスラッシュ (`/`) で始まる場合は、ビューファイルのパスは、ビュー名の前に、現在アクティブな [モジュール](structure-modules.md)[[yii\base\Module::viewPath|ビューパス]] を置くことによって形成されます。
  アクティブなモジュールが無い場合は、`@app/views/ViewName` が使用されます。
  例えば、`/user/create` は、現在アクティブなモジュールが `user` である場合は、`@app/modules/user/views/user/create.php` へと解決されます。
  アクティブなモジュールが無い場合は、ビューファイルのパスは `@app/views/user/create.php` となります。
* ビューが [[yii\base\View::context|コンテキスト]] を伴ってレンダリングされ、そのコンテキストが [[yii\base\ViewContextInterface]] を実装している場合は、
  ビューファイルのパスは、コンテキストの [[yii\base\ViewContextInterface::getViewPath()|ビューパス]] をビュー名の前に置くことによって形成されます。
  これは、主として、コントローラとウィジェットの中でレンダリングされるビューに当てはまります。
  例えば、コンテキストが `SiteController` コントローラである場合、`site/about``@app/views/site/about.php` へと解決されます。
* あるビューが別のビューの中でレンダリングされる場合は、後者のビューファイルを含んでいるディレクトリが前者のビュー名の前に置かれて、実際のビューファイルのパスが形成されます。
  例えば、`item` は、`@app/views/post/index.php` というビューの中でレンダリングされる場合、`@app/views/post/item` へと解決されます。

上記の規則によると、コントローラ `app\controllers\PostController` の中で `$this->render('view')` を呼ぶと、実際には、ビューファイル `@app/views/post/view.php` がレンダリングされ、
一方、そのビューの中で `$this->render('_overview')` を呼ぶと、ビューファイル `@app/views/post/_overview.php` がレンダリングされることになります。
241 242 243 244


### ビューの中でデータにアクセスする <a name="accessing-data-in-views"></a>

245
ビューの中でデータにアクセスするためのアプローチが二つあります。「プッシュ」と「プル」です。
246

247 248
ビューをレンダリングするメソッドに二番目のパラメータとしてデータを渡すのが「プッシュ」のアプローチです。
データは、「名前-値」のペアの配列として表されなければなりません。
249 250
ビューがレンダリングされるときに、PHP の `extract()` 関数がこの配列に対して呼び出され、ビューの中でこの配列から変数が抽出されます。
例えば、次のコードはコントローラの中でビューをレンダリングしていますが、`report` ビューに二つの変数、すなわち、`$foo = 1``$bar = 2` をプッシュしています。
251 252 253 254 255 256 257 258

```php
echo $this->render('report', [
    'foo' => 1,
    'bar' => 2,
]);
```

259 260 261 262
「プル」のアプローチは、[[yii\base\View|ビューコンポーネント]] またはビューからアクセス出来るその他のオブジェクト (例えば `Yii::$app`) から積極的にデータを読み出すものです。
下記のコード例のように、ビューの中では `$this->context` という式でコントローラオブジェクトを取得することが出来ます。
その結果、`report` ビューの中で、コントローラの全てのプロパティやメソッドにアクセスすることが出来ます。
次の例ではコントローラ ID にアクセスしています。
263 264 265 266 267 268

```php
The controller ID is: <?= $this->context->id ?>
?>
```

269 270 271
通常は「プッシュ」アプローチが、ビューでデータにアクセスする方法として推奨されます。
なぜなら、ビューのコンテキストオブジェクトに対する依存がより少ないからです。
その短所は、常にデータ配列を手作業で作成する必要がある、ということです。
272
ビューが共有されてさまざまな場所でレンダリングされる場合、その作業が面倒くさくなり、また、間違いも生じやすくなります。
273 274


275
### ビューの間でデータを共有する <a name="sharing-data-among-views"></a>
276

277
[[yii\base\View|ビューコンポーネント]] が提供する [[yii\base\View::params|params]] プロパティを使うと、ビューの間でデータを共有することが出来ます。
278

279
例えば、`about` というビューで、次のようなコードを使って、パン屑リストの現在の区分を指定することが出来ます。
280 281 282 283 284

```php
$this->params['breadcrumbs'][] = 'About Us';
```

285
そして、[レイアウト](#layouts) ファイル (これも一つのビューです) の中で、[[yii\base\View::params|params]] によって渡されたデータを使って、パン屑リストを表示することが出来ます。
286 287 288 289 290 291 292 293

```php
<?= yii\widgets\Breadcrumbs::widget([
    'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
]) ?>
```


294
## レイアウト <a name="layouts"></a>
295

296 297
レイアウトは、複数のビューの共通部分をあらわす特殊なタイプのビューです。
例えば、たいていのウェブアプリケーションでは、ページは共通のヘッダとフッタを持っています。
298
すべてのビューで同じヘッダとフッタを繰り返すことも出来ますが、もっと良い方法は、そういうことはレイアウトの中で一度だけして、コンテンツビューのレンダリング結果をレイアウトの中の適切な場所に埋め込むことです。
299 300


301
### レイアウトを作成する <a name="creating-layouts"></a>
302

303 304 305 306 307
レイアウトもまたビューですので、通常のビューと同様な方法で作成することが出来ます。
既定では、レイアウトは `@app/views/layouts` ディレクトリに保存されます。
[モジュール](structure-modules.md) の中で使用されるレイアウトについては、[[yii\base\Module::basePath|モジュールディレクトリ]]
の下の `views/layouts` ディレクトリに保存されるべきものとなります。
既定のレイアウトディレクトリは、アプリケーションまたはモジュールの [[yii\base\Module::layoutPath]] プロパティを構成することでカスタマイズすることが出来ます。
308

309 310
次の例は、レイアウトがどのようなものであるかを示すものです。説明のために、レイアウトの中のコードを大幅に単純化していることに注意してください。
実際には、ヘッドのタグやメインメニューなど、もっと多くのコンテンツを追加する必要があるでしょう。
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338

```php
<?php
use yii\helpers\Html;

/* @var $this yii\web\View */
/* @var $content string */
?>
<?php $this->beginPage() ?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <?= Html::csrfMetaTags() ?>
    <title><?= Html::encode($this->title) ?></title>
    <?php $this->head() ?>
</head>
<body>
<?php $this->beginBody() ?>
    <header>My Company</header>
    <?= $content ?>
    <footer>&copy; 2014 by My Company</footer>
<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage() ?>
```

339 340
見ると分かるように、レイアウトはすべてのページに共通な HTML タグを生成しています。`<body>` セクションの中でレイアウトが `$content` という変数をエコーしていますが、
これは、コンテンツビューのレンダリング結果を表すものであり、[[yii\base\Controller::render()]] が呼ばれるときに、レイアウトにプッシュされるものです。
341 342

上記のコードに示されているように、たいていのレイアウトは次に挙げるメソッドを呼び出すべきです。
343
これらのメソッドは主としてレンダリングの過程に関するイベントをトリガして、他の場所で登録されたスクリプトやタグが、メソッドが呼ばれた場所に正しく注入されるようにするためのものです。
344 345 346 347 348 349 350 351 352

- [[yii\base\View::beginPage()|beginPage()]]: このメソッドがレイアウトの一番初めに呼ばれるべきです。
  これは、ページの開始を示す [[yii\base\View::EVENT_BEGIN_PAGE|EVENT_BEGIN_PAGE]] イベントをトリガします。
- [[yii\base\View::endPage()|endPage()]]: このメソッドがレイアウトの最後で呼ばれるべきです。
  これは、ページの終了を示す [[yii\base\View::EVENT_END_PAGE|EVENT_END_PAGE]] イベントをトリガします。
- [[yii\web\View::head()|head()]]: このメソッドが HTML ページの `<head>` セクションの中で呼ばれるべきです。
  このメソッドは、ページのレンダリングが完了したときに、登録された head の HTML コード (リンクタグ、メタタグなど) に置き換えられるプレースホルダを生成します。
- [[yii\web\View::beginBody()|beginBody()]]: このメソッドが `<body>` セクションの最初で呼ばれるべきです。
  このメソッドは [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]] イベントをトリガし、
353
  body の開始位置を目的とする登録された HTML コード (JavaScript など) によって置き換えられるプレースホルダを生成します。
354 355
- [[yii\web\View::endBody()|endBody()]]: このメソッドが `<body`> セクションの最後で呼ばれるべきです。
  このメソッドは  [[yii\web\View::EVENT_END_BODY|EVENT_END_BODY]] イベントをトリガし、
356
  body の終了位置を目的とする登録された HTML コード (JavaScript など) によって置き換えられるプレースホルダを生成します。
357 358 359 360


### レイアウトでデータにアクセスする <a name="accessing-data-in-layouts"></a>

361 362 363
レイアウトの中では、事前定義された二つの変数、すなわち、`$this``$content` にアクセス出来ます。
前者は、通常のビューにおいてと同じく、[[yii\base\View|ビュー]] コンポーネントを参照します。
一方、後者は、コントローラの中で [[yii\base\Controller::render()|render()]] メソッドを呼ぶことによってレンダリングされる、
364 365
コンテンツビューのレンダリング結果を含むものです。

366 367
レイアウトの中で他のデータにアクセスする必要があるときは、[ビューの中でデータにアクセスする](#accessing-data-in-views) の項で説明されている「プル」の方法を使う必要があります。
コンテンツビューからレイアウトにデータを渡す必要があるときは、[ビューの間でデータを共有する](#sharing-data-among-views) の項で説明されている方法を使うことが出来ます。
368 369 370 371 372


### レイアウトを使う <a name="using-layouts"></a>

[コントローラでのレンダリング](#rendering-in-controllers) の項で説明されているように、コントローラの中で
373 374 375 376 377 378 379
[[yii\base\Controller::render()|render()]] メソッドを呼んでビューをレンダリングすると、レンダリング結果にレイアウトが適用されます。
既定では、`@app/views/layouts/main.php` というレイアウトが使用されます。

[[yii\base\Application::layout]] または [[yii\base\Controller::layout]] のどちらかを構成することによって、異なるレイアウトを使うことが出来ます。
前者は全てのコントローラによって使用されるレイアウトを決定するものですが、後者は個々のコントローラについて前者をオーバーライドするものです。
例えば、次のコードは、`post` コントローラがビューをレンダリングするときに `@app/views/layouts/post.php` をレイアウトとして使うようにするものです。
その他のコントローラは、`layout` プロパティに触れられていないと仮定すると、引き続き既定の `@app/views/layouts/main.php` をレイアウトとして使います。
380 381 382 383 384 385 386 387 388 389 390 391 392 393
 
```php
namespace app\controllers;

use yii\web\Controller;

class PostController extends Controller
{
    public $layout = 'post';
    
    // ...
}
```

394
モジュールに属するコントローラについては、モジュールの [[yii\base\Module::layout|layout]] プロパティを構成して、モジュール内のコントローラに特定のレイアウトを使用することも出来ます。
395

396
`layout` プロパティは異なるレベル (コントローラ、モジュール、アプリケーション) で構成されうるものですので、Yii は舞台裏で二つのステップを踏んで、特定のコントローラで実際に使われるレイアウトファイルが何であるかを決定します。
397

398
最初のステップで、Yii はレイアウトの値とコンテキストモジュールを決定します。
399

400 401 402 403 404 405
- コントローラの [[yii\base\Controller::layout]] プロパティが null でないときは、それをレイアウトの値として使い、
  コントローラの [[yii\base\Controller::module|モジュール]] をコンテキストモジュールとして使う。
- [[yii\base\Controller::layout|layout]] が null のときは、コントローラの祖先となっている全てのモジュール
  (アプリケーション自体も含む) を探して、[[yii\base\Module::layout|layout]] プロパティが null でない最初のモジュールを見つける。
  見つかったモジュールとその [[yii\base\Module::layout|layout]] の値をコンテキストモジュールと選ばれたレイアウトの値とする。
  そのようなモジュールが見つからなかったときは、レイアウトは適用されないということを意味する。
406

407
第二のステップでは、最初のステップで決定されたレイアウトの値とコンテキストモジュールに従って、実際のレイアウトファイルを決定します。
408
レイアウトの値は下記のいずれかであり得ます。
409

410 411 412 413 414 415 416
- パスエイリアス (例えば、`@app/views/layouts/main`)。
- 絶対パス (例えば、`/main`): すなわち、スラッシュで始まるレイアウトの値の場合。
  実際のレイアウトファイルはアプリケーションの [[yii\base\Application::layoutPath|レイアウトパス]]
  (デフォルトでは `@app/views/layouts`) の下で探される。
- 相対パス (例えば、`main`): 実際のレイアウトファイルはコンテキストモジュールの [[yii\base\Module::layoutPath|レイアウトパス]]
  (デフォルトでは [[yii\base\Module::basePath|モジュールディレクトリ]] の下の `views/layouts` ディレクトリ) の下で探される。
- 真偽値 `false`: レイアウトは適用されない。
417

418
レイアウトの値がファイル拡張子を含んでいない場合は、デフォルト値である `.php` を使います。
419 420


421
### 入れ子のレイアウト <a name="nested-layouts"></a>
422

423 424 425 426
ときとして、あるレイアウトの中に別のレイアウトを入れたい場合があるでしょう。
例えば、ウェブサイトの別々のセクションにおいて、違うレイアウトを使いたいけれども、
それらのレイアウトは全て、全体としての HTML5 ページ構造を生成する同一の基本レイアウトを共有している、という場合です。
この目的を達することは、次のように、子レイアウトの中で
427
[[yii\base\View::beginContent()|beginContent()]] と [[yii\base\View::endContent()|endContent()]]
428
を呼ぶことで可能になります。
429 430 431 432

```php
<?php $this->beginContent('@app/views/layouts/base.php'); ?>

433
... 子レイアウトのコンテンツをここに ...
434 435 436 437

<?php $this->endContent(); ?>
```

438 439
上のコードが示すように、子レイアウトのコンテンツは [[yii\base\View::beginContent()|beginContent()]] と
[[yii\base\View::endContent()|endContent()]] によって囲まれなければなりません。
440 441
[[yii\base\View::beginContent()|beginContent()]] に渡されるパラメータは、親レイアウトで何であるかを指定するものです。
レイアウトのファイルまたはエイリアスのどちらかを使うことが出来ます。
442

443
上記のアプローチを使って、2レベル以上のレイアウトを入れ子にすることも出来ます。
444 445


446
### ブロックを使う <a name="using-blocks"></a>
447

448
ブロックを使うと、ある場所でビューコンテンツを規定して、別の場所でそれを表示することが可能になります。
449 450
ブロックはたいていはレイアウトと一緒に使われます。
例えば、ブロックをコンテンツビューで定義して、それをレイアウトで表示する、ということが出来ます。
451

452
[[yii\base\View::beginBlock()|beginBlock()]] と [[yii\base\View::endBlock()|endBlock()]] を呼んでブロックを定義します。
453 454
すると、そのブロックを `$view->blocks[$blockID]` によってアクセス出来るようになります。
ここで `$blockID` は、定義したときにブロックに割り当てたユニークな ID を指します。
455

456
次の例は、どのようにブロックを使えば、レイアウトの特定の部分をコンテンツビューでカスタマイズすることが出来るかを示すものです。
457

458
最初に、コンテンツビューで、一つまたは複数のブロックを定義します。
459 460 461 462 463 464

```php
...

<?php $this->beginBlock('block1'); ?>

465
... block1 のコンテンツ ...
466 467 468 469 470 471 472

<?php $this->endBlock(); ?>

...

<?php $this->beginBlock('block3'); ?>

473
... block3 のコンテンツ ...
474 475 476 477

<?php $this->endBlock(); ?>
```

478
次に、レイアウトビューで、得ることが出来ればブロックをレンダリングし、ブロックが定義されていないときは何らかの既定のコンテンツを表示します。
479 480 481 482 483 484

```php
...
<?php if (isset($this->blocks['block1'])): ?>
    <?= $this->blocks['block1'] ?>
<?php else: ?>
485
    ... block1 の既定のコンテンツ ...
486 487 488 489 490 491 492
<?php endif; ?>

...

<?php if (isset($this->blocks['block2'])): ?>
    <?= $this->blocks['block2'] ?>
<?php else: ?>
493
    ... block2 の既定のコンテンツ ...
494 495 496 497 498 499 500
<?php endif; ?>

...

<?php if (isset($this->blocks['block3'])): ?>
    <?= $this->blocks['block3'] ?>
<?php else: ?>
501
    ... block3 の既定のコンテンツ ...
502 503 504 505 506
<?php endif; ?>
...
```


507
## ビューコンポーネントを使う <a name="using-view-components"></a>
508

509
[[yii\base\View|ビューコンポーネント]] はビューに関連する多くの機能を提供します。
510 511
ビューコンポーネントは、[[yii\base\View]] またはその子クラスの個別のインスタンスを作成することによっても取得できますが、たいていの場合は、`view` アプリケーションコンポーネントを主として使うことになるでしょう。
このコンポーネントは [アプリケーションの構成情報](structure-applications.md#application-configurations) の中で、次のようにして構成することが出来ます。
512 513 514 515 516 517 518 519 520 521 522 523 524

```php
[
    // ...
    'components' => [
        'view' => [
            'class' => 'app\components\View',
        ],
        // ...
    ],
]
```

525
ビューコンポーネントは、次に挙げるビュー関連の有用な機能を提供します。それぞれについては、独立の節で更に詳細に説明されます。
526

527 528 529
* [テーマ](output-theming.md): ウェブサイトのテーマを開発し変更することを可能にします。
* [フラグメントキャッシュ](caching-fragment.md): ウェブページの中の断片をキャッシュすることを可能にします。
* [クライアントスクリプトの取り扱い](output-client-scripts.md): CSS と JavaScript の登録とレンダリングをサポートします。
530 531
* [アセットバンドルの取り扱い](structure-assets.md): [アセットバンドル](structure-assets.md) の登録とレンダリングをサポートします。
* [代替のテンプレートエンジン](tutorial-template-engines.md): [Twig](http://twig.sensiolabs.org/)[Smarty](http://www.smarty.net/) など、他のテンプレートエンジンを使用することを可能にします。
532

533
次に挙げるマイナーではあっても有用な諸機能は、ウェブページを開発するときに頻繁に使用するでしょう。
534 535


536
### ページタイトルを設定する <a name="setting-page-titles"></a>
537

538 539 540
どんなウェブページにもタイトルが無ければなりません。通常、タイトルタグは [layout](#layouts) の中で表示されます。
しかし、実際においては、多くの場合、タイトルはレイアウトではなくコンテンツビューで決められます。
この問題を解決するために、[[yii\web\View]] は、タイトル情報をコンテンツビューからレイアウトに渡すための [[yii\web\View::title|title]] プロパティを提供しています。
541

542
この機能を利用するためには、全てのコンテンツビューにおいて、次のようにタイトルを設定します。
543 544 545 546 547 548 549

```php
<?php
$this->title = 'My page title';
?>
```

550
そして、レイアウトビューで、`<head>` セクションに次のコードを忘れずに書くようにします。
551 552 553 554 555 556

```php
<title><?= Html::encode($this->title) ?></title>
```


557
### メタタグを登録する <a name="registering-meta-tags"></a>
558

559 560
ウェブページは、通常、いろいろな関係者によって必要とされるさまざまなメタタグを生成する必要があります。
ページタイトルと同じように、メタタグは `<head>` セクションに出現して、通常はレイアウトの中で生成されます。
561

562
どのようなメタタグを生成するかをコンテンツビューの中で指定したい場合は、下記のように、[[yii\web\View::registerMetaTag()]] をコンテンツビューの呼ぶことが出来ます。
563 564 565 566 567 568 569

```php
<?php
$this->registerMetaTag(['name' => 'keywords', 'content' => 'yii, framework, php']);
?>
```

570 571
上記のコードは、ビューコンポーネントによって "keywords" メタタグを登録するものです。登録されたメタタグは、レイアウトがレンダリングを完了した後でレンダリングされます。
すなわち、レイアウトの中で [[yii\web\View::head()]] を呼び出した場所に、次の HTML コードが生成されて挿入されます。
572 573 574 575 576

```php
<meta name="keywords" content="yii, framework, php">
```

577
[[yii\web\View::registerMetaTag()]] を複数回呼び出した場合は、メタタグが同じものか否かに関係なく、複数のメタタグが登録されることに注意してください。
578

579 580
ある型のメタタグのインスタンスが一つだけになることを保証したい場合は、このメソッドを呼ぶときに第二のパラメータとしてキーを指定することが出来ます。
例えば、次のコードでは、二つの "description" メタタグを登録していますが、二番目のものだけがレンダリングされることになります。
581 582

```html
583 584
$this->registerMetaTag(['name' => 'description', 'content' => '俺が Yii で作ったクールなウェブサイトだぜぃ!!'], 'description');
$this->registerMetaTag(['name' => 'description', 'content' => '面白いアライグマに関するウェブサイトです。'], 'description');
585 586 587
```


588
### リンクタグを登録する <a name="registering-link-tags"></a>
589

590 591 592 593
[メタタグ](#registering-meta-tags) と同じように、リンクタグも多くの場合において有用なものです。
例えば、favicon をカスタマイズしたり、RSS フィードを指し示したり、OpenID を別のサーバに委任したり、等々。
リンクタグも、[[yii\web\View::registerLinkTag()]] を使って、メタタグと同じような方法で取り扱うことが出来ます。
例えば、コンテンツビューにおいて、次のようにしてリンクタグを登録することが出来ます。
594 595 596

```php
$this->registerLinkTag([
597
    'title' => 'Yii ライブニューズ',
598 599 600 601 602 603
    'rel' => 'alternate',
    'type' => 'application/rss+xml',
    'href' => 'http://www.yiiframework.com/rss.xml/',
]);
```

604
上記のコードは、次の結果になります。
605 606

```html
607
<link title="Yii ライブニューズ" rel="alternate" type="application/rss+xml" href="http://www.yiiframework.com/rss.xml/">
608 609
```

610 611
[[yii\web\View::registerMetaTag()|registerMetaTags()]] と同じように、[[yii\web\View::registerLinkTag()|registerLinkTag()]]
を呼ぶときにキーを指定すると、同じリンクタグを繰り返して生成するのを避けることが出来ます。
612 613


614
## ビューのイベント <a name="view-events"></a>
615

616
[[yii\base\View|ビューコンポーネント]] はビューをレンダリングする過程においていくつかのイベントをトリガします。
617
これらのイベントに反応することによって、ビューにコンテンツを注入したり、エンドユーザに送信される前にレンダリング結果を加工したりすることが出来ます。
618

619 620 621
- [[yii\base\View::EVENT_BEFORE_RENDER|EVENT_BEFORE_RENDER]]: コントローラでファイルをレンダリングする前にトリガされます。
  このイベントのハンドラは、[[yii\base\ViewEvent::isValid]] を false にセットして、レンダリングのプロセスをキャンセルすることが出来ます。
- [[yii\base\View::EVENT_AFTER_RENDER|EVENT_AFTER_RENDER]]: ファイルのレンダリングの後、[[yii\base\View::afterRender()]] を呼ぶことによってトリガされます。
622
  このイベントのハンドラは、レンダリング結果をプロパティ [[yii\base\ViewEvent::output]] を通じて取得して、それを修正してレンダリング結果を変更することが出来ます。
623 624 625 626
- [[yii\base\View::EVENT_BEGIN_PAGE|EVENT_BEGIN_PAGE]]: レイアウトの中で [[yii\base\View::beginPage()]] を呼ぶことによってトリガされます。
- [[yii\base\View::EVENT_END_PAGE|EVENT_END_PAGE]]: レイアウトの中で [[yii\base\View::endPage()]] を呼ぶことによってトリガされます。
- [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]]: レイアウトの中で [[yii\web\View::beginBody()]] を呼ぶことによってトリガされます。
- [[yii\web\View::EVENT_END_BODY|EVENT_END_BODY]]: レイアウトの中で [[yii\web\View::endBody()]] を呼ぶことによってトリガされます。
627

628
例えば、次のコードはページの body の最後に現在の日付を注入するものです。
629 630 631 632 633 634 635 636

```php
\Yii::$app->view->on(View::EVENT_END_BODY, function () {
    echo date('Y-m-d');
});
```


637
## 静的なページをレンダリングする <a name="rendering-static-pages"></a>
638

639
静的なページというのは、主たるコンテンツのほとんどが静的なもので、コントローラからプッシュされる動的なデータにアクセスする必要がないページを指します。
640

641
静的なページは、そのコードをビューに置き、そして、コントローラで次のようなコードを使うと表示することが出来ます。
642 643 644 645 646 647 648 649

```php
public function actionAbout()
{
    return $this->render('about');
}
```

650 651 652
ウェブサイトが多くの静的なページを含んでいる場合、同じようなコードを何度も繰り返すのは非常に面倒くさいでしょう。
この問題を解決するために、[[yii\web\ViewAction]] という [スタンドアロンアクション](structure-controllers.md#standalone-actions)
をコントローラに導入することが出来ます。例えば、
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671

```php
namespace app\controllers;

use yii\web\Controller;

class SiteController extends Controller
{
    public function actions()
    {
        return [
            'page' => [
                'class' => 'yii\web\ViewAction',
            ],
        ];
    }
}
```

672
このようにすると、ディレクトリ `@app/views/site/pages` の下に `about` という名前のビューを作成したときに、次の URL によってこのビューを表示することが出来るようになります。
673 674 675 676 677

```
http://localhost/index.php?r=site/page&view=about
```

678 679 680
`view` という `GET` パラメータが、どのビューがリクエストされているかを [[yii\web\ViewAction]] に教えます。
そこで、アクションはこのビューをディレクトリ `@app/views/site/pages` の下で探します。
[[yii\web\ViewAction::viewPrefix]] を構成して、ビューを探すディレクトリを変更することが出来ます。
681 682


683
## ベストプラクティス <a name="best-practices"></a>
684

685
ビューはエンドユーザが望む形式でモデルを表現することに対して責任を持ちます。一般的に、ビューは
686

687
* 主として表示目的のコードを含むべきです。例えば、HTML、または、データをたどって書式化してレンダリングする簡単な PHP コードなど。
688 689 690 691
* DB クエリを実行するコードは含むべきではありません。そのようなコードはモデルの中で実行されるべきです。
* `$_GET``$_POST` のようなリクエストデータに直接アクセスするべきではありません。それはコントローラの仕事です。
  リクエストデータが必要な場合は、コントローラからビューにプッシュされるべきです。
* モデルのプロパティを読み出すことが出来ます。しかし、それを修正するべきではありません。
692

693
ビューを管理しやすいものにするために、複雑すぎるビューや、冗長なコードをあまりに多く含むビューを作ることは避けましょう。
694
この目的を達するために、次のテクニックを使うことが出来ます。
695

696
* 共通の表示セクション (ページのヘッダやフッタなど) を表すために [レイアウト](#layouts) を使う。
697
* 複雑なビューはいくつかの小さなビューに分割する。既に説明したレンダリングのメソッドを使えば、小さなビューをレンダリングして大きなビューを組み上げることが出来る。
698
* ビューの構成要素として [ウィジェット](structure-widgets.md) を使う。
699
* ビューでデータを変換し書式化するためのヘルパクラスを作成して使う。
700