歡迎加入QQ討論群258996829
麥子學(xué)院 頭像
蘋果6袋
6
麥子學(xué)院

基于 Laravel 的用戶動態(tài)模塊開發(fā)

發(fā)布時間:2017-09-24 21:57  回復(fù):0  查看:2617   最后回復(fù):2017-09-24 21:57  

本文和大家分享的主要是基于Laravel的用戶動態(tài)模塊開發(fā)相關(guān)內(nèi)容,一起來看看吧,希望對大家學(xué)習(xí)Laravel有所幫助。

  幾乎所有的社區(qū)應(yīng)用都有用戶動態(tài)這個部分,用戶可以通過好友動態(tài)獲能取到更多感興趣的內(nèi)容,從而提高社區(qū)活躍度和用戶粘性。它的實現(xiàn)相對來講比普通的內(nèi)容發(fā)布要復(fù)雜一些,主要體現(xiàn)在內(nèi)容多樣性上。

  為了解決這個問題,我們得把這些不同類型的內(nèi)容抽象,提取共性,使用相同的結(jié)構(gòu)來處理,開發(fā)起來就會簡單很多。

  概念抽象

  用戶動態(tài),顧名思義,動態(tài)的產(chǎn)生,就是一系列 事件 的歷史記錄,所以首先關(guān)注事件 ”這個名詞,它有哪些屬性:

  1. 觸發(fā)者 ,基于社區(qū)所有的事件幾乎都是由用戶觸發(fā)的

  2. 事件主體 ,事件的主體信息,例如“xxx發(fā)布了文章中的 文章。

  3. 事件屬性 ,事件主體不同,所需要的附加信息也不同,比如事件類型。

  4. 發(fā)生時間 ,記錄事件產(chǎn)生的時間,當(dāng)然了在我們的數(shù)據(jù)庫通常記錄了所有數(shù)據(jù)產(chǎn)生的時間。

  我們將用戶動態(tài)抽象成只有 4 個基礎(chǔ)屬性的結(jié)構(gòu),就比較容易實現(xiàn)了:

- description             事件描述

- causer_id 或者 user_id   事件觸發(fā)者

- subject_id               主體 ID

- subject_type            主體類型

- properties              事件附加屬性

