相信上一節你必定看了觀察者模式,咱們如今開始說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