You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
723 lines
30 KiB
723 lines
30 KiB
10 years ago
|
Views
|
||
|
=====
|
||
|
|
||
|
Views are part of the [MVC](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) architecture.
|
||
|
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.
|
||
|
|
||
|
|
||
|
## Creating Views <a name="creating-views"></a>
|
||
|
|
||
|
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 $this yii\web\View */
|
||
|
/* @var $form yii\widgets\ActiveForm */
|
||
|
/* @var $model app\models\LoginForm */
|
||
|
|
||
|
$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 `$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 way of documenting your views.
|
||
|
|
||
|
|
||
|
### Security <a name="security"></a>
|
||
|
|
||
|
When creating views that generate HTML pages, it is important that you encode and/or filter the data coming
|
||
|
from end users before presenting them. Otherwise, your application may be subject to
|
||
|
[cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting) attacks.
|
||
|
|
||
|
To display a plain text, encode it first by calling [[yii\helpers\Html::encode()]]. For example, the following code
|
||
|
encodes the user name before displaying it:
|
||
|
|
||
|
```php
|
||
|
<?php
|
||
|
use yii\helpers\Html;
|
||
|
?>
|
||
|
|
||
|
<div class="username">
|
||
|
<?= Html::encode($user->name) ?>
|
||
|
</div>
|
||
|
```
|
||
|
|
||
|
To display HTML content, use [[yii\helpers\HtmlPurifier]] to filter the content first. For example, the following
|
||
|
code filters the post content before displaying it:
|
||
|
|
||
|
```php
|
||
|
<?php
|
||
|
use yii\helpers\HtmlPurifier;
|
||
|
?>
|
||
|
|
||
|
<div class="post">
|
||
|
<?= HtmlPurifier::process($post->text) ?>
|
||
|
</div>
|
||
|
```
|
||
|
|
||
|
> Tip: While HTMLPurifier does excellent job in making output safe, it is not fast. You should consider
|
||
|
[caching](caching-overview.md) the filtering result if your application requires high performance.
|
||
|
|
||
|
|
||
|
### Organizing Views <a name="organizing-views"></a>
|
||
|
|
||
|
Like [controllers](structure-controllers.md) and [models](structure-models.md), there are conventions to organize views.
|
||
|
|
||
|
* For views rendered by a controller, they should be put under the directory `@app/views/ControllerID` by default,
|
||
|
where `ControllerID` refers to the [controller ID](structure-controllers.md#routes). For example, if
|
||
|
the controller class is `PostController`, the directory would be `@app/views/post`; If it 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 <a name="rendering-views"></a>
|
||
|
|
||
|
You can render views in [controllers](structure-controllers.md), [widgets](structure-widgets.md), or any
|
||
|
other places by calling view rendering methods. These methods share a similar signature shown as follows,
|
||
|
|
||
|
```
|
||
|
/**
|
||
|
* @param string $view view name or file path, depending on the actual rendering method
|
||
|
* @param array $params the data to be passed to the view
|
||
|
* @return string rendering result
|
||
|
*/
|
||
|
methodName($view, $params = [])
|
||
|
```
|
||
|
|
||
|
|
||
|
### Rendering in Controllers <a name="rendering-in-controllers"></a>
|
||
|
|
||
|
Within [controllers](structure-controllers.md), you may call the following controller methods to render views:
|
||
|
|
||
|
* [[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.
|
||
|
* [[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.
|
||
|
* [[yii\base\Controller::renderFile()|renderFile()]]: renders a view specified in terms of a view file path or
|
||
|
[alias](concept-aliases.md).
|
||
|
|
||
|
For example,
|
||
|
|
||
|
```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,
|
||
|
]);
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
|
||
|
### Rendering in Widgets <a name="rendering-in-widgets"></a>
|
||
|
|
||
|
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).
|
||
|
|
||
|
For example,
|
||
|
|
||
|
```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,
|
||
|
]);
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
|
||
|
### Rendering in Views <a name="rendering-in-views"></a>
|
||
|
|
||
|
You can render a view within another view by calling one of the following methods provided by the [[yii\base\View|view component]]:
|
||
|
|
||
|
* [[yii\base\View::render()|render()]]: renders a [named view](#named-views).
|
||
|
* [[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.
|
||
|
* [[yii\base\View::renderFile()|renderFile()]]: renders a view specified in terms of a view file path or
|
||
|
[alias](concept-aliases.md).
|
||
|
|
||
|
For example, the following code in a view renders the `_overview.php` view file which is in the same directory
|
||
|
as the view being currently rendered. Remember that `$this` in a view refers to the [[yii\base\View|view]] component:
|
||
|
|
||
|
```php
|
||
|
<?= $this->render('_overview') ?>
|
||
|
```
|
||
|
|
||
|
|
||
|
### Rendering in Other Places <a name="rendering-in-other-places"></a>
|
||
|
|
||
|
In any place, you can get access to the [[yii\base\View|view]] application component by the expression
|
||
|
`Yii::$app->view` and then call its aforementioned methods to render a view. For example,
|
||
|
|
||
|
```php
|
||
|
// displays the view file "@app/views/site/license.php"
|
||
|
echo \Yii::$app->view->renderFile('@app/views/site/license.php');
|
||
|
```
|
||
|
|
||
|
|
||
|
### Named Views <a name="named-views"></a>
|
||
|
|
||
|
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`.
|
||
|
* 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
|
||
|
`@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, calling `$this->render('view')` in a controller `app\controllers\PostController` will
|
||
|
actually render the view file `@app/views/post/view.php`, while calling `$this->render('_overview')` in that view
|
||
|
will render the view file `@app/views/post/_overview.php`.
|
||
|
|
||
|
|
||
|
### Accessing Data in Views <a name="accessing-data-in-views"></a>
|
||
|
|
||
|
There are two approaches to access data within a view: push and pull.
|
||
|
|
||
|
By passing the data as the second parameter to the view rendering methods, you are using the push approach.
|
||
|
The data should be represented as 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`.
|
||
|
|
||
|
```php
|
||
|
echo $this->render('report', [
|
||
|
'foo' => 1,
|
||
|
'bar' => 2,
|
||
|
]);
|
||
|
```
|
||
|
|
||
|
The pull approach actively retrieves data from the [[yii\base\View|view component]] or other objects accessible
|
||
|
in views (e.g. `Yii::$app`). Using the code below as an example, within the view you can get the controller object
|
||
|
by the expression `$this->context`. And as a result, it is possible for you to access any properties or methods
|
||
|
of the controller in the `report` view, such as the controller ID shown in the following:
|
||
|
|
||
|
```php
|
||
|
The controller ID is: <?= $this->context->id ?>
|
||
|
?>
|
||
|
```
|
||
|
|
||
|
The push 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
|
||
|
become tedious and error prone if a view is shared and rendered in different places.
|
||
|
|
||
|
|
||
|
### Sharing Data among Views <a name="sharing-data-among-views"></a>
|
||
|
|
||
|
The [[yii\base\View|view component]] provides the [[yii\base\View::params|params]] property that you can use
|
||
|
to share data among views.
|
||
|
|
||
|
For example, in an `about` view, you can have the following code which specifies the current segment of the
|
||
|
breadcrumbs.
|
||
|
|
||
|
```php
|
||
|
$this->params['breadcrumbs'][] = 'About Us';
|
||
|
```
|
||
|
|
||
|
Then, in the [layout](#layouts) file, which is also a view, you can display the breadcrumbs using the data
|
||
|
passed along [[yii\base\View::params|params]]:
|
||
|
|
||
|
```php
|
||
|
<?= yii\widgets\Breadcrumbs::widget([
|
||
|
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
|
||
|
]) ?>
|
||
|
```
|
||
|
|
||
|
|
||
|
## Layouts <a name="layouts"></a>
|
||
|
|
||
|
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.
|
||
|
|
||
|
|
||
|
### Creating Layouts <a name="creating-layouts"></a>
|
||
|
|
||
|
Because layouts are also views, they can be created in the similar way as normal views. By default, layouts
|
||
|
are stored in the directory `@app/views/layouts`. For layouts used within a [module](structure-modules.md),
|
||
|
they should be stored in the `views/layouts` directory under the [[yii\base\Module::basePath|module directory]].
|
||
|
You may customize the default layout directory by configuring the [[yii\base\Module::layoutPath]] property of
|
||
|
the application or modules.
|
||
|
|
||
|
The following example shows how a layout looks like. Note that for illustrative purpose, we have greatly simplified
|
||
|
the code in the layout. In practice, you may want to add more content to it, such as head tags, main menu, etc.
|
||
|
|
||
|
```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>© 2014 by My Company</footer>
|
||
|
<?php $this->endBody() ?>
|
||
|
</body>
|
||
|
</html>
|
||
|
<?php $this->endPage() ?>
|
||
|
```
|
||
|
|
||
|
As you can see, the layout generates the HTML tags that are common to all pages. Within the `<body>` section,
|
||
|
the layout echoes the `$content` variable which represents the rendering result of content views and is pushed
|
||
|
into the layout when [[yii\base\Controller::render()]] is called.
|
||
|
|
||
|
Most layouts should call the following methods like shown in the above code. These methods mainly trigger events
|
||
|
about the rendering process so that scripts and tags registered in other places can be properly injected into
|
||
|
the places where these methods are called.
|
||
|
|
||
|
- [[yii\base\View::beginPage()|beginPage()]]: This method should be called at the very beginning of the layout.
|
||
|
It triggers the [[yii\base\View::EVENT_BEGIN_PAGE|EVENT_BEGIN_PAGE]] event which indicates the beginning of a page.
|
||
|
- [[yii\base\View::endPage()|endPage()]]: This method should be called at the end of the layout.
|
||
|
It triggers the [[yii\base\View::EVENT_END_PAGE|EVENT_END_PAGE]] event which indicates the end of a page.
|
||
|
- [[yii\web\View::head()|head()]]: This method should be called within the `<head>` section of an HTML page.
|
||
|
It generates a placeholder which will be replaced with the registered head HTML code (e.g. link tags, meta tags)
|
||
|
when a page finishes rendering.
|
||
|
- [[yii\web\View::beginBody()|beginBody()]]: This method should be called at the beginning of the `<body>` section.
|
||
|
It triggers the [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]] event and generates a placeholder which will
|
||
|
be replaced by the registered HTML code (e.g. JavaScript) targeted at the body begin position.
|
||
|
- [[yii\web\View::endBody()|endBody()]]: This method should be called at the end of the `<body>` section.
|
||
|
It triggers the [[yii\web\View::EVENT_END_BODY|EVENT_END_BODY]] event and generates a placeholder which will
|
||
|
be replaced by the registered HTML code (e.g. JavaScript) targeted at the body end position.
|
||
|
|
||
|
|
||
|
### Accessing Data in Layouts <a name="accessing-data-in-layouts"></a>
|
||
|
|
||
|
Within a layout, you have access to two predefined variables: `$this` and `$content`. The former refers to
|
||
|
the [[yii\base\View|view]] component, like in normal views, while the latter contains the rendering result of a content
|
||
|
view which is rendered by calling the [[yii\base\Controller::render()|render()]] method in controllers.
|
||
|
|
||
|
If you want to access other data in layouts, you have to use the pull method as described in
|
||
|
the [Accessing Data in Views](#accessing-data-in-views) subsection. If you want to pass data from a content view
|
||
|
to a layout, you may use the method described in the [Sharing Data among Views](#sharing-data-among-views) subsection.
|
||
|
|
||
|
|
||
|
### Using Layouts <a name="using-layouts"></a>
|
||
|
|
||
|
As described in the [Rendering in Controllers](#rendering-in-controllers) subsection, when you render a view
|
||
|
by calling the [[yii\base\Controller::render()|render()]] method in a controller, a layout will be applied
|
||
|
to the rendering result. By default, the layout `@app/views/layouts/main.php` will be used.
|
||
|
|
||
|
You may use a different layout by configuring either [[yii\base\Application::layout]] or [[yii\base\Controller::layout]].
|
||
|
The former governs the layout used by all controllers, while the latter overrides the former for individual controllers.
|
||
|
For example, the following code makes the `post` controller to use `@app/views/layouts/post.php` as the layout
|
||
|
when rendering its views. Other controllers, assuming their `layout` property is untouched, will still use the default
|
||
|
`@app/views/layouts/main.php` as the layout.
|
||
|
|
||
|
```php
|
||
|
namespace app\controllers;
|
||
|
|
||
|
use yii\web\Controller;
|
||
|
|
||
|
class PostController extends Controller
|
||
|
{
|
||
|
public $layout = 'post';
|
||
|
|
||
|
// ...
|
||
|
}
|
||
|
```
|
||
|
|
||
|
For controllers belonging to a module, you may also configure the module's [[yii\base\Module::layout|layout]] property to
|
||
|
use a particular layout for these controllers.
|
||
|
|
||
|
Because the `layout` property may be configured at different levels (controllers, modules, application),
|
||
|
behind the scene Yii takes two steps to determine what is the actual layout file being used for a particular controller.
|
||
|
|
||
|
In the first step, it determines the layout value and the context module:
|
||
|
|
||
|
- If the [[yii\base\Controller::layout]] property of the controller is not null, use it as the layout value and
|
||
|
the [[yii\base\Controller::module|module]] of the controller as the context module.
|
||
|
- If [[yii\base\Controller::layout|layout]] is null, search through all ancestor modules (including the application itself) of the controller and
|
||
|
find the first module whose [[yii\base\Module::layout|layout]] property is not null. Use that module and
|
||
|
its [[yii\base\Module::layout|layout]] value as the context module and the chosen layout value.
|
||
|
If such a module cannot be found, it means no layout will be applied.
|
||
|
|
||
|
In the second step, it determines the actual layout file according to the layout value and the context module
|
||
|
determined in the first step. The layout value can be:
|
||
|
|
||
|
- a path alias (e.g. `@app/views/layouts/main`).
|
||
|
- an absolute path (e.g. `/main`): the layout value starts with a slash. The actual layout file will be
|
||
|
looked for under the application's [[yii\base\Application::layoutPath|layout path]] which defaults to
|
||
|
`@app/views/layouts`.
|
||
|
- a relative path (e.g. `main`): the actual layout file will be looked for under the context module's
|
||
|
[[yii\base\Module::layoutPath|layout path]] which defaults to the `views/layouts` directory under the
|
||
|
[[yii\base\Module::basePath|module directory]].
|
||
|
- the boolean value `false`: no layout will be applied.
|
||
|
|
||
|
If the layout value does not contain a file extension, it will use the default one `.php`.
|
||
|
|
||
|
|
||
|
### Nested Layouts <a name="nested-layouts"></a>
|
||
|
|
||
|
Sometimes you may want to nest one layout in another. For example, in different sections of a Web site, you
|
||
|
want to use different layouts, while all these layouts share the same basic layout that generates the overall
|
||
|
HTML5 page structure. You can achieve this goal by calling [[yii\base\View::beginContent()|beginContent()]] and
|
||
|
[[yii\base\View::endContent()|endContent()]] in the child layouts like the following:
|
||
|
|
||
|
```php
|
||
|
<?php $this->beginContent('@app/views/layouts/base.php'); ?>
|
||
|
|
||
|
...child layout content here...
|
||
|
|
||
|
<?php $this->endContent(); ?>
|
||
|
```
|
||
|
|
||
|
As shown above, the child layout content should be enclosed within [[yii\base\View::beginContent()|beginContent()]] and
|
||
|
[[yii\base\View::endContent()|endContent()]]. The parameter passed to [[yii\base\View::beginContent()|beginContent()]]
|
||
|
specifies what is the parent layout. It can be either a layout file or alias.
|
||
|
|
||
|
Using the above approach, you can nest layouts in more than one levels.
|
||
|
|
||
|
|
||
|
### Using Blocks <a name="using-blocks"></a>
|
||
|
|
||
|
Blocks allow you to specify the view content in one place while displaying it in another. They are often used together
|
||
|
with layouts. For example, you can define a block in a content view and display it in the layout.
|
||
|
|
||
|
You call [[yii\base\View::beginBlock()|beginBlock()]] and [[yii\base\View::endBlock()|endBlock()]] to define a block.
|
||
|
The block can then be accessed via `$view->blocks[$blockID]`, where `$blockID` stands for a unique ID that you assign
|
||
|
to the block when defining it.
|
||
|
|
||
|
The following example shows how you can use blocks to customize specific parts of a layout in a content view.
|
||
|
|
||
|
First, in a content view, define one or multiple blocks:
|
||
|
|
||
|
```php
|
||
|
...
|
||
|
|
||
|
<?php $this->beginBlock('block1'); ?>
|
||
|
|
||
|
...content of block1...
|
||
|
|
||
|
<?php $this->endBlock(); ?>
|
||
|
|
||
|
...
|
||
|
|
||
|
<?php $this->beginBlock('block3'); ?>
|
||
|
|
||
|
...content of block3...
|
||
|
|
||
|
<?php $this->endBlock(); ?>
|
||
|
```
|
||
|
|
||
|
Then, in the layout view, render the blocks if they are available, or display some default content if a block is
|
||
|
not defined.
|
||
|
|
||
|
```php
|
||
|
...
|
||
|
<?php if (isset($this->blocks['block1'])): ?>
|
||
|
<?= $this->blocks['block1'] ?>
|
||
|
<?php else: ?>
|
||
|
... default content for block1 ...
|
||
|
<?php endif; ?>
|
||
|
|
||
|
...
|
||
|
|
||
|
<?php if (isset($this->blocks['block2'])): ?>
|
||
|
<?= $this->blocks['block2'] ?>
|
||
|
<?php else: ?>
|
||
|
... default content for block2 ...
|
||
|
<?php endif; ?>
|
||
|
|
||
|
...
|
||
|
|
||
|
<?php if (isset($this->blocks['block3'])): ?>
|
||
|
<?= $this->blocks['block3'] ?>
|
||
|
<?php else: ?>
|
||
|
... default content for block3 ...
|
||
|
<?php endif; ?>
|
||
|
...
|
||
|
```
|
||
|
|
||
|
|
||
|
## Using View Components <a name="using-view-components"></a>
|
||
|
|
||
|
[[yii\base\View|View components]] provides many view-related features. While you can get view components
|
||
|
by creating individual instances of [[yii\base\View]] or its child class, in most cases you will mainly use
|
||
|
the `view` application component. You can configure this component in [application configurations](structure-applications.md#application-configurations)
|
||
|
like the following:
|
||
|
|
||
|
```php
|
||
|
[
|
||
|
// ...
|
||
|
'components' => [
|
||
|
'view' => [
|
||
|
'class' => 'app\components\View',
|
||
|
],
|
||
|
// ...
|
||
|
],
|
||
|
]
|
||
|
```
|
||
|
|
||
|
View components provide the following useful view-related features, each described in more details in a separate section:
|
||
|
|
||
|
* [theming](output-theming.md): allows you to develop and change the theme for your Web site.
|
||
|
* [fragment caching](caching-fragment.md): allows you to cache a fragment within a Web page.
|
||
|
* [client script handling](output-client-scripts.md): supports CSS and JavaScript registration and rendering.
|
||
|
* [asset bundle handling](structure-assets.md): supports registering and rendering of [asset bundles](structure-assets.md).
|
||
|
* [alternative template engines](tutorial-template-engines.md): allows you to use other template engines, such as
|
||
|
[Twig](http://twig.sensiolabs.org/), [Smarty](http://www.smarty.net/).
|
||
|
|
||
|
You may also frequently use the following minor yet useful features when you are developing Web pages.
|
||
|
|
||
|
|
||
|
### Setting Page Titles <a name="setting-page-titles"></a>
|
||
|
|
||
|
Every Web page should have a title. Normally the title tag is being displayed in a [layout](#layouts). However, in practice
|
||
|
the title is often determined in content views rather than layouts. To solve this problem, [[yii\web\View]] provides
|
||
|
the [[yii\web\View::title|title]] property for you to pass the title information from content views to layouts.
|
||
|
|
||
|
To make use of this feature, in each content view, you can set the page title like the following:
|
||
|
|
||
|
```php
|
||
|
<?php
|
||
|
$this->title = 'My page title';
|
||
|
?>
|
||
|
```
|
||
|
|
||
|
Then in the layout, make sure you have the following code in the `<head>` section:
|
||
|
|
||
|
```php
|
||
|
<title><?= Html::encode($this->title) ?></title>
|
||
|
```
|
||
|
|
||
|
|
||
|
### Registering Meta Tags <a name="registering-meta-tags"></a>
|
||
|
|
||
|
Web pages usually need to generate various meta tags needed by different parties. Like page titles, meta tags
|
||
|
appear in the `<head>` section and are usually generated in layouts.
|
||
|
|
||
|
If you want to specify what meta tags to generate in content views, you can call [[yii\web\View::registerMetaTag()]]
|
||
|
in a content view, like the following:
|
||
|
|
||
|
```php
|
||
|
<?php
|
||
|
$this->registerMetaTag(['name' => 'keywords', 'content' => 'yii, framework, php']);
|
||
|
?>
|
||
|
```
|
||
|
|
||
|
The above code will register a "keywords" meta tag with the view component. The registered meta tag is
|
||
|
rendered after the layout finishes rendering. By then, the following HTML code will be inserted
|
||
|
at the place where you call [[yii\web\View::head()]] in the layout and generate the following HTML code:
|
||
|
|
||
|
```php
|
||
|
<meta name="keywords" content="yii, framework, php">
|
||
|
```
|
||
|
|
||
|
Note that if you call [[yii\web\View::registerMetaTag()]] multiple times, it will register multiple meta tags,
|
||
|
regardless whether the meta tags are the same or not.
|
||
|
|
||
|
To make sure there is only a single instance of a meta tag type, you can specify a key as a second parameter when calling the method.
|
||
|
For example, the following code registers two "description" meta tags. However, only the second one will be rendered.
|
||
|
|
||
|
```html
|
||
|
$this->registerMetaTag(['name' => 'description', 'content' => 'This is my cool website made with Yii!'], 'description');
|
||
|
$this->registerMetaTag(['name' => 'description', 'content' => 'This website is about funny raccoons.'], 'description');
|
||
|
```
|
||
|
|
||
|
|
||
|
### Registering Link Tags <a name="registering-link-tags"></a>
|
||
|
|
||
|
Like [meta tags](#adding-meta-tags), link tags are useful in many cases, such as customizing favicon, pointing to
|
||
|
RSS feed or delegating OpenID to another server. You can work with link tags in the similar way as meta tags
|
||
|
by using [[yii\web\View::registerLinkTag()]]. For example, in a content view, you can register a link tag like follows,
|
||
|
|
||
|
```php
|
||
|
$this->registerLinkTag([
|
||
|
'title' => 'Live News for Yii',
|
||
|
'rel' => 'alternate',
|
||
|
'type' => 'application/rss+xml',
|
||
|
'href' => 'http://www.yiiframework.com/rss.xml/',
|
||
|
]);
|
||
|
```
|
||
|
|
||
|
The code above will result in
|
||
|
|
||
|
```html
|
||
|
<link title="Live News for Yii" rel="alternate" type="application/rss+xml" href="http://www.yiiframework.com/rss.xml/">
|
||
|
```
|
||
|
|
||
|
Similar as [[yii\web\View::registerMetaTag()|registerMetaTags()]], you can specify a key when calling
|
||
|
[[yii\web\View::registerLinkTag()|registerLinkTag()]] to avoid generated repeated link tags.
|
||
|
|
||
|
|
||
|
## View Events <a name="view-events"></a>
|
||
|
|
||
|
[[yii\base\View|View components]] trigger several events during the view rendering process. You may respond
|
||
|
to these events to inject content into views or process the rendering results before they are sent to end users.
|
||
|
|
||
|
- [[yii\base\View::EVENT_BEFORE_RENDER|EVENT_BEFORE_RENDER]]: triggered at the beginning of rendering a file
|
||
|
in a controller. Handlers of this event may set [[yii\base\ViewEvent::isValid]] to be false to cancel the rendering process.
|
||
|
- [[yii\base\View::EVENT_AFTER_RENDER|EVENT_AFTER_RENDER]]: triggered by the call of [[yii\base\View::beginPage()]] in layouts.
|
||
|
Handlers of this event may obtain the rendering result through [[yii\base\ViewEvent::output]] and may modify
|
||
|
this property to change the rendering result.
|
||
|
- [[yii\base\View::EVENT_BEGIN_PAGE|EVENT_BEGIN_PAGE]]: triggered by the call of [[yii\base\View::beginPage()]] in layouts.
|
||
|
- [[yii\base\View::EVENT_END_PAGE|EVENT_END_PAGE]]: triggered by the call of [[yii\base\View::endPage()]] in layouts.
|
||
|
- [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]]: triggered by the call of [[yii\web\View::beginBody()]] in layouts.
|
||
|
- [[yii\web\View::EVENT_END_BODY|EVENT_END_BODY]]: triggered by the call of [[yii\web\View::endBody()]] in layouts.
|
||
|
|
||
|
For example, the following code injects the current date at the end of the page body:
|
||
|
|
||
|
```php
|
||
|
\Yii::$app->view->on(View::EVENT_END_BODY, function () {
|
||
|
echo date('Y-m-d');
|
||
|
});
|
||
|
```
|
||
|
|
||
|
|
||
|
## Rendering Static Pages <a name="rendering-static-pages"></a>
|
||
|
|
||
|
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 output static pages by putting their code in the view, and then using the code like the following in a controller:
|
||
|
|
||
|
```php
|
||
|
public function actionAbout()
|
||
|
{
|
||
|
return $this->render('about');
|
||
|
}
|
||
|
```
|
||
|
|
||
|
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,
|
||
|
|
||
|
```php
|
||
|
namespace app\controllers;
|
||
|
|
||
|
use yii\web\Controller;
|
||
|
|
||
|
class SiteController extends Controller
|
||
|
{
|
||
|
public function actions()
|
||
|
{
|
||
|
return [
|
||
|
'page' => [
|
||
|
'class' => 'yii\web\ViewAction',
|
||
|
],
|
||
|
];
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
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 <a name="best-practices"></a>
|
||
|
|
||
|
Views are responsible for presenting models in the format that end users desire. In general, views
|
||
|
|
||
|
* should mainly contain presentational code, such as HTML, and simple PHP code to traverse, format and render data.
|
||
|
* should not contain code that performs DB queries. Such code should be done in models.
|
||
|
* should avoid direct access to request data, such as `$_GET`, `$_POST`. This belongs to controllers.
|
||
|
If request data is needed, they should be pushed into views by controllers.
|
||
|
* may read model properties, but should not modify them.
|
||
|
|
||
|
To make views more manageable, avoid creating views that are too complex or contain too much redundant code.
|
||
|
You may use the following techniques to achieve this goal:
|
||
|
|
||
|
* use [layouts](#layouts) to represent common presentational sections (e.g. page header, footer).
|
||
|
* divide a complicated view into several smaller ones. The smaller views can be rendered and assembled into a bigger
|
||
|
one using the rendering methods that we have described.
|
||
|
* create and use [widgets](structure-widgets.md) as building blocks of views.
|
||
|
* create and use helper classes to transform and format data in views.
|
||
|
|