logo头像

Hello World

Yii2 Event事件-初识

yii2-事件 系列 第一篇

博主使用yii2时间不长,用于备忘分享,若有不正之处欢迎指正。十分感谢。
本文仅用于快速使用yii2事件。后续文章将详细介绍yii2事件的更多细节。


前言

最近在使用框架做项目中,多次使用到了Behavior。
但是在使用的时候,切记不要盲目使用behavior,而是要区分场景。明白了场景到底需要什么的时候,再去选择使用事件(event),还是行为(behavior)。

使用事件,可以在特定的时点,触发执行预先设定的一段代码,事件既是代码解耦的一种方式,也是设计业务流程的一种模式。现代软件中,事件无处不在,比如,你发了个微博,触发了一个事件,导致关注你的人,看到了你新发出来的内容。对于事件而言,有这么几个要素 [1]

yii2事件方法

Event文件( \yii\base\Event )函数模型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Event extends Object
{
public $name; // 事件名
public $sender; // 事件发布者,通常是调用了 trigger() 的对象或类。
public $handled = false; // 是否终止事件的后续处理
public $data; // 事件相关数据

private static $_events = [];

public static function on($class, $name, $handler, $data = null,
$append = true)
{
// ... ...
// 用于绑定事件handler
}

public static function off($class, $name, $handler = null)
{
// ... ...
// 用于取消事件handler绑定
}

public static function hasHandlers($class, $name)
{
// ... ...
       // 用于判断是否有相应的handler与事件对应
}

public static function trigger($class, $name, $event = null)
{
// ... ...
// 用于触发事件
}
}

  • on =>绑定事件handler

    一个最简单的绑定:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?php
    \yii\base\Event::on(
    BaseActiveRecord::className(),//需要绑定的类名
    BaseActiveRecord::EVENT_BEFORE_INSERT,//绑定插入前事件
       function ($event){//事件handler。这里的$event即是上面类中的Event。
        echo 'I will insert a record into database';
    //...
    }
    );

    以上例子表示将AR数据库插入之前事件,与自定义handler函数绑定。

  • off =>解绑事件handler

    一个最简单的解除绑定:

    1
    2
    3
    4
    5
    6
    <?php
    \yii\base\Event::off(
    BaseActiveRecord::className(),//要接触绑定的类名
    BaseActiveRecord::EVENT_AFTER_DELETE,//解除绑定的事件
    //如果不写第三个参数,默认为null,将移除事件所有的handler。
    );

    以上例子表示移除AR数据被删除后事件绑定的所有的handler.该函数将返回TrueFalse表示是否找到并移除了该handler。

  • hasHandlers =>判断这个类以及其父类的指定事件是否具有handler。

    一个最简单的判断:

    1
    2
    3
    4
    5
    <?php
    \yii\base\Event::hasHandlers(
    BaseActiveRecord::className(),//要判断的类
    BaseActiveRecord::EVENT_BEFORE_UPDATE//要判断的事件名称
    );

    以上例子表示 判断AR类数据库记录变更行为下有没有handler。
    注:仔细阅读了源码后,发现该函数不仅会检查指定的这个类,也会检查其所有的父类。

  • offAll =>解除所有类级别的事件处理程序。

    一个最简单的解除所有绑定:

    1
    2
    <?php
    \yii\base\Event::offAll();

Yii2 内置事件

在上面我们明白了如何绑定解绑事件,Yii2也很贴心的给我们提供了许多内置的事件,在这里列举一下,以用于快速查询。Tips:此内容可以在Yii2速查表里找到。

Application # 应用主体

  • 应用处理请求before之前触发
    • Application::EVENT_BEFORE_REQUEST
  • 应用处理请求before之后触发
    • Application::EVENT_AFTER_REQUEST

Controller # 控制器

  • 在每个Action运行之前触发
    • Controller::EVENT_BEFORE_ACTION
  • 在每个Action运行之后触发
    • Controller::EVENT_AFTER_ACTION

Model # 模型

  • 在验证Model属性之前触发
    • Model::EVENT_BEFORE_VALIDATE
  • 在验证Model属性之后触发
    • Model::EVENT_AFTER_VALIDATE

Module # 模块

  • 一个模块的Action运行前触发
    • Module::EVENT_BEFORE_ACTION
  • 一个模块的Action运行后触发
    • Module::EVENT_AFTER_ACTION

