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

Qiang Xue committed
4 5
View is an important part of MVC and is responsible for presenting data to end users.

Alexander Makarov committed
6 7 8 9 10 11 12 13 14 15 16 17 18

Basics
------

Yii uses PHP in view templates by default so in a web application a view typically contains some HTML, `echo`, `foreach`
and such basic constructs. It may also contain widget calls. Using complex code in views is considered a bad practice.
Such code should be moved to controller or widgets.

View is typically called from controller action like the following:

```php
public function actionIndex()
{
Alexander Makarov committed
19
	return $this->render('index', ['username' => 'samdark']);
Alexander Makarov committed
20 21 22 23 24 25 26 27 28 29 30
}
```

First argument is the view name. In context of the controller Yii will search for its views in `views/site/` where `site`
is controller ID. For details on how view name is resolved please refer to [yii\base\Controller::render] method.
Second argument is data array that contains key-value pairs. Value is available in the view as a variable named the same
as the corresponding key.

So the view for the action above should be in `views/site/index.php` and can be something like:

```php
31
<p>Hello, <?= $username ?>!</p>
Alexander Makarov committed
32 33
```

34
Instead of just scalar values you can pass anything else such as arrays or objects.
Alexander Makarov committed
35 36 37 38

Widgets
-------

39 40
Widgets are a self-contained building blocks for your views. A widget may contain advanced logic, typically takes some
configuration and data and returns HTML. There is a good number of widgets bundled with Yii such as [active form](form.md),
Alexander Mohorev committed
41
breadcrumbs, menu or [wrappers around bootstrap component framework](bootstrap-widgets.md). Additionally there are
42 43 44 45 46 47
extensions providing additional widgets such as official one for jQueryUI components.

In order to use widget you need to do the following:

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

// Passing an array to initialize the object properties
Alexander Makarov committed
51 52 53 54
$form = \yii\widgets\ActiveForm::begin([
	'options' => ['class' => 'form-horizontal'],
	'fieldConfig' => ['inputOptions' => ['class' => 'input-xlarge']],
]);
55 56 57 58 59 60 61 62
... form inputs here ...
\yii\widgets\ActiveForm::end();
```

In the code above `widget` method is used for a widget that just outputs content while `begin` and `end` are used for a
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.

Alexander Makarov committed
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
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 toolset in order help you escaping 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">
Alexander Makarov committed
79
	<?= Html::encode($user->name) ?>
Alexander Makarov committed
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
</div>
```

