【项目实站】 php 实现抽奖代码详解【下篇】重构后的代码

本文介绍了一个基于PHP的抽奖系统的实现细节,包括需求分析、代码设计与实现等方面的内容。重点讲解了如何通过类和方法实现抽奖逻辑,如用户资格验证、抽奖机会使用及奖品分配等。

接上篇。点击查看--》项目实站】 php 实现抽奖代码详解【中篇】 如何面对需求变更

上篇讲了如何设计代码,封装需求, 接下来就是代码实现了,如下:

class DemoLottery{

    public function lottery($lottery_id , $uid){

        //一些防并发的代码,略。。。。
        try {
            //取用户
            $trans = Yii::app()->db->beginTransaction();
            $sql = "select * from demo_user where id = $uid for update";  //对用户数据加行锁
            $userRow = Yii::app()->db->createCommand($sql)->queryRow();

            //进行校验处理,用户是否可抽奖。
            $sql = "select * from demo_lottery where id = $lottery_id ";
            $lotteryRow = Yii::app()->db->createCommand($sql)->queryRow();   //得到抽奖活动数据
            //2.1 校验用户可否抽奖    list( $bool  ,  $msg) = $this->validate($lotteryRow , $userRow);   //进行校验。
          if( !$bool ) exit($msg );
            //2.2 使用抽奖机会。
            list($bool ,$msg)=  $this->useChance($lotteryRow , $userRow);  //使用掉用户的抽奖机会。
            if( !$bool ) exit($msg );

            //2.3 获得奖品数据
            $prizeRow = $this->getPrize( $lotteryRow , $userRow);

            //2.4 将奖品发放给客户。
            list($bool , $msg ) = $this->award($lotteryRow , $userRow , $prizeRow);
            if( !$bool ) exit($msg );return true; } 
            catch (Exception $e) { 
                    Yii::log($e->getMessage(), CLogger::LEVEL_INFO, "log_error"); $trans->rollback(); return false; 
              } } }
             //调用代码 $uid = 1; $lottery_id = 1; $lotteryObj = new DemoLottery(); $lotteryOjb->lottery($lottery_id , $uid);
首先处理校验问题,这里代码有点绕。但这是一种非常常用的写法,很多框架内的实现(例如yii 的validate ) 就是用的这种写法。 这种写法习惯了后,还有个好的副作用,就是以后看框架源码会比较顺畅一点点

 /**
     * 校验抽奖.
     * @param $lotteryRow  抽奖活动
     * @param $userRow
     */
    public  function validate($lotteryRow , $userRow){

        //将基础版本的校验移过来.
        if( !$lotteryRow )  exit( "活动不存在!" );
        $time = time();
        if( $time < $lotteryRow["start_time"] || $time > $lotteryRow["end_time"]) { return array(false , "活动未开始或已结束");}
        $sql = "select * from demo_user where id = ".$userRow["id"];
        $userRow = Yii::app()->db->createCommand($sql)->queryRow();
        if( $userRow["free_chance"] + $userRow["points"]/$lotteryRow["spend_point"] < 1) {   return array(false , "无抽奖机会");}


        //对json 里配置的需要校验的部分进行校验。
        $jsonParam = json_decode($lotteryRow["params"]);
        if(isset($jsonParam->validate)){
            foreach( $jsonParam->validate as $key =>  $options ):
                $methodName = "valid_".$key;
                $className = "lotteryValid".ucfirst($key);

                //如果存在内部方法,则调用内部方法进行校验.
                if( method_exists($this , $methodName)){  //如果有  $this->valid_perday_limit  则使用$this->valid_day_limit 进行校验。
                    list($bool , $msg ) =    $this->$methodName($lotteryRow , $userRow , $options);
                    if( !$bool)  exit($msg);
                }else if(@class_exists($className)){ //若无内联方法,则找到对应的校验类,调用对应的校验对象进行校验。   
                     $validObj = new $className;
                    /**@var $validObj abstractLotteryValidate */
                    $validObj->setLotteryRow($lotteryRow);
                    $validObj->setUserRow($userRow);
                    $validObj->setOptions($options);
                    list($bool , $msg ) =    $validObj->validate();
                    if( !$bool)  exit($msg);
                }

            endforeach;
        }
        return array(true , "success");
    }

这样,形成了一个约定,当你配置里面的validate 
有一个 perday_limit (每日限制)的设置的时候,
你可以在DemoLottery 中写一个 valid_perday_limit($xx)  方法来进行校验。
也可以 用 lotteryValidPerday_limit   对象来处理。 下面这段代码就是 map 的规则。
$methodName = "valid_".$key;
$className = "lotteryValid".ucfirst($key);

