一、简要

  第一次做这种设计,当然有许多不足,希望多多指出。

  评论盖楼,就是每条评论一个楼层,而楼层里面可以嵌套很多引用的评论,直接上图

  

  A:牛什么牛(见图 Top4)

  B回复A:好牛啊。(所以这里就嵌套了A的内容,见图Top3)

  C回复B:多谢。(这里同样嵌套B的内容以及B引用的内容,见图Top2)

二、数据库设计

  2.1、评论表设计的sql语句  

 CREATE TABLE `comment` (
      `id_comment` int(11) NOT NULL AUTO_INCREMENT COMMENT '评论ID',
      `id_at` int(11) NOT NULL DEFAULT '' COMMENT '文章Id',
      `id_wx_from` int(11) NOT NULL DEFAULT '' COMMENT '发布者的ID',
      `content` longtext COMMENT '评论内容',
      `time_create` int(11) NOT NULL DEFAULT '' COMMENT '加入时间',
      `path` varchar(255) DEFAULT NULL COMMENT '回复的ID路径:1/2/3/5',
      `num_praise` int(11) NOT NULL DEFAULT '' COMMENT '点赞次数',
      `status` tinyint(4) NOT NULL DEFAULT '' COMMENT '状态',
      `re_comment_id` int(11) NOT NULL DEFAULT '' COMMENT '引用的回复Id',
      `like_ids` longtext COMMENT '点赞用户Ids',
      PRIMARY KEY (`id_comment`)
    ) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8;

  

  2.2、评论表的视图 

    

 CREATE VIEW `view_all_comment` AS
      select `c`.`id_comment` AS `commentid`,`c`.`id_wx_from` AS `fromid`,
`u`.`username` AS `fromname`,`u`.`cover` AS `fromcover`,
`c`.`content` AS `content`,`u2`.`id_wx` AS `originid`,
`u2`.`username` AS `originname`,`u2`.`cover` AS `origincover`,
`c2`.`content` AS `origincontent`,
`c`.`time_create` AS `time`,
`c`.`status` AS `status`,`c`.`path` AS `path`,`c`.`num_praise` AS `num_praise`,`c`.`like_ids` AS `like_ids`,`p`.`id_at` AS `id_at`,`p`.`title` AS `title`
      from ((((`comment` `c`
      left join `wx_user` `u` on((`c`.`id_wx_from` = `u`.`id_wx`)))
      left join `article` `p` on((`c`.`id_at` = `p`.`id_at`)))
      left join `comment` `c2` on((`c`.`re_comment_id` = `c2`.`id_comment`))) left join `wx_user` `u2` on((`c2`.`id_wx_from` = `u2`.`id_wx`)))
      order by `c`.`time_create` ;

 

    视图需要注意的是:分别连接一次评论表和两次用户表,是为了获取评论和被评论的内容、发布者和接受者的用户信息。此处为了方便程序读取信息,数据库设计知识尚浅,不知是否妥当。

    

三、评论读取接口(PHP+Yii2)

  3.1、前端需要的接口格式

 [{
name: '阿萨德',
headPic:require('../../assets/action.jpg'),
like: 7633,
content: '感谢撒发生的分里卡享哈哈阿萨德里卡多巴拉巴享哈哈阿萨德里卡多巴拉巴享哈哈阿萨德里卡多巴拉巴多巴拉巴拉',
time: '2017-06-20',
oldComment: []
}, {
name: '蒂法',
headPic:require('../../assets/action.jpg'),
like: 134,
content: '感谢楼主分享大事发生',
time: '2017-06-20',
oldComment: [{
name: 'CHOWCHIHANG',
comment: '大夫敢死队风格对方是个豆腐干地方供电所覆盖豆腐干受到广泛的斯蒂芬豆腐干斯蒂芬。'
}, {
name: 'CHOWCHIHANG',
comment: '大夫敢死队风格对方是个豆腐干地方供电所覆盖豆腐干受到广泛的斯蒂芬豆腐干斯蒂芬。'
}, {
name: 'CHOWCHIHANG',
comment: '大夫敢死队风格对方是个豆腐干地方供电所覆盖豆腐干受到广泛的斯蒂芬豆腐干斯蒂芬。'
}, {
name: 'CHOWCHIHANG',
comment: '大夫敢死队风格对方是个豆腐干地方供电所覆盖豆腐干受到广泛的斯蒂芬豆腐干斯蒂芬。'
}, {
name: 'CHOWCHIHANG',
comment: '大夫敢死队风格对方是个豆腐干地方供电所覆盖豆腐干受到广泛的斯蒂芬豆腐干斯蒂芬。'
}, {
name: 'CHOWCHIHANG',
comment: '大夫敢死队风格对方是个豆腐干地方供电所覆盖豆腐干受到广泛的斯蒂芬豆腐干斯蒂芬。'
}]
}]

  3.2、获取全部评论的接口以及数据封装 

  /**
* 【根据文章Id获取更多评论(分页获取)】
* 20170724
*
* @param int $id_at 文章Id
* @param int $pageIndex 页码
* @param int $pageSize 每页条数
* @return array 返回的数组
*
*/
public function getMoreCommentsByAtId($id_at, $uid, $pageIndex, $pageSize)
{
//0、判断数据数据是否有误
if(!is_numeric($id_at) || !is_numeric($pageSize) || !is_numeric($pageIndex) || !is_numeric($uid)){
return $this->reErrorMsg(401);
} //1、读取所有原始数据(分页获取)
$rst = (new Query)
->select('commentid as id, fromname as name, fromcover as headPic, num_praise as like, content, time, path, like_ids')
->from('view_all_comment')
->where(['id_at'=>$id_at])
->andWhere('status IN ('.implode(',', [9,10]).')')
->orderBy('time desc')
->offset($pageSize*($pageIndex -1))
->limit($pageSize)
->asArray()
->all(); //2、处理时间和数据整理
foreach ($rst as &$row){
//[ 20170818 验证是否点赞
$ids = [];
if(!empty($row['like_ids'])) {
$ids = explode(',', $row['like_ids']);
} if(in_array($uid, $ids)){
$row['liked'] = true;
}else{
$row['liked'] = false;
}
unset($row['like_ids']);
// 20170818 ] $row['time'] = date('Y-m-d',$row['time']);
if(empty($row['path'])){
$row['oldComment'] = [];//回复作者
unset($row['path']);//去掉此列
continue;
}
//2.1 回复其他读者,楼层
$ids = explode('/',$row['path']);//path => 1/2/3 //按照IN顺序排序
$sql = "SELECT `commentid` AS `id`, `fromname` AS `name`, `content` AS `comment` FROM `view_all_comment` WHERE (`id_at`={$id_at}) AND (`status` IN (".implode(',', [9,10]).")) AND (commentid IN(".implode(',',$ids).")) ORDER BY field(`commentid`, ".implode(',', $ids).")";
$oldComment = $this->findBySql($sql)->asArray()->all(); $row['oldComment'] = $oldComment;
unset($row['path']);
} return $rst;
}

