最近正在准备设计自己的社区网站,到设计评论这里的时候,引出了很多疑惑,于是记录一下,希望大佬们可以多多提出自己的想法,集思广益。
首先声明一下,我自己的项目不会这么做的,大家应该都没有类似的场景出现,我自己准备做一级评论对应多个回复的模式,不会有递归的方式。
ok,开始正文。
一般我们的个人项目中,评论方式基本是一对一,或者有限的一对多,类似于网易云音乐的评论:
这种设计比较简单。当然还有稍微复杂的类似bbs的有限评论:
ok,接下来探讨一下我们要说的无限极的设计思路。
首先并不推荐这种方式,因为在实际场景中根本不会有这种场景,如果是有限的话,会有更多优秀的解决思路,比如左右值。
我的解决思路是这样的,每一条评论记录除主体内容之外,还记录parent_id,也就是父级评论,当parent_id为0则为主体评论,这样一张表即可解决数据存储的问题。
接下来,我们不能直接把这样的list给前端,因为要考虑到分页的情况,而我们根本不知道每一条主体评论的层级深度。
于是现在出现了两种做法:1.先筛选出几条主体评论,然后依次用ajax取出下面的回复。2.递归。 ajax的就比较基础了,接下来我来说一下递归的方式。
通过递归直接把主体评论与下面对应的回复返回给前端,数据结构如下:
这样前端在展示的时候也可以使用递归(我不会),或者另一种基础的方式,比如我新增一个字段给出每条主体评论的回复层级深度,这样前端使用 foreach(for(foreach())) 即可完成展示工作。
不过这种方式,我能想象,对性能的要求应该不少,谁让是无限极的呢,如果您有更屌的想法欢迎到https://www.litblc.com留言。
示例代码 :
<?php
/**
* Author huaixiu.zhen
* http://litblc.com
* User: litblc
* Date: 2018/3/20
* Time: 15:14
*/
namespace App\Http\Controllers\Home;
use App\Model\Comment;
use App\Model\User;
class CommentController
{
/**
* 得到该图片的所有评论信息
* Author huaixiu.zhen
* http://litblc.com
* @param $imageId
* @return array
*/
public function getAllComments($imageId = 1)
{
$comments = Comment::where('image_id', $imageId)
->whereParentId(0)
->orderBy('created_at')
//分页处理,取出特定几条
->get();
$res = [];
foreach ($comments as $key => $value) {
$comm['id'] = $value->id;
$comm['user_id'] = $value->user_id;
$comm['username'] = $this->getUserName($value->user_id);
$comm['avatar'] = $this->getAvatar($value->user_id);
$comm['comment'] = $value->content;
$comm['created_at'] = $value->created_at;
$comm['son'] = $this->getSonComment($value->id); // 多维数组 所有父级为$value->id的评论
$res[] = $comm;
}
dd($res);
}
/**
* Author huaixiu.zhen
* http://litblc.com
* @param $userId
* @return string
*/
private function getUserName($userId)
{
$user = User::find($userId);
if ($user) {
$userName = $user->name;
} else {
$userName = '用户已注销';
}
return $userName;
}
/**
* Author huaixiu.zhen
* http://litblc.com
* @param $userId
* @return string
*/
private function getAvatar($userId)
{
$user = User::find($userId);
if ($user) {
$avatar = $user->avatar;
} else {
$avatar = 'default.jpg';
}
return $avatar;
}
/**
* 递归得到所有子评论
* Author huaixiu.zhen
* http://litblc.com
* @param $commentId
* @return mixed
*/
private function getSonComment($commentId)
{
$comments = Comment::whereParentId($commentId)
->orderBy('created_at', 'desc')
->get();
$res = [];
if ($comments->count() > 0) {
foreach ($comments as $key => $value) {
$comm['id'] = $value->id;
$comm['user_id'] = $value->user_id;
$comm['username'] = $this->getUserName($value->user_id);
$comm['avatar'] = $this->getAvatar($value->user_id);
$comm['comment'] = $value->content;
$comm['created_at'] = $value->created_at;
$comm['son'] = $this->getSonComment($value->id);
$res[] = $comm;
}
}
return $res;
}
}
/**
* 初始化子用户ID数组
*
* @Author huaixiu.zhen
* http://litblc.com
* @var array
*/
private $userIds = [];
/**
* 迭代获取所有子用户ID
*
* @Author huaixiu.zhen
* http://litblc.com
*
* @param $userId
*
* @return array
*/
private function getSonUserIds($userId)
{
$users = Users::where('partent_id', $userId)
->get(['id']);
if ($users->count() > 0) {
foreach ($users as $value) {
$this->getSonUserIds($value->id);
$this->userIds[] = $value->id;
}
}
return $this->userIds;
}
ok,如果是有限的话就简单很多了,最近刚刚发现一个很吊的思路:参考左右值无限层级存储方法https://segmentfault.com/a/1190000000329012
在消除了递归操作的前提下实现了无限分组,而且查询条件是基于整形数字的比较,效率很高。 但是节点的添加、删除及修改代价较大,将会涉及到表中多方面数据的改动。有兴趣的朋友可以研究一下。