下面,一样取一个例子来实现。

    //校验当日的抽奖上限次数。  使用的内联方法 $this-> valid_perday_limit 进行校验。

    private  function valid_perday_limit( $lotteryRow , $userRow , $options){

        //特殊不受限制天数
        if( isset($options->except_days) && $options->except_days){
            $except_day_arr = explode("," , $options->except_days);
            if( in_array( date("Y-m-d") , $except_day_arr)) { return array(true , "success");}
        }

        $s_time = strtotime(date("Y-m-d"));  $e_time = strtotime(date("Y-m-d 23:59:59"));
        $sql = "select count(id) from demo_prize_log where uid = ".$userRow["id"]." && create_at>= $s_time && create_at <= $e_time";
        $count = Yii::app()->db->createCommand($sql)->queryScalar();
        if( $count > $options->limit ){
            return array(false , "单日次数超限!");
        } else {
            return array(true , "success");
        }
    }
//使用外部校验类校验方法。
//每周的星期六,日 ,限vip,5,6,7 可以抽奖.
class lotteryValidVip_level extends abstractLotteryValidate{
    public function validate(){

        $options = $this->options;

        $w = date("w"); //今天周几
        if(isset($options->week_num) && in_array($w , explode(",", $options->week_num))){

             $user_level = $this->userRow["vip_level"];
             if( ! in_array($user_level , explode("," , $options->limit))){
                    return array(false , "用户vip等级不符");
             }
        }
        return array(true , "success");
    }
}


//抽象校验类。
abstract class  abstractLotteryValidate {

    public $userRow = array();
    public $lotteryRow = array();
    public $options;

   public function setUserRow( $userRow) { $this->userRow = $userRow;}
   public function setLotteryRow( $lotteryRow) { $this->lotteryRow = $lotteryRow;}
   public function setOptions( $options) { $this->options = $options; }


    /**
     * @return array( bool ,msg)
     */
   abstract  public function validate();
}   //2.2 使用掉抽奖机会。
//校验完后。接下来是消耗掉用户的抽奖机会或积分。

    public function useChance($lotteryRow ,$userRow){  //
        $lottery_type = $userRow["free_chance"]>0?"free_chance":"points";  //用户使用哪种方式抽奖。
        //扣除掉用户的抽奖机会.
        if( $lottery_type == "free_chance"){
            $sql = "update demo_user set free_chance = free_chance - 1 where id = ".$userRow["id"];
            $bool = Yii::app()->db->createCommand($sql)->execute();  if( !$bool ){ throw new Exception("执行失败".$sql); }
        }else{
            $spend_point = $lotteryRow["spend_point"];
            $sql  = "update demo_user set points = points - $spend_point  where id = ".$userRow["id"];;
            $bool = Yii::app()->db->createCommand($sql)->execute();
            if( !$bool ){ throw new Exception("执行失败".$sql); }
        }
        return array( true ,"success");

    }

