structure-views.md 29.6 KB
Newer Older
Qiang Xue committed
1 2
Views
=====
Alexander Makarov committed
3

Qiang Xue committed
4
Views are part of the [MVC](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) architecture.
Qiang Xue committed
5 6 7 8 9
They are code responsible for presenting data to end users. In a Web application, views are usually created
in terms of *view templates* which are PHP script files containing mainly HTML code and presentational PHP code.
They are managed by the [[yii\web\View|view]] application component which provides commonly used methods
to facilitate view composition and rendering. For simplicity, we often call view templates or view template files
as views.
Qiang Xue committed
10

Qiang Xue committed
11

Qiang Xue committed
12
## Creating Views
Qiang Xue committed
13

Qiang Xue committed
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
As aforementioned, a view is simply a PHP script mixed with HTML and PHP code. The following is the view
that presents a login form. As you can see, PHP code is used to generate the dynamic content, such as the
page title and the form, while HTML code organizes them into a presentable HTML page.

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

/**
 * @var yii\web\View $this
 * @var yii\widgets\ActiveForm $form
 * @var app\models\LoginForm $model
 */
$this->title = 'Login';
?>
<h1><?= Html::encode($this->title) ?></h1>

<p>Please fill out the following fields to login:</p>

<?php $form = ActiveForm::begin(); ?>
    <?= $form->field($model, 'username') ?>
    <?= $form->field($model, 'password')->passwordInput() ?>
    <?= Html::submitButton('Login') ?>
<?php ActiveForm::end(); ?>
```

Within a view, you can access `$this` which refers to the [[yii\web\View|view component]] managing
and rendering this view template.

Besides `$this`, there may be other predefined variables in a view, such as `$form` and `$model` in the above
example. These variables represent the data that are *pushed* into the view by [controllers](structure-controllers.md)
or other objects whose trigger the [view rendering](#rendering-views).

> Tip: The predefined variables are listed in a comment block at beginning of a view so that they can
  be recognized by IDEs. It is also a good practice to document your views.

TODO: features in creating views


Qiang Xue committed
54 55


Qiang Xue committed
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
## Organizing Views

Like [controllers](structure-controllers.md) and [models](structure-models.md), there are conventions to organize views.

* For views rendered in a controller, they should be put under the directory `@app/views/ControllerID` by default,
  where `ControllerID` refers to [the ID of the controller](structure-controllers.md#routes). For example, if
  the controller class is `PostController`, the directory would be `@app/views/post`; If the class is `PostCommentController`,
  the directory would be `@app/views/post-comment`. In case the controller belongs to a module, the directory
  would be `views/ControllerID` under the [[yii\base\Module::basePath|module directory]].
* For views rendered in a [widget](structure-widgets.md), they should be put under the `WidgetPath/views` directory by
  default, where `WidgetPath` stands for the directory containing the widget class file.
* For views rendered by other objects, it is recommended that you follow the similar convention as that for widgets.

You may customize these default view directories by overriding the [[yii\base\ViewContextInterface::getViewPath()]]
method of controllers or widgets.


## Rendering Views

You can render views in [controllers](structure-controllers.md), [widgets](structure-widgets.md), or any
Qiang Xue committed
76
other places by calling view rendering methods. These methods share a similar signature shown as follows,
Qiang Xue committed
77 78 79 80

```
/**
 * @param string $view view name or file path, depending on the actual rendering method
Qiang Xue committed
81 82
 * @param array $params the data to be passed to the view
 * @return string rendering result
Qiang Xue committed
83 84 85 86 87 88 89
 */