四、评论写入接口

  4.1 Yii的方式

 /**
* 【发布评论】
* 20170725
* 20170818
*
* @return array
*/
public function actionPostComment(){
$model = new TblComment();
if($model->load(Yii::$app->request->post()) && $model->validate()){ if( isset($model->re_comment_id) && $model->re_comment_id != 0){
$remodel = TblComment::findOne($model->re_comment_id);
if(!$remodel){
return $this->retMsg('401');//保存失败
} if(empty($remodel->path)){
$model->path = $model->re_comment_id;
}else {
$model->path = $remodel->path . '/' . $model->re_comment_id;// 1/2/3
}
} if(!$model->save()){
return $this->retMsg('400');//保存失败
}
return $this->retMsg('200');//操作成
}else{
return $this->retMsg('401');//数据格式错误
} }

    说明:发表评论需求的数据:re_comment_id 引用的评论Id,content:评论内容,文章Id,以及用户Id

      path表示为引用的楼层,判断是否为空

  4.2 TP5的方式

 /**
* 【发布评论】
* 20170725
* 20170818
*
* @return array
*/
public function Post_Comment(){
try{
$data = input();//获取POST实体数据 $model =$this->commentModel;//对应评论表
$path = null; //评论引用的楼层
$remodel = $this->commentModel->where(['id_comment'=> $data['re_comment_id']])->find(); //获取所引用的评论model //处理path,空则直接赋值,否则追加 '/re_comment_id'
if(empty($remodel->path)){
$path = $data['re_comment_id'];
}else {
$path = $remodel->path . '/' . $data['re_comment_id'];// 1/2/3
} //组装数据
$lists[] = [
'id_at' => $data['id_at'], //文章Id
'id_wx_from' => $this->uid, //用户Id,后面直接读取session
'content' => $data['content'], //评论内容
'path'=>$path, //楼层路径
'time_create'=> time(), //加入时间
'status' => 9, //状态 9 => 未读, 10 => 已读
're_comment_id' => $data['re_comment_id'] //引用的评论Id
]; if($model->saveAll($lists)){
return $this->retMsg('200');//操作成
}else{
return $this->retMsg('400');//保存失败
}
}catch(Exection $e){
return $this->retMsg('401');//数据格式错误
} }