//后面的写法类似,暂不赘述。
2017.9.27 更新:处理可能出现的一些重复签到的情况 更新:现在被禁用的用户,在刷新签到列表后不会再显示在签到列表中 更新:增加了功能的快捷键 2017.9.25 更新:增加了手机端的观众中奖信息查看功能 2017.8.30 更新:处理了一个开幕墙,闭幕墙的二维码bug 2017.8.25 更新:增加了红包功能 更新:3d签到预设图形增加了网格 更新:对对碰里面增加了昵称显示 更新:修复一个幸运数字的bug 2017.9.18 更新:优化了很多用户体验细节 更新:处理了一些细节方面的bug 2017.8.25 更新:增加了红包功能 更新:3d签到预设图形增加了网格 更新:对对碰里面增加了昵称显示 更新:修复一个幸运数字的bug 2017.8.23 更新:增强了一个php配置的兼容性 更新:新手指南优化 更新:砸金蛋中奖人数较多时滚动条无法滚动的问题 更新:摇一摇增加了气球风格 更新:调整后台的一些文字描述 更新:新增中奖列表导出 更新:新手指南更新到8月22日 2017.8.11 更新:修复一个循环播放时随机出现重复消息的问题 更新:每场活动现在有独特的活动签到连接,不会出现串场的问题了 2017.8.8 更新:可以修改管理员密码 更新:增加开幕墙 更新:增加闭幕墙 更新:大屏幕右上角二维码增加中等大小的显示(3种大小状态,适合各种场景使用) 2017.8.6 更新:优化了一些js文件 更新:优化前台登录跳转页面的 更新:上墙消息增加了显示方式、循环播放设置、循环信息条数、放大显示图片消息开关、放大显示图片消息时间设置 更新:后台关闭上墙、摇一摇、投票后,手机端的菜单也会相应的消失,并且如果不小心连接放错了,可以跳转到签到页面去。 更新:系统会自动生成二维码 更新:安装好之后有更多的默认设置可以用,减少配置,即装即用 2017.8.5 更新:可以后台修改2段欢迎文字 更新:新手指南更新 更新:修复一个投票页面全屏后背景消失的问题 更新:增加了上墙首页右下角logo的上传功能 增加:相册 更新:处理一个在部分服务器上上传会报错的bug 更新:修复一个影响部分服务器的session相关的系统错误 更新:新增文字弹幕 更新:解决了砸金蛋每次只能砸1个人的问题 更新:优化了抽奖箱的效果,声音和摇晃的动作更加符合现 2017.8.2 更新:优化签到顺序号码,减少不连续的情况出现 更新:增加最新的新手使用指南 更新:修复一个使用自己公众号授权的时候页面不跳转的问题 更新:现在可以自己编辑3d签到的图形的顺序及数量 更新:3d签到增加支持文字 更新:3d签到增加倒计时支持 更新:3d签到增加3个控制参数 2017.7.27 新增:增加内定列表,方便查看和管理内定人员信息 2017.7.26 更新:屏蔽用户的效果能正常运行了 更新:给抽奖箱和砸金蛋增加抽奖内定功能 更新:修复一个摇一摇后台显示错误的bug 更新:新版后台增加了开启和关闭签到填写姓名和手机号功能 2017.7.24 更新:优化界面 更新:优化手机页面的跳转 更新:增加签到名单导出功能 2017.7.6 新增:对对碰 更新:去掉后台进入摇一摇的链接(已经不需要了) 更新:一个可能会跳转到404页面的错误 更新:新版摇一摇菜单不正常显示的问题 更新:抽奖重新抽奖清空数据报错的问题 更新:优化了3d签到的效果 2017.7.5 新增:幸运手机号 新增:砸金蛋 更新:修复一个签到头像可能会重复出现的问题 更新:功能菜单修改 2017.7.4 新增:幸运号码抽奖 2017.7.3 更新:版本号从今天开始改为类似201707021这种形式,前八位是大版本日期,后面的数字是小版本的序号 2017.7.2 更新:前端UI界面全部优化 更新:抽奖支持多轮抽奖,可以内定 2017.6.25 更新:摇一摇功能全面优化升级,支持多轮摇一摇游戏 2017.6.14 更新:现在对对碰签到完成即可参与 更新:优化手机签到页背景 更新:部分文字说明更新 更新:优化了摇一摇功能 更新:图片上传功能优化,上传速度更快,支持jpg和png 2017.6.7 更新:去除不常用的功能,拍拍乐,拔河 更新:简化代码,优化性能 更新:系统不再需要对接公众号,使用更方便更自由 更新:修复了一个在windows系统下session可能失效的bug 更新:去除了公众号对接指南 更新:去除数据库中很多不再使用的表和字段,并且增加了大量备注 更新:重新写了签到功能 2017.6.6 更新:3D签到功能优化 2017.5.18 更新:更新图片保存的相关功能 更新:简化程序 2017.5.17 更新:修改session保存方式 2017.5.16 更新:修改缓存类,使代码更简介,结构性更好,方便二次开发 更新:修复摇一摇系统使用memcache的一些bug 2017.5.13 更新:简化所有主题的界面 更新:优化了后台系统设置页的内容,去掉了已经不用的项目 2017.5.10 更新:优化了3d签到的效果,减少屏幕分辨率对效果的影响 2017.5.5 更新:开场界面更新 更新:视屏背景主题的视频更新 更新:简化默认自定义主题的界面,使用更方便简洁 更新:修复一个拔河的默认没有自动安装上的问题 2017.5.2 新增:增加拔河功能 2017.4.24 更新:可以自定义修改版权信息 2017.4.13 更新:进一步提升摇一摇性能,减少数据库数据库访问次数 更新:改进完善微信上墙使用教程 2017.4.5 更新:修复一些小bug 2017.4.1 更新:修复了后台的信息显示的一个bug 2017.2.14 更新:优化签到列表的数据读取方式,现在几千人的活动,也不会卡在列表处了 2017.2.13 更新:增加了后台可以删除已审核信息的功能 2017.2.7 更新:优化抽奖功能,记录每个人被抽中的时间 2017.1.25(数据库结构发生变化) 更新:投票管理删除投票项功能 更新:可以设置2D签到时显示的微信昵称,真姓名和手机号 更新:优化了上传图片的功能,增加了默认值,现在安装完成后不需要再上传自定义的图片才能正常显示页面了 新增:自定义上传摇一摇背景图 2017.1.24(数据库结构发生变化) 新增:签到触发关键字,可以设置关键字来触发签到的图文信息 新增:抽奖可以设置显示签到时填写姓名或手机号 更新:优化拍拍乐的参数设置 2017.1.23 更新:优化默认值,使系统安装完成之后设置简化 2017.1.22(数据库结构发生变化) 更新:修改了对公众号发送帮助后返回的信息内容,稍微简化了摇一摇和投票的流程 更新:把上传的图片存放目录转到更合适的目录下 2017.1.14 更新:解决弹幕必须循环播放的问题 2017.1.10 更新:修改了拍拍乐的多个bug 更新:修改了拍拍乐的图片排序 更新:修改了多个主题上墙内容重复滚动的问题 2016.12.30 更新:修改了新年主题的对联,改到鸡年的对联 2016.12.16 更新:处理了参与抽奖的人数大于150人时的一个人数显示错误 2016.11.22 更新:文字提醒优化 2016.11.14 更新:摇一摇显示人数的bug 2016.9.23 更新:处理一个数据库的兼容问题 更新:修改了多个js bug 更新:修改了smarty 的缓存目录,统一都放到data目录下,避免出现没有权限的情况 更新:优化用户信息获取方法,减少接口使用次数,避免现场观众太多导致接口次数用完的问题。 更新:优化系统设置界面,让人更容易看懂,为之后新增功能做准备 更新:现在支持所有类型的公众号。 2016.9.12 更新:处理一个微信墙js失效的bug。 2016.9.9 更新:摇一摇前台页面新增重置按钮,方便进行第多轮活动。 更新:简化数据库,并提供数据获取的性能 更新:调整系统后台细节,更方便使用 2016.9.7 更新:优化抽奖功能,千人万人抽奖都不卡。 更新:签到名单导出按钮,在php5.3以下的版本中自动不显示 新增:增加图文并茂的微信上墙使用教程word文档 2016.9.5 更新:提高摇一摇性能 更新:修复一个显示图片时候点击抽奖、摇一摇、投票界面,会被自动弹出的bug 2016.9.1 新增:增加关键字触发自动回复功能。 更新:微信上墙成功后自动回复后可增加自定义文字。 2016.8.29 更新:增加了程序和服务器的兼容性 更新:增加了系统内置的后台帮助信息 新增:签到用户列表导出excel 新增:增加更新日志按钮,最新更新一目了然 2016.8.18 更新:优化程序,降低误操作可能性 更新:更新拍拍乐,修复了一些小bug 2016.8.18 更新:修改了所有主题的3d签到按钮 更新:普通签到功能优化,修复了一个小bug 2016.8.3 更新:修改可以设置抽奖条件,签到即可抽奖和签到并发消息才可参与抽奖 2016.8.2 更新:修复抽奖结果查询bug,现在不是认证的号可以通过查询的方式获得中奖信息,认证的号在抽中的时候可以直接发送消息提醒中奖 2016.7.22 更新:3D签到墙修复不会时更新签到用户的信息的bug 2016.7.21 更新:处理一些兼容性问题 2016.7.18 更新:修复拍拍乐抽奖阶段头像不显示bug 2016.7.16 更新:抽奖内定功能更新,优化设置流程 更新:美化授权成功页面 2016.7.15 更新:优化3D签到墙 更新:优化签到流程,使用更方便 2016.7.14 新增:3D签到墙 2016.7.13 更新:增加了后台的memcache配置功能,开始缓存后性能大大提升哦 2016.7.11 更新:修复一个宇宙弹幕不显示内容的bug 2016.7.7 更新:修复了一个最近更新中出现的sql语句错误 更新:修复可能导致借用公众号无法获取到用户信息的bug 2016.7.2 更新:修改了签到方式,签到更简单,更美观,可后台自定义记录姓名和手机号 2016.6.14 更新:修复了一个安装失败的bug 2016.6.11 新增:未认证订阅号和未认证服务号上墙功能 更新:修改了部分代码,方便阅读 更新:去掉了,很多不再使用的代码和注释,减少系统体积 更新:修改了 安装配置说明.txt 2016.6.6 更新:一键安装中增加了拍拍乐安装功能 2016.6.2 更新:微信菜单功能现在支持php5.4以下的版本 2016.6.1 更新:某些服务器上安装会出现微信token验证失败的一个问题 更新:数据库文件中的一个语法错误 2016.5.28 更新:支持本地缓存memcache,大幅提高摇一摇性能 2016.5.27 新增:微信菜单管理 更新:增加默认设置,一键触发帮助,摇一摇,拍拍乐,投票 2016.5.17 更新:宇宙弹幕主题,可以设置循环播放是否开启 新增:拍拍乐 2016.5.14 更新:增加了一些代码注释 更新:强化了代码的兼容性 2016.5.7 更新:数据获取方式调整,减少网络流量,性能更好。 2016.3.30 更新:美化摇一摇手机端界面 2016.3.28 更新:增加了抽奖内定功能 更新:去除签到页,改成用手机号签到,方便兑奖 更新:认证订阅号也可以使用 2016.3.25 更新:优化了摇一摇的操作,摇动记录功能更灵敏 2016.3.18 更新:降低了后台配置难度,使配置更简单 更新:增加了必填项的引导填写功能,操作更简单便捷 2016.3.9 更新:上墙首页关注部分的效果,提升了用户体验 更新:摇一摇参与界面的部分效果,提升了用户体验 更新:摇一摇背景变更,提升了用户体验 2016.1.30 更新:解决后台未审核信息类型错误的bug 更新:微信墙的一些细节更新,用户体验更好 2016.1.29 更新:修改系统的部分程序结构和目录结构 更新:修改更新日志结构 2016.1.28 新增:增加签到成功之后,微信公众号自动提醒签到成消息 新增:增加了用户中奖之后,公众号会发送提醒信息 更新:修改了一键安装程序,检测内容更完善 2016.1.22 更新:压缩了所有背景图,增加打开微信墙的速度 更新:更新了数据库安装导入文件,数据更小 2016.1.20 更新:修改了登录页面,新页面更大气上档次 2016.1.19 新增:后台增加了签到用户的信息 2016.1.6 更新:简化微信上墙的程序流程,提高程序运行效率 2016.1.5 更新:修复一些自动更新微信墙的bug 2015.12.30 更新:数据库连接相关内容 2015.12.23 更新:过滤一些字符串的空格,减少误操作的可能性 2015.12.20 更新:更新摇一摇提示信息,避免产生不必要的误会 2015.12.19 新增:增加1个自定义背景图的主题 新增:可以自定义上传logo图片 更新:微信上墙后台刷新待审核息功能完成 更新:修改了微信强签到页面的摇一摇按钮,使用更方便 更新:优化摇一摇功能减少大量无用的请求 更新:摇一摇优化,现在手机端和电脑端的数字会显示一致,不会因为网络卡而导致不一样的情况发生 2015.12.12 更新:更新了安装文档中的一个错误。 更新:更新了上墙换肤图相关的一个js错误。 更新:优化一键安装流程,精简代码,降低服务器要求 更新:不再要求开启php短标签支持,适用更多的服务器 更新:修改二维码存放目录,并在安装时检测存放目录的权限 2015.12.11 更新:更新了上墙首页的一个js错误。 2015.12.8 更新:安装教程更新 2015.12.5 新增:系统增加一键安装功能 更新:修改了大量数据库相关的内容,试程序更容易被读懂 更新:删除不必要的代码,简化程序方便二次开发 更新:优化代码,解决了页面上的一些js错误,提高页面运行效率,页面打开更快 更新:优化界面,使每一屏显示的消息更多 更新:优化页面资源加载顺序,使活动页面打开速度翻倍 2015.12.4 更新:去除领奖验证按钮,简化领奖操作流程 更新:简化系统配置文件,简化安装流程 更新:处理了一个抽奖完成后,没法再次抽奖的bug 更新:重新做了代码的排版,使代码修改更方便 更新:优化程序的存放目录结构,找文件更容易 更新:删除一些不必要的文件,减小源码包的体积,下载更轻松。 2015.12.2 更新:更新了大量的服务器配置兼容性问题,使安装更容易 2015.11.25 更新:修复了一些泄露微信公众号信息的问题 更新:完善了安装说明
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值