关于无限极(类似楼盖楼)评论回复系统的想法与构思

in web技术 with 0 comment 访问: 2,024 次

缘起

最近正在准备设计自己的社区网站,到设计评论这里的时候,引出了很多疑惑,于是记录一下,希望大佬们可以多多提出自己的想法,集思广益。

首先声明一下,我自己的项目不会这么做的,大家应该都没有类似的场景出现,我自己准备做一级评论对应多个回复的模式,不会有递归的方式。

ok,开始正文。

正文

一般我们的个人项目中,评论方式基本是一对一,或者有限的一对多,类似于网易云音乐的评论:

image2018-3-23 15_26_13.png

这种设计比较简单。当然还有稍微复杂的类似bbs的有限评论:

image2018-3-23 15_27_43.png

ok,接下来探讨一下我们要说的无限极的设计思路。

首先并不推荐这种方式,因为在实际场景中根本不会有这种场景,如果是有限的话,会有更多优秀的解决思路,比如左右值。

我的解决思路是这样的,每一条评论记录除主体内容之外,还记录parent_id,也就是父级评论,当parent_id为0则为主体评论,这样一张表即可解决数据存储的问题。

image2018-3-23 15_32_9.png

接下来,我们不能直接把这样的list给前端,因为要考虑到分页的情况,而我们根本不知道每一条主体评论的层级深度。

于是现在出现了两种做法:1.先筛选出几条主体评论,然后依次用ajax取出下面的回复。2.递归。
ajax的就比较基础了,接下来我来说一下递归的方式。

通过递归直接把主体评论与下面对应的回复返回给前端,数据结构如下:

image2018-3-23 15_41_53.png

这样前端在展示的时候也可以使用递归(我不会),或者另一种基础的方式,比如我新增一个字段给出每条主体评论的回复层级深度,这样前端使用 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

在消除了递归操作的前提下实现了无限分组,而且查询条件是基于整形数字的比较,效率很高。
但是节点的添加、删除及修改代价较大,将会涉及到表中多方面数据的改动。有兴趣的朋友可以研究一下。

赞赏支持
Responses