discuzx2系列之群组积分排行

很长一段时间内都在忙着一个用discuzX2二次开发的项目。刚开始接触discuzx,查看里面的代码的时候感觉就像渣渣一样。虽然功能很强大,但是觉得代码真是太混乱了。不过随着后来项目定制的深入以及慢慢对discuzx的了解,discuzx真的很强大。尽管有些代码不是很规范,比如全局变量的滥用,函数里面require文件,输入数据的检测,模板里面的逻辑混乱可阅读性不高,整体架构只是类mvc还是很传统的函数编程等等还有很多。不过discuzx确实是一款成功的论坛类cms的系统,是一款很好的产品,可扩展性高,数据承载量大,功能强大,快速高效。现在就介绍下遇到的问题以及对这些问题的处理方法。

discuzx的资料:

discuzx的技术文库 http://dev.discuz.org/wiki

discuzx主站 http://www.discuz.net/

现在discuzx已经更新到2.5了。听说3.0现在正在研发中,2.5版本的整体架构变更比较大,很多之前直接写sql的以及用函数的地方都使用类库来替代了,不过代码还没有细看详细了解自行看源码。

这次要记录的内容是discuzx群组模块里面的一个功能扩展,这个功能就是群组的积分排行以及群组的当月积分排行。

可以看出群组排行可以按两项排行,一是总积分排行,二是当月积分排行。

一群组总积分排行,这个其实很简单。

我们知道用户创建的群组数据都存储在forum_forum表中,我们通过查看数据字典可以很轻松的知道该表中的字段所代表的意义。

如上图commoncredits就是“群组公共积分”,那么现在就可以很轻松的按这个字段的值进行desc排序了。不过群组的公共积分是怎样计算的呢?下面在详细了解。

二群组当月积分的总排行

这个会比较麻烦,因为discuzx木有这个功能啊(侧面说明discuzx很强大,很多功能都不需要进行改动直接拿来用)。不过我们可以马上进行扩展。

首先就是要搞明白群组的“公共积分”是怎么得来的,不管是总积分排行还是当月积分排行,数据更新的来源都是同一处。不过现在无处下手不知道积分增加的代码在哪,不过积分增加一定是与用户在群组内的操作有关的,比如发帖,回复,回帖等。所以只好监控表数据,通过回帖操作,发现总积分commoncredits数据+1,不过第二次操作时数据就没有变化了,那就说明回帖的时候一定进行了数据的更新。

可以查找到帖子回复的代码文件是source/include/post/post_newreply.php

不过再次查找就是麻烦了,一段一段的读代码时间也太长了,所以简单的办法来了,直接source搜索commoncredits,commoncredits数据变更一定是有“commoncredits=commoncredits+1”的sql语句了,于是搜之就出现结果了,就是function_grouplog.php这个文件里面,只有这一个函数。然后再用“updategroupcreditlog”在post_newreply.php里面搜索是在哪调用的就知道了

我们还可以具体了解到updategroupcreditlog是在哪些的动作中调用的。

可以看到发帖、回帖、发布商品动作都会对群组的公共积分进行增加。

那么接下来要做的事就是了解updategroupcreditlog函数了。

查看源代码可以了解到这个函数对于增加积分的行为。使用cookie可以避免用户每次回帖或发帖都检测数据库,同时在服务器端forum_groupcreditslog中保存用户今天在该论坛是否回帖的数据是很有必要的。因为这样可以规避用户更改客户端时间或删除cookie信息来为增加群组的积分。接下来就是通过检查$_G是否存在当前群组的信息;然后再检测群组的等级,判断群组是否足够积分进行升级。


<?php

/**
 *      [Discuz!] (C)2001-2099 Comsenz Inc.
 *      This is NOT a freeware, use is subject to license terms
 *
 *      $Id: function_grouplog.php 16644 2010-09-11 03:33:30Z monkey $
 */

if(!defined('IN_DISCUZ')) {
 exit('Access Denied');
 }

