1、TbActiveForm.php文件
分析:TbActiveForm的type属性的不同,通过getInputClassName()会引用不同的文件
Yii::import('bootstrap.widgets.input.TbInput');
/**
* Bootstrap active form widget.
*/
class TbActiveForm extends CActiveForm
{
// Form types.
const TYPE_VERTICAL = 'vertical';
const TYPE_INLINE = 'inline';
const TYPE_HORIZONTAL = 'horizontal';
const TYPE_SEARCH = 'search';
// Input classes.
const INPUT_HORIZONTAL = 'bootstrap.widgets.input.TbInputHorizontal';
const INPUT_INLINE = 'bootstrap.widgets.input.TbInputInline';
const INPUT_SEARCH = 'bootstrap.widgets.input.TbInputSearch';
const INPUT_VERTICAL = 'bootstrap.widgets.input.TbInputVertical';
/**
* Bootstrap active form widget.
*/
class TbActiveForm extends CActiveForm
{
// Form types.
const TYPE_VERTICAL = 'vertical';
const TYPE_INLINE = 'inline';
const TYPE_HORIZONTAL = 'horizontal';
const TYPE_SEARCH = 'search';
// Input classes.
const INPUT_HORIZONTAL = 'bootstrap.widgets.input.TbInputHorizontal';
const INPUT_INLINE = 'bootstrap.widgets.input.TbInputInline';
const INPUT_SEARCH = 'bootstrap.widgets.input.TbInputSearch';
const INPUT_VERTICAL = 'bootstrap.widgets.input.TbInputVertical';
由以上代码可知,需要更改的文件有TbInput TbInputHorizontal TbInputInline TbInputSearch TbInputVertical,对应于以下文件
2、TbInput 文件添加以下代码
分析:此类为抽象类,所以不能被实例化。调用抽象类必定是写子类实例出对象。在第三段代码中调用此抽象方法有很高的重用性,不用管Vertical、Horizontal这些参数设置。由于为抽象方法(效果如同接口interface),子类TbInputVertical TbInputHorizontal TbInputInline TbInputSearch中则必须重写datetimepickerField()的具体方法。
TbInput 继承于 CInputWidget 继承于 Widget 含有getController()方法 继承于 CBaseController 继承于 CComponent base文件夹中
//新添加datetimepicker
const TYPE_DATETIMEPICKER = 'datetimepicker';
const TYPE_DATETIMEPICKER = 'datetimepicker';
abstract protected function datetimepickerField();
case self::TYPE_DATETIMEPICKER:
$this->datetimepickerField();
break;
$this->datetimepickerField();
break;
3、TbInputHorizontal TbInputVertical文件添加以下代码
分析:TbInputHorizontal TbInputVertical 继续于TbInput,datetimepickerField()重写抽象父类中的此抽象方法
TbInputInline继承于TbInputVertical TbInputSearch继承于TbInputInline 因此都不需要添加
protected function datetimepickerField()
{
if (isset($this->htmlOptions['options']))
{
$options = $this->htmlOptions['options'];
unset($this->htmlOptions['options']);
}
echo $this->getLabel();
echo '<div class="controls">';
echo $this->getPrepend();
$this->widget('bootstrap.widgets.TbDateTimePicker', array(
'model' => $this->model,
'attribute' => $this->attribute,
'options' => isset($options) ? $options : array(),
'htmlOptions' => $this->htmlOptions,
));
echo $this->getAppend();
echo $this->getError() . $this->getHint();
echo '</div>';
}
{
if (isset($this->htmlOptions['options']))
{
$options = $this->htmlOptions['options'];
unset($this->htmlOptions['options']);
}
echo $this->getLabel();
echo '<div class="controls">';
echo $this->getPrepend();
$this->widget('bootstrap.widgets.TbDateTimePicker', array(
'model' => $this->model,
'attribute' => $this->attribute,
'options' => isset($options) ? $options : array(),
'htmlOptions' => $this->htmlOptions,
));
echo $this->getAppend();
echo $this->getError() . $this->getHint();
echo '</div>';
}
4、TbActiveForm.php文件添加以下代码
分析:当调用$form->datetimepickerRow($model, $attribute, $htmlOptions = array())时,会调用方法inputRow()和其参数TbInput::TYPE_DATETIMEPICKER,按理说TbInput是个抽象类,没法直接实例出对象。而在此处直接调用其静态常量,应该是在抽象类中的静态常量和方法,都能直接调用吧。(未实验)
public function datetimepickerRow($model, $attribute, $htmlOptions = array())
{
return $this->inputRow(TbInput::TYPE_DATETIMEPICKER, $model, $attribute, null, $htmlOptions);
}
{
return $this->inputRow(TbInput::TYPE_DATETIMEPICKER, $model, $attribute, null, $htmlOptions);
}
注:此后是分析过程,不是需要添加的代码。
分析:inputRow() 方法源代码
public function inputRow($type, $model, $attribute, $data = null, $htmlOptions = array())
{
ob_start();
Yii::app()->controller->widget($this->getInputClassName(), array(
'type' => $type,
'form' => $this,
'model' => $model,
'attribute' => $attribute,
'data' => $data,
'htmlOptions' => $htmlOptions,
));
return ob_get_clean();
}
{
ob_start();
Yii::app()->controller->widget($this->getInputClassName(), array(
'type' => $type,
'form' => $this,
'model' => $model,
'attribute' => $attribute,
'data' => $data,
'htmlOptions' => $htmlOptions,
));
return ob_get_clean();
}
注:Yii::app()->controller的调用机制???
const INPUT_HORIZONTAL = 'bootstrap.widgets.input.TbInputHorizontal';
const INPUT_INLINE = 'bootstrap.widgets.input.TbInputInline';
const INPUT_SEARCH = 'bootstrap.widgets.input.TbInputSearch';
const INPUT_VERTICAL = 'bootstrap.widgets.input.TbInputVertical';
protected function getInputClassName()
{
if (isset($this->input))
return $this->input;
else
{
switch ($this->type)
{
case self::TYPE_HORIZONTAL:
return self::INPUT_HORIZONTAL;
break;
case self::TYPE_INLINE:
return self::INPUT_INLINE;
break;
case self::TYPE_SEARCH:
return self::INPUT_SEARCH;
break;
case self::TYPE_VERTICAL:
default:
return self::INPUT_VERTICAL;
break;
}
}
}
const INPUT_INLINE = 'bootstrap.widgets.input.TbInputInline';
const INPUT_SEARCH = 'bootstrap.widgets.input.TbInputSearch';
const INPUT_VERTICAL = 'bootstrap.widgets.input.TbInputVertical';
protected function getInputClassName()
{
if (isset($this->input))
return $this->input;
else
{
switch ($this->type)
{
case self::TYPE_HORIZONTAL:
return self::INPUT_HORIZONTAL;
break;
case self::TYPE_INLINE:
return self::INPUT_INLINE;
break;
case self::TYPE_SEARCH:
return self::INPUT_SEARCH;
break;
case self::TYPE_VERTICAL:
default:
return self::INPUT_VERTICAL;
break;
}
}
}
分析:调用了widget()方法,应该是抽象类CBaseController的widget()方法。
$this->getInputClassName()是根据type类型返回的相应的路径名并传入$className。
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;
}
}
{
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;
}
}
分析:调用此类方法createWidget()。
注:$captureOutput为true即返回html字符串,可以多次输出。
public function createWidget($className,$properties=array())
{
$widget=Yii::app()->getWidgetFactory()->createWidget($this,$className,$properties);
//exit(var_dump($widget));
$widget->init();
//exit(var_dump($widget));
return $widget;
}
{
$widget=Yii::app()->getWidgetFactory()->createWidget($this,$className,$properties);
//exit(var_dump($widget));
$widget->init();
//exit(var_dump($widget));
return $widget;
}
分析:Yii::app()->getWidgetFactory()引用CWidgetFactory类
public function createWidget($owner,$className,$properties=array())
{
//exit(var_dump($properties));
$className=Yii::import($className,true);
$widget=new $className($owner);
//exit(var_dump(isset($this->widgets[$className])));
if(isset($this->widgets[$className]))
$properties=$properties===array() ? $this->widgets[$className] : CMap::mergeArray($this->widgets[$className],$properties);
if($this->enableSkin)
{
if($this->skinnableWidgets===null || in_array($className,$this->skinnableWidgets))
{
$skinName=isset($properties['skin']) ? $properties['skin'] : 'default';
if($skinName!==false && ($skin=$this->getSkin($className,$skinName))!==array())
$properties=$properties===array() ? $skin : CMap::mergeArray($skin,$properties);
}
}
foreach($properties as $name=>$value)
$widget->$name=$value;
//exit(var_dump($widget->title));
return $widget;
}
{
//exit(var_dump($properties));
$className=Yii::import($className,true);
$widget=new $className($owner);
//exit(var_dump(isset($this->widgets[$className])));
if(isset($this->widgets[$className]))
$properties=$properties===array() ? $this->widgets[$className] : CMap::mergeArray($this->widgets[$className],$properties);
if($this->enableSkin)
{
if($this->skinnableWidgets===null || in_array($className,$this->skinnableWidgets))
{
$skinName=isset($properties['skin']) ? $properties['skin'] : 'default';
if($skinName!==false && ($skin=$this->getSkin($className,$skinName))!==array())
$properties=$properties===array() ? $skin : CMap::mergeArray($skin,$properties);
}
}
foreach($properties as $name=>$value)
$widget->$name=$value;
//exit(var_dump($widget->title));
return $widget;
}
分析:$className=Yii::import($className,true);通过import引入TbInputHorizontal TbInputInline TbInputSearch TbInputVertical中的任何一个子类。