Laravel5.2之Model Observer模型觀察者

說明:本文主要學習下Laravel的Model Observer模型觀察者,把一點點經驗分享出來但願對別人能有幫助。同時,會將開發過程當中的一些截圖和代碼黏上去,提升閱讀效率。php

備註:上一篇文章:Laravel5.2之Redis保存頁面瀏覽量,在開發的時候有個邏輯有點在乎:那篇文章再用Redis保存瀏覽量後,當瀏覽量達到設置的次數後刷到MySQL裏,同時把Redis裏該瀏覽量鍵抹掉,還有Post的內容鍵抹掉,以便下一次請求從MySQL裏請求到新的數據並緩存。研究時,發現能夠使用Model Observer來實現Model的事件變化來自動刷新flush下Redis,我的以爲有點像是定義了一個事件監聽器監聽模型事件同樣。這篇文章就用下Model Observer從新組織下代碼。能夠大概看下上篇文章的基本邏輯laravel

開發環境:Laravel5.1+MAMP+PHP7+MySQL5.5redis

沒有Model Observer邏輯

看下最主要的瀏覽量達到必定量後刷到MySQL裏的邏輯:數據庫

/** * 不一樣用戶訪問,更新緩存中瀏覽次數 * @param $id * @param $ip */
    public function updateCacheViewCount($id, $ip)
    {
        $cacheKey        = 'post:view:'.$id;
        //這裏以Redis哈希類型存儲鍵,就和數組相似,$cacheKey就相似數組名,$ip爲$key.HEXISTS指令判斷$key是否存在$cacheKey中
        if(Redis::command('HEXISTS', [$cacheKey, $ip])){
            //哈希類型指令HINCRBY,就是給$cacheKey[$ip]加上一個值,這裏一次訪問就是1
            $incre_count = Redis::command('HINCRBY', [$cacheKey, $ip, 1]);
            //redis中這個存儲瀏覽量的值達到30後,就往MySQL裏刷下,這樣就不須要每一次瀏覽,來一次query,效率不高
            if($incre_count == self::postViewLimit){
                $this->updateModelViewCount($id, $incre_count);
                //本篇post,redis中瀏覽量刷進MySQL後,把該篇post的瀏覽量鍵抹掉,等着下一次請求從新開始計數

                Redis::command('HDEL', [$cacheKey, $ip]);//瀏覽量這個刪除key操做也能夠在Model Observer裏作,不過要把Redis改爲Cache的方法,這裏就不寫了

                //同時,抹掉post內容的緩存鍵,這樣就不用等10分鐘後再更新view_count了,
                //如該篇post在100秒內就達到了30訪問量,就在3分鐘時更新下MySQL,並把緩存抹掉,下一次請求就從MySQL中請求到最新的view_count,
                //固然,100秒內view_count仍是緩存的舊數據,極端狀況300秒內都是舊數據,而緩存裏已經有了29個新增訪問量
                //實際上也能夠這樣作:在緩存post的時候,能夠把view_count單獨拿出來存入鍵值裏如single_view_count,每一次都是給這個值加1,而後把這個值傳入視圖裏
                //或者平衡設置下postViewLimit和ipExpireSec這兩個參數,對於view_count這種實時性要求不高的能夠這樣作來着
                //加上laravel前綴,由於Cache::remember會自動在每個key前加上laravel前綴,能夠看cache.php中這個字段:'prefix' => 'laravel'
               
                //使用Model Observer後註銷這句
// Redis::command('DEL', ['laravel:post:cache:'.$id]);//利用Model Observer,這裏就不用刷掉這個key,邏輯可在模型觀察器裏作
            }
        }else{
            //哈希類型指令HSET,和數組相似,就像$cacheKey[$ip] = 1;
            Redis::command('HSET', [$cacheKey, $ip, '1']);
        }
    }

這裏在瀏覽量達到self::postViewLimit後把view_count刷到MySQL裏並刷新下Redis,使用這個邏輯:數組

Redis::command('DEL', ['laravel:post:cache:'.$id]);

有Model Observer邏輯

