laravel 事件/監聽器 實例

導語

上一篇文章實現了記錄用戶訪問,設計上是有缺陷的,代碼緊耦合在中間件。若是後續修改需求,不只記錄 ip、城市,還須要記錄數據到新的數據表,或者須要進行其它統計,那麼不停的增長、修改代碼是不合理的。這個時候能夠使用 Laravel 的事件/監聽器進行處理。代碼可查看 GitHubphp

事件/監聽器

Laravel 事件提供了簡單的觀察者模式實現,容許你訂閱和監聽應用中的事件。

觀察者模式有時也被稱做發佈/訂閱模式,該模式用於爲對象實現發佈/訂閱功能:一旦主體對象狀態發生改變,與之關聯的觀察者對象會收到通知,並進行相應操做。html

以上是事件/監聽器、觀察者模式的簡要說明。結合此次的需求理解,當觸發用戶訪問事件,它的觀察者進行處理。觀察者能夠是多個,本例僅作入庫操做。laravel

建立事件/監聽器

app/Providers/EventServiceProvider.php 文件中添加事件/監聽器,以下git

/**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
        'App\Events\UserBrowse' => [
            'App\Listeners\CreateBrowseLog',
            // 其它監聽器
        ],
    ];

添加好以後,執行 php artisan event:generate,會自動建立對應的事件/監聽器。分別建立了 app/Events/UserBrowse.phpapp/Listeners/CreateBrowseLog.php 兩個文件。github

實現代碼

把目光彙集到事件 app/Events/UserBrowse.php 文件,這裏須要接收數據以便後續處理,代碼以下segmentfault

public $ip_addr;
    public $request_url;
    public $city_name;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct($ip_addr, $request_url, $city_name)
    {
        $this->ip_addr = $ip_addr;
        $this->request_url = $request_url;
        $this->city_name = $city_name;
    }

而後是監聽器 app/Listeners/CreateBrowseLog.php,這裏要作的是,將事件中接收到的數據進行入庫操做,代碼以下app

/**
     * Handle the event.
     *
     * @param  UserBrowse $event
     * @return void
     */
    public function handle(UserBrowse $event)
    {
        $log = new \App\Models\BrowseLog();

        $log->ip_addr = $event->ip_addr;
        $log->request_url = $event->request_url;
        $log->city_name = $event->city_name;

        $log->save();
    }

分發事件

最後就是分發事件,修改 app/Http/Middleware/BrowseLog.php 中間件的代碼,修改後以下ide

/**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // 使用事件/監聽器入庫
        event(new UserBrowse($request->getClientIp(), $request->path(), get_city_by_ip(false, 'null')));
        
        return $next($request);
    }

測試以後是沒有問題的。post

結語

此次所作的修改,感官上來看,就是將入庫操做從中間件轉移到監聽器中,實際上的意義遠不止於此。例如同一個事件,能夠分發在不一樣的地方;事件添加了需求,只須要在添加一個監聽器便可;監聽器中也能夠使用隊列等等。測試


參考資料:事件觀察者模式

相關文章
相關標籤/搜索