Views are part of the MVC 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 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.
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
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 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
or other objects which trigger the view rendering.
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.
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 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
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
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 the filtering result if your application requires high performance.
Like controllers and models, there are conventions to organize views.
@app/views/ControllerID
by default,
where ControllerID
refers to the controller ID. 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 module directory.WidgetPath/views
directory by
default, where WidgetPath
stands for the directory containing the widget class file.You may customize these default view directories by overriding the yii\base\ViewContextInterface::getViewPath() method of controllers or widgets.
You can render views in controllers, widgets, 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 = [])
Within controllers, you may call the following controller methods to render views:
For example,
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,
]);
}
}
Within widgets, you may call the following widget methods to render views.
For example,
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,
]);
}
}
You can render a view within another view by calling one of the following methods provided by the view component:
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 view component:
<?= $this->render('_overview') ?>
In any place, you can get access to the view application component by the expression
Yii::$app->view
and then call its aforementioned methods to render a view. For example,
// displays the view file "@app/views/site/license.php"
echo \Yii::$app->view->renderFile('@app/views/site/license.php');
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:
.php
will be used as the extension. For example,
the view name about
corresponds to the file name about.php
.//
, the corresponding view file path would be @app/views/ViewName
.
That is, the view is looked for under the application's view path.
For example, //site/about
will be resolved into @app/views/site/about.php
./
, the view file path is formed by prefixing the view name
with the view path of the currently active module.
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
.about
will be resolved into @app/views/site/about.php
if the context is the controller SiteController
.item
will be resolved into @app/views/post/item.php
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
.
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
.
echo $this->render('report', [
'foo' => 1,
'bar' => 2,
]);
The pull approach actively retrieves data from the 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:
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.
The view component provides the 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.
$this->params['breadcrumbs'][] = 'About Us';
Then, in the layout file, which is also a view, you can display the breadcrumbs using the data passed along params:
<?= yii\widgets\Breadcrumbs::widget([
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
]) ?>
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.
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,
they should be stored in the views/layouts
directory under the 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
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.
<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.<body>
section.
It triggers the 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.<body>
section.
It triggers the 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.Within a layout, you have access to two predefined variables: $this
and $content
. The former refers to
the view component, like in normal views, while the latter contains the rendering result of a content
view which is rendered by calling the 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 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 subsection.
As described in the Rendering in Controllers subsection, when you render a view
by calling the 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.
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 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:
null
, use it as the layout value and
the module of the controller as the context module.null
, search through all ancestor modules (including the application itself) of the controller and
find the first module whose layout property is not null
. Use that module and
its 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:
@app/views/layouts/main
)./main
): the layout value starts with a slash. The actual layout file will be
looked for under the application's layout path which defaults to
@app/views/layouts
.main
): the actual layout file will be looked for under the context module's
layout path which defaults to the views/layouts
directory under the
module directory.false
: no layout will be applied.If the layout value does not contain a file extension, it will use the default one .php
.
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 beginContent() and endContent() in the child layouts like the following:
<?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 beginContent() and endContent(). The parameter passed to 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.
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 beginBlock() and 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 $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 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; ?>
...
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
like the following:
[
// ...
'components' => [
'view' => [
'class' => 'app\components\View',
],
// ...
],
]
View components provide the following useful view-related features, each described in more details in a separate section:
You may also frequently use the following minor yet useful features when you are developing Web pages.
Every Web page should have a title. Normally the title tag is being displayed in a layout. However, in practice the title is often determined in content views rather than layouts. To solve this problem, yii\web\View provides the 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
$this->title = 'My page title';
?>
Then in the layout, make sure you have the following code in the <head>
section:
<title><?= Html::encode($this->title) ?></title>
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
$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. The following HTML code will be generated and inserted at the place where you call yii\web\View::head() in the layout:
<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.
$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');
Like 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,
$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
<link title="Live News for Yii" rel="alternate" type="application/rss+xml" href="http://www.yiiframework.com/rss.xml/">
Similar as registerMetaTag(), you can specify a key when calling registerLinkTag() to avoid generating repeated link tags.
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.
false
to cancel the rendering process.For example, the following code injects the current date at the end of the page body:
\Yii::$app->view->on(View::EVENT_END_BODY, function () {
echo date('Y-m-d');
});
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:
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 called yii\web\ViewAction in a controller. For example,
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%2Fpage&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.
Views are responsible for presenting models in the format that end users desire. In general, views
$_GET
, $_POST
. This belongs to controllers.
If request data is needed, they should be pushed into views by controllers.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:
Found a typo or you think this page needs improvement?
Edit it on github !
Signup or Login in order to comment.