When you want to render HTML it becomes complex so we're delegating the task to excellent
[HTMLPurifier](http://htmlpurifier.org/) library. In order to use it you need to modify your `composer.json` first by
adding the following to `require`:

```javascript
"ezyang/htmlpurifier": "v4.5.0"
```

After it's done run `php composer.phar install` and wait till package is downloaded. Now everything is prepared to use
Yii's HtmlPurifier helper:

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

<div class="post">
Alexander Makarov committed
100
	<?= HtmlPurifier::process($post->text) ?>
Alexander Makarov committed
101 102 103 104 105 106 107 108 109
</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
------------------------------

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

113 114
Using View object in templates
------------------------------
Alexander Makarov committed
115

Alexander Makarov committed
116
An instance of `yii\web\View` component is available in view templates as `$this` variable. Using it in templates you
117
can do many useful things including setting page title and meta, registering scripts and accessing the context.
Alexander Makarov committed
118 119 120 121 122 123 124 125 126 127 128 129

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

130
Adding meta tags such as encoding, description, keywords is easy with view object as well:
Alexander Makarov committed
131 132

```php
Alexander Makarov committed
133
$this->registerMetaTag(['encoding' => 'utf-8']);
Alexander Makarov committed
134 135 136 137 138 139 140 141 142 143 144
```

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
145 146
$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
147 148
```

Aris Karageorgos committed
149
If there are multiple calls with the same value of the second argument (`meta-description` in this case), the latter will
150
override the former and only a single tag will be rendered:
Alexander Makarov committed
151 152 153 154 155 156 157

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

### Registering link tags

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

```php
Alexander Makarov committed
162
$this->registerLinkTag([
Alexander Makarov committed
163 164 165 166
	'title' => 'Lives News for Yii Framework',
	'rel' => 'alternate',
	'type' => 'application/rss+xml',
	'href' => 'http://www.yiiframework.com/rss.xml/',
Alexander Makarov committed
167
]);
Alexander Makarov committed
168 169 170 171 172 173 174 175 176 177 178 179 180
```

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

You can register CSS using `registerCss` or `registerCssFile`. Former is for outputting code in `<style>` tags directly
Aris Karageorgos committed
181
to the page which is not recommended in most cases (but still valid). Latter is for registering CSS file. In Yii it's
Alexander Makarov committed
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
much better to [use asset manager](assets.md) to deal with these since it provides extra features so `registerCssFile`
is manly useful for external CSS files.

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

If you want to specify additional properties of the style tag, pass array of name-values to the second argument. If you
need to make sure there's only a single style tag use third argument as was mentioned in meta tags description.

```php
Alexander Makarov committed
201
$this->registerCssFile("http://example.com/css/themes/black-and-white.css", ['media' => 'print'], 'css-print-theme');
Alexander Makarov committed
202 203 204 205 206 207 208
```

The code above will add a link to CSS file to the head section of the page. The CSS will be used only when printing the
page. We're using third argument so one of the views could override it.

### Registering scripts

209
With View object you can register scripts. There are two dedicated methods for it: `registerJs` for inline scripts
Alexander Makarov committed
210 211
and `registerJsFile` for external scripts. Inline scripts are useful for configuration and dynamically generated code.
The method for adding these can be used as follows:
Alexander Makarov committed
212

Alexander Makarov committed
213
```php
214
$this->registerJs("var options = ".json_encode($options).";", View::POS_END, 'my-options');
Alexander Makarov committed
215 216 217 218 219 220 221 222 223 224 225 226
```

First argument is the actual code where we're converting a PHP array of options to JavaScript one. Second argument
determines where script should be in the page. Possible values are:

- `View::POS_HEAD` for head section.
- `View::POS_BEGIN` for right after opening `<body>`.
- `View::POS_END` for right before closing `</body>`.
- `View::POS_READY` for executing code on document `ready` event. This one registers jQuery automatically.

The last argument is unique script ID that is used to identify code block and replace existing one with the same ID
instead of adding a new one.
Alexander Makarov committed
227

Alexander Makarov committed
228 229 230 231 232 233 234
External script can be added like the following:

```php
$this->registerJsFile('http://example.com/js/main.js');
```

Same as with external CSS it's preferred to use asset bundles for external scripts.
Alexander Makarov committed
235 236 237 238 239 240 241 242

### 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
243
frontend\assets\AppAsset::register($this);
Alexander Makarov committed
244 245 246 247
```

### Layout

Alexander Makarov committed
248 249 250 251 252 253 254 255 256
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 fine 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.

```php
<?php
use yii\helpers\Html;
?>
Алексей committed
257
<?php $this->beginPage() ?>
Alexander Makarov committed
258
<!DOCTYPE html>
259
<html lang="<?= Yii::$app->language ?>">
Alexander Makarov committed
260
<head>
Alexander Makarov committed
261 262
	<meta charset="<?= Yii::$app->charset ?>"/>
	<title><?= Html::encode($this->title) ?></title>
Алексей committed
263
	<?php $this->head() ?>
Alexander Makarov committed
264 265
</head>
<body>
Алексей committed
266
<?php $this->beginBody() ?>
Alexander Makarov committed
267
	<div class="container">
Alexander Makarov committed
268
		<?= $content ?>
Alexander Makarov committed
269 270
	</div>
	<footer class="footer">© 2013 me :)</footer>
Алексей committed
271
<?php $this->endBody() ?>
Alexander Makarov committed
272 273
</body>
</html>
Алексей committed
274
<?php $this->endPage() ?>
Alexander Makarov committed
275 276 277 278 279
```

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.

280 281 282 283 284 285
We are importing `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 `beginPage`/`endPage`, `head`, `beginBody`/`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 rendering to work correctly.
Alexander Makarov committed
286

Alexander Makarov committed
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
### 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
303 304
	<h2><?= Html::encode($username) ?></h2>
	<p><?= Html::encode($tagline) ?></p>
Alexander Makarov committed
305 306 307 308 309 310 311 312
</div>
```

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

```php
<div class="user-index">
	<?php
313
	foreach ($users as $user) {
Alexander Makarov committed
314
		echo $this->render('_profile', [
Alexander Makarov committed
315 316
			'username' => $user->name,
			'tagline' => $user->tagline,
Alexander Makarov committed
317
		]);
Alexander Makarov committed
318 319 320 321 322 323 324 325
	}
	?>
</div>
```

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

```php
Alexander Makarov committed
326
echo $this->render('_profile', [
Alexander Makarov committed
327 328
	'username' => $user->name,
	'tagline' => $user->tagline,
Alexander Makarov committed
329
]);
Alexander Makarov committed
330 331 332 333 334 335 336 337 338 339 340 341 342 343
```

### 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
344
To learn about caching of view fragments please refer to [caching](caching.md) section of the guide.
345 346 347 348 349

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

Since view is also an application component named `view` you can replace it with your own component that extends
Alexander Makarov committed
350
from `yii\base\View` or `yii\web\View`. It can be done via application configuration file such as `config/web.php`:
351 352

```php
Alexander Makarov committed
353
return [
354
	// ...
Alexander Makarov committed
355 356
	'components' => [
		'view' => [
357
			'class' => 'app\components\View',
Alexander Makarov committed
358
		],
359
		// ...
Alexander Makarov committed
360 361
	],
];
362
```