php表設(shè)計(jì)實(shí)現(xiàn)短視頻評(píng)論區(qū)完整功能
前言
現(xiàn)如今,不管是哪種類型的應(yīng)用,評(píng)論區(qū)都少不了。從工具類的到媒體信息流類的,評(píng)論留言都是最基本的互動(dòng)環(huán)節(jié)。比如抖音短視頻下,針對(duì)視頻每個(gè)用戶都可以發(fā)表自己的觀點(diǎn);而針對(duì)用戶的評(píng)論,其他的用戶又可以對(duì)其進(jìn)行評(píng)論,依次回復(fù)下去。
那么,一個(gè)視頻的評(píng)論回復(fù)的表如何設(shè)計(jì)?功能如何實(shí)現(xiàn)呢?如標(biāo)題,這里是用一張表完成,但是在我完成功能后發(fā)現(xiàn)拆成兩個(gè)張更合適(評(píng)論表和回復(fù)表),這個(gè)后面已經(jīng)改了,最后也會(huì)說(shuō)一下。
效果
頁(yè)面上展示是,視頻下分頁(yè)展示第一級(jí)的評(píng)論列表,評(píng)論下的評(píng)論是進(jìn)行折疊,點(diǎn)擊“查看全部”分頁(yè)顯示所有層級(jí)的評(píng)論。一張表的設(shè)計(jì)下,評(píng)論下的評(píng)論下……的評(píng)論是通過(guò)關(guān)聯(lián)上一級(jí)主鍵的,也就是遞歸的方式。
但是下面的是只要是對(duì)評(píng)論進(jìn)行評(píng)論都放在第一級(jí)的評(píng)論下,而遞歸是樹(shù)形結(jié)構(gòu)。雖然也能通過(guò)對(duì)樹(shù)形結(jié)構(gòu)數(shù)據(jù)處理拉伸到二季下,但是在底下評(píng)論特別多的情況就會(huì)體驗(yàn)特別差。所以針對(duì)這個(gè)我對(duì)表格加了一個(gè)面包屑字段,表結(jié)構(gòu)如下,然后再分次完成評(píng)論數(shù)據(jù)的如何添加,按頁(yè)面方式查詢的。
表結(jié)構(gòu)
CREATE TABLE `short_video_comment` ( `id` int(11) NOT NULL AUTO_INCREMENT, `pid` int(11) DEFAULT '0' COMMENT '父級(jí)ID', `crumbs` json DEFAULT NULL COMMENT '面包屑', `video_id` int(11) DEFAULT '0', `user_id` int(11) DEFAULT '0', `commented_user_id` int(11) DEFAULT '0' COMMENT '被評(píng)論者用戶ID', `is_pubisher` tinyint(1) DEFAULT '0' COMMENT '是否作者', `content` varchar(255) DEFAULT '' COMMENT '評(píng)論', `state` int(1) DEFAULT '1' COMMENT '1. 顯示 0. 隱藏', `like_count` int(11) DEFAULT '0' COMMENT '點(diǎn)贊數(shù)', `create_time` int(11) DEFAULT '0' COMMENT '創(chuàng)建時(shí)間', `delete_time` int(11) DEFAULT '0' COMMENT '刪除時(shí)間', `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時(shí)間', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=282 DEFAULT CHARSET=utf8mb4 COMMENT='用戶評(píng)論記錄表';
如上圖的 “crumbs” 字段是一個(gè)數(shù)組方式的json,也就是添加時(shí)會(huì)記錄當(dāng)前評(píng)論的關(guān)系鏈,從最頂層ID到最近的上一級(jí)。而實(shí)現(xiàn)分頁(yè)顯示第二級(jí)下的所有評(píng)論,只需要把 “crumbs” 索引為1的pid作為查詢條件就能找到該id下的所有評(píng)論,如下是查詢二級(jí)評(píng)論ID為285的所有評(píng)論列表。
select * from short_video_comment where json_extract(crumbs, "$[1]") = 285
而對(duì)于關(guān)于crumbs如何存入和誰(shuí)回復(fù)誰(shuí),就只需要在評(píng)論添加的時(shí)候,對(duì)上一級(jí)評(píng)論ID進(jìn)行遞歸查詢所有上級(jí)ID放入 "crumbs", 被回復(fù)者就更好辦了,查詢上一級(jí)評(píng)論的評(píng)論者ID(user_id),放入當(dāng)前評(píng)論記錄的 "commented_user_id",展示的時(shí)候只需要關(guān)聯(lián)一下用戶信息表就可以了,接下來(lái)就是業(yè)務(wù)代碼演示了。
代碼演示
▲評(píng)論添加
public static function commentAdd($videoInfo, $userId, $content, $commentInfo = []) { $commentId = 0; $videoId = $videoInfo['id'] ?? 0; $publisherId = $videoInfo['user_id'] ?? 0; try { $crumbs = [0]; if ($commentInfo) { $pid = $commentInfo['id'] ?? 0; $insert['commented_user_id'] = $commentInfo['user_id'] ?? 0; $insert['pid'] = $pid; $crumbs = ShortVideoComment::getCrumbs($pid); } $insert['video_id'] = $videoId; $insert['user_id'] = $userId; $insert['is_pubisher'] = $userId == $publisherId ? 1 : 0; $insert['content'] = $content; $insert['state'] = ShortVideoComment::STATE['SHOW']; $insert['create_time'] = time(); $insert['crumbs'] = json_encode($crumbs); $commentId = ShortVideoComment::insertGetId($insert); if ($commentId && $videoId) { $map[] = ['id', '=', $videoId]; ShortVideoModel::where($map)->setInc('comment_count'); $userId && self::setRating(6, $userId, $videoId); } } catch (\Exception $e) { $preFileName = str::snake(__FUNCTION__); $path = self::getClassName(); write_log("msg:" . $e->getMessage(), $preFileName . "_error", $path); } return $commentId; }
▲獲取面包屑
public static function getCrumbs($cateId = 0, &$ids = []) { $idArr = array_merge((array)$cateId, $ids); $info = self::where('id', $cateId)->find(); if ($info['pid'] != 0) { $idArr = self::getCrumbs($info['pid'], $idArr); } else { array_unshift($idArr, 0); } return $idArr; }
▲數(shù)據(jù)查詢
public static function getList($map, $page = 1, $size = 30, $pid = 0) { $where[] = ['delete_time', '=', 0]; $where[] = ['state', '=', self::STATE['SHOW']]; $map = array_merge($where, $map); $field = ['id,crumbs,pid,video_id,user_id,commented_user_id,content']; $queryObj = self::field($field) ->with([ 'user' => function ($query) { $query->withField('id, nickname, avatar, mobile'); }, 'commented_user' => function ($query) { $query->withField('id, nickname, avatar, mobile'); } ]) ->where($map); $pid && $queryObj->whereRaw("JSON_EXTRACT(`crumbs` ,'$[1]') = $pid"); $list = $queryObj->page($page, $size) ->order('like_count desc') ->select(); return $list; }
寫在最后
以上是初版時(shí)候根據(jù)業(yè)務(wù)設(shè)計(jì)的表格,后來(lái)的評(píng)論區(qū)完全仿照某音,所以也就對(duì)表格進(jìn)行了拆分。分成了評(píng)論表和回復(fù)表,只要是對(duì)評(píng)論進(jìn)行評(píng)論就是回復(fù),這樣在后面數(shù)據(jù)龐大的時(shí)候,性能會(huì)更好一點(diǎn)。但是如何是前期設(shè)計(jì)的就是一張表,而迭代的時(shí)候也要有某音評(píng)論的效果,可以作為解決方法嘗試滴,更多關(guān)于php短視頻評(píng)論區(qū)功能的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
golang 調(diào)用 php7詳解及實(shí)例
這篇文章主要介紹了golang 調(diào)用 php7詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-01-01PHP開(kāi)發(fā)實(shí)現(xiàn)微信退款功能示例
這篇文章主要介紹了PHP開(kāi)發(fā)實(shí)現(xiàn)微信退款功能的方法,涉及php針對(duì)微信接口的相關(guān)調(diào)用操作技巧,需要的朋友可以參考下2017-11-11Zend?Framework框架等常用php框架中存在的問(wèn)題
這篇文章主要介紹了Zend?Framework框架等常用php框架中存在的問(wèn)題2008-01-01PHP利用ThinkPHP6完整實(shí)現(xiàn)用戶分頁(yè)功能
分頁(yè)功能在Web開(kāi)發(fā)中是一個(gè)非常常見(jiàn)的需求,特別是在處理大量數(shù)據(jù)時(shí),為了提高用戶體驗(yàn)和性能,將數(shù)據(jù)分頁(yè)展示是必不可少的,ThinkPHP6作為一款流行的PHP框架,自帶了強(qiáng)大的分頁(yè)功能,本文將詳細(xì)介紹如何使用ThinkPHP6實(shí)現(xiàn)分頁(yè)功能,需要的朋友可以參考下2023-12-12php漏洞之跨網(wǎng)站請(qǐng)求偽造與防止偽造方法
今天我來(lái)給大家介紹在php中跨網(wǎng)站請(qǐng)求偽造的實(shí)現(xiàn)方法與最后我們些常用的防止偽造的具體操作方法,有需要了解的朋友可進(jìn)入?yún)⒖?/div> 2013-08-08php通過(guò)文件頭檢測(cè)文件類型通用代碼類(zip,rar等)
在做web應(yīng)用時(shí)候,通過(guò)web擴(kuò)展名判斷上存文件類型,這個(gè)是我們常使用的。2010-10-10php+Ajax無(wú)刷新驗(yàn)證用戶名操作實(shí)例詳解
這篇文章主要介紹了php+Ajax無(wú)刷新驗(yàn)證用戶名操作,簡(jiǎn)單介紹了ajax的原理并結(jié)合實(shí)例形式分析了php結(jié)合ajax無(wú)刷新驗(yàn)證用戶名相關(guān)操作技巧,需要的朋友可以參考下2019-03-03關(guān)于Appserv無(wú)法打開(kāi)localhost問(wèn)題的解決方法
安裝了Appserv時(shí),無(wú)法打開(kāi)http://localhost或是http://127.0.0.1 下面的具體的解決方法,大家可以參考下。多注意看下端口占用問(wèn)題。2009-10-10php實(shí)現(xiàn)的Curl封裝類Curl.class.php用法實(shí)例分析
這篇文章主要介紹了php實(shí)現(xiàn)的Curl封裝類Curl.class.php用法,以完整實(shí)例形式較為詳細(xì)的分析了Curl封裝類的定義及相關(guān)使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09最新評(píng)論