能夠註冊一個模型觀察者,在觀察者類裏作一些模型對應事件的邏輯,這裏就是刷掉一些緩存鍵值。在app/Observers/PostObserver.php(模型觀察類放在哪裏能夠自定義)裏:緩存

<?php
/** * Created by PhpStorm. * User: liuxiang * Date: 16/6/19 * Time: 17:11 */
namespace App\Observers;

use App\Post;
use Cache;

class PostObserver
{
    public function saved()
    {
        //原來邏輯是:view_count達到30次後,把view_count刷進MySQL裏,同時刪掉緩存在Redis裏的$post整個模型的內容.
        //這裏觀察saved事件,當把save_count值save()進MySQL後,就在這裏刷下redis這個post的key.
        //在把內容緩存進Redis裏,加上tag標籤以便於識別和分別操做,我的以爲這是一個好習慣.
        Cache::tags([Post::table(), 'model'])->flush();
    }

    public function saving()
    {

    }

    public function deleted()
    {

    }
}

這裏使用flush()方法只刷指定tag的緩存鍵,省得把別的key也刷了。這裏打的標籤實際上是:['posts', 'model'],Post::table()定義返回Model關聯的表名,看下Post這個Model:app

class Post extends Model
{
    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    public function comments()
    {
        return $this->hasMany(Comment::class);
    }

    public function tags()
    {
        return $this->belongsToMany(Tag::class)->withTimestamps();
    }

    /** * 在boot()方法裏註冊下模型觀察類 * boot()和observe()方法都是從Model類繼承來的 * 主要是observe()來註冊模型觀察類,能夠用Post::observe(new PostObserve()) * 並放在代碼邏輯其餘地方如路由都行,這裏放在這個Post Model的boot()方法裏自啓動。 */
    public static function boot()
    {
        parent::boot(); // TODO: Change the autogenerated stub
        static::observe(new PostObserver());
    }

    /** * 返回該Model關聯的表 * @return string */
    public static function table()
    {
        $model = new static;
        //調用Model類的public function getTable()
        return $model->getTable();
    }
}

還有別忘了在PostController裏緩存Post Model的時候打上標籤:post

public function showPostCache(Request $request, $id)
    {
        //Redis緩存中沒有該post,則從數據庫中取值,並存入Redis中,該鍵值key='post:cache'.$id生命時間10分鐘
        //在把內容緩存進Redis裏,加上tag標籤以便於識別和分別操做,我的以爲這是一個好習慣實際上.這裏加個該post對應的表名標籤,保持惟一性
        $post = Cache::tags([Post::table(), 'model'])->remember('post:cache:'.$id, self::modelCacheExpires, function () use ($id) {
            return Post::whereId($id)->first();
        });

        //獲取客戶端IP
        $ip   = $request->ip();
        //觸發瀏覽量計數器事件
        event(new PostViewCount($post, $ip));

        return view('browse.post', compact('post'));
    }

如今測試下當view_count被刷進MySQL時,即saved()事件後,模型觀察類有沒有把['posts', 'model']這個標籤的鍵給刷掉。這裏設置下:學習

class PostEventListener
{
    /** * 同一post最大訪問次數,再刷新數據庫 */
    const postViewLimit = 3;

    ...    
}

不一樣IP刷下3次後緩存的Post Model有沒有被刷掉。
第一個IP訪問時Post Model已經被刷到Redis裏了:
第三個IP訪問時,Post Model已經被從Redis裏刷掉了:
it is working!!!
這證實了view_count被save()進MySQL時,模型觀察類邏輯起做用了。固然第四個IP訪問後頁面就會顯示最新的瀏覽量了。測試

模型觀察者這個功能能作不少事情,好比Model Update模型更新時發個通知。或者就像一篇文章的內容從新編輯保存後,把原來緩存內的該篇文章內容刷新下,這樣下一個請求來的時候讀的就是最新的文章內容了。做者之後會繼續研究研究,發現挺好玩的東西到時候分享出來吧。

總結:本篇文章主要學了下Laravel的Model Observer模型觀察者,發現這個功能也能使代碼結構更清晰,以爲挺好的。最近一直在瞎研究,有遇到好玩的再分享出來吧。

相關文章
相關標籤/搜索