前言
相信大家都知道,幾乎所有的社區應用都有用戶動態這個部分,用戶可以通過好友動態獲能取到更多感興趣的內容,從而提高社區活躍度和用戶粘性。它的實現相對來講比普通的內容發布要復雜一些,主要體現在內容多樣性上。
為了解決這個問題,我們得把這些不同類型的內容抽象,提取共性,使用相同的結構來處理,開發起來就會簡單很多。
概念抽象
用戶動態,顧名思義,動態的產生,就是一系列事件的歷史記錄,所以首先關注“事件”這個名詞,它有哪些屬性:
我們將用戶動態抽象成只有 4 個基礎屬性的結構,就比較容易實現了:
- description 事件描述- causer_id 或者 user_id 事件觸發者- subject_id 主體 ID- subject_type 主體類型- properties 事件附加屬性- created_at 事件產生時間
而主體部分就是 Laravel 里的 morph relation, 多態關聯。
怎么展示
我們的動態展示需求通常有以下幾種:
我最近正在開發 EasyWeChat 新版網站,其中也有用戶動態,舉例:
xxx 發布了討論 《請問大家怎么使用 xxx》xxx 評論了 xxx 的話題 《請問大家怎么使用 xxx》xxx 回復了 xxx 的評論 “我是按照文檔上 ...”xxx 購買了 《微信開發:自定義菜單的使用》xxx 關注了 xxx...
你會發現,基本上每種動態的寫法都不一樣,所以我們還需要記錄一個 “事件類型” ,比如 “關注”、 “發布”、“回復”、“購買”。
然后我們在 blade 或者其它模板引擎的使用中,就可以 switch ... case 寫法,來應用不同的模板渲染這些樣式,比如 blade 中,我的用法:
@switch($activity->properties['event'] ?? '') @case('discussion.created') ... @break @case('comment.created') ... @break@endswitch
代碼實現
前面我們已經討論完了數據存儲以及展示方面的設計,接著就是怎么實現,如果你比較勤勞,可以原生實現,畢竟上面的實現方法已經描述清晰,寫點代碼實現就搞定了,今天我要推薦的是使用 spatie/laravel-activitylog 來實現:
安裝一直很簡單對吧:
$ composer install spatie/laravel-activitylog -vvv
記錄動態
activity()->log('Look, I logged something');
當然了這種記錄沒意義,幾乎沒有任何有用的信息,所以我們通常的用法應該是這樣:
activity() ->performedOn($anEloquentModel) ->causedBy($user) ->withProperties(['customProperty' => 'customValue']) ->log('Look, I logged something'); $lastLoggedActivity = Activity::all()->last();$lastLoggedActivity->subject; //returns an instance of an eloquent model$lastLoggedActivity->causer; //returns an instance of your user model$lastLoggedActivity->getExtraProperty('customProperty'); //returns 'customValue'$lastLoggedActivity->description; //returns 'Look, I logged something'
方法介紹:
performedOn($model)
設置事件主體,也就是 Eloquent Model 實例causedBy($user)
設置事件觸發者, User 實例withProperties($properties)
上面我們概念里的事件屬性withProperty($key, $value)
事件屬性的單個用法log($description)
事件描述比如,我們要記錄一條,用戶發布了討論:
$discussion = App/Discussion::create([...]);activity()->on($discussion)->withProperty('event', 'discussion.created')->log('發表了話題');
或者用戶注冊時,我要記錄一條動態:
activity()->on($user)->withProperty('event', 'user.created')->log('加入 EasyWeChat');
你會發現我都沒有設置觸發者,因為這個模塊如果你沒設置觸發者默認就是當前登錄用戶。
展示動態
展示動態就是根據條件從數據庫拿出來,這里使用包提供的模型類:Spatie/Activitylog/Models/Activity
use Spatie/Activitylog/Models/Activity;
// 全部動態$activities = Activity::all();// 用戶 ID 為 2 的動態 $activities = Activity::causedBy(User::find(2))->paginate(15);// 以文章 ID 為 13 為主體的動態$activities = Activity::forSubject(Post::find(13))->paginate(15);
接著就是遍歷展示就好了。
一些經驗與技巧
設置一個專門的動態觀察者類來記錄動態
$ ./artisan make:listener UserActivitySubscriber
代碼如下:
<?php namespace App/Listeners;class UserActivitySubscriber{ protected $lisen = [ 'eloquent.created: App/User' => 'onUserCreated', 'eloquent.created: App/Discussion' => 'onDiscussionCreated', ]; public function subscribe($events) { foreach ($this->lisen as $event => $listener) { $events->lisen($event, __CLASS__.'@'.$listener); } } public function onUserCreated($user) { activity()->on($user) ->withProperty('event', 'user.created') ->log('加入 EasyWeChat'); } public function onDiscussionCreated($discussion) { activity()->on($discussion) ->withProperty('event', 'discussion.created')->log('發表了話題'); }}
然后我們去注冊這個訂閱類:
在 App/Providers/EventServiceProvider 中 $subscribe 中注冊這個訂閱類:
/** * @var array */protected $subscribe = [ /App/Listeners/UserActivitySubscriber::class,];
上面我們利用了 Eloquent 模型事件來監聽模型的變化,當各種模型事件創建的時候我們調用對應的方法來記錄動態,所以實現起來非常的方便。
在事件屬性里記錄關鍵信息
看到上面記錄動態的時候你可能會問,只存儲了 ID,這種多態關聯,查詢的時候會壓力很大,比如,我們要將動態顯示為:
安小超 發布了文章 《自定義菜單的使用》
我們如果只是存儲了文章的 id 與類型,我們還需要查詢一次文章表,才能得到標題用于顯示,這樣一個動態列表的話,可能會幾十條 SQL 了,的確是這樣的,我的解決方案是這樣的:
其實我們的用戶動態是不要求 100% 精準的,所以,我如果在記錄時把文章的標題一起存下來是不是就不用再查表了?其實就是,我們在動態列表需要展示的關鍵信息,比如標題這些一起用 withProperties 存起來,這樣就一條 SQL 解決了動態列表問題。
這樣的做法也有弊端,比如文章改了標題的時候,這里就不同步了,當然你也可以在文章修改時來改這個屬性,不過我個人認為沒有多大必要。畢竟動態就是記錄了當時的情況,后來改標題了并沒有什么問題。
OK,用戶動態模塊的開發就分享到這里,如果你有更高級的實現歡迎隨時交流。
關于好友動態部分的實現,根據你的應用量級,以及好友關系的存儲各有不同,大家自己集思廣益即可,大部分都是先查好友關系再查動態,關聯查詢也可以,自己實現吧。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對VeVb武林網的支持。
新聞熱點
疑難解答
圖片精選