一個活生生的Yii2事件例子

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

相關文章
相關標籤/搜索