view.md 15.2 KB
Newer Older
Alexander Makarov committed
1 2 3
View
====

4 5
The view component is an important part of MVC. The view acts as the interface to the application, making it responsible
for presenting data to end users, displaying forms, and so forth.
Qiang Xue committed
6

Alexander Makarov committed
7 8 9 10

Basics
------

11 12 13 14
By default, Yii uses PHP in view templates to generate content and elements. A web application view typically contains
some combination of HTML, along with PHP `echo`, `foreach`, `if`, and other basic constructs.
Using complex PHP code in views is considered to be bad practice. When complex logic and functionality is needed,
such code should either be moved to a controller or a widget.
Alexander Makarov committed
15

16
The view is typically called from controller action using the [[yii\base\Controller::render()|render()]] method:
Alexander Makarov committed
17 18 19 20

```php
public function actionIndex()
{
Alexander Makarov committed
21
	return $this->render('index', ['username' => 'samdark']);
Alexander Makarov committed
22 23 24
}
```

25 26
The first argument to [[yii\base\Controller::render()|render()]] is the name of the view to display.
In the context of the controller, Yii will search for its views in `views/site/` where `site`
Qiang Xue committed
27
is the controller ID. For details on how the view name is resolved, refer to the [[yii\base\Controller::render()]] method.
Alexander Makarov committed
28

29 30 31
The second argument to [[yii\base\Controller::render()|render()]] is a data array of key-value pairs.
Through this array, data can be passed to the view, making the value available in the view as a variable
named the same as the corresponding key.
32 33

The view for the action above would be `views/site/index.php` and can be something like:
Alexander Makarov committed
34 35

```php
36
<p>Hello, <?= $username ?>!</p>
Alexander Makarov committed
37 38
```

39
Any data type can be passed to the view, including arrays or objects.
Alexander Makarov committed
40

41 42 43 44 45 46 47 48 49 50 51
Besides the above [[yii\web\Controller::render()|render()]] method, the [[yii\web\Controller]] class also provides
several other rendering methods. Below is a summary of these methods:

* [[yii\web\Controller::render()|render()]]: renders a view and applies the layout to the rendering result.
  This is most commonly used to render a complete page.
* [[yii\web\Controller::renderPartial()|renderPartial()]]: renders a view without applying any layout.
  This is often used to render a fragment of a page.
* [[yii\web\Controller::renderAjax()|renderAjax()]]: renders a view without applying any layout, and injects all
  registered JS/CSS scripts and files. It is most commonly used to render an HTML output to respond to an AJAX request.
* [[yii\web\Controller::renderFile()|renderFile()]]: renders a view file. This is similar to
  [[yii\web\Controller::renderPartial()|renderPartial()]] except that it takes the file path
Qiang Xue committed
52 53 54
  of the view instead of the view name.


Alexander Makarov committed
55 56 57
Widgets
-------

58 59 60 61 62 63 64 65
Widgets are self-contained building blocks for your views, a way to combine complex logic, display, and functionality into a single component. A widget:

* May contain advanced PHP programming
* Is typically configurable
* Is often provided data to be displayed
* Returns HTML to be shown within the context of the view