PHP 仿网易云的评论盖楼的更多相关文章

  1. 《云阅》一个仿网易云音乐UI,使用Gank.Io及豆瓣Api开发的开源项目

    CloudReader 一款基于网易云音乐UI,使用GankIo及豆瓣api开发的符合Google Material Desgin阅读类的开源项目.项目采取的是Retrofit + RxJava + ...

  2. [干货教程]仿网易云课堂微信小程序开发实战经验

    本篇文章想跟大家分享下:我们公司“湖北诚万兴科技”最近刚帮客户定制开发.目前已上线的“哎咆课堂”微信小程序的开发经验分享.首先大概介绍下这个小程序所涉及到的主要技术点:微信登录.微信支付.微信小程序F ...

  3. C# WPF 低仿网易云音乐(PC)Banner动画控件

    原文:C# WPF 低仿网易云音乐(PC)Banner动画控件 由于技术有限没能做到一模一样的动画,只是粗略地做了一下.动画有点生硬,还有就是没做出网易云音乐的立体感.代码非常简单粗暴,而且我也写有很 ...

  4. C# WPF 低仿网易云音乐(PC)歌词控件

    原文:C# WPF 低仿网易云音乐(PC)歌词控件 提醒:本篇博客记录了修改的过程,废话比较多,需要项目源码和看演示效果的直接拉到文章最底部~ 网易云音乐获取歌词的api地址 http://music ...

  5. 爬取网易云音乐评论!python 爬虫入门实战(六)selenium 入门!

    说到爬虫,第一时间可能就会想到网易云音乐的评论.网易云音乐评论里藏了许多宝藏,那么让我们一起学习如何用 python 挖宝藏吧! 既然是宝藏,肯定是用要用钥匙加密的.打开 Chrome 分析 Head ...

  6. Flutter仿网易云音乐:播放界面

    写在前头 本来是要做一个仿网易云音乐的flutter项目,但是因为最近事情比较多,项目周期跨度会比较长,因此分几个步骤来完成.这是仿网易云音乐项目系列文章的第一篇.没有完全照搬网易云音乐的UI,借鉴了 ...

  7. 新鲜出炉高仿网易云音乐 APP

    我的引语 晚上好,我是吴小龙同学,我的公众号「一分钟GitHub」会推荐 GitHub 上好玩的项目,一分钟 get 一个优秀的开源项目,挖掘开源的价值,欢迎关注我. 项目中成长是最快的,如何成长,就 ...

  8. python爬虫+词云图,爬取网易云音乐评论

    又到了清明时节,用python爬取了网易云音乐<清明雨上>的评论,统计词频和绘制词云图,记录过程中遇到一些问题 爬取网易云音乐的评论 一开始是按照常规思路,分析网页ajax的传参情况.看到 ...

  9. NetCloud——一个网易云音乐评论抓取和分析的Python库

    在17的四月份,我曾经写了一篇关于网易云音乐爬虫的文章,还写了一篇关于评论数据可视化的文章.在这大半年的时间里,有时会有一些朋友给我发私信询问一些关于代码方面的问题.所以我最近抽空干脆将原来的代码整理 ...

随机推荐

  1. linux初学者-输出输入管理

      1.输出重定向 在linux中,因为用户的权限不同,所以访问某些文件或者目录会被拒绝而形成错误输出,这些错误的输出也会显示出来.一般正确输出的编号为1,错误输出的编号为2.如下图,在普通用户stu ...

  2. 转发后找不到css

    当在jsp中引入css时,如果其相对路径相对于当前jsp文件的,而在一个和这个jsp的路径不一样的servlet中forward这个jsp时,就会发现这个css样式根本没有起作用. 这是因为在serv ...

  3. 多线程编程(Linux C)

    多线程编程可以说每个程序员的基本功,同时也是开发中的难点之一,本文以Linux C为例,讲述了线程的创建及常用的几种线程同步的方式,最后对多线程编程进行了总结与思考并给出代码示例. 一.创建线程 多线 ...

  4. Mybatis与Spring集成时都做了什么?

    Mybatis是java开发者非常熟悉的ORM框架,Spring集成Mybatis更是我们的日常开发姿势. 本篇主要讲Mybatis与Spring集成所做的事情,让读过本文的开发者对Mybatis和S ...

  5. Linux系统下增加LV(逻辑卷)容量 、Linux系统下减少LV(逻辑卷)容量

    查看文件系统现有lv_test容量,总计4.9G,已使用3% 命令 df -h   查看现有磁盘情况,我们发现磁盘sdb共有1305个柱面,每个柱面大小是8225280 bytes (大约8M).有一 ...

  6. Linux再学习(一)-学习路线规划

    1 抛弃旧文化,迎接Linux命令新文化 Linux第一步,从Windows思维,切换到Linux的"命令行+文件"模式 在Linux中,做什么都有相应命令.一般就在bin或者sb ...

  7. 夯实Java基础(九)——final关键字

    1.前言 Java语言中的final关键字,想必大家都不是很陌生,我们自己用的最多的应该是用来定义常量吧,那么今天我们就来了解final这个关键字的用法,这个关键字还是非常简单的. final从字面意 ...

  8. java并发编程(十二)----(JUC原子类)数组类型介绍

    上一节我们介绍过三个基本类型的原子类,这次我们来看一下数组类型: AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray.其中前两个的使用方 ...

  9. xcode自动刷新resource下的文件

    修改resource下的lua或者ccbi文件时,xcode并不会察觉到,所以需要手动清理xcode缓存和模拟器缓存,开发效率比较低下. 通过以下步骤可以实现自动刷新resource下的文件,且无需手 ...

  10. jmh源码解析-整体架构

    我理解的jmh运行架构图 生成字节码,字节码负责维护测试的状态和调用被测试的方法 默认在fork的进程中进行测试,可以配置多个fork进程,以减少误差 通过线程池,提交每个迭代的测试任务,任务执行后, ...