methodName($view, $params = [])
```


### Rendering in Controllers

Qiang Xue committed
90
Within [controllers](structure-controllers.md), you may call the following controller methods to render views:
Qiang Xue committed
91 92 93 94

* [[yii\base\Controller::render()|render()]]: renders a [named view](#named-views) and applies a [layout](#layouts)
  to the rendering result.
* [[yii\base\Controller::renderPartial()|renderPartial()]]: renders a [named view](#named-views) without any layout.
Qiang Xue committed
95 96
* [[yii\web\Controller::renderAjax()|renderAjax()]]: renders a [named view](#named-views) without any layout,
  and injects all registered JS/CSS scripts and files. It is usually used in response to AJAX Web requests.
Qiang Xue committed
97 98 99 100
* [[yii\base\Controller::renderFile()|renderFile()]]: renders a view specified in terms of a view file path or
  [alias](concept-aliases.md).

For example,
Qiang Xue committed
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118

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

Qiang Xue committed
119
        // renders a view named "view" and applies a layout to it
Qiang Xue committed
120 121 122 123 124 125 126 127
        return $this->render('view', [
            'model' => $model,
        ]);
    }
}
```


Qiang Xue committed
128 129 130 131 132 133 134
### Rendering in Widgets

Within [widgets](structure-widgets.md), you may call the following widget methods to render views.

