Yii Behavior的理解

来源:互联网 发布:若水软件 免费软件 编辑:程序博客网 时间:2024/05/22 08:06
下面这段是转自他人的内容:http://www.myexception.cn/program/670355.html
我们在自定义,或直接为事件添加处理函数时,都需要想办法找到一个切入点(就是一个添加事件处理函数的位置)
比如,上面的actionContract中的$model->onSendMail=function(…和上面的index.php中添加的 Yii::app()->onBeginRequest=function(…代码也不是很优雅 有些时候,你并不知道你要添加事件的组件,
是在什么时候创建的,或者说你在为组件添加事件处理函数时,找不到合适的时候,如果添加早了,组件还没创建,如果添加晚了,事件不被执行,有可能组件已经执行完了比如controller,

上面我们已经介绍了事件的使用,和他的一些不足,下在我们来介绍一个Behavior行为,
先来看个例子
在protected创建目录behaviors,并在protected/behaviors目录下创建ApplicationBehavior.php,
打开此文件输入如下代码:

<?phpclass ApplicationBehavior extends CBehavior {        public function events()        {                return array_merge(parent::events(),array(                                'onBeginRequest'=>'beginRequest'                ));        }        public function beginRequest($event) {                echo "Hello this Behavior beginRequest";        }}

此行为文件,是要为CApplication服务,仔细查看这个行为文件,我们可以看到,
events方法定义了些行为可以处理的事件,上面的类,可以处理onBeginRequest事件,当然如果你自己定义的组件也有一个叫做onBeginRequest方法,你也可以使用此行为
后面的beginRequest就是事件的处理函数,这个处理函数必须要有行为类中定义
ok,让我们将此行为类附加到CApplication
打开index.php,输入以下代码

$app = Yii::createWebApplication($config);Yii::app()->onBeginRequest=function($event) {        echo "Hello this onBeginRequest<br />";};Yii::app()->onBeginRequest=function($event) {        echo "Hello this onBeginRequest2<br />";};Yii::app()->onEndRequest=function($event) {        echo "Hello this onEndRequest<br />";};$app->attachBehavior('app', 'application.behaviors.ApplicationBehavior');$app->run();

刷新页面,你将会在头部看到一行Hello this Behavior beginRequest

如果说单从上面这个附加行为的方式来说,行为并没有比事件有多少方便,与优雅
下在我们换一种方式,去掉index.php中的$app->attachBehavior(‘app’, ‘application.behaviors.ApplicationBehavior’);这行代码
如果你们yii的组件定义了解的话,你应该知道每一个组件,都有一个behaviors方法,些方法中定义的相关行为,在组件初始化时,会自动附件,
ok,下面我们就为CApplication定义behaviors,由于CApplication是系统级类,我们可以扩展此类,并添加behaviors方法,但是这样显的有点繁锁,
如果你知道,CApplication会根据config/main.php配置进行初始化,那么我们就可以将behaviors定义在main.php
打开config/main.php文件,加入以下代码

  'behaviors' => array(                'app' => 'application.behaviors.ApplicationBehavior',        ),

刷新页面,你将在头部看到如下文字
Hello this Behavior beginRequest

Hello this onBeginRequest

Hello this onBeginRequest2

这里请注意,Hello this Behavior beginRequest 在行为中定义的方法,优先显示在了事件处理函数之前

OK,让我们再看看如何在刚才的ContactForm模型中使用行为

创建目录protected/models/behaviors,在models下创建behaviors的目的是与应用级的behaviors区分

在protected/models/behaviors创建SendmailBehavior.php,并输入如下内容

<?phpclass SendmailBehavior extends CBehavior {        public function events()        {                return array_merge(parent::events(),array(                                'onSendmail'=>'sendmail'                ));        }        public function sendmail($event) {                        $headers="From: {$event->sender->email}\r\nReply-To: {$event->sender->email}";                        mail(Yii::app()->params['adminEmail'],$event->sender->subject,$event->sender->body,$headers);        }}

为ContactForm附加行为

打开ContactForm.php,添加behaviors方法,输入以下内容

  public function behaviors() {                return array(                                'sendmail'=>'application.models.behaviors.SendmailBehavior'                );        }

好的,现在去修改SiteController.php文件,找到actionContact,注掉以下代码

               /*                $model->onSendMail=function($event) {                        $headers="From: {$event->sender->email}\r\nReply-To: {$event->sender->email}";                        mail(Yii::app()->params['adminEmail'],$event->sender->subject,$event->sender->body,$headers);                };*/

ok,打开程序,重新提交Contact表单,与之前的功能一样,

3. 使用现有的行为,Yii框架已经为我们预先定义了一些行为,如CTimestampBehavior,它在zii包下,要使用它,我们先要了解它
这个行为主要目的是将模型AR类中的两个时间属性,create/update自动赋值

ok,让我们打开应用程序默认的sqlite数据库,数据库所在位置是prodcted/data/testdrive.db,创建一个表tbl_test
创建id主键,cTime int类型,还有uTime int类型允许为空,因为当插入时,yii的模型不会处理uTime字段

修改config/main.php 打开gii,方便创建模型文件models/Test.php
模型文件创建成功了,我们打开models/Test.php,附加行为,输入如下代码

   public function behaviors(){                return array(                                'CTimestampBehavior' => array(                                        'class' => 'zii.behaviors.CTimestampBehavior',                                        'createAttribute' => 'cTime',        //创建属性,对应用模型的字段名                                        'updateAttribute' => 'uTime',                                )                );        }

行为附加完成后,我们打开SiteController.php文件,创建如下代码

   public function actionCar() {                $model = new Test;                if ($model->save()) {                        echo 'ok';                }                else echo 'no';        }        public function actionUar() {                $model = Test::model()->find('id=?', array(1));                $model->save();        }

这里我们创建了两个action,一个是模型插入,一个是模型更新
每操作一次你查看一下数据库记录,可以看到,cTime字段会自动填充,更新时uTime也会自动填充

本人水平有限,希望此篇文章对你有用

转载地址:http://yiibook.yiiblogs.com/?p=584,感谢原作者

这里我自己做点补充,在上面有提到在ContactForm.php,添加behaviors方法,也就是在model中添加了behaviors方法,这个behaviors是重写了CActiveRecord的behaviors方法(该方法返回空数组),当ContactForm被实例化时,相应的behaviors就会被绑定到ContactForm的实例上,在CActiveRecord的__construct函数中

(上面那个例子的行为绑定到组件上,并且关联了事件的流程如下

public function __construct($scenario='insert')
{
    if(
$scenario===null// internally used by populateRecord() and model()
        
return;

    
$this->setScenario($scenario);
    
$this->setIsNewRecord(true);
    
$this->_attributes=$this->getMetaData()->attributeDefaults;

    
$this->init();

    
$this->attachBehaviors($this->behaviors());
    
$this->afterConstruct();
}

我们可以看到在构造函数中,会把behaviors中的行为绑定到实例上
public function attachBehaviors($behaviors)
{
    foreach(
$behaviors as $name=>$behavior)
        
$this->attachBehavior($name,$behavior);//$name是sendmail,$behavior指向SendmailBehavior.php的路径
}

public function attachBehavior($name,$behavior)
{
    if(!(
$behavior instanceof IBehavior))
        
$behavior=Yii::createComponent($behavior);//实例化SendmailBehavior
    
$behavior->setEnabled(true);
    
$behavior->attach($this);
    return 
$this->_m[$name]=$behavior;//这里$this->_m[$name]被赋空值
}

public function setEnabled($value)
{
    if(
$this->_enabled!=$value && $this->_owner)//_enabled默认的false,_owner被绑定行为的组件,默认是没赋值的,所以这里没执行
    {
        if(
$value)
        {
            foreach(
$this->events() as $event=>$handler)
                
$this->_owner->attachEventHandler($event,array($this,$handler));
        }
        else
        {
            foreach(
$this->events() as $event=>$handler)
                
$this->_owner->detachEventHandler($event,array($this,$handler));
        }
    }
    
$this->_enabled=$value;
}

public functionattach($owner)
{
$this->_enabled=true;
$this->_owner=$owner;//owner被绑定行为的组件
$this->_attachEventHandlers();

}
private function_attachEventHandlers()
{
$class=new ReflectionClass($this);
foreach($this->events() as $event=>$handler)
//这里events()返回array('onSendmail'=>'sendmail')
{
if($class->getMethod($handler)->isPublic())
$this->_owner->attachEventHandler($event,array($this,$handler));
}
}
public function attachEventHandler($name,$handler)
{
$this->getEventHandlers($name)->add($handler);//$event为onSendmail,$handler为array(SendmailBehavior实例,sendmail),
返回了$event的CList实例,为$event添加事件处理函数
}
public function getEventHandlers($name)//$name为onSendmail
{
if($this->hasEvent($name))
{
$name=strtolower($name);
if(!isset($this->_e[$name]))
$this->_e[$name]=new CList;
return $this->_e[$name];
}
else
throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.',
array('{class}'=>get_class($this), '{event}'=>$name)));

}
public function hasEvent($name)
{
return !strncasecmp($name,'on',2) && method_exists($this,$name);
}
由上面的流程可知,behavior是事件的集合,为组件绑定行为,其实就是为组件绑定各类事件以及事件的处理函数
原创粉丝点击