Home > Article > Backend Development > Advanced use of View in PHP's Yii framework_php skills
View name
When rendering a view, you can specify a view name or a view file path/alias. In most cases, the former is used because it is concise and flexible. We call the view with a name a view name.
The view name can be assigned to the corresponding view file path according to the following rules:
The file extension can be omitted in the view name. In this case, .php is used as the extension. The view name about corresponds to the about.php file name;
The view name starts with double slashes //, and the corresponding view file path is @app/views/ViewName. That is to say, the view file is found under the path yiibaseApplication::viewPath. For example, //site/about corresponds to @app/views/ site/about.php.
The view name starts with a single slash /, and the view file path starts with yiibaseModule::viewPath of the currently used module. If the module does not exist, it starts with @app/views/ViewName. For example, if the current module is user, /user/create corresponds It becomes @app/modules/user/views/user/create.php. If it is not in the module, /user/create corresponds to @app/views/user/create.php.
If yiibaseView::context renders the view and the context implements yiibaseViewContextInterface, the view file path starts with the context's yiibaseViewContextInterface::getViewPath(). This is mainly used to render views in controllers and widgets. For example, if the context is a controller SiteController, site /about corresponds to @app/views/site/about.php.
If the view renders another view, the directory containing the other view's files starts with the current view's file path, e.g. an item rendered by the view @app/views/post/index.php corresponds to @app/views/post/item.
According to the above rules, in the controller, appcontrollersPostController calls $this->render('view'), which actually renders the @app/views/post/view.php view file. When $this-> is called in the view file, render('_overview') will render the @app/views/post/_overview.php view file.
Access data in view
There are two ways to access data in a view: push and pull.
The push method is to pass data through the second parameter of the view rendering method. The data format should be a name-value array. When the view is rendered, the PHP extract() method is called to convert the array into a variable accessible to the view. For example, the following controller's rendering view code pushes two variables to the report view: $foo = 1 and $bar = 2.
echo $this->render('report', [ 'foo' => 1, 'bar' => 2, ]);
The pull method allows the view to actively obtain data from the yiibaseView view component or other objects (such as Yii::$app). Use the following expression $this->context in the view to obtain the controller ID. Allows you to get any properties or methods of the controller in the report view, such as the following code to get the controller ID.
The controller ID is: <?= $this->context->id ?> ?>
The push method makes the view less dependent on the context object and is the preferred way for the view to obtain data. The disadvantage is that it requires manual construction of the array, which is somewhat cumbersome and prone to errors when rendering in different places.
Sharing data between views
The yiibaseView view component provides the yiibaseView::params parameter attribute to allow different views to share data.
For example, in the about view, you can use the following code to specify the current part of the current breadcrumbs.
$this->params['breadcrumbs'][] = 'About Us';
In the layout file (also a view), the values added to the yiibaseView::params array can be used to generate display breadcrumbs:
<?= yii\widgets\Breadcrumbs::widget([ 'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], ]) ?>
Layout
A layout is a special view that represents a common part of multiple views. For example, most web applications share the same header and footer. It is better to repeat the same header and footer in each view. The way is to put these public views into a layout, render the content view and embed it into the layout at the appropriate place.
Create layout
Since the layout is also a view, it can be created like a normal view. The layout is stored in the @app/views/layouts path by default. The layout used in the module should be stored in the views/layouts path in the yiibaseModule::basePath module directory. , you can configure yiibaseModule::layoutPath to customize the default layout path of the application or module.
The following example is a rough layout. Note that as an example, a lot of code has been simplified. In practice, you may want to add more content, such as header 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() ?>
如上所示,布局生成每个页面通用的HTML标签,在6c04bd5ca3fcae76e30b72ad730ca86d标签中,打印$content变量, $content变量代表当yii\base\Controller::render()控制器渲染方法调用时传递到布局的内容视图渲染结果。
大多数视图应调用上述代码中的如下方法,这些方法触发关于渲染过程的事件, 这样其他地方注册的脚本和标签会添加到这些方法调用的地方。
布局中访问数据
在布局中可访问两个预定义变量:$this 和 $content,前者对应和普通视图类似的yii\base\View 视图组件 后者包含调用yii\base\Controller::render()方法渲染内容视图的结果。
如果想在布局中访问其他数据,必须使用视图中访问数据一节介绍的拉取方式, 如果想从内容视图中传递数据到布局,可使用视图间共享数据一节中的方法。
使用布局
如控制器中渲染一节描述,当控制器调用yii\base\Controller::render() 方法渲染视图时,会同时使用布局到渲染结果中,默认会使用@app/views/layouts/main.php布局文件。
可配置yii\base\Application::layout 或 yii\base\Controller::layout 使用其他布局文件, 前者管理所有控制器的布局,后者覆盖前者来控制单个控制器布局。 例如,如下代码使 post 控制器渲染视图时使用 @app/views/layouts/post.php 作为布局文件, 假如layout 属性没改变,控制器默认使用 @app/views/layouts/main.php 作为布局文件。
namespace app\controllers; use yii\web\Controller; class PostController extends Controller { public $layout = 'post'; // ... }
对于模块中的控制器,可配置模块的 yii\base\Module::layout 属性指定布局文件应用到模块的所有控制器。
由于layout 可在不同层级(控制器、模块,应用)配置,在幕后Yii使用两步来决定控制器实际使用的布局。
第一步,它决定布局的值和上下文模块:
如果控制器的 yii\base\Controller::layout 属性不为空null,使用它作为布局的值, 控制器的 yii\base\Controller::module模块 作为上下文模块。
如果 yii\base\Controller::layout 为空,从控制器的祖先模块(包括应用) 开始找 第一个yii\base\Module::layout 属性不为空的模块,使用该模块作为上下文模块, 并将它的yii\base\Module::layout 的值作为布局的值, 如果都没有找到,表示不使用布局。
第二步,它决定第一步中布局的值和上下文模块对应到实际的布局文件,布局的值可为:
路径别名 (如 @app/views/layouts/main).
绝对路径 (如 /main): 布局的值以斜杠开始,在应用的[[yii\base\Application::layoutPath|layout path] 布局路径 中查找实际的布局文件,布局路径默认为 @app/views/layouts。
相对路径 (如 main): 在上下文模块的yii\base\Module::layoutPath布局路径中查找实际的布局文件, 布局路径默认为yii\base\Module::basePath模块目录下的views/layouts 目录。
布尔值 false: 不使用布局。
布局的值没有包含文件扩展名,默认使用 .php作为扩展名。
嵌套布局
有时候你想嵌套一个布局到另一个,例如,在Web站点不同地方,想使用不同的布局, 同时这些布局共享相同的生成全局HTML5页面结构的基本布局,可以在子布局中调用 yii\base\View::beginContent() 和yii\base\View::endContent() 方法,如下所示:
<?php $this->beginContent('@app/views/layouts/base.php'); ?> ...child layout content here... <?php $this->endContent(); ?>
如上所示,子布局内容应在 yii\base\View::beginContent() 和 yii\base\View::endContent() 方法之间,传给 yii\base\View::beginContent() 的参数指定父布局,父布局可为布局文件或别名。
使用以上方式可多层嵌套布局。
使用数据块
数据块可以在一个地方指定视图内容在另一个地方显示,通常和布局一起使用, 例如,可在内容视图中定义数据块在布局中显示它。
调用 yii\base\View::beginBlock() 和 yii\base\View::endBlock() 来定义数据块, 使用 $view->blocks[$blockID] 访问该数据块,其中 $blockID 为定义数据块时指定的唯一标识ID。
如下实例显示如何在内容视图中使用数据块让布局使用。
首先,在内容视图中定一个或多个数据块:
... <?php $this->beginBlock('block1'); ?> ...content of block1... <?php $this->endBlock(); ?> ... <?php $this->beginBlock('block3'); ?> ...content of block3... <?php $this->endBlock(); ?>
然后,在布局视图中,数据块可用的话会渲染数据块,如果数据未定义则显示一些默认内容。
... <?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; ?> ...
使用视图组件
yii\base\View视图组件提供许多视图相关特性,可创建yii\base\View或它的子类实例来获取视图组件, 大多数情况下主要使用 view应用组件,可在应用配置中配置该组件, 如下所示:
[ // ... 'components' => [ 'view' => [ 'class' => 'app\components\View', ], // ... ], ]
视图组件提供如下实用的视图相关特性,每项详情会在独立章节中介绍:
开发Web页面时,也可能频繁使用以下实用的小特性。
设置页面标题
每个Web页面应有一个标题,正常情况下标题的标签显示在 布局中, 但是实际上标题大多由内容视图而不是布局来决定,为解决这个问题, yii\web\View 提供 yii\web\View::title 标题属性可让标题信息从内容视图传递到布局中。
为利用这个特性,在每个内容视图中设置页面标题,如下所示:
<?php $this->title = 'My page title'; ?> 然后在视图中,确保在 <head> 段中有如下代码: <title><?= Html::encode($this->title) ?></title>
注册Meta元标签
Web页面通常需要生成各种元标签提供给不同的浏览器,如93f0f5c25f18dab9d176bd4f6de5d30e中的页面标题,元标签通常在布局中生成。
如果想在内容视图中生成元标签,可在内容视图中调用yii\web\View::registerMetaTag()方法,如下所示:
<?php $this->registerMetaTag(['name' => 'keywords', 'content' => 'yii, framework, php']); ?>
以上代码会在视图组件中注册一个 "keywords" 元标签,在布局渲染后会渲染该注册的元标签, 然后,如下HTML代码会插入到布局中调用yii\web\View::head()方法处:
<meta name="keywords" content="yii, framework, php">
注意如果多次调用 yii\web\View::registerMetaTag() 方法,它会注册多个元标签,注册时不会检查是否重复。
为确保每种元标签只有一个,可在调用方法时指定键作为第二个参数, 例如,如下代码注册两次 "description" 元标签,但是只会渲染第二个。
$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');
注册链接标签
和 Meta标签 类似,链接标签有时很实用,如自定义网站图标,指定Rss订阅,或授权OpenID到其他服务器。 可以和元标签相似的方式调用yii\web\View::registerLinkTag(),例如,在内容视图中注册链接标签如下所示:
$this->registerLinkTag([ 'title' => 'Live News for Yii', 'rel' => 'alternate', 'type' => 'application/rss+xml', 'href' => 'http://www.yiiframework.com/rss.xml/', ]);
上述代码会转换成
0c6bd91b444b9de3c6ff536a95babeb4
视图事件
yii\base\View 视图组件会在视图渲染过程中触发几个事件, 可以在内容发送给终端用户前,响应这些事件来添加内容到视图中或调整渲染结果。
例如,如下代码将当前日期添加到页面结尾处:
\Yii::$app->view->on(View::EVENT_END_BODY, function () { echo date('Y-m-d'); });
渲染静态页面
静态页面指的是大部分内容为静态的不需要控制器传递动态数据的Web页面。
可将HTML代码放置在视图中,在控制器中使用以下代码输出静态页面:
public function actionAbout() { return $this->render('about'); }
如果Web站点包含很多静态页面,多次重复相似的代码显得很繁琐, 为解决这个问题,可以使用一个在控制器中称为 yii\web\ViewAction 的独立操作。 例如:
namespace app\controllers; use yii\web\Controller; class SiteController extends Controller { public function actions() { return [ 'page' => [ 'class' => 'yii\web\ViewAction', ], ]; } }
现在如果你在@app/views/site/pages目录下创建名为 about 的视图, 可通过如下rul显示该视图:
http://localhost/index.php?r=site/page&view=about
GET 中 view 参数告知 yii\web\ViewAction 操作请求哪个视图,然后操作在 @app/views/site/pages目录下寻找该视图,可配置 yii\web\ViewAction::viewPrefix 修改搜索视图的目录。
最佳实践
视图负责将模型的数据展示用户想要的格式,总之,视图