举枪消灭"烂代码"的实战案例
前言
之前我写过一篇如何少写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);
}
}
}
致谢
感谢你看到这里,希望本篇文章可以帮到你。有什么问题可在下方评论区留言。谢谢
举枪消灭"烂代码"的实战案例的更多相关文章
- php 网站301重定向设置代码实战案例
php 网站301重定向设置代码实战案例 301重定向就是页面永久性移走的意思,搜索引擎知道这个页面是301重定向的话,就会把旧的地址替换成重定向之后的地址. 302重定向就是页面暂时性转移,搜索引擎 ...
- Java生鲜电商平台-一次代码重构的实战案例
Java生鲜电商平台-一次代码重构的实战案例 说明,Java开源生鲜电商平台-一次代码重构的实战案例,根据实际的例子,分析出重构与抽象,使代码更加的健壮与高效. 1.业务说明 系统原先已有登录功能,我 ...
- 如何从40亿整数中找到不存在的一个 webservice Asp.Net Core 轻松学-10分钟使用EFCore连接MSSQL数据库 WPF实战案例-打印 RabbitMQ与.net core(五) topic类型 与 headers类型 的Exchange
如何从40亿整数中找到不存在的一个 前言 给定一个最多包含40亿个随机排列的32位的顺序整数的顺序文件,找出一个不在文件中的32位整数.(在文件中至少确实一个这样的数-为什么?).在具有足够内存的情况 ...
- 【Redis3.0.x】实战案例
Redis3.0.x 实战案例 简介 <Redis实战>的学习笔记和总结. 书籍链接 初识 Redis Redis 简介 Redis 是一个速度非常快的键值对存储数据库,它可以存储键和五种 ...
- python实战案例--银行系统
stay hungry, stay foolish.求知若饥,虚心若愚. 今天和大家分享一个python的实战案例,很多人在学习过程中都希望通过一些案例来试一下,也给自己一点动力.那么下面介绍一下这次 ...
- 分布式事务之——tcc-transaction分布式TCC型事务框架搭建与实战案例(基于Dubbo/Dubbox)
转载请注明出处:http://blog.csdn.net/l1028386804/article/details/73731363 一.背景 有一定分布式开发经验的朋友都知道,产品/项目/系统最初为了 ...
- 企业Shell面试题及企业运维实战案例(三)
1.企业Shell面试题1:批量生成随机字符文件名案例 使用for循环在/oldboy目录下批量创建10个html文件,其中每个文件需要包含10个随机小写字母加固定字符串oldboy,名称示例如下: ...
- 烂代码 git blame
关于烂代码的那些事(上) - Axb的自我修养 http://blog.2baxb.me/archives/1343 关于烂代码的那些事(上) 六月 21, 2015 57 条评论 目录 [显示] 1 ...
- 基于SpringCloud的Microservices架构实战案例-在线API管理
simplemall项目前几篇回顾: 1基于SpringCloud的Microservices架构实战案例-序篇 2基于SpringCloud的Microservices架构实战案例-架构拆解 3基于 ...
随机推荐
- IFFT 的实现
IFFT 的实现 前些天给出了FFT的实现,如今给出IFFT(inverse FFT)的实现 基于IFFT 算法.对FFT的核心程序稍作改动就可以 : ) %%******************** ...
- [CF391E2]Three Trees
https://zybuluo.com/ysner/note/1246822 题面 有三棵树,建两条边让他们相连,最大化所有点对距离之和. \(40pts\ n\leq1000\) \(100pts\ ...
- la3713
2-sat...求解2-sat方案直接每个变量枚举就行了,lrj的代码很靠谱... #include<bits/stdc++.h> using namespace std; ; struc ...
- MSP430 使用时 RST引脚一定拉高
因为这次省去了RESET按键,RST没做任何处理,程序下载完之后插上电池无法运行,最终原因:RST引脚没有拉高.呼呼切记啊
- 关于pycharm中pip版本10.0无法使用的解决办法
背景: 近期在利用 pycharm 安装第三方库时会提示 pip 不是最新版本, 因此对 pip 进行更新,但是生成最新版本之后, pip 中由于缺少 main 函数,导致在 pycharm 中无法自 ...
- [Swift通天遁地]五、高级扩展-(2)扩展集合类型
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- [Swift通天遁地]六、智能布局-(5)给视图添加Align(对齐)和Fill(填充的约束以及Label的约束
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- linux 查看 cpu
如何获得CPU的详细信息: linux命令:cat /proc/cpuinfo 用命令判断几个物理CPU,几个核等: 逻辑CPU个数:# cat /proc/cpuinfo | grep " ...
- Spark 概念学习系列之Spark基本概念和模型(十八)
打好基础,别小瞧它! spark的运行模式多种多样,在单机上既可以本地模式运行,也可以伪分布模式运行.而当以分布式的方式在集群中运行时.底层的资源调度可以使用Mesos或者Yarn,也可使用spark ...
- Js打开QQ聊天对话窗口
function openQQ() { var qq = $(this).attr('data-qq');//获取qq号 window.open('http://wpa.qq.com/msgrd?v= ...