There are a good number of widgets bundled with Yii, such as [active form](form.md),
Qiang Xue committed
66
breadcrumbs, menu, and [wrappers around bootstrap component framework](bootstrap-widgets.md). Additionally there are
67
extensions that provide more widgets, such as the official widget for [jQueryUI](http://www.jqueryui.com) components.
68

69
In order to use a widget, your view file would do the following:
70 71 72

```php
// Note that you have to "echo" the result to display it
Alexander Makarov committed
73
echo \yii\widgets\Menu::widget(['items' => $items]);
74 75

// Passing an array to initialize the object properties
Alexander Makarov committed
76 77 78 79
$form = \yii\widgets\ActiveForm::begin([
	'options' => ['class' => 'form-horizontal'],
	'fieldConfig' => ['inputOptions' => ['class' => 'input-xlarge']],
]);
80 81 82 83
... form inputs here ...
\yii\widgets\ActiveForm::end();
```

84 85 86
In the first example in the code above, the [[yii\base\Widget::widget()|widget()]] method is used to invoke a widget
that just outputs content. In the second example, [[yii\base\Widget::begin()|begin()]] and [[yii\base\Widget::end()|end()]]
are used for a
87 88 89
widget that wraps content between method calls with its own output. In case of the form this output is the `<form>` tag
with some properties set.

90

Alexander Makarov committed
91 92 93 94 95 96 97
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.

Qiang Xue committed
98
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
Alexander Makarov committed
99 100 101 102 103 104 105 106
markup. You can deal with it like the following:

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

<div class="username">
Alexander Makarov committed
107
	<?= Html::encode($user->name) ?>
Alexander Makarov committed
108 109 110 111
</div>
```

When you want to render HTML it becomes complex so we're delegating the task to excellent
Qiang Xue committed
112
[HTMLPurifier](http://htmlpurifier.org/) library which is wrapped in Yii as a helper [[yii\helpers\HtmlPurifier]]:
Alexander Makarov committed
113 114 115 116 117 118 119

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

<div class="post">
Alexander Makarov committed
120
	<?= HtmlPurifier::process($post->text) ?>
Alexander Makarov committed
121 122 123 124 125 126 127 128 129
</div>
```

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

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

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

133 134
Using View object in templates
------------------------------
Alexander Makarov committed
135

136
An instance of [[yii\web\View]] component is available in view templates as `$this` variable. Using it in templates you
137
can do many useful things including setting page title and meta, registering scripts and accessing the context.
Alexander Makarov committed
138 139 140 141 142 143 144 145 146 147 148 149

### 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

150
Adding meta tags such as encoding, description, keywords is easy with view object as well:
Alexander Makarov committed
151 152

```php
Alexander Makarov committed
153
$this->registerMetaTag(['encoding' => 'utf-8']);
Alexander Makarov committed
154 155 156 157 158 159 160 161 162 163 164
```

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
Alexander Makarov committed
165 166
$this->registerMetaTag(['description' => 'This is my cool website made with Yii!'], 'meta-description');
$this->registerMetaTag(['description' => 'This website is about funny raccoons.'], 'meta-description');
Alexander Makarov committed
167 168
```

Aris Karageorgos committed
169
If there are multiple calls with the same value of the second argument (`meta-description` in this case), the latter will
170
override the former and only a single tag will be rendered:
Alexander Makarov committed
171 172 173 174 175 176 177

```html
<meta description="This website is about funny raccoons.">
```

### Registering link tags

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

```php
Alexander Makarov committed
182
$this->registerLinkTag([
Alexander Makarov committed
183 184 185 186
	'title' => 'Lives News for Yii Framework',
	'rel' => 'alternate',
	'type' => 'application/rss+xml',
	'href' => 'http://www.yiiframework.com/rss.xml/',
Alexander Makarov committed
187
]);
Alexander Makarov committed
188 189 190 191 192 193 194 195 196 197 198 199
```

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

200 201
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
202 203 204 205 206 207 208 209 210 211 212 213 214

```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
215
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
216
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
217 218

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

Qiang Xue committed
222 223 224
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.
225 226 227
* 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
228 229 230 231 232 233
* 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
234 235
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
236

Alexander Makarov committed
237 238 239

### Registering scripts

240 241 242 243
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
244
The method for adding these can be used as follows:
Alexander Makarov committed
245

Alexander Makarov committed
246
```php
247
$this->registerJs("var options = ".json_encode($options).";", View::POS_END, 'my-options');
Alexander Makarov committed
248 249
```

Qiang Xue committed
250 251
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
252

253 254 255 256 257
- [[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
258

Qiang Xue committed
259 260
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
261

Qiang Xue committed
262
An external script can be added like the following:
Alexander Makarov committed
263 264

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

268 269
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
270 271 272 273
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.

274 275
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
276

Alexander Makarov committed
277 278 279 280 281 282 283 284

### 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
285
\frontend\assets\AppAsset::register($this);
Alexander Makarov committed
286 287 288 289
```

### Layout

Alexander Makarov committed
290 291
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
292
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
293 294 295 296 297 298
basic one without any widgets or extra markup.

```php
<?php
use yii\helpers\Html;
?>
Алексей committed
299
<?php $this->beginPage() ?>
Alexander Makarov committed
300
<!DOCTYPE html>
301
<html lang="<?= Yii::$app->language ?>">
Alexander Makarov committed
302
<head>
Alexander Makarov committed
303 304
	<meta charset="<?= Yii::$app->charset ?>"/>
	<title><?= Html::encode($this->title) ?></title>
Алексей committed
305
	<?php $this->head() ?>
Alexander Makarov committed
306 307
</head>
<body>
Алексей committed
308
<?php $this->beginBody() ?>
Alexander Makarov committed
309
	<div class="container">
Alexander Makarov committed
310
		<?= $content ?>
Alexander Makarov committed
311 312
	</div>
	<footer class="footer">© 2013 me :)</footer>
Алексей committed
313
<?php $this->endBody() ?>
Alexander Makarov committed
314 315
</body>
</html>
Алексей committed
316
<?php $this->endPage() ?>
Alexander Makarov committed
317 318 319 320 321
```

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.

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

325 326 327 328
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
329

Alexander Makarov committed
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
### 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">
Alexander Makarov committed
346 347
	<h2><?= Html::encode($username) ?></h2>
	<p><?= Html::encode($tagline) ?></p>
Alexander Makarov committed
348 349 350 351 352 353 354 355
</div>
```

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

```php
<div class="user-index">
	<?php
356
	foreach ($users as $user) {
Alexander Makarov committed
357
		echo $this->render('_profile', [
Alexander Makarov committed
358 359
			'username' => $user->name,
			'tagline' => $user->tagline,
Alexander Makarov committed
360
		]);
Alexander Makarov committed
361 362 363 364 365 366 367 368
	}
	?>
</div>
```

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

```php
Alexander Makarov committed
369
echo $this->render('_profile', [
Alexander Makarov committed
370 371
	'username' => $user->name,
	'tagline' => $user->tagline,
Alexander Makarov committed
372
]);
Alexander Makarov committed
373 374 375 376 377 378 379 380 381 382 383 384 385 386
```

### Accessing context

Views are generally used either by controller or by widget. In both cases the object that called view rendering is
available in the view as `$this->context`. For example if we need to print out the current internal request route in a
view rendered by controller we can use the following:

```php
echo $this->context->getRoute();
```

### Caching blocks

Alexander Makarov committed
387
To learn about caching of view fragments please refer to [caching](caching.md) section of the guide.
388 389 390 391 392

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

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

```php
Alexander Makarov committed
396
return [
397
	// ...
Alexander Makarov committed
398 399
	'components' => [
		'view' => [
400
			'class' => 'app\components\View',
Alexander Makarov committed
401
		],
402
		// ...
Alexander Makarov committed
403 404
	],
];
405
```