项目背景:
新项目是一个分销系统,核心技术就是无限极分类,每个会员都可以邀请别人进入这个团队,会员可以升级,可以享受奖励,前提是不断地邀请别人加入,这样每个团队的长远可以层层绑定关系。
数据库设计:
数据库的user表这样设计,invite_id为邀请人id,parent_id为直接父级id,path表示当前会员在团队里的路径,当前的会员可以通过parent_id一直找到他的父级,直到最顶层。也可以通过parent_id找到他的直接邀请人。
下面以一段代码说明无限极分类和递归的关系:
代码片段:
static function teamUpgrade($parent_id)
{
$userObj = new IModel('user');
$parentRow = $userObj->getObj('id = '.$parent_id);
//获取children信息
$childrenObj = new IQuery('user');
$childrenObj->where = 'parent_id='.$parent_id;
$childrenObj->fields = 'id,path,group_code';
$childrenRows = $childrenObj->find();
//当前用户直接邀请人
$inviteSum = self::getInviteSum($parent_id);
//查询当前用户团队人数
$group_sum = self::getAllTeam($parent_id,$parentRow['path'],$parentRow['group_code']);
//根据团队总数和直接邀请人数判断是否升级(常规情形)
switch ($group_sum['group_sum']-1) {
case 10:
if ($inviteSum['invite_sum'] >= 2) {
$levelTmp = self::teamUpdate($parentRow['level']);
}
break;
case 30:
if ($inviteSum['invite_sum'] >= 3) {
$levelTmp = self::teamUpdate($parentRow['level']);
}
break;
//A区或者B区大于等于30单(最小区大于等于30单)
case 100:
if ($childrenRows[0]['path'] && $childrenRows[1]['path'])
{
//A,B区同时存在,并且大于等于30单
$aZone = self::getAllTeam($childrenRows[0]['id'],$childrenRows[0]['path'],$childrenRows[0]['group_code']);
$bZone = self::getAllTeam($childrenRows[1]['id'],$childrenRows[1]['path'],$childrenRows[1]['group_code']);
if($aZone['group_sum']>=30 && $bZone['group_sum']>=30)
{
$levelTmp = self::teamUpdate($parentRow['level']);
}
}
break;
case 300:
if ($childrenRows[0]['path'] && $childrenRows[1]['path'])
{
//A,B区同时存在,并且大于等于100单
$aZone = self::getAllTeam($childrenRows[0]['id'],$childrenRows[0]['path'],$childrenRows[0]['group_code']);
$bZone = self::getAllTeam($childrenRows[1]['id'],$childrenRows[1]['path'],$childrenRows[1]['group_code']);
if($aZone['group_sum']>=100 && $bZone['group_sum']>=100)
{
$levelTmp = self::teamUpdate($parentRow['level']);
}
}
break;
case 900:
if ($childrenRows[0]['path'] && $childrenRows[1]['path'] && $childrenRows[2]['path'])
{
//A,B,C区同时存在,最小两边之和大于300单
$aZone = self::getAllTeam($childrenRows[0]['id'],$childrenRows[0]['path'],$childrenRows[0]['group_code']);
$bZone = self::getAllTeam($childrenRows[1]['id'],$childrenRows[1]['path'],$childrenRows[1]['group_code']);
$cZone = self::getAllTeam($childrenRows[2]['id'],$childrenRows[2]['path'],$childrenRows[2]['group_code']);
$sum = array($aZone['group_sum'],$bZone['group_sum'],$cZone['group_sum']);
array_multisort($sum,SORT_ASC,SORT_NUMERIC);
if($sum[0] + $sum[1] >= 300)
{
$levelTmp = self::teamUpdate($parentRow['level']);
}
}
break;
case 2500:
if ($childrenRows[0]['path'] && $childrenRows[1]['path'] && $childrenRows[2]['path'] && $childrenRows[3]['path'])
{
//A,B,C,D区同时存在,最小三边之和大于900单
$aZone = self::getAllTeam($childrenRows[0]['id'],$childrenRows[0]['path'],$childrenRows[0]['group_code']);
$bZone = self::getAllTeam($childrenRows[1]['id'],$childrenRows[1]['path'],$childrenRows[1]['group_code']);
$cZone = self::getAllTeam($childrenRows[2]['id'],$childrenRows[2]['path'],$childrenRows[2]['group_code']);
$dZone = self::getAllTeam($childrenRows[3]['id'],$childrenRows[3]['path'],$childrenRows[3]['group_code']);
$sum = array($aZone['group_sum'],$bZone['group_sum'],$cZone['group_sum'],$dZone['group_sum']);
array_multisort($sum,SORT_ASC,SORT_NUMERIC);
if($sum[0] + $sum[1] + $sum[2]>= 833)
{
$levelTmp = self::teamUpdate($parentRow['level']);
}
}
break;
case 7500:
if ($childrenRows[0]['path'] && $childrenRows[1]['path'] && $childrenRows[2]['path'] && $childrenRows[3]['path'])
{
//A,B,C,D区同时存在,最小三边之和大于2500单
$aZone = self::getAllTeam($childrenRows[0]['id'],$childrenRows[0]['path'],$childrenRows[0]['group_code']);
$bZone = self::getAllTeam($childrenRows[1]['id'],$childrenRows[1]['path'],$childrenRows[1]['group_code']);
$cZone = self::getAllTeam($childrenRows[2]['id'],$childrenRows[2]['path'],$childrenRows[2]['group_code']);
$dZone = self::getAllTeam($childrenRows[3]['id'],$childrenRows[3]['path'],$childrenRows[3]['group_code']);
$sum = array($aZone['group_sum'],$bZone['group_sum'],$cZone['group_sum'],$dZone['group_sum']);
array_multisort($sum,SORT_ASC,SORT_NUMERIC);
if($sum[0] + $sum[1] + $sum[2] >= 2500)
{
$levelTmp = self::teamUpdate($parentRow['level']);
}
}
break;
case 16667:
if ($childrenRows[0]['path'] && $childrenRows[1]['path'] && $childrenRows[2]['path'] && $childrenRows[3]['path'])
{
//A,B,C,D区同时存在,最小三边之和大于5000单
$aZone = self::getAllTeam($childrenRows[0]['id'],$childrenRows[0]['path'],$childrenRows[0]['group_code']);
$bZone = self::getAllTeam($childrenRows[1]['id'],$childrenRows[1]['path'],$childrenRows[1]['group_code']);
$cZone = self::getAllTeam($childrenRows[2]['id'],$childrenRows[2]['path'],$childrenRows[2]['group_code']);
$dZone = self::getAllTeam($childrenRows[3]['id'],$childrenRows[3]['path'],$childrenRows[3]['group_code']);
$sum = array($aZone['group_sum'],$bZone['group_sum'],$cZone['group_sum'],$dZone['group_sum']);
array_multisort($sum,SORT_ASC,SORT_NUMERIC);
if($sum[0] + $sum[1] + $sum[2] >= 5000)
{
$levelTmp = self::teamUpdate($parentRow['level']);
}
}
break;
default:
# code...
break;
}
/*****非常规情况下的升级结束*****/
//等级升级和轨道升级
if($levelTmp)
{
//当升级为区代理时,升级为三个轨道,升级为市代理时,升级为四个轨道
if($levelTmp == 22)
{
$pathway=3;
}
if($levelTmp == 23)
{
$pathway=4;
}
if($pathway)
{
$userObj->setData(array('level'=>$levelTmp,'pathway'=>$pathway));
}
else
{
$userObj->setData(array('level'=>$levelTmp));
}
$res = $userObj->update('id = '.$parent_id);
}
//不管是否升级成功,都有等级奖励并写入日志
// $parentRow = $userObj->getObj('id = '.$parent_id);//重新查询,等级可能有变动
// $levelTmp = $parentRow['level'];
// $award = self::levelAward($levelTmp);
//添加等级奖励写入日志(不管是否升级)
// self::addAward($parent_id,$levelTmp,$award);
//当前等级下的其他等级如果没有,奖励归当前等级所有
// self::addPlusAward($parent_id);
//写入升级日志(不计算奖励)
if($levelTmp)
{
self::upgradeLog($parent_id,$levelTmp);
}
*****//判断父级的父级,存在则递归计算
if($parentRow['parent_id']==0){
//没有父级,直接退出
return;
}
//有父级,回调自身继续计算
if($parentRow['parent_id']>0)
{
self::teamUpgrade($parentRow['parent_id']);
}*****
}
总结:
代码的主要逻辑是判断父级是否满足升级的条件,满足的话去更新user表的level字段并且记入日志。代码的最后判断当前父级是否还有父级,这个条件是递归的入口条件,不然可能导致递归会无限循环。 该方法的触发条件是为当前会员设置父级的时候,下级与上级一一绑定树状图的关系,并在升级的时候和递归很好的用到了一起。功能是实现了,考虑性能的话肯定还有更好的方法,在今后的工作与学习中会继续完善它,表达能力有限,相信自己可以不断进步。