- created_at              事件產(chǎn)生時間

  而主體部分就是 Laravel 里的 morph relation, 多態(tài)關(guān)聯(lián)。

  怎么展示

  我們的動態(tài)展示需求通常有以下幾種:

  1. 我的好友的動態(tài)

  2. 某個人的動態(tài),通常是個人中心

  3. 全部動態(tài),比如 Laravel China 首頁的全部動態(tài)

  4. 動態(tài)搜索,比較少見

  我最近正在開發(fā) EasyWeChat 新版網(wǎng)站,其中也有用戶動態(tài),舉例:

  xxx 發(fā)布了討論 《請問大家怎么使用 xxx

  xxx 評論了 xxx 的話題 《請問大家怎么使用 xxx

  xxx 回復(fù)了 xxx 的評論 我是按照文檔上 ...”

  xxx 購買了 《微信開發(fā):自定義菜單的使用》

  xxx 關(guān)注了 xxx

  ...

  你會發(fā)現(xiàn),基本上每種動態(tài)的寫法都不一樣,所以我們還需要記錄一個事件類型,比如 關(guān)注、 發(fā)布、回復(fù)購買。

  然后我們在 blade 或者其它模板引擎的使用中,就可以 switch ... case 寫法,來應(yīng)用不同的模板渲染這些樣式,比如 blade 中,我的用法:

  @switch($activity->properties['event'] ?? '')

  @case('discussion.created')

  ...

  @break

  @case('comment.created')

  ...

  @break@endswitch

  代碼實現(xiàn)

  前面我們已經(jīng)討論完了數(shù)據(jù)存儲以及展示方面的設(shè)計,接著就是怎么實現(xiàn),如果你比較勤勞,可以原生實現(xiàn),畢竟上面的實現(xiàn)方法已經(jīng)描述清晰,寫點代碼實現(xiàn)就搞定了,今天我要推薦的是使用 spatie/laravel-activitylog 來實現(xiàn):

  安裝一直很簡單對吧:

  $ composer install spatie/laravel-activitylog -vvv

  記錄動態(tài)

  activity()->log('Look, I logged something');

  當(dāng)然了這種記錄沒意義,幾乎沒有任何有用的信息,所以我們通常的用法應(yīng)該是這樣:

  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) 設(shè)置事件主體,也就是 Eloquent Model 實例

  · causedBy($user) 設(shè)置事件觸發(fā)者, User 實例

  · withProperties($properties) 上面我們概念里的 事件屬性

  · withProperty($key, $value) 事件屬性的單個用法

  · log($description) 事件描述

  比如,我們要記錄一條,用戶發(fā)布了討論:

  $discussion = App\Discussion::create([...]);

  activity()->on($discussion)

  ->withProperty('event', 'discussion.created')

  ->log('發(fā)表了話題');

  或者用戶注冊時,我要記錄一條動態(tài):

  activity()->on($user)

  ->withProperty('event', 'user.created')

  ->log('加入 EasyWeChat');

  你會發(fā)現(xiàn)我都沒有設(shè)置觸發(fā)者,因為這個模塊如果你沒設(shè)置觸發(fā)者默認(rèn)就是當(dāng)前登錄用戶。

  展示動態(tài)

  展示動態(tài)就是根據(jù)條件從數(shù)據(jù)庫拿出來,這里使用包提供的模型類:Spatie\Activitylog\Models\Activity

  use Spatie\Activitylog\Models\Activity;

  // 全部動態(tài)

  $activities = Activity::all();// 用戶 ID 2 的動態(tài)

  $activities = Activity::causedBy(User::find(2))->paginate(15);// 以文章 ID 13 為主體的動態(tài)

  $activities = Activity::forSubject(Post::find(13))->paginate(15);

  接著就是遍歷展示就好了。

  一些經(jīng)驗與技巧

  設(shè)置一個專門的動態(tài)觀察者類來記錄動態(tài)

  $ ./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('發(fā)表了話題');

  }

  }

  然后我們?nèi)プ赃@個訂閱類:

  在 App\Providers\EventServiceProvider $subscribe 中注冊這個訂閱類:

  /**

  * @var array

  */protected $subscribe = [

  \App\Listeners\UserActivitySubscriber::class,];

  上面我們利用了 Eloquent 模型事件來監(jiān)聽模型的變化,當(dāng)各種模型事件創(chuàng)建的時候我們調(diào)用對應(yīng)的方法來記錄動態(tài),所以實現(xiàn)起來非常的方便。

  在事件屬性里記錄關(guān)鍵信息

  看到上面記錄動態(tài)的時候你可能會問,只存儲了 ID,這種多態(tài)關(guān)聯(lián),查詢的時候會壓力很大,比如,我們要將動態(tài)顯示為:

  安小超 發(fā)布了文章 《自定義菜單的使用》

  我們?nèi)绻皇谴鎯α宋恼碌?/span> id 與類型,我們還需要查詢一次文章表,才能得到標(biāo)題用于顯示,這樣一個動態(tài)列表的話,可能會幾十條 SQL 了,的確是這樣的,我的解決方案是這樣的:

  其實我們的用戶動態(tài)是不要求 100% 精準(zhǔn)的,所以,我如果在記錄時把文章的標(biāo)題一起存下來是不是就不用再查表了?其實就是,我們在動態(tài)列表需要展示的關(guān)鍵信息,比如標(biāo)題這些一起用 withProperties 存起來,這樣就一條 SQL 解決了動態(tài)列表問題。

  這樣的做法也有弊端,比如文章改了標(biāo)題的時候,這里就不同步了,當(dāng)然你也可以在文章修改時來改這個屬性,不過我個人認(rèn)為沒有多大必要。畢竟動態(tài)就是記錄了當(dāng)時的情況,后來改標(biāo)題了并沒有什么問題。

  OK,用戶動態(tài)模塊的開發(fā)就分享到這里,如果你有更高級的實現(xiàn)歡迎隨時交流。

  關(guān)于好友動態(tài)部分的實現(xiàn),根據(jù)你的應(yīng)用量級,以及好友關(guān)系的存儲各有不同,大家自己集思廣益即可,大部分都是先查好友關(guān)系再查動態(tài),關(guān)聯(lián)查詢也可以,自己實現(xiàn)吧。

 

 

來源:PHP / Laravel / 全棧

您還未登錄,請先登錄

熱門帖子

最新帖子

?