YII 事件event和行为Behavior
To declare an event in your CComponent child class, you should add a method with a
name starting with on. For example, if you add the onRegister method, you will get a
corresponding event declared.
A method used to declare an event becomes the default
event handler.
Typically, events are used like this:
1 Declare an event by adding a corresponding method
2Attach one or multiple event handlers
3 The component raises an event by using the CComponent::raiseEvent method
4 All subscribed handlers are called automatically
让我们来看看怎么把一个事件句柄附加到事件上去。我们可以通过CComponent::attachEventHandler方法来实现。它接受2个参数:
- $name: 事件名
- $handler: 事件句柄。 这里应该使用一个标准的PHP回调。
在PHP中,我们有几种方法定义一个回调:
- 使用一个全局函数,只要通过它的名字,像’my_function’这样的字符串。
- 使用一个静态类方法,你应该传递一个数组: array('ClassName', 'staticMethodName') .
- 使用对象方法: array($object, 'objectMethod').
- 你可以创建和传递匿名函数,通过使用create_function:
$component->attachEventHandler('onClick', create_function('$event', 'echo "Click!";'));
- 从PHP5.3以后,你可以直接使用匿名函数,不需create_function:
$component->attachEventHandler('onClick', function($event){
echo "Click!";
});
当你使用CComponent::attachEventHandler时候,事件句柄被添加到句柄列表的尾部。
- 为了使得你的代码精简,你可以使用组件属性来管理这些事件句柄:
$component->onClick=$handler; // 或者:$component->onClick->add($handler);
- 为了更精确的管理事件句柄,你可以使用CComponent::getEventHandlers来获取句柄列表(CList),并且使用它。例如,你可以用下面的代码来附加事件句柄,跟attachEventHandler一样。
$component->getEventHandlers('onClick')->add($handler);
- 添加事件句柄到句柄列表头:
$component->getEventHandlers('onClick')->insertAt(0, $handler);
- 删除具体的句柄,你可以使用CComponent::detachEventHandler:
$component->detachEventHandler('onClick', $handler);
- 或者像上面的那样获取句柄列表并且从表中删除一些句柄。
CComponent::检查指定的事件是否在组件中定义了。
CComponent::hasEventHandler检查指定的事件是否有句柄依附。
既然我们都知道了怎样定义和使用这些句柄,那么我们来回顾下一些真实的例子吧。
- 用gzip压缩你的应用输出,来节省客户带宽,来加速页面加载时间,是件司空见惯的事情。如果你有权限能调整你的服务器,你可以让它这样,但是在一些环境下如共享主机,你就不能了。
- 幸运的是PHP能使用输出缓冲和ob_gzhandler来压缩应用输出。要这样做的话,我们得在应用程序开始的时候开始缓冲输出,并且在它结束的时候释放压缩的输出。
- 在我们的例子中,Yii应用程序有2个事件迟早有用:CApplication::onBeginRequest和CApplication::onEndRequest。我们现在就来使用它们,将以下代码放置在index.php中的应用程序配置之后,运行之前:
...
require_once($yii);
$app = Yii::createWebApplication($config);
// 在应用程序的开始附加一个句柄
Yii::app()->onBeginRequest = function($event)
{
// 用ob_gzhandler来开始输出缓冲
return ob_start("ob_gzhandler");
};
// 附加一个句柄到应用结束
Yii::app()->onEndRequest = function($event)
{
// 释放输出缓冲
return ob_end_flush();
};
$app->run();
在Yii核心类中定义了很多便捷的事件。你可以使用你喜爱IDE(集成开发环境)在framework文件夹里面通过“function on”的字样来查找到它们。
我们来看另外一个例子。在Yii中,你可以使用Yii::t来把字符串翻译成不同的语言。我们都追求完美的项目,所以所有的语言翻译都必须是最新的。倘若它们不是,我们将非常乐意收到您的邮件提醒。
在这里事件再次派上用场。尤其是当传递给Yii::t的翻译字符串丢失时调用CMessageSource::onMissingTranslation事件
这次我们使用应用配置文件protected/config/main.php来附加事件句柄:
...
'components' => array(
...
// messages组件类默认的是CPhpMessageSource
'messages' => array(
// 使用静态类方法作为事件句柄
'onMissingTranslation' => array('MyEventHandler',
'handleMissingTranslation'),
),
...
)
...
现在我们应该实现这个句柄,创建protected/components/MyEventHandler.php文件并输入以下代码:
class MyEventHandler
{
static function handleMissingTranslation($event)
{
// 这个事件的事件类是 CMissingTranslationEvent
// 因此我们能获得这个message的一些信息
$text = implode("\n", array(
'Language: '.$event->language,
'Category:'.$event->category,
'Message:'.$event->message
));
// 发送邮件
mail('admin@example.com', 'Missing translation', $text);
}
}
我们来看最后一个例子。我们有一个博客应用程序,我们需要在有新评论(Comment)提交到博客(Post)的时候就发一份邮件。
Comment是个用Gii生成的标准AR模型。Post也同样是Gii生成的模型,除了一些自定义的方法。我们需要定义一个事件NewCommentEvent来存储Post和Comment 两个模型和句柄类Notifier,它将处理工作。
- 让我们开始创建protected/components/NewCommentEvent.php:
class NewCommentEvent extends CModelEvent {
public $comment;
public $post;
}
这相当简单。我们只是添加了2个属性。
- 现在我们去看看protected/models/Post.php。为了突出显示添加了什么,我们省略了所有标准的AR方法。
class Post extends CActiveRecord {
// 给添加评论到当前提交上定义方法
function addComment(Comment $comment){
$comment->post_id = $this->id; // 创建事件类实例
$event = new NewCommentEvent($this);
$event->post = $this;
$event->comment = $comment; // 触发事件 trigger event
$this->onNewComment($event);
return $event->isValid;
} // 定义 onNewComment 事件
public function onNewComment($event) {
// 事实上事件是在这里触发的.这样的话我们可以使用
// onNewComment 方法来取代 raiseEvent.
$this->raiseEvent('onNewComment', $event);
}
}
- 现在,实现Notifie。创建 protected/components/Notifier.php输入如下代码:
class Notifier {
function comment($event){
$text = "There was new comment from {$event->comment->author}
on post {$event->post->title}";
mail('admin@example.com', 'New comment', $text);
}
}
- 现在是时候在protected/controllers/ PostController.php中一起进行操作了。
class PostController extends CController
{
function actionAddComment()
{
$post = Post::model()->findByPk(10);
$notifier = new Notifier(); // 附加事件句柄
$post->onNewComment = array($notifier, 'comment');
// 在真实的应用中,数据应来自$_POST
$comment = new Comment();
$comment->author = 'Sam Dark';
$comment->text = 'Yii events are amazing!';
// 添加评论
$post->addComment($comment);
}
}
- 所有的评论都将被添加后,管理员将会收到一份相关的邮件。
还有更多...
附加句柄这步不总是必需的。我们来看看怎样处理一个通过重写基类方法定义在已经存在的组件当中的事件。例如,我们有个表格模型UserForm来收集关于我们应用的用户的一些信息,并且我们要求通过用户输入的姓和名来获取完整的姓名。
幸运的,在CModel里面定义有CModel::afterValidate方法,CModel是提供给所有Yii模型的基类,当然包括表单模型了。在成功的表单验证后,这个方法就被调用了。让我们在UserForm模型中使用它吧:
class UserForm extends CFormModel
{
public $firstName;
public $lastName;
public $fullName; public function rules()
{
return array(
// 姓和名是必填的
array('firstName, lastName', 'required'),
);
} // 这里的$event参数是CEvent 实例
// 这个实例在调用事件方法的时候被创建了
// 在我们的案例,它发生在CModel::afterValidate()里面。
function afterValidate()
{
// 模型已经被填充了有效数据的时候调用这个方法
// 因此我们安全可靠的使用它:
$this->fullName = $this->firstName.' '.$this->lastName; // 把事件传递给父类很重要。
// 因此其他事件句柄都被调用了。
return parent::afterValidate();
}
}We need to call parent method inside of afterValidate because parent implementation calls onAfterValidate that actually raises events:
protected function afterValidate()
{
$this->onAfterValidate(new CEvent($this));
}一个事件方法名应该一直被定义成这个形式:eventHandler($event){...},其中的$event是CEvent的实例。CEvent类就只有2个属性:sender和handled(发送者和已经处理的)。第一个包含一个叫当前事件的对象,而第二个通过设置自己为false来阻止调用其他尚未被执行的句柄。
上面描述的方法能用来定制你的Active Record 模型和实现你模型的行为。
参考:
http://yiibook.com/book/yii1.1_application_development_cookbook/chapter-1
更多:
http://www.yiiframework.com/wiki/44/behaviors-events
http://www.yiiframework.com/wiki/481/how-to-implement-an-event-and-attach-it-in-a-behavior/
http://blog.csdn.net/kun_php/article/details/8564325
http://www.cnblogs.com/JosephLiu/archive/2011/12/12/2285078.html
http://www.cnblogs.com/davidhhuan/archive/2012/01/19/2326123.html
http://blog.csdn.net/wclovesjl/article/details/11571127
http://luchuan.iteye.com/blog/910251
YII 事件event和行为Behavior的更多相关文章
- YII事件EVENT示例
模型中/** * 在初始化时进行事件绑定 */ public function init() { $this->on(self::EVENT_HELLO,[$this,'sendMail']); ...
- Yii2的深入学习--事件Event
我们先来看下事件在 Yii2 中的使用,如下内容摘自 Yii2中文文档 事件可以将自定义代码“注入”到现有代码中的特定执行点.附加自定义代码到某个事件,当这个事件被触发时,这些代码就会自动执行.例如, ...
- yii事件
控制器: public function actionTests1(){ $c = new \app\components\cat(); $m = new \app\components\mou; $ ...
- Yii2的深入学习--yii\base\Event 类
根据之前一篇文章,我们知道 Yii2 的事件分两类,一是类级别的事件,二是实例级别的事件.类级别的事件是基于 yii\base\Event 实现,实例级别的事件是基于 yii\base\Compone ...
- Yii2基本概念之——事件(Event)
说起事件(event),我们可是一点都不陌生.现实生活当中的事件无处不在,比如你发了一条微博,触发了一条事件,导致关注你的人收到了一条消息,看到你发的内容:比如你通过支付宝买东西,付了款,触发一个事件 ...
- WPF 路由事件 Event Routing
原文:WPF 路由事件 Event Routing 1.路由事件介绍 之前介绍了WPF的新的依赖属性系统,本篇将介绍更高级的路由事件,替换了之前的.net普通事件.相比.net的事件,路由事件具有更强 ...
- 简单理解yii事件
https://blog.csdn.net/qq43599939/article/details/80363827 通过观察者来理解yii事件 测试 class TestController ext ...
- libevent源码学习(9):事件event
目录在event之前需要知道的event_baseevent结构体创建/注册一个event向event_base中添加一个event设置event的优先级激活一个event删除一个event获取指定e ...
- 事件EVENT与waitforsingleobject的使用
事件event与waitforsingleobject的配合使用,能够解决很多同步问题,也可以在数据达到某个状态时启动另一个线程的执行,如报警. event的几个函数: 1.CreateEvent和O ...
随机推荐
- SpringMVC+SwfUpload进行多文件同时上传
由于最近项目需要做一个多文件同时上传的功能,所以好好的看了一下各种上传工具,感觉uploadify和SwfUpload的功能都比较强大,并且使用起来也很方便.SWFUpload是一个flash和js相 ...
- 多态 JAVA
多态(Java) 一.多态 1.什么是多态? 不同的对象对于同一个操作,做出的响应不同 具有表现多种形态的能力的特征 2.使用多态的优点 : 为了实现统一调用 二.子类到父类的转换(向上转型) ① ...
- Context中嵌套<Environment>元素
环境条目 可以在Context中嵌套<Environment>元素,配置命名的值,这些值作为环境条目资源(Environment Entry Resource),对整个web应用可见.比 ...
- Android中完全退出当前应用系统
一.将统一管理Activity的类ActivityManager复制到工程里面. package com.jsmtr.www.Helper; import java.util.LinkedList; ...
- Java基础知识强化30:String类之String的特点(String为什么是final)
1. String字符串特点: 一旦被赋值,字符串值就不能改变. 这里String是final修饰的,具有不可继承性. 2. 为什么String是final? 主要是为了"效率" ...
- MediaPlayer+SurfaceView 视频播放 示例
SurfaceView的原理 SurfaceView在视频播放中起到显示画面的作用,而视频的播放主要通过MediaPlayer来控制. SurfaceView 允许我们 ...
- Oracle 11g随Redhat 5系统自动启动与关闭的设置方法
最近,ORACLE系统基本调试通过,是时候设置ORACLE随RHEL自动启动与关闭服务的时候了,之所以把这个任务放在最后来做,是因为我觉得这个应该不会很难,但真正实施起来,还是遇到了个不小的障碍:写好 ...
- 检查DOM能力的函数
var a=document.implementation.hasFeature("Core","2.0"); var b=document.implement ...
- hdu1025 最长不下降子序列nlogn算法
C - DP Crawling in process... Crawling failed Time Limit:1000MS Memory Limit:32768KB 64bit I ...
- XDubg的配置与应用
XDUG调试器配置与应用 1.什么是xbug xbug是一个开发源代码的php程序员调试器,可以用来跟踪,调试和分析Php程序的运行状况. Xbug(free) ZendDebugger(need m ...