在视图active_form中我们可以看到,在渲染表单的时候,调用了控制器的beginWidget方法,这个方法表示初始化一个挂件,那么挂件是什么,怎么使用列
挂件都继承自基类CWidget
一个微件是自包含的组件,它可以基于模型数据显示相应的内容。我们可以将其视为一个嵌入到控制器管理的视图中的微控制器。
挂件的使用方式有两种,一种是使用$controller->widget();一种是使用$controller->beginWidget()和$controller->endWidget()组合使用
我们进入Controller里面分别看一下这两种方法
在beginWidget中我们看到 yii使用挂件工厂生产了一个挂件,并执行了他的init()方法
public function beginWidget($className,$properties=array())
{
$widget=$this->createWidget($className,$properties);
$this->_widgetStack[]=$widget;
return $widget;
}
public function createWidget($className,$properties=array())
{
$widget=Yii::app()->getWidgetFactory()->createWidget($this,$className,$properties);
$widget->init();
return $widget;
}
在endWidget中我们看到,执行了widget的run方法public function endWidget($id='')
{
if(($widget=array_pop($this->_widgetStack))!==null)
{
$widget->run();
return $widget;
}
else
throw new CException(Yii::t('yii','{controller} has an extra endWidget({id}) call in its view.',
array('{controller}'=>get_class($this),'{id}'=>$id)));
}
如果直接使用widget方法则既调用init()方法也调用run方法,第三个参数表示是否返回值,如果为false则直接输出public function widget($className,$properties=array(),$captureOutput=false)
{
if($captureOutput)
{
ob_start();
ob_implicit_flush(false);
$widget=$this->createWidget($className,$properties);
$widget->run();
return ob_get_clean();
}
else
{
$widget=$this->createWidget($className,$properties);
$widget->run();
return $widget;
}
}
下面我分别就这两种挂件来举个例子
一.widget的使用
首先在应用基础目录protected下新建一个widgets的文件夹
然后在config配置目录下修改main.php
// autoloading model and component classes
'import'=>array(
'application.models.*',
'application.components.*',
'application.widgets.*',//将widgets类导入
),
做一个展示最近新添加的n用户的挂件
新建widgets/DbWidget
class DbWidget extends CWidget{
public $num;//显示的用户个数
//显示最近添加的n个用户,init方法可有可无
public function init() {
//初始化num值为3,如果使用挂件时没有传递num参数,则num=3
if($this->num == false){
$this->num = 3;
}
}
public function run() {
$users = $this->getUsers();
//渲染db挂件视图
$this->render('db',array(
'users'=>$users,
));
}
//获取最新添加的n个用户
protected function getUsers(){
return Yii::app()->db->createCommand()
->select('id,username,create_time')
->from('user')
->limit($this->num)
->order('id desc')
->queryAll();
}
}
在widgets目录下新建视图views/db.php
<?php if (!empty($users)): ?>
<table>
<tr>
<th>用户ID</th>
<th>用户名</th>
</tr>
<?php foreach ($users as $k => $user): ?>
<tr>
<td><?php echo $user['id']; ?></td>
<td><?php echo $user['username']; ?></td>
</tr>
<?php endforeach; ?>
</table>
<?php else: ?>
没有用户信息
<?php endif; ?>
挂件的引用
新建文件controllers/WidgetController
class WidgetController extends Controller{
public function actionWidget(){
$this->render('widget');
}
}
新建文件views/widget/widget.php
<?php $this->widget('application.widgets.DbWidget',array('num'=>5));?>
在浏览器中输入 http://localhost/bootstrap/index.php/widget/widget,输出结果如图
注:挂件的视图层中$this 指向的是挂件对象,如果想使用当前controller对象,需要使用Yii::app()->controller
二.beginWidget和endWidget的使用
比如我们做一个表单挂件
创建挂件 widgets/FormWidget.php
class FormWidget extends CWidget{
public $action = '';
public $method = 'POST';
public $htmlOptions = array();
public function init() {
echo CHtml::beginForm($this->action, $this->method, $this->htmlOptions);
}
public function run() {
echo CHtml::endForm();
}
//渲染一个文本框
public function textField($name,$value='',$htmlOptions=array()){
echo CHtml::textField($name, $value, $htmlOptions);
}
//渲染一个下拉框
public function dropDownList($name,$value='',$data=array(),$htmlOptions=array()){
echo CHtml::dropDownList($name, $value, $data, $htmlOptions);
}
}
WidgetController中
public function actionBeginwidget(){
$this->render('begin_widget');
}
view中views/begin_widget.php
<div class="form">
<?php
//$form是返回的挂件对象
$form = $this->beginWidget('application.widgets.FormWidget');
?>
<div class="row">
<?php echo $form->textField('username', '用户名'); ?>
</div>
<div class="row">
<?php echo $form->dropDownList('city_id', 1, User::getCitys()); ?>
</div>
<?php echo CHtml::submitButton('提交') ?>
<?php
$this->endWidget();
?>
</div>