說明:本文主要學習下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.5
redis
看下最主要的瀏覽量達到必定量後刷到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]);
能夠註冊一個模型觀察者,在觀察者類裏作一些模型對應事件的邏輯,這裏就是刷掉一些緩存鍵值。在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模型觀察者,發現這個功能也能使代碼結構更清晰,以爲挺好的。最近一直在瞎研究,有遇到好玩的再分享出來吧。