基于Laravel實(shí)現(xiàn)的用戶動(dòng)態(tài)模塊開發(fā)
前言
相信大家都知道,幾乎所有的社區(qū)應(yīng)用都有用戶動(dòng)態(tài)這個(gè)部分,用戶可以通過好友動(dòng)態(tài)獲能取到更多感興趣的內(nèi)容,從而提高社區(qū)活躍度和用戶粘性。它的實(shí)現(xiàn)相對(duì)來講比普通的內(nèi)容發(fā)布要復(fù)雜一些,主要體現(xiàn)在內(nèi)容多樣性上。
為了解決這個(gè)問題,我們得把這些不同類型的內(nèi)容抽象,提取共性,使用相同的結(jié)構(gòu)來處理,開發(fā)起來就會(huì)簡(jiǎn)單很多。
概念抽象
用戶動(dòng)態(tài),顧名思義,動(dòng)態(tài)的產(chǎn)生,就是一系列事件的歷史記錄,所以首先關(guān)注“事件”這個(gè)名詞,它有哪些屬性:
- 觸發(fā)者,基于社區(qū)所有的事件幾乎都是由用戶觸發(fā)的
- 事件主體,事件的主體信息,例如“xxx發(fā)布了文章” 中的 “文章”。
- 事件屬性,事件主體不同,所需要的附加信息也不同,比如事件類型。
- 發(fā)生時(shí)間,記錄事件產(chǎn)生的時(shí)間,當(dāng)然了在我們的數(shù)據(jù)庫通常記錄了所有數(shù)據(jù)產(chǎn)生的時(shí)間。
我們將用戶動(dòng)態(tài)抽象成只有 4 個(gè)基礎(chǔ)屬性的結(jié)構(gòu),就比較容易實(shí)現(xiàn)了:
- description 事件描述 - causer_id 或者 user_id 事件觸發(fā)者 - subject_id 主體 ID - subject_type 主體類型 - properties 事件附加屬性 - created_at 事件產(chǎn)生時(shí)間
而主體部分就是 Laravel 里的 morph relation, 多態(tài)關(guān)聯(lián)。
怎么展示
我們的動(dòng)態(tài)展示需求通常有以下幾種:
- 我的好友的動(dòng)態(tài)
- 某個(gè)人的動(dòng)態(tài),通常是個(gè)人中心
- 全部動(dòng)態(tài),比如 Laravel China 首頁的全部動(dòng)態(tài)
- 動(dòng)態(tài)搜索,比較少見
我最近正在開發(fā) EasyWeChat 新版網(wǎng)站,其中也有用戶動(dòng)態(tài),舉例:
xxx 發(fā)布了討論 《請(qǐng)問大家怎么使用 xxx》 xxx 評(píng)論了 xxx 的話題 《請(qǐng)問大家怎么使用 xxx》 xxx 回復(fù)了 xxx 的評(píng)論 “我是按照文檔上 ...” xxx 購(gòu)買了 《微信開發(fā):自定義菜單的使用》 xxx 關(guān)注了 xxx ...
你會(huì)發(fā)現(xiàn),基本上每種動(dòng)態(tài)的寫法都不一樣,所以我們還需要記錄一個(gè) “事件類型” ,比如 “關(guān)注”、 “發(fā)布”、“回復(fù)”、“購(gòu)買”。
然后我們?cè)?blade 或者其它模板引擎的使用中,就可以 switch ... case 寫法,來應(yīng)用不同的模板渲染這些樣式,比如 blade 中,我的用法:
@switch($activity->properties['event'] ?? '') @case('discussion.created') ... @break @case('comment.created') ... @break @endswitch
代碼實(shí)現(xiàn)
前面我們已經(jīng)討論完了數(shù)據(jù)存儲(chǔ)以及展示方面的設(shè)計(jì),接著就是怎么實(shí)現(xiàn),如果你比較勤勞,可以原生實(shí)現(xiàn),畢竟上面的實(shí)現(xiàn)方法已經(jīng)描述清晰,寫點(diǎn)代碼實(shí)現(xiàn)就搞定了,今天我要推薦的是使用 spatie/laravel-activitylog 來實(shí)現(xiàn):
安裝一直很簡(jiǎn)單對(duì)吧:
$ composer install spatie/laravel-activitylog -vvv
記錄動(dòng)態(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 實(shí)例causedBy($user)
設(shè)置事件觸發(fā)者, User 實(shí)例withProperties($properties)
上面我們概念里的事件屬性withProperty($key, $value)
事件屬性的單個(gè)用法log($description)
事件描述
比如,我們要記錄一條,用戶發(fā)布了討論:
$discussion = App\Discussion::create([...]); activity()->on($discussion) ->withProperty('event', 'discussion.created') ->log('發(fā)表了話題');
或者用戶注冊(cè)時(shí),我要記錄一條動(dòng)態(tài):
activity()->on($user) ->withProperty('event', 'user.created') ->log('加入 EasyWeChat');
你會(huì)發(fā)現(xiàn)我都沒有設(shè)置觸發(fā)者,因?yàn)檫@個(gè)模塊如果你沒設(shè)置觸發(fā)者默認(rèn)就是當(dāng)前登錄用戶。
展示動(dòng)態(tài)
展示動(dòng)態(tài)就是根據(jù)條件從數(shù)據(jù)庫拿出來,這里使用包提供的模型類:Spatie\Activitylog\Models\Activity
use Spatie\Activitylog\Models\Activity;
// 全部動(dòng)態(tài) $activities = Activity::all(); // 用戶 ID 為 2 的動(dòng)態(tài) $activities = Activity::causedBy(User::find(2))->paginate(15); // 以文章 ID 為 13 為主體的動(dòng)態(tài) $activities = Activity::forSubject(Post::find(13))->paginate(15);
接著就是遍歷展示就好了。
一些經(jīng)驗(yàn)與技巧
設(shè)置一個(gè)專門的動(dòng)態(tài)觀察者類來記錄動(dòng)態(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)プ?cè)這個(gè)訂閱類:
在 App\Providers\EventServiceProvider 中 $subscribe 中注冊(cè)這個(gè)訂閱類:
/** * @var array */ protected $subscribe = [ \App\Listeners\UserActivitySubscriber::class, ];
上面我們利用了 Eloquent 模型事件來監(jiān)聽模型的變化,當(dāng)各種模型事件創(chuàng)建的時(shí)候我們調(diào)用對(duì)應(yīng)的方法來記錄動(dòng)態(tài),所以實(shí)現(xiàn)起來非常的方便。
在事件屬性里記錄關(guān)鍵信息
看到上面記錄動(dòng)態(tài)的時(shí)候你可能會(huì)問,只存儲(chǔ)了 ID,這種多態(tài)關(guān)聯(lián),查詢的時(shí)候會(huì)壓力很大,比如,我們要將動(dòng)態(tài)顯示為:
安小超 發(fā)布了文章 《自定義菜單的使用》
我們?nèi)绻皇谴鎯?chǔ)了文章的 id 與類型,我們還需要查詢一次文章表,才能得到標(biāo)題用于顯示,這樣一個(gè)動(dòng)態(tài)列表的話,可能會(huì)幾十條 SQL 了,的確是這樣的,我的解決方案是這樣的:
其實(shí)我們的用戶動(dòng)態(tài)是不要求 100% 精準(zhǔn)的,所以,我如果在記錄時(shí)把文章的標(biāo)題一起存下來是不是就不用再查表了?其實(shí)就是,我們?cè)趧?dòng)態(tài)列表需要展示的關(guān)鍵信息,比如標(biāo)題這些一起用 withProperties 存起來,這樣就一條 SQL 解決了動(dòng)態(tài)列表問題。
這樣的做法也有弊端,比如文章改了標(biāo)題的時(shí)候,這里就不同步了,當(dāng)然你也可以在文章修改時(shí)來改這個(gè)屬性,不過我個(gè)人認(rèn)為沒有多大必要。畢竟動(dòng)態(tài)就是記錄了當(dāng)時(shí)的情況,后來改標(biāo)題了并沒有什么問題。
OK,用戶動(dòng)態(tài)模塊的開發(fā)就分享到這里,如果你有更高級(jí)的實(shí)現(xiàn)歡迎隨時(shí)交流。
關(guān)于好友動(dòng)態(tài)部分的實(shí)現(xiàn),根據(jù)你的應(yīng)用量級(jí),以及好友關(guān)系的存儲(chǔ)各有不同,大家自己集思廣益即可,大部分都是先查好友關(guān)系再查動(dòng)態(tài),關(guān)聯(lián)查詢也可以,自己實(shí)現(xiàn)吧。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
- Laravel實(shí)現(xiàn)用戶注冊(cè)和登錄
- Laravel 5框架學(xué)習(xí)之用戶認(rèn)證
- Laravel重寫用戶登錄簡(jiǎn)單示例
- laravel5.2實(shí)現(xiàn)區(qū)分前后臺(tái)用戶登錄的方法
- Laravel框架用戶登陸身份驗(yàn)證實(shí)現(xiàn)方法詳解
- Laravel實(shí)現(xiàn)用戶多字段認(rèn)證的解決方法
- 通過修改Laravel Auth使用salt和password進(jìn)行認(rèn)證用戶詳解
- Laravel多用戶認(rèn)證系統(tǒng)示例詳解
- 詳解用vue.js和laravel實(shí)現(xiàn)微信授權(quán)登陸
- Laravel用戶授權(quán)系統(tǒng)的使用方法示例
相關(guān)文章
Thinkphp5+Redis實(shí)現(xiàn)商品秒殺代碼實(shí)例講解
這篇文章主要介紹了Thinkphp5+Redis實(shí)現(xiàn)商品秒殺代碼實(shí)例講解,代碼和步驟講解的很清楚,有需要的同學(xué)可以借鑒參考下2020-12-12PHP實(shí)現(xiàn)字母數(shù)字混合驗(yàn)證碼功能
PHP實(shí)現(xiàn)字母數(shù)字混合驗(yàn)證碼,支持自定義驗(yàn)證碼、驗(yàn)證碼圖片、寬度、高度、個(gè)數(shù)、背景圖片,本文給大家分享實(shí)例代碼,感興趣的朋友跟隨小編一起看看吧2019-07-07Yii框架視圖、視圖布局、視圖數(shù)據(jù)塊操作示例
這篇文章主要介紹了Yii框架視圖、視圖布局、視圖數(shù)據(jù)塊操作,結(jié)合實(shí)例形式分析了Yii框架相關(guān)的視圖、布局、控制器及數(shù)據(jù)相關(guān)操作技巧,需要的朋友可以參考下2019-10-10phpstudy2018升級(jí)MySQL5.5為5.7教程(圖文)
這篇文章主要介紹了phpstudy2018升級(jí)MySQL5.5為5.7教程(圖文),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-10-10ecshop適應(yīng)在PHP7的修改方法解決報(bào)錯(cuò)的實(shí)現(xiàn)
下面小編就為大家?guī)硪黄猠cshop適應(yīng)在PHP7的修改方法解決報(bào)錯(cuò)的實(shí)現(xiàn)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11ThinkPHP5框架實(shí)現(xiàn)簡(jiǎn)單的批量查詢功能示例
這篇文章主要介紹了ThinkPHP5框架實(shí)現(xiàn)簡(jiǎn)單的批量查詢功能,結(jié)合實(shí)例形式分析了thinkPHP5框架使用原生SQL語句查詢、批量查詢、快速查詢、聚合查詢等操作實(shí)現(xiàn)技巧,需要的朋友可以參考下2018-06-06PHP 對(duì)象接口簡(jiǎn)單實(shí)現(xiàn)方法示例
這篇文章主要介紹了PHP 對(duì)象接口,結(jié)合實(shí)例形式簡(jiǎn)單分析了PHP面向?qū)ο蟪绦蛟O(shè)計(jì)中接口的基本概念、功能、實(shí)現(xiàn)方法及操作注意事項(xiàng),需要的朋友可以參考下2020-04-04詳解將數(shù)據(jù)從Laravel傳送到vue的四種方式
這篇文章主要介紹了詳解將數(shù)據(jù)從Laravel傳送到vue的四種方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10