相信上一节你必定看了观察者模式,咱们如今开始说Yii2的事件,请你们用观察者的思惟去看它。php
为了让话题轻松一点,咱们模拟一个场景,假设经理小X要北哥作一个登录,登录后还要作另外一些事情:app
本地留一个logyii
告诉登录者的朋友它登录了函数
发送一个邮件给管理员this
如何实现“另外一些事情”那?他们未来要具备多变性,如何保证他们最小程度污染登录逻辑那?spa
这时我忽然想到了“耦合度最低、可是依然牛逼交互中的观察者模式”,话说咱们本身又未尝不是那,白百合被小鲜肉摸了一下屁股而已,有人发朋友圈、有人发微博、有人发声明,观察者是真操碎了心。????日志
@@nai8@@code
先来熟悉一下登录的代码 appcontrollersUserController.php视频
class UserController extends Controller { public function actionIndex(){ // 这里有一些代码..... Yii::$app->user->login($user); // todo 登录后要作的事情 } }
没错,为了实现经理的需求,我必须用观察者实现这段逻辑,由于它具备很强的扩展性,能轻松应付小X经理多变的性格,随时增减登录后的事情。对象
而Yii中有一个观察者的深度执行者,那就是事件机制。
首先咱们要知道一切都是由于会员登录,这就是主题。所以咱们要为登录起一个事件名字,对于事件咱们喜欢用大写的常量标识,这就相似于js中的click、change这些关键词,它表明一些事情发生了。
根据观察者模式的原理,在 Yii::$app->user->login($user); 以前,咱们须要订阅(事件的绑定),登录后须要通知订阅者(事件触发)。
好,从需求看如今一共有三个观察者,咱们暂时命名为
OLog 记录日志
Admin 给管理员发邮件
Friend 通知登录者朋友
咱们先来实现这些观察者
// OLog app\models\OLog.php class OLog { static public function add($event){ echo "我记录了一条登录记录"; } }
// Admin app\models\Admin.php class Admin { static public function sendMail($event){ echo "我给管理员发了邮件"; } }
// User app\models\User.php class User { static public function notifyFirend($event){ echo "告诉了朋友们我登录了"; } }
上面三个类,咱们实现了每一个观察者自行的代码,你必定注意到了,这些方法统统有一个叫作$event的形参,它会将本次事件一些必要的参数传递给每一个观察者的方法,本文后面会对其有讲解。
ok
接下来咱们要让三个观察者订阅登录主题,就是事件中的绑定,它应该在登录以前就完成。
为了实现方便,我决定在 UserController 的构造函数里作这个事情
appcontrollersUserController.php
class UserController extends Controller { // 定义事件名字 const EVENT_USER_LOGIN = 'user_login'; public function __construct(){ // 绑定事件 $this->on(self::EVENT_USER_LOGIN,['app\models\OLog','add']); $this->on(self::EVENT_USER_LOGIN,['app\models\Admin','sendMail']); $this->on(self::EVENT_USER_LOGIN,['app\models\User','notifyFirend']); } public function actionIndex(){ ..... // login } }
由于我知道Yii的 Component 类引入了Event事件,全部继承于Component的类均可以使用它,Controller继承了Component类。
咱们能够经过
$this->on("事件名称","方法")
绑定一个方法到某个指定事件上,这个方法能够是一个全局的方法、一个类的静态方法、一个对象的方法,还能是一个匿名方法,这个后续会讲到。
本次我用的是类的静态方法。
ok,订阅(事件的绑定)完活。
接下来就是等待,等待某个会员登录后通知全部咱们上面绑定的方法,那么如何通知那?这就是事件的触发,Yii已经为咱们提供了方法。
appcontrollersUserController.php
class UserController extends Controller { // 定义事件名字 const EVENT_USER_LOGIN = 'user_login'; public function __construct(){ // 绑定事件 $this->on(self::EVENT_USER_LOGIN,['app\models\OLog','add']); $this->on(self::EVENT_USER_LOGIN,['app\models\Admin','sendMail']); $this->on(self::EVENT_USER_LOGIN,['app\models\User','notifyFirend']); } public function actionIndex(){ // 这里有一些代码..... Yii::$app->user->login($user); $this->trigger(self::EVENT_USER_LOGIN); } }
没错,就是一句
$this->trigger(self::EVENT_USER_LOGIN);
它通知了全部绑定了该事件的方法,写日志的写日志,发邮件的发邮件。
事件成功应用于此。
没完,你应该发现了,这个代码有一个问题,就是trigger函数的确告诉了全部的订阅者会员登录了,可是,可是它没有告诉是哪一个会员登录了。。。。。
那观察者如何发邮件、如何群发好友、如何如何那?
还记得咱们实现观察者类时候的那个形参么$event,咱们知道它能接收一些事件相关信息,可是,是谁传递给他们的那?
这就要欢迎trigger的第二个参数出场了
// Component类中 public function trigger($name, Event $event = null)
咱们能够传递一个事件类对象给触发函数,你可能有点蒙,简单点说就是Yii中有一个与事件紧密相关的 yiibaseEvent 类,它封装了与事件相关的有关数据,并提供一些功能函数做为辅助。
咱们能够本身定义事件类,继承于它就完事了。
开始吧,这个事件类能帮我把会员的ID传递给每一个观察者。
如今咱们在@app下创建一个events的文件夹,新建一个类叫作UserLoginEvent.php
// event/UserLoginEvent.php namespace app\events; use yii\base\Event; class UserLoginEvent extends Event { public $userId = 0; }
这样就完事了,如今咱们重写触发函数。
appcontrollersUserController.php
use app\events\UserLoginEvent; class UserController extends Controller { ....... ....... public function actionIndex(){ // 这里有一些代码..... Yii::$app->user->login($user); $event = new UserLoginEvent(); $event->userId = $user->id; $this->trigger(self::EVENT_USER_LOGIN,$event); } }
这样$event对象就带着会员id飞鸽传书到每一个订阅者方法中去了。
咱们看看订阅者如何使用它那?
// User app\models\User.php class User { static public function notifyFirend($event){ $userId = $event->userId; echo "告诉了朋友们我登录了"; } }
看明白了吧~
ok,到此我实现了小X经理的需求,开始提交代码了。
想知道小X经理看到后的结果么?等北哥下回分解。
欢迎来到个人yii原创视频小站 http://nai8.me