摘要:初学yii,为了巩固基础,将框架survey过程记录下来,便于记忆。也供初学者一同参考,理解有误之处,请不吝指教。
通常我们使用yiic自动生成代码框架后,会有这个application.components.Controller控制器类,然后其他自定义的控制器类都继承于这个Controller类,这样便于对所有的控制器进行过滤操作。这是后话。
这篇博客主要讨论的是,我们在application.controllers.SiteController的actionIndex方法中调用:$this->render(‘index’);在这之后都发生了什么,控制器如何调用了视图,layout文件和模板文件怎么被渲染,它们之间又发生了什么呢,来就看看这个问题是怎么回事。
framework/web/CController.php
public function render($view,$data=null,$return=false){
//先渲染index模板文件
$output=$this->renderPartial($view,$data,true);
//根据loyout文件名来寻找layout脚本文件,默认loyout文件是'//layouts/column1'所以肯定能找到,会返回非false,所以这个if能够进入
if(($layoutFile=$this->getLayoutFile($this->layout))!==false)
//在这里再次调用renderFile()来渲染layout文件,并且把渲染过的模板文件赋值给$content变量给到layout文件,第三个参数是true,所以返回渲染后的结果,这个$output就是最终layout文件和模板文件渲染后结合到一块的文件
$output=$this->renderFile($layoutFile,array('content'=>$output),true);
//什么也不做
$this->afterRender($view,$output);
//再次加工一下$output。测试:当在控制器里面这样引入jquery
//Yii::app()->clientScript->registerCoreScript('jquery');
//那么下面这个方法就会把jQuery引入的script代码放在$output的里面
$output=$this->processOutput($output);
if($return)
return $output;
else
echo $output;
}
public function renderPartial($view,$data=null,$return=false,$processOutput=false){
//返回给定的view name 对应的view file
if(($viewFile=$this->getViewFile($view))!==false)
{
//渲染这个模板文件(protected/views/site/index.php)
$output=$this->renderFile($viewFile,$data,true);
if($processOutput)
$output=$this->processOutput($output);
if($return)
//第三个参数是true,所以返回渲染后的内容,这个方法结束。
return $output;
else
echo $output;
}
else
throw new CException(Yii::t('yii','{controller} cannot find the requested view "{view}".',
array('{controller}'=>get_class($this), '{view}'=>$view)));
}
综上:当控制器调用$this->render()的时候,是先渲染模板文件application.views.site.index.php,然后把渲染以后的结果赋值给layout文件(appliaction.views.layouts.column1.php)里面的$content。
还有一个奇怪的问题,在application.views.layous.column1.php里面调用了这个方法:
$this->beginContent(‘//layouts/main’);
这是干什么用的呢,再看代码:发现这个方法是CController继承CBaseController的方法,函数原型如下:
public function beginContent($view=null,$data=array()){
$this->beginWidget('CContentDecorator',array('view'=>$view, 'data'=>$data));
}
public function beginWidget($className,$properties=array()){
$widget=$this->createWidget($className,$properties);
//在这里我猜应该是创建了小物件的组,将它们给到控制器的_widgetStack[]里面,这样一来,不管是Layout文件还是模板文件里面如果需要使用小物件,就可以直接使用$this->widget()或者$this->beginWidget()这样的方法快速创建HTML了。
$this->_widgetStack[]=$widget;
return $widget;
}
public function createWidget($className,$properties=array()){
$widget=Yii::app()->getWidgetFactory()->createWidget($this,$className,$properties);
$widget->init();
return $widget;
}
另外还有一个问题,在views/layouts/下这两个文件column1.php 和 main.php
//column1.php
$this->beginContent('//layouts/main'); ?>
<div id="content">
echo $content; ?>
div>
$this->endContent(); ?>
在这个文件,它使用layouts/main.php来覆盖,beginContent(‘//layouts/main’) 表示以 main 为布局,在 beginContent() 和 endContent() 之间为 content 呈现的修改。
所以说yii在 $this->render(‘index’) 一个页面的时候,使用 column1.php 包含 main.php,再由 main.php 包含 index.php,最后返回内容.
所以说,在column1.php里面的$content,是用main.php的内容来替换;在main.php里面的$content,是用views/site/index.php来替换。