View # 视图

  • 执行视图的beforePage时触发
    • View::EVENT_BEGIN_PAGE
  • 执行视图的endPage函数时触发
    • View::EVENT_END_PAGE
  • 在renderFile渲染一个视图文件之前触发
    • View::EVENT_BEFORE_RENDER
  • 在renderFile渲染一个视图文件之后触发
    • View::EVENT_AFTER_RENDER
  • 执行视图的beginBody函数时触发
    • View::EVENT_BEGIN_BODY
  • 执行视图的endBody函数时触发
    • View::EVENT_END_BODY

Widget # 挂件

  • Widget初始化时触发
    • Widget::EVENT_INIT
  • Widget执行前触发
    • Widget::EVENT_BEFORE_RUN
  • Widget执行之后触发
    • Widget::EVENT_AFTER_RUN

ActiveQuery

  • 由ActiveQuery的init函数触发
    • ActiveQuery::EVENT_INIT

BaseActiveRecord & ActiveRecord # 这也许是内置事件中最重要的一批了。

  • AR对象被初始化init时触发
    • BaseActiveRecord::EVENT_INIT
  • AR执行查询结束时触发
    • BaseActiveRecord::EVENT_AFTER_FIND
  • 插入结束时触发
    • BaseActiveRecord::EVENT_BEFORE_INSERT
  • 插入之后触发
    • BaseActiveRecord::EVENT_AFTER_INSERT
  • 更新记录之前触发
    • BaseActiveRecord::EVENT_BEFORE_UPDATE
  • 更新记录之后触发
    • BaseActiveRecord::EVENT_AFTER_UPDATE
  • 删除记录之前触发
    • BaseActiveRecord::EVENT_BEFORE_DELETE
  • 删除记录之后触发
    • BaseActiveRecord::EVENT_AFTER_DELETE
  • 在数据refresh成功之后触发
    • BaseActiveRecord::EVENT_AFTER_REFRESH

Connection # 数据库连接

  • 数据库连接被打开后触发
    • Connection::EVENT_AFTER_OPEN
  • 事务被启动时触发
    • Connection::EVENT_BEGIN_TRANSACTION
  • 事务被提交后触发
    • Connection::EVENT_COMMIT_TRANSACTION
  • 事务回滚后触发
    • Connection::EVENT_ROLLBACK_TRANSACTION

Response # Http响应

  • Response响应发送之前触发
    • Response::EVENT_BEFORE_SEND
  • Response响应发送之后触发
    • Response::EVENT_AFTER_SEND
  • Response响应内容准备好之后触发
    • Response::EVENT_AFTER_PREPARE

User # 会员登陆授权

  • 登陆之前触发
    • User::EVENT_BEFORE_LOGIN
  • 登陆之后触发
    • User::EVENT_AFTER_LOGIN
  • 注销之前触发
    • User::EVENT_BEFORE_LOGOUT
  • 注销之后触发
    • User::EVENT_AFTER_LOGOUT

一些使用技巧

使用事件不仅可以写到controller里面,实现这些用户注册成功触发SayHelloToUser事件这个场景。

也可以写到BootStrap文件中,实现一些比如全局安全检测,日志等功能。另外也可以写到配置文件中。下面简单介绍一下配置文件实现绑定事件handler的流程。

下面贴一个用户登录事件绑定的实现,代码实现了登录后修改最后登录时间。
config/main.php

1
2
3
4
5
6
7
8
9
10
11
'components' => [
'user' => [
'identityClass' => 'common\models\User',
'enableAutoLogin' => true,
'on afterLogin' => function($event){
$user = $event->identity;
     $user->loginTime = time();
$user->save();
}
],
]

上面就是在配置文件中绑定事件handler的基本形式。
大体模型如下:

1
2
3
4
5
6
7
8
'components' => [
'自定义component'=>[
'class'=>'\path\自定义',
'on Event名称'=> function($event){
//handler内容
}
],
],

一些其它需要留意的地方

  • 事件是在Component引入的,yii\base\Object是不支持事件的。使用时要从yii\base\Component进行继承
  • Handler的形式必须是函数形式的。

文中部分内容引用自:
[1]深入理解Yii2.0-事件

上一篇