前几日,需要做到一个评论系统;要求在普通的评论功能基础上加上,能够无限引用的功能,即“盖楼”。那就做吧。。。
首先普通的评论,很简单;知道数据库设计的一般都知道。但现在是需要类似“盖楼”这样的情况;所以,没了头绪,Google,baidu。
找到一篇牛人文章:自反+递归 实现评论的无限引用
不得不说牛人就是牛人,对数据库表设计真是的很有见解的。大家可以去看看,现在结合我所面对的说我自己的理解吧(当然是看过这篇文章后额。^-^)
术语:初始评论:表示这个评论没有引用其他任何评论。
引用评论:表示这个评论包含对其他评论的引用。 (引用自以上博文)
类似“盖楼”的评论结构,大体上有两种模式。
一、传统模式
如下表结构:
Cm_feedback 留言表
Id
Article_id --文章id
Archive_title --文章标题
Userid --用户id
Username --用户名
Ip --ip
Ischeck --是否审核
Dtime --发表时间
Good --支持数
Msg --留言内容
效果图
这个评论存储不论是初始评论,还是引用评论都存放到msg这个字段中。这样的好处就是方便存储,业务逻辑清晰,存入取出;不合理的地方呢就是要是某条评论被删除了,但某条评论的引用中却还存在这段内容。所以这样审核就比较关键,要保证展示出来的评论,都是能够被引用的。如果是十几楼,二十几楼这样很多的内容,那么都是重复的,所以就很占数据库空间;其次这些都是html代码,所以存入数据库时还要把html正则匹配替换为分隔符,然后再存入数据库;所以缺点也是很明显的。
示例:
css
<style type="text/css" >
*{margin:0;padding:0;}
body{margin:10px;font-size:14px;font-family:宋体}
h1{font-size:26px;margin:10px 0 15px;}
#commentHolder{width:540px;border-bottom:1px solid #aaa;}
.comment{padding:5px 8px;background:#f8fcff;border:1px solid #aaa;font-size:14px;border-bottom:none;}
.comment p{padding:5px 0;}
.comment p.title{color:#1f3a87;font-size:12px;}
.comment p span{float:right;color:#666}
.comment div{background:#ffe;padding:3px;border:1px solid #aaa;line-height:140%;margin-bottom:5px;}
.comment div span{color:#1f3a87;font-size:12px;}
</style>
html
<div class='comment'>
<p class='title'><span>2008-3-24 16:33:49 发表</span>内蒙古网友</p>
<div>
<div>
<div><span>广州网友 原贴:</span><br />
向马XX同志荣升台湾省省长表示祝贺!
</div>
<span>四川网友 原贴:</span><br />
四川人民发来贺电!
</div>
<span>陕西西安网友 原贴:</span><br />
陕西网友发来贺电
</div>
<p>内蒙网友发来贺电</p>
</div>
共同点是明显的。我是这样匹配的。
{quote}
{quote}
{quote}
{title}广州网友 原贴:{/title}
向马XX同志荣升台湾省省长表示祝贺!
{/quote}
{title}四川网友 原贴:{/title}
四川人民发来贺电!
{/quote}
{title}陕西西安网友 原贴:{/title}
陕西网友发来贺电!
{/quote}
{content}内蒙网友发来贺电{/content}
就是 <div> => {quote} ; </div> =>{/quote} ; <span> => {title} ;</span><br/> =>{/title} ;<p> =>{content} ;</p> =>{/content} 一一对应。
这个方案的优缺点:
优点:1、方便存储很写入,
2、业务逻辑清晰简单,写入,取出。
缺点:1、占用数据库空间;
2、html代码正则匹配有点麻烦。
3、不能删除已被删除评论的引用内容。
虽然比较麻烦。但是我还是采用了这个模式。关键还是业务逻辑比较简单,服务器压力比较小。
二、自反模式:
先看表结构:
Cm_feedback 留言表
Id
Article_id --文章id
Archive_title --文章标题
Userid --用户id
Username --用户名
Ip --ip
Ischeck --是否审核
Dtime --发表时间
Good --支持数
Msg --留言内容
commentid --评论id
可以看到表结构和上面比起来,就是多了一个commentid字段。这个字段就是本身的外键,相当于自己引用自己。初始评论的commentid默认为0,而引用评论的commentid则是对应的其他评论的id。默认为0时,只有评论内容,不包含引用分隔符。commentid不等于0时,则查找commentid=id的评论,然后再次验证被查找id评论的commentid是否为0,如果为0则停止;果然不为0则继续查找,直到找到commentid=0的评论记录为止。
业务逻辑:
写出一方法或函数。据id 来获取对应的记录,即可获得commentid的值;然后判断commentid是否等于0,如等于则退出返回记录显示;如不等于则把commentid作为参数调用方法或函数本身。即递归。
示例:
//返回一条评论记录
function getComment($id){
return $rs;
}
//递归函数,调用getcomment()
function comment($id){
$rs = getComment($id);
if( $rs['commentid'] ==0){ //初始评论
return $rs;
}else{
$rs = comment( $rs['commentid']);
$comm[] = $rs;
return $comm;
}
}
commentid!=0这个情况,那么这个$rs应该存放在一个list中。在php里即数组中,那么就存放在数组$comm中;$comm就是一个二维数组了。而这些返回的二维数组然后再与只有一条评论的记录组合成一个数组,即初始评论与引用评论这个二维数组一起组合成为一个新的数组,从而把这个数组返回到前台页面展示;相当于把引用评论的二维数组当做了一条普通的评论记录,在页面展示中在加上上面的html。
这个也是我自己的想法,不知道是否与上面的大牛有出入,仅供各位参考,如有不正之处,请指出。
第二方案优缺点:
优点:1、很方便的管理每一条评论。如审核不当也可以随时删除该条评论。
2、数据库空间占用很小;不存在评论内容重复情况。
缺点:1、因为使用的递归操作,如果有几十楼层那样的情况,那么会很占服务器资源。
2、逻辑不是那么清晰;个人感觉很绕人。