首先我们介绍一下Controller类的render()方法的执行流程,需要查看vendoryiisoftyii2baseContorller.php文件中的render()方法源代码。
代码语言:javascript复制class Controller extends Component implements ViewContextInterface
{
......
public function render($view, $params = [])
{
$content = $this->getView()->render($view, $params, $this);
return $this->renderContent($content);
}
public function renderContent($content)
{
$layoutFile = $this->findLayoutFile($this->getView());
if ($layoutFile !== false) {
return $this->getView()->renderFile($layoutFile, ['content' => $content], $this);
}
return $content;
}
}
分析render()方法源代码,画一个比较直观的流程图。
当render()方法被调用,首先调用View类的render()方法,该方法返回的内容赋值给变量content,接下来把content作为参数传递给renderController()方法。在renderController()方法中首先调用findLayoutFile()方法,渲染出布局文件,然后调用View类的renderFile()方法,完成局部文件和使徒的渲染。
开始应用级布局
在一个应用中多个控制器使用一个布局文件,那么可以在应用级配置文件config/web.php中设置yii/base/Application的$layout属性,代码如下:
代码语言:javascript复制$config = [
//layout config
'layout' => 'headerfooter',
];
我们要做一个这样的布局页面
首先,创建ArticleController.php文件,代码如下:
代码语言:javascript复制<?php
/**
* Created by ZhengNiu.
* User: admin
* Date: 2019/10/12
* Time: 17:49
*/
namespace appcontrollers;
use yiiwebController;
class ArticleController extends Controller
{
public $layout = 'right';
public function actionIndex()
{
return $this->render('article');
}
}
创建views/article.php,代码如下:
代码语言:javascript复制我是中间内容
创建views/layout/headerfooter.php,代码如下:
代码语言:javascript复制<h1>头部</h1>
<?= $content;?>
<h1>尾部</h1>
创建views/layout/right.php,代码如下:
代码语言:javascript复制<?php
$this->beginContent('@app/views/layouts/headerfooter.php');
?>
<?php
echo $content;
?>
我是left
<?php $this->endContent(); ?>
嵌套布局实现页面渲染流程:
- 首先渲染视图文件article.php的内容,存储到布局文件reght.php的$content中。
- 因为在布局文件right.php 中使用了另外一个布局文件headerfooter.php,所以又把article.php和right.php两个文件的内容存储到headerfooter.php文件的$content中。
- 最后渲染headerfooter.php布局文件,并且结果返回给用户。
视图文件的存储路径
修改配置文件config/web.php,代码如下:
代码语言:javascript复制return [
......
'viewPath' => 'xxx',
];
配置文件config/web.php中的“viewPath”是yiibashApplication类的属性.该类继承了yiibaseModule类,在Module类中定义了getViewPath()和setViewPath()方法,来获取和设置视图文件路径,代码如下所示:
代码语言:javascript复制//所在文件路径vendoryiisoftyii2baseApplication.php
abstract class Application extends Module
{
}
//所在文件路径vendoryiisoftyii2baseModule.php
class Module extends ServiceLocator
{
......
private $_viewPath;
public function getViewPath()
{
if ($this->_viewPath === null) {
$this->_viewPath = $this->getBasePath() . DIRECTORY_SEPARATOR . 'views';
}
return $this->_viewPath;
}
public function setViewPath($path)
{
$this->_viewPath = Yii::getAlias($path);
}
}
在Module中并没有设施成员属性viewPath,但是使用viewPath成员属性时将自动调用_get()魔术方法间接调用getViewPath(),同理在设置viewPath成员属性时将自动调用_get()魔术方法间接调用setViewPath()方法。