function updategroupcreditlog($fid, $uid) {
 global $_G;
 if(empty($fid) || empty($uid)) {
 return false;
 }
 $today = date('Ymd', TIMESTAMP);
 $month = date('Ym', TIMESTAMP);

$updategroupcredit = getcookie('groupcredit_'.$fid);
 if($updategroupcredit < $today) {
 $status = DB::result_first("SELECT logdate FROM ".DB::table('forum_groupcreditslog')." WHERE fid='$fid' AND uid='$uid' AND logdate='$today'");
 if(empty($status)) {

DB::query("UPDATE ".DB::table('forum_forum')." SET commoncredits=commoncredits+1 WHERE fid='$fid'");
 DB::query("REPLACE INTO ".DB::table('forum_groupcreditslog')." (fid, uid, logdate) VALUES ('$fid', '$uid', '$today')");
 if(empty($_G['forum']) || empty($_G['forum']['level'])) {
 $forum = DB::fetch_first("SELECT name, level, commoncredits FROM ".DB::table('forum_forum')." WHERE fid='$fid'");
 } else {
 $_G['forum']['commoncredits'] ++;
 $forum = &$_G['forum'];
 }
 if(empty($_G['grouplevels'])) {
 loadcache('grouplevels');
 }
 $grouplevel = $_G['grouplevels'][$forum['level']];

if($grouplevel['type'] == 'default' && !($forum['commoncredits'] >= $grouplevel['creditshigher'] && $forum['commoncredits'] < $grouplevel['creditslower'])) {
 $levelid = DB::result_first("SELECT levelid FROM ".DB::table('forum_grouplevel')." WHERE type='default' AND creditshigher<='$forum[commoncredits]' AND creditslower>'$forum[commoncredits]' LIMIT 1");
 if(!empty($levelid)) {
 DB::query("UPDATE ".DB::table('forum_forum')." SET level='$levelid' WHERE fid='$fid'");
 $groupfounderuid = DB::result_first("SELECT founderuid FROM ".DB::table('forum_forumfield')." WHERE fid='$fid' LIMIT 1");
 notification_add($groupfounderuid, 'system', 'grouplevel_update', array(
 'groupname' => '<a href="forum.php?mod=group&fid='.$fid.'">'.$forum['name'].'</a>',
 'newlevel' => $_G['grouplevels'][$levelid]['leveltitle']
 ));
 }
 }
// 当月积分排行的处理
// 当前月份财富记录判断
 $monthstatus = DB::result_first("SELECT *  FROM ".DB::table('forum_groupmonthcredits')." WHERE fid='$fid' AND month='$month'");
 // 已存在当月财富记录
 if( $monthstatus){
 DB::query("UPDATE ".DB::table('forum_forum')." SET monthcommoncredits=monthcommoncredits+1 WHERE fid='$fid'");
 DB::query("UPDATE ".DB::table('forum_groupmonthcredits')." SET credit=credit+1 WHERE fid='$fid' AND month = {$month}");
 }else {
 // 需创建新的记录
 DB::query("INSERT INTO ".DB::table('forum_groupmonthcredits')." (fid, month, credit) VALUES ('$fid', '$month', '1')");
 DB::query("UPDATE ".DB::table('forum_forum')." SET monthcommoncredits=1,creditmonth = {$month} WHERE fid='$fid'");
 }

}
 dsetcookie('groupcredit_'.$fid, $today, 86400);
 }
 }


那么我们的目的明确了,接下来就是要分析处理了。

记录群组每月的增长财富值,并按当前月份的财富值进行排行。

群组表forum_forum新加入字段
monthcommoncredits // 当前月份财富值,积分值
creditmonth          // 财富值的当前月份,便于群组排序是与当前月份进行匹配

第一步
用户每天发帖,群组财富积分会增长。

第二部
借此机会可以实现每月的财富积分记录
新建一个数据表“群组每月的财富积分记录”

groupmonthcredits
fid  // 群组id
month // 月份
credit // 当月积分
可以用来记录统计某个群组的每个月的积分,对应可以扩展实现群组的当月积分趋势
普通用户if(empty($status)) 今天第一次进行发帖时
群组总积分+1
判断 groupmonthcredits 表的当前月份的财富积分记录是否存在?
如存在 则当前月份财富积分 credit 继续+1,群组表中的公共积分 monthcommoncredits 继续+1
否则不存在,说明现在进入新的月份,在 groupmonthcredits 创建新的当前月财富积分记录,credit默认为1(因为用户今天在群组内的第一次操作有财富积分+1奖励)。
同时forum_forum表中的当月财富积分 monthcommoncredits 更新为1,将当前财富月份 creditmonth 更新为当前的月份
第三步
群组按当前月份财富额排行,可以直接使用群组表 forum_forum 中的monthcommoncredits 进行desc排序。
但这里会存在一个bug,就是某群组8月的“当月财富积分”为1000,排名第一,这时候进入9月
但群组中的任何一位成员都没有进行发帖、回复等操作。于是该群组的财富积分还是 1000 ,还是高居榜首,原因就是第二步中的所有当月财富积分的判断都需要在用户进行发帖,回复等操作下进行处理。这时候要解决这个问题就需要用到 creditmonth 财富值月份字段了。只查询与当前月份匹配的群组记录

这样就可以避免了。尽管这样的可能性比较小,但是还需要做考虑。
对于财富积分的增长,始终放在用户手中。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*