* [[yii\base\Widget::render()|render()]]: renders a [named view](#named-views).
* [[yii\base\Widget::renderFile()|renderFile()]]: renders a view specified in terms of a view file path or
  [alias](concept-aliases.md).
Qiang Xue committed
135

Qiang Xue committed
136
For example,
Qiang Xue committed
137

Qiang Xue committed
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
```php
namespace app\components;

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

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

    public function run()
    {
        // renders a view named "list"
        return $this->render('list', [
            'items' => $this->items,
        ]);
    }
}
```
Qiang Xue committed
157 158


Qiang Xue committed
159
### Rendering in Other Places
Qiang Xue committed
160

Qiang Xue committed
161 162
In any place, you can render views with the help of the [[yii\base\View|view]] application component by calling
its following methods:
Qiang Xue committed
163

Qiang Xue committed
164
* [[yii\base\View::render()|render()]]: renders a [named view](#named-views).
Qiang Xue committed
165 166
* [[yii\web\View::renderAjax()|renderAjax()]]: renders a [named view](#named-views) and injects all registered
  JS/CSS scripts and files. It is usually used in response to AJAX Web requests.
Qiang Xue committed
167 168
* [[yii\base\View::renderFile()|renderFile()]]: renders a view specified in terms of a view file path or
  [alias](concept-aliases.md).
Qiang Xue committed
169

Qiang Xue committed
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
For example,

```php
// displays the view file "@app/views/site/license.php"
echo \Yii::$app->view->renderFile('@app/views/site/license.php');
```

If you are rendering a view within another view, you can use the following code, because `$this` in a view refers to
the [[yii\base\View|view]] component:

```php
<?= $this->renderFile('@app/views/site/license.php') ?>
```


## Named Views

When you render a view, you can specify the view using either a view name or a view file path/alias. In most cases,
you would use the former because it is more concise and flexible. We call views specified using names as *named views*.

A view name is resolved into the corresponding view file path according to the following rules:

* A view name may omit the file extension name. In this case, `.php` will be used as the extension. For example,
  the view name `about` corresponds to the file name `about.php`.
* If the view name starts with double slashes `//`, the corresponding view file path would be `@app/views/ViewName`.
  That is, the view is looked for under the [[yii\base\Application::viewPath|application's view path]].
  For example, `//site/about` will be resolved into `@app/views/site/about.php`.
Qiang Xue committed
197 198 199
* If the view name starts with a single slash `/`, the view file path is formed by prefixing the view name
  with the [[yii\base\Module::viewPath|view path]] of the currently active [module](structure-modules.md).
  If there is no active module, `@app/views/ViewName` will be used. For example, `/user/create` will be resolved into
Qiang Xue committed
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
  `@app/modules/user/views/user/create.php`, if the currently active module is `user`. If there is no active module,
  the view file path would be `@app/views/user/create.php`.
* If the view is rendered with a [[yii\base\View::context|context]] and the context implements [[yii\base\ViewContextInterface]],
  the view file path is formed by prefixing the [[yii\base\ViewContextInterface::getViewPath()|view path]] of the
  context to the view name. This mainly applies to the views rendered within controllers and widgets. For example,
  `site/about` will be resolved into `@app/views/site/about.php` if the context is the controller `SiteController`.
* If a view is rendered within another view, the directory containing the other view file will be prefixed to
  the new view name to form the actual view file path. For example, `item` will be resolved into `@app/views/post/item`
  if it is being rendered in the view `@app/views/post/index.php`.

According to the above rules, the following code in a controller is actually rendering the view file
`@app/views/post/view.php`

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

        // renders a view named "view" and applies a layout to it
        return $this->render('view', [
            'model' => $model,
        ]);
    }
}
```

And the following code in the view `@app/views/post/view.php` is actually rendering the view file
Qiang Xue committed
239
`@app/views/post/_overview.php`:
Qiang Xue committed
240 241

```php
Qiang Xue committed
242
<?= $this->render('_overview', ['model' => $model]) ?>
Qiang Xue committed
243
```
Qiang Xue committed
244 245


Qiang Xue committed
246
### Accessing Data in Views
Qiang Xue committed
247

Qiang Xue committed
248
There are two approaches to access data within a view: push and pull.
Qiang Xue committed
249

Qiang Xue committed
250 251 252 253 254
By passing the data as the second parameter to the view rendering methods, you are using the push approach.
The data should be represented be an array of name-value pairs. When the view is being rendered, the PHP
`extract()` function will be called on this array so that the array is extracted into variables in the view.
For example, the following view rendering code in a controller will push two variables to the `report` view:
`$foo = 1` and `$bar = 2`.
Qiang Xue committed
255

Qiang Xue committed
256 257 258 259 260 261
```php
echo $this->render('report', [
    'foo' => 1,
    'bar' => 2,
]);
```
Qiang Xue committed
262

Qiang Xue committed
263 264 265 266
The pull approach actively retrieves data from the [[yii\base\View::context|view context object]]. Using the above
code as an example, within the view you can get the controller object by the expression `$this->context`.
As a result, it is possible for you to access any properties or methods of the controller in the `report` view.
For example, in the `report` view you may pull the `id` data like the following:
Qiang Xue committed
267

Qiang Xue committed
268 269 270 271 272 273 274 275
```php
The controller ID is: <?= $this->context->id ?>
?>
```

The pull approach is usually the preferred way of accessing data in views, because it makes views less dependent
on context objects. Its drawback is that you need to manually build the data array all the time, which could
becomes tedious and error prone if a view is shared and rendered in different places.
Qiang Xue committed
276

Qiang Xue committed
277

Qiang Xue committed
278 279 280 281 282 283
## Layouts

Layouts are a special type of views that represent the common parts of multiple views. For example, the pages
for most Web applications share the same page header and footer. While you can repeat the same page header and footer
in every view, a better way is to do this once in a layout and embed the rendering result of a content view at
an appropriate place in the layout.
Alexander Makarov committed
284 285


Qiang Xue committed
286
### Creating Layouts
Alexander Makarov committed
287

Qiang Xue committed
288 289
Because layouts are also views, they can be created in the similar way as normal views. The following example
shows how a layout looks like:
Alexander Makarov committed
290 291

```php
Qiang Xue committed
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
<?php
use yii\helpers\Html;
/**
 * @var yii\web\View $this
 * @var string $content
 */
?>
<?php $this->beginPage() ?>
<!DOCTYPE html>
<html lang="<?= Yii::$app->language ?>">
<head>
    <meta charset="<?= Yii::$app->charset ?>"/>
    <title><?= Html::encode($this->title) ?></title>
    <?php $this->head() ?>
</head>
<body>
<?php $this->beginBody() ?>
    <div class="container">
        <?= $content ?>
    </div>
    <footer class="footer">&copy; 2014 by me :)</footer>
<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage() ?>
Alexander Makarov committed
317 318
```

Qiang Xue committed
319 320
The above layout is used to generate HTML pages. It generates HTML tags that are common to all pages. You may
also generate other common HTML tags in the layout, such as head tags, main menu, etc.
Alexander Makarov committed
321

Qiang Xue committed
322 323 324 325
Within a layout, you have access to a special variable named `$content`. This is the only variable injected into
the layout by the controller when the [[yii\base\Controller::render()]] method is called to render a view.
The value of `$content` represents the rendering result of the view. As you can see in the above code,
`$content` is embedded within the body part of the layout.
326

Qiang Xue committed
327
Besides `$content`, you can also access the [[yii\base\View|view]] component via `$this`, like in normal views.
Alexander Makarov committed
328 329


Qiang Xue committed
330
### Organizing Layouts
Alexander Makarov committed
331

332

Qiang Xue committed
333 334


Qiang Xue committed
335
### Using Layouts
Alexander Makarov committed
336

Qiang Xue committed
337 338 339
A layout is applied when you call the [[yii\base\Controller::render()|render()]] method in a controller. The method
will first render the view being requested; it will then render the layout specified by the [[yii\base\Controller::layout]]
property of the controller and push the rendering result of the view into the layout as a variable `$content`.
340 341


342

Qiang Xue committed
343
### View Events
344 345


Qiang Xue committed
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
The [[yii\base\View|view]] component provides several *placeholder* methods, such as `head()` and `beginBody()`,
which generate placeholders which will be replaced later by



 code shows a typical layout
A layout is a very convenient way to represent the part of the page that is common for all or at least for most pages
generated by your application. Typically it includes `<head>` section, footer, main menu and alike elements.
You can find a fine example of the layout in a [basic application template](apps-basic.md). Here we'll review the very
basic one without any widgets or extra markup.


In the markup above there's some code. First of all, `$content` is a variable that will contain result of views rendered
with controller's `$this->render()` method.

We are importing [[yii\helpers\Html|Html]] helper via standard PHP `use` statement. This helper is typically used for almost all views
where one need to escape outputted data.

Several special methods such as [[yii\web\View::beginPage()|beginPage()]]/[[yii\web\View::endPage()|endPage()]],
[[yii\web\View::head()|head()]], [[yii\web\View::beginBody()|beginBody()]]/[[yii\web\View::endBody()|endBody()]]
are triggering page rendering events that are used for registering scripts, links and process page in many other ways.
Always include these in your layout in order for the rendering to work correctly.

By default layout is loaded from `views/layouts/main.php`. You may change it at controller or module level by setting
different value to `layout` property.

In order to pass data from controller to layout, that you may need for breadcrumbs or similar elements, use view component
params property. In controller it can be set as:

```php
$this->view->params['breadcrumbs'][] = 'Contact';
377 378
```

Qiang Xue committed
379
In a view it will be:
380

Qiang Xue committed
381 382 383
```php
$this->params['breadcrumbs'][] = 'Contact';
```
384

Qiang Xue committed
385
In layout file the value can be used like the following:
Alexander Makarov committed
386

Qiang Xue committed
387 388 389 390 391
```php
<?= Breadcrumbs::widget([
    'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
]) ?>
```
Alexander Makarov committed
392

Qiang Xue committed
393 394
You may also wrap the view render result into a layout using [[yii\base\View::beginContent()]], [[yii\base\View::endContent()]].
This approach can be used while applying nested layouts:
Alexander Makarov committed
395 396

```php
Qiang Xue committed
397 398 399 400 401 402
<?php $this->beginContent('//layouts/overall') ?>
<div class="content">
    <?= $content ?>
<div>
<?php $this->endContent() ?>
```
Alexander Makarov committed
403

Qiang Xue committed
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
### Nested Layouts

### Accessing Data in Layouts


## View Components

### Setting page title
### Adding meta tags
### Registering link tags
### Registering CSS
### Registering scripts
### Static Pages
### Assets
### Alternative Template Engines


### Rendering Static Pages

Static pages refer to those Web pages whose main content are mostly static without the need of accessing
dynamic data pushed from controllers.

You can generate static pages using the code like the following in a controller:

```php
public function actionAbout()
{
    return $this->render('about');
}
Alexander Makarov committed
433 434
```

Qiang Xue committed
435 436 437
If a Web site contains many static pages, it would be very tedious repeating the similar code many times.
To solve this problem, you may introduce a [standalone action](structure-controllers.md#standalone-actions)
called [[yii\web\ViewAction]] in a controller. For example,
Alexander Makarov committed
438 439

```php
Qiang Xue committed
440
namespace app\controllers;
Alexander Makarov committed
441

Qiang Xue committed
442 443 444 445 446 447 448 449 450 451 452 453 454
use yii\web\Controller;

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

Qiang Xue committed
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
Now if you create a view named `about` under the directory `@app/views/site/pages`, you will be able to
display this view by the following URL:

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

The `GET` parameter `view` tells [[yii\web\ViewAction]] which view is requested. The action will then look
for this view under the directory `@app/views/site/pages`. You may configure [[yii\web\ViewAction::viewPrefix]]
to change the directory for searching these views.


## Best Practices


Alexander Makarov committed
472 473 474 475

Alternative template languages
------------------------------

476
There are official extensions for [Smarty](http://www.smarty.net/) and [Twig](http://twig.sensiolabs.org/). In order
Alexander Makarov committed
477
to learn more refer to [Using template engines](template.md) section of the guide.
Alexander Makarov committed
478

479 480
Using View object in templates
------------------------------
Alexander Makarov committed
481

482
An instance of [[yii\web\View]] component is available in view templates as `$this` variable. Using it in templates you
483
can do many useful things including setting page title and meta, registering scripts and accessing the context.
Alexander Makarov committed
484 485 486 487 488 489 490 491 492 493 494 495

### Setting page title

A common place to set page title are view templates. Since we can access view object with `$this`, setting a title
becomes as easy as:

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

### Adding meta tags

496
Adding meta tags such as encoding, description, keywords is easy with view object as well:
Alexander Makarov committed
497 498

```php
Alexander Makarov committed
499
$this->registerMetaTag(['encoding' => 'utf-8']);
Alexander Makarov committed
500 501 502 503 504 505 506 507 508 509 510
```

The first argument is an map of `<meta>` tag option names and values. The code above will produce:

```html
<meta encoding="utf-8">
```

Sometimes there's a need to have only a single tag of a type. In this case you need to specify the second argument:

```html
511 512
$this->registerMetaTag(['name' => 'description', 'content' => 'This is my cool website made with Yii!'], 'meta-description');
$this->registerMetaTag(['name' => 'description', 'content' => 'This website is about funny raccoons.'], 'meta-description');
Alexander Makarov committed
513 514
```

Aris Karageorgos committed
515
If there are multiple calls with the same value of the second argument (`meta-description` in this case), the latter will
516
override the former and only a single tag will be rendered:
Alexander Makarov committed
517 518

```html
519
<meta name="description" content="This website is about funny raccoons.">
Alexander Makarov committed
520 521 522 523
```

### Registering link tags

524
`<link>` tag is useful in many cases such as customizing favicon, pointing to RSS feed or delegating OpenID to another
Alexander Makarov committed
525 526 527
server. Yii view object has a method to work with these:

```php
Alexander Makarov committed
528
$this->registerLinkTag([
529 530 531 532
    'title' => 'Lives News for Yii Framework',
    'rel' => 'alternate',
    'type' => 'application/rss+xml',
    'href' => 'http://www.yiiframework.com/rss.xml/',
Alexander Makarov committed
533
]);
Alexander Makarov committed
534 535 536 537 538 539 540 541 542 543 544 545
```

The code above will result in

```html
<link title="Lives News for Yii Framework" rel="alternate" type="application/rss+xml" href="http://www.yiiframework.com/rss.xml/" />
```

Same as with meta tags you can specify additional argument to make sure there's only one link of a type registered.

### Registering CSS

546 547
You can register CSS using [[yii\web\View::registerCss()|registerCss()]] or [[yii\web\View::registerCssFile()|registerCssFile()]].
The former registers a block of CSS code while the latter registers an external CSS file. For example,
Alexander Makarov committed
548 549 550 551 552 553 554 555 556 557 558 559 560

```php
$this->registerCss("body { background: #f00; }");
```

The code above will result in adding the following to the head section of the page:

```html
<style>
body { background: #f00; }
</style>
```

Anderson Müller committed
561
If you want to specify additional properties of the style tag, pass an array of name-values to the third argument.
Anderson Müller committed
562
If you need to make sure there's only a single style tag use fourth argument as was mentioned in meta tags description.
Alexander Makarov committed
563 564

```php
Qiang Xue committed
565
$this->registerCssFile("http://example.com/css/themes/black-and-white.css", [BootstrapAsset::className()], ['media' => 'print'], 'css-print-theme');
Alexander Makarov committed
566 567
```

Qiang Xue committed
568 569 570
The code above will add a link to CSS file to the head section of the page.

* The first argument specifies the CSS file to be registered.
571 572 573
* The second argument specifies that this CSS file depends on [[yii\bootstrap\BootstrapAsset|BootstrapAsset]], meaning it will be added
  AFTER the CSS files in [[yii\bootstrap\BootstrapAsset|BootstrapAsset]]. Without this dependency specification, the relative order
  between this CSS file and the [[yii\bootstrap\BootstrapAsset|BootstrapAsset]] CSS files would be undefined.
Qiang Xue committed
574 575 576 577 578 579
* The third argument specifies the attributes for the resulting `<link>` tag.
* The last argument specifies an ID identifying this CSS file. If it is not provided, the URL of the CSS file will be
  used instead.


It is highly recommended that you use [asset bundles](assets.md) to register external CSS files rather than
580 581
using [[yii\web\View::registerCssFile()|registerCssFile()]]. Using asset bundles allows you to combine and compress
multiple CSS files, which is desirable for high traffic websites.
Qiang Xue committed
582

Alexander Makarov committed
583 584 585

### Registering scripts

586 587 588 589
With the [[yii\web\View]] object you can register scripts. There are two dedicated methods for it:
[[yii\web\View::registerJs()|registerJs()]] for inline scripts and
[[yii\web\View::registerJsFile()|registerJsFile()]] for external scripts.
Inline scripts are useful for configuration and dynamically generated code.
Alexander Makarov committed
590
The method for adding these can be used as follows:
Alexander Makarov committed
591

Alexander Makarov committed
592
```php
593
$this->registerJs("var options = ".json_encode($options).";", View::POS_END, 'my-options');
Alexander Makarov committed
594 595
```

Qiang Xue committed
596 597
The first argument is the actual JS code we want to insert into the page. The second argument
determines where script should be inserted into the page. Possible values are:
Alexander Makarov committed
598

599 600 601 602 603
- [[yii\web\View::POS_HEAD|View::POS_HEAD]] for head section.
- [[yii\web\View::POS_BEGIN|View::POS_BEGIN]] for right after opening `<body>`.
- [[yii\web\View::POS_END|View::POS_END]] for right before closing `</body>`.
- [[yii\web\View::POS_READY|View::POS_READY]] for executing code on document `ready` event. This will register [[yii\web\JqueryAsset|jQuery]] automatically.
- [[yii\web\View::POS_LOAD|View::POS_LOAD]] for executing code on document `load` event. This will register [[yii\web\JqueryAsset|jQuery]] automatically.
Alexander Makarov committed
604

Qiang Xue committed
605 606
The last argument is a unique script ID that is used to identify code block and replace existing one with the same ID
instead of adding a new one. If you don't provide it, the JS code itself will be used as the ID.
Alexander Makarov committed
607

Qiang Xue committed
608
An external script can be added like the following:
Alexander Makarov committed
609 610

```php
Qiang Xue committed
611
$this->registerJsFile('http://example.com/js/main.js', [JqueryAsset::className()]);
Alexander Makarov committed
612 613
```

614 615
The arguments for [[yii\web\View::registerJsFile()|registerJsFile()]] are similar to those for
[[yii\web\View::registerCssFile()|registerCssFile()]]. In the above example,
Qiang Xue committed
616 617 618 619
we register the `main.js` file with the dependency on `JqueryAsset`. This means the `main.js` file
will be added AFTER `jquery.js`. Without this dependency specification, the relative order between
`main.js` and `jquery.js` would be undefined.

620 621
Like for [[yii\web\View::registerCssFile()|registerCssFile()]], it is also highly recommended that you use
[asset bundles](assets.md) to register external JS files rather than using [[yii\web\View::registerJsFile()|registerJsFile()]].
Qiang Xue committed
622

Alexander Makarov committed
623 624 625 626 627 628 629 630

### Registering asset bundles

As was mentioned earlier it's preferred to use asset bundles instead of using CSS and JavaScript directly. You can get
details on how to define asset bundles in [asset manager](assets.md) section of the guide. As for using already defined
asset bundle, it's very straightforward:

```php
631
\frontend\assets\AppAsset::register($this);
Alexander Makarov committed
632 633 634 635
```

### Layout

Alexander Makarov committed
636 637
A layout is a very convenient way to represent the part of the page that is common for all or at least for most pages
generated by your application. Typically it includes `<head>` section, footer, main menu and alike elements.
Reazul Iqbal committed
638
You can find a fine example of the layout in a [basic application template](apps-basic.md). Here we'll review the very
Alexander Makarov committed
639 640 641 642 643 644
basic one without any widgets or extra markup.

```php
<?php
use yii\helpers\Html;
?>
Алексей committed
645
<?php $this->beginPage() ?>
Alexander Makarov committed
646
<!DOCTYPE html>
647
<html lang="<?= Yii::$app->language ?>">
Alexander Makarov committed
648
<head>
649 650 651
    <meta charset="<?= Yii::$app->charset ?>"/>
    <title><?= Html::encode($this->title) ?></title>
    <?php $this->head() ?>
Alexander Makarov committed
652 653
</head>
<body>
Алексей committed
654
<?php $this->beginBody() ?>
655 656 657
    <div class="container">
        <?= $content ?>
    </div>
658
    <footer class="footer">&copy; 2013 me :)</footer>
Алексей committed
659
<?php $this->endBody() ?>
Alexander Makarov committed
660 661
</body>
</html>
Алексей committed
662
<?php $this->endPage() ?>
Alexander Makarov committed
663 664 665 666 667
```

In the markup above there's some code. First of all, `$content` is a variable that will contain result of views rendered
with controller's `$this->render()` method.

668
We are importing [[yii\helpers\Html|Html]] helper via standard PHP `use` statement. This helper is typically used for almost all views
669 670
where one need to escape outputted data.

671 672 673 674
Several special methods such as [[yii\web\View::beginPage()|beginPage()]]/[[yii\web\View::endPage()|endPage()]],
[[yii\web\View::head()|head()]], [[yii\web\View::beginBody()|beginBody()]]/[[yii\web\View::endBody()|endBody()]]
are triggering page rendering events that are used for registering scripts, links and process page in many other ways.
Always include these in your layout in order for the rendering to work correctly.
Alexander Makarov committed
675

676
By default layout is loaded from `views/layouts/main.php`. You may change it at controller or module level by setting
677
different value to `layout` property.
678 679

In order to pass data from controller to layout, that you may need for breadcrumbs or similar elements, use view component
Alexander Makarov committed
680
params property. In controller it can be set as:
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699

```php
$this->view->params['breadcrumbs'][] = 'Contact';
```

In a view it will be:

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

In layout file the value can be used like the following:

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

700 701 702 703 704 705 706 707 708 709 710
You may also wrap the view render result into a layout using [[yii\base\View::beginContent()]], [[yii\base\View::endContent()]].
This approach can be used while applying nested layouts:

```php
<?php $this->beginContent('//layouts/overall') ?>
<div class="content">
    <?= $content ?>
<div>
<?php $this->endContent() ?>
```

Alexander Makarov committed
711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
### Partials

Often you need to reuse some HTML markup in many views and often it's too simple to create a full-featured widget for it.
In this case you may use partials.

Partial is a view as well. It resides in one of directories under `views` and by convention is often started with `_`.
For example, we need to render a list of user profiles and, at the same time, display individual profile elsewhere.

First we need to define a partial for user profile in `_profile.php`:

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

<div class="profile">
727 728
    <h2><?= Html::encode($username) ?></h2>
    <p><?= Html::encode($tagline) ?></p>
Alexander Makarov committed
729 730 731 732 733 734 735
</div>
```

Then we're using it in `index.php` view where we display a list of users:

```php
<div class="user-index">
736 737 738 739 740 741 742 743
    <?php
    foreach ($users as $user) {
        echo $this->render('_profile', [
            'username' => $user->name,
            'tagline' => $user->tagline,
        ]);
    }
    ?>
Alexander Makarov committed
744 745 746 747 748 749
</div>
```

Same way we can reuse it in another view displaying a single user profile:

```php
Alexander Makarov committed
750
echo $this->render('_profile', [
751 752
    'username' => $user->name,
    'tagline' => $user->tagline,
Alexander Makarov committed
753
]);
Alexander Makarov committed
754 755
```

756 757 758 759 760 761 762 763 764 765 766 767 768 769

When you call `render()` to render a partial in a current view, you may use different formats to refer to the partial.
The most commonly used format is the so-called relative view name which is as shown in the above example.
The partial view file is relative to the directory containing the current view. If the partial is located under
a subdirectory, you should include the subdirectory name in the view name, e.g., `public/_profile`.

You may use path alias to specify a view, too. For example, `@app/views/common/_profile`.

And you may also use the so-called absolute view names, e.g., `/user/_profile`, `//user/_profile`.
An absolute view name starts with a single slashes or double slashes. If it starts with a single slash,
the view file will be looked for under the view path of the currently active module. Otherwise, it will
will be looked for under the application view path.


Evgeniy Tkachenko committed
770 771


Alexander Makarov committed
772 773
### Caching blocks

Alexander Makarov committed
774
To learn about caching of view fragments please refer to [caching](caching.md) section of the guide.
775 776 777 778 779

Customizing View component
--------------------------

Since view is also an application component named `view` you can replace it with your own component that extends
780
from [[yii\base\View]] or [[yii\web\View]]. It can be done via application configuration file such as `config/web.php`:
781 782

```php
Alexander Makarov committed
783
return [
784 785 786 787 788 789 790
    // ...
    'components' => [
        'view' => [
            'class' => 'app\components\View',
        ],
        // ...
    ],
Alexander Makarov committed
791
];
792
```
Qiang Xue committed
793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829


Security
--------

One of the main security principles is to always escape output. If violated it leads to script execution and,
most probably, to cross-site scripting known as XSS leading to leaking of admin passwords, making a user to automatically
perform actions etc.

Yii provides a good tool set in order to help you escape your output. The very basic thing to escape is a text without any
markup. You can deal with it like the following:

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

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

When you want to render HTML it becomes complex so we're delegating the task to excellent
[HTMLPurifier](http://htmlpurifier.org/) library which is wrapped in Yii as a helper [[yii\helpers\HtmlPurifier]]:

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

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

Note that besides HTMLPurifier does excellent job making output safe it's not very fast so consider
[caching result](caching.md).