前言

之前我写过一篇如何少写PHP "烂"代码 https://segmentfault.com/a/11...
感觉很多新人对此不太理解。今天以打卡功能为例,去讲解其中的奥秘。那篇文章讲过代码开发的过程中分几种类型。

增删改的需求


Route -> Controller -> Service -> Action

查的需求


Route -> Controller -> Service -> Repository

经过多次实际开发验证后,发现Repository完全是多次一举。所以在这里更正下,取消Repository。


Route -> Controller -> Service

打卡系统逻辑架构图

需求是这样的,用户每天打卡获得积分,积分计入用户账户,并且需记录用户积分的获取及消费情况。如图所示,请求到控制器后,通过控制器去调用服务,服务又调用创建用户打卡模块完成打开,在用户打卡过程中对用户账户积分进行变更及记录用户积分获取记录。

数据表结构

打卡数据表


CREATE TABLE `member_attendance` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`member_id` int(11) NOT NULL COMMENT '用户编码',
`status` enum('0','1') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0' COMMENT '1签到成功',
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

用户钱包表


CREATE TABLE `wallet` (
`user_id` bigint(20) NOT NULL COMMENT '用户标示',
`balance` decimal(12,2) NOT NULL COMMENT '钱包余额',
`integral` decimal(12,2) NOT NULL DEFAULT '0',
`add_time` int(11) NOT NULL COMMENT '添加时间',
`update_time` int(11) NOT NULL COMMENT '更改时间',
UNIQUE KEY `wallet_user_id_unique` (`user_id`),
KEY `wallet_user_id_index` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

用户积分交易记录表


CREATE TABLE `member_integral_detail` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`member_id` int(11) NOT NULL COMMENT '用户编码',
`title` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '来源或消费',
`integral` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '积分数',
`type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '类型 0收入 -1支出',
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

具体业务实现

Route


$api->post ('user/attendance','UserController@attendance');

MemberController


public function attendance()
{
$result = $this->userService->attendance ($this->request); if ($result) {
return $this->response->array (Response::return (200, '打卡成功'));
} return $this->response->array (Response::return (0, "打卡失败或已打卡"));
}

MemberService


public function attendance($request)
{
return (new CreateUserAttendance())->execute ($request);
}

CreateUserAttendance


public function issetToday($userId)
{
$result = MemberAttendance::where ([
['member_id', '=', $userId],
])
->whereDate ('created_at', date ('Y-m-d', time ()))
->exists ();
return $result;
}
// -------------------- 上述是下方issetToday方法,写在MemberModel中
class CreateUserAttendance
{
public function execute($data)
{ if ((new MemberAttendance())->issetToday ($data->user_id)) {
return false;
} $models = new MemberAttendance();
$models->member_id = $data->user_id;
$models->status = (string)"1"; $result = $models->save (); if ($result) {
(new CreateUserIntegralDetail())->execute ($data->user_id, '打卡', 10, 0);
return true;
} return false;
}
}

CreateUserIntegralDetail


interface integralDetail
{
public function execute($userId, $title, $integral, $type);
} class CreateUserIntegralDetail extends UpdateUserWalletIntegral implements integralDetail
{
public function execute($userId, $title, $integral, $type)
{
parent::exec ($userId, $integral, $type); $models = new MemberIntegralDetail();
$models->member_id = $userId;
$models->title = $title;
$models->integral = $integral;
$models->type = $type; return $models->save ();
}
}

上述代码继承了更新用户积分的动作,在每次打卡成功后,我们调用父类方法直接更新用户积分。

UpdateUserWalletIntegral


class UpdateUserWalletIntegral
{
public function exec($userId, $integral, $type)
{
if ($type == 0) {
Wallet::where (['user_id', '=', $userId])->increment ('integral', $integral);
} else {
Wallet::where (['user_id', '=', $userId])->decrement ('integral', $integral);
}
}
}

致谢

感谢你看到这里,希望本篇文章可以帮到你。有什么问题可在下方评论区留言。谢谢

举枪消灭"烂代码"的实战案例的更多相关文章

  1. php 网站301重定向设置代码实战案例

    php 网站301重定向设置代码实战案例 301重定向就是页面永久性移走的意思,搜索引擎知道这个页面是301重定向的话,就会把旧的地址替换成重定向之后的地址. 302重定向就是页面暂时性转移,搜索引擎 ...

  2. Java生鲜电商平台-一次代码重构的实战案例

    Java生鲜电商平台-一次代码重构的实战案例 说明,Java开源生鲜电商平台-一次代码重构的实战案例,根据实际的例子,分析出重构与抽象,使代码更加的健壮与高效. 1.业务说明 系统原先已有登录功能,我 ...

  3. 如何从40亿整数中找到不存在的一个 webservice Asp.Net Core 轻松学-10分钟使用EFCore连接MSSQL数据库 WPF实战案例-打印 RabbitMQ与.net core(五) topic类型 与 headers类型 的Exchange

    如何从40亿整数中找到不存在的一个 前言 给定一个最多包含40亿个随机排列的32位的顺序整数的顺序文件,找出一个不在文件中的32位整数.(在文件中至少确实一个这样的数-为什么?).在具有足够内存的情况 ...

  4. 【Redis3.0.x】实战案例

    Redis3.0.x 实战案例 简介 <Redis实战>的学习笔记和总结. 书籍链接 初识 Redis Redis 简介 Redis 是一个速度非常快的键值对存储数据库,它可以存储键和五种 ...

  5. python实战案例--银行系统

    stay hungry, stay foolish.求知若饥,虚心若愚. 今天和大家分享一个python的实战案例,很多人在学习过程中都希望通过一些案例来试一下,也给自己一点动力.那么下面介绍一下这次 ...

  6. 分布式事务之——tcc-transaction分布式TCC型事务框架搭建与实战案例(基于Dubbo/Dubbox)

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/73731363 一.背景 有一定分布式开发经验的朋友都知道,产品/项目/系统最初为了 ...

  7. 企业Shell面试题及企业运维实战案例(三)

    1.企业Shell面试题1:批量生成随机字符文件名案例 使用for循环在/oldboy目录下批量创建10个html文件,其中每个文件需要包含10个随机小写字母加固定字符串oldboy,名称示例如下: ...

  8. 烂代码 git blame

    关于烂代码的那些事(上) - Axb的自我修养 http://blog.2baxb.me/archives/1343 关于烂代码的那些事(上) 六月 21, 2015 57 条评论 目录 [显示] 1 ...

  9. 基于SpringCloud的Microservices架构实战案例-在线API管理

    simplemall项目前几篇回顾: 1基于SpringCloud的Microservices架构实战案例-序篇 2基于SpringCloud的Microservices架构实战案例-架构拆解 3基于 ...

随机推荐

  1. Linux/Android多点触摸协议【转】

    本文转载自: 链接点击打开链接 关于Linux多点触摸协议大家可以参考kernel中的文档:https://www.kernel.org/doc/Documentation/input/multi-t ...

  2. Git新建本地分支与远程分支关联问题:git branch --set-upstream【转】

    本文转载自:http://blog.csdn.net/netwalk/article/details/21088405 Git新建本地分支与远程分支关联问题:git branch --set-upst ...

  3. 在word中doc与docx的区别是什么(整理)

    在word中doc与docx的区别是什么(整理) docx 是Office2007使用的,是用新的基于XML的压缩文件格式取代了其目前专有的默认文件格式,在传统的文件名扩展名后面添加了字母x(即.do ...

  4. YES,IT IS

  5. 为什么要使用XHTML?

    XHTML 是什么? XHTML 指可扩展超文本标签语言(EXtensible HyperText Markup Language). XHTML 的目标是取代 HTML. XHTML 与 HTML ...

  6. 同一个Tomcat下不同项目之间的session共享

    最近发现项目运行过程中经常会抛出一个 NullPointerException的异常,经检查发现异常出现的地方是日志模板,一阵检查,正常无误 (把所有记录日志的地方都点了一遍,心里是崩溃的),万念俱灰 ...

  7. In 7-bit

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3713 题意:给定一个字符串,首先输出这个字符串的长度(以两位的十六进制的形 ...

  8. 数据库mysql原生代码基本操作

    创建表: CREATE TABLE `biao` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '测试表', `createtime` ...

  9. Android内存管理(13)常见产生内存泄漏的原因

    1.集合类泄漏 集合类如果仅仅有添加元素的方法,而没有相应的删除机制,导致内存被占用.如果这个集合类是全局性的变量 (比如类中的静态属性,全局性的 map 等即有静态引用或 final 一直指向它), ...

  10. RabbitMQ~消费者实时与消息服务器保持通话

    这个文章主要介绍简单的消费者的实现,rabbitMQ实现的消费者可以对消息服务器进行实时监听,当有消息(生产者把消息推到服务器上之后),消费者可以自动去消费它,这通常是开启一个进程去维护这个对话,它与 ...