11 KiB
11 KiB
todos:
- id: "phase0-prep" content: "Phase 0:确认 minus() 死代码、补 PHPDoc、更新 README 入口索引" status: pending
- id: "phase1-base-query-register" content: "Phase 1:新建 AbstractWalletMutationLogic + WalletQueryLogic + WalletRegisterLogic,WalletLogic 委托 register/query" status: pending
- id: "phase2-bet-win" content: "Phase 2:新建 WalletBetWinLogic,迁移 bet/win 及 Redis round 辅助逻辑" status: pending
- id: "phase3-recharge" content: "Phase 3:新建 WalletRechargeLogic,迁移 inc/recharge/reward 与 Trial Pool 充值链" status: pending
- id: "phase4-withdraw-trial" content: "Phase 4:新建 WalletWithdrawLogic + WalletTrialLogic,修复 switchBonus 路由(如需要)" status: pending isProject: false
WalletLogic 分阶段拆分方案
现状诊断
slot-wallet/app/api/logic/WalletLogic.php 当前 1885 行,承担了钱包服务几乎全部资金用例编排:
| 域 | 主要方法 | 约行数 | 已有下沉 |
|---|---|---|---|
| 路由门面 | run, runRechargeOrder, ACTION_METHOD_MAP |
~80 | — |
| 注册 | register, initWalletWithoutMoney |
~120 | RegisterService |
| 下注/派奖 | bet, win, pending win Redis, bet split |
~450 | BetService, WinService |
| 入账/充值 | inc, recharge, rechargeSign, reward, Trial Pool |
~400 | RechargeFundLotService |
| 提现/Bonus 转换 | withdraw*, rollbackWithdraw, bonusToDeposit, switchBonus |
~350 | WithdrawTaskService |
| Trial 体验金 | grantTrial, expireTrial |
~250 | — |
| 查询 | query, queryBizLog (static) |
~70 | — |
| 公共能力 | addLog, maxRetry, sendConsoleBus, getBalance 等 |
~200 | — |
问题:单文件混合 6+ 业务域,事务边界、幂等、Redis 辅助状态交织,Review 和改动风险都高。
已有良好先例:同目录 GrantLogic、PlayerTaskLogic 已是「一用例一 Logic」;核心扣款/派奖细节已在 Service 层,Logic 层再拆是合理下一步。
额外发现(非本次必做):minus() 未出现在 ACTION_METHOD_MAP 且无调用方,疑似历史遗留,可在 Phase 0 确认后删除。
目标架构
flowchart TB
subgraph controller [Controller 不变]
WC[WalletController]
end
subgraph facade [门面层]
WL[WalletLogic]
end
subgraph domain [子 Logic 按域]
WQ[WalletQueryLogic]
WRg[WalletRegisterLogic]
WBw[WalletBetWinLogic]
WRe[WalletRechargeLogic]
WWd[WalletWithdrawLogic]
WTr[WalletTrialLogic]
end
subgraph shared [共享]
Base[AbstractWalletMutationLogic]
end
subgraph service [已有 Service 不动]
BS[BetService]
WS[WinService]
RS[RegisterService]
end
WC --> WL
WL --> WRg & WBw & WRe & WWd & WTr
GrantLogic --> WQ
WL --> WQ
WRg & WBw & WRe & WWd & WTr --> Base
WBw --> BS & WS
WRg --> RS
原则(对齐 backend-layering):
- Logic 拆用例、Service 保公共能力:不再新建「只做 Model 转发」的 Service。
- WalletLogic 只做分发 + 缓存清理:保留
run()/runRechargeOrder()对外签名;ACTION_METHOD_MAP改为指向子 Logic 方法。 - Controller 不改:继续只注入
WalletLogic(你已确认)。 - 共享状态收敛:子 Logic 继承抽象基类,统一持有
WalletUpdateRequestDTO;rechargeOrderDto仅留在WalletRechargeLogic。
共享基类设计
新建 slot-wallet/app/api/logic/AbstractWalletMutationLogic.php:
abstract class AbstractWalletMutationLogic
{
protected WalletUpdateRequestDTO $requestDTO;
/** 绑定本次 mutation 请求上下文 */
protected function bindRequest(WalletUpdateRequestDTO $requestDTO): void { ... }
/** 写 wallet_log、PWA 流水、乐观锁重试、Console Bus 等 */
protected function addLog(...): int { ... }
protected function addTransactionRecord(...): void { ... }
protected function getBalance(WalletAccountModel $model): int { ... }
protected function maxRetry(callable $callback, int $retryCount = 3): WalletEntity { ... }
protected function sendConsoleBus(string $type, int $amount): void { ... }
protected function initWalletWithoutMoney(): ?WalletAccountModel { ... }
}
- 从现有
WalletLogic原样迁移上述 protected/private 方法,避免行为变化。 - 子 Logic 方法签名改为显式接收 DTO 或在门面
bindRequest()后调用,不再依赖$this->requestDTO隐式全局状态跨文件散落。
子 Logic 划分
| 新类 | 职责 | 从 WalletLogic 迁出的方法 |
|---|---|---|
WalletQueryLogic |
只读查询 | query, queryBizLog |
WalletRegisterLogic |
注册赠金 | register |
WalletBetWinLogic |
游戏下注/派奖编排 | bet, win, executeTrialBet/Win, executeFreeSpinPaidBet, pending win / bet split Redis, getWinAllocationByRound, buildBetSplitRemark |
WalletRechargeLogic |
入账/充值 | inc, executeIncWithTransaction, recharge, rechargeSign, reward, Trial Pool 扣减链, resolveRechargeOrderDtoForLots, insertRechargeFundLotsIfNeeded |
WalletWithdrawLogic |
提现与 Bonus 桶转换 | withdraw, withdrawFrozen, rollbackWithdraw, doneWithdraw, bonusToDeposit, switchBonus |
WalletTrialLogic |
Trial 体验金生命周期 | grantTrial, expireTrial, resolveTrialAmount, makeTrialPoolBizId, buildTrialPoolRemark, deductTrialPoolInRechargeTransaction(若仍被 Recharge 调用则保留在 Recharge 或抽 TrialPoolSupport trait) |
Trial Pool 边界:planTrialPoolDeductionForRecharge / finalizeTrialPoolAfterRechargeInc 与充值事务强耦合,建议 Phase 3 随 RechargeLogic 一起迁;Trial 发放/过期独立进 WalletTrialLogic。
门面 WalletLogic(拆分后 ~150 行)
class WalletLogic
{
public function __construct(
private WalletRegisterLogic $registerLogic,
private WalletBetWinLogic $betWinLogic,
private WalletRechargeLogic $rechargeLogic,
private WalletWithdrawLogic $withdrawLogic,
private WalletTrialLogic $trialLogic,
) {}
public function run(WalletUpdateRequestDTO $requestDTO) { /* 分发 + deleteWalletCache */ }
public function runRechargeOrder(WalletRechargeRequestDTO $dto) { /* 委托 rechargeLogic */ }
// 兼容 GrantLogic / 外部 static 调用
public static function query(...) { return WalletQueryLogic::query(...); }
public static function queryBizLog(...) { return WalletQueryLogic::queryBizLog(...); }
}
ACTION_METHOD_MAP 改为 Logic 实例 + 方法名 或 callable 数组,例如:
WalletLogModel::BIZ_TYPE_BET => [$this->betWinLogic, 'bet'],
Webman DI 需在 config/ 或现有容器绑定中注册子 Logic(若项目无自动注入,门面构造函数内 new 亦可,与当前 GrantLogic 风格一致)。
分阶段实施(你已选 phased + facade)
Phase 0:准备(低风险)
- 为
WalletLogic现有 public 方法补全/核对中文 PHPDoc(拆分时会移动代码,趁此对齐php-clean-code)。 - 确认
minus()无调用后删除(或加@deprecated注释待下一版删)。 - 更新
README.md「实现入口」一节,列出子 Logic 索引。
Phase 1:Query + Register + 基类
- 新建
AbstractWalletMutationLogic、WalletQueryLogic、WalletRegisterLogic。 WalletLogic::query/queryBizLog改为委托;GrantLogic可继续WalletLogic::query()不动。register从 WalletLogic 迁出;run()分发到WalletRegisterLogic。- 验收:注册接口、余额查询、Grant 通知链路回归。
Phase 2:BetWin(最高复杂度)
- 新建
WalletBetWinLogic,迁移bet/win及 Redis round 状态方法。 WalletController的bet/win专用入口仍走walletLogic->run(),行为不变。- 注意:
win()内对$requestDTO->fee的临时修改必须在 BetWinLogic 内用try/finally保持,避免泄漏到其他域。 - 验收:下注/派奖、Trial 阶段 bet/win、FreeSpin 代付、中间派奖
is_end=0、幂等 hit。
Phase 3:Recharge / Inc
- 新建
WalletRechargeLogic,迁移inc全链路 +recharge/rechargeSign/reward。 runRechargeOrder委托给 RechargeLogic(含rechargeOrderDto生命周期)。- 验收:充值主链路、首充 Trial Pool 扣减、Fund Lot 落库、签到充值
sign。
Phase 4:Withdraw + Trial
- 新建
WalletWithdrawLogic、WalletTrialLogic。 - 补齐
ACTION_METHOD_MAP中缺失的switchBonus映射(若 slot-sdk 仍在调type=switchBonus,当前可能未路由到方法——拆分时可一并修复)。 - 验收:提现冻结/成功/失败回滚、Bonus 转 Deposit、Trial 发放/过期。
不建议的做法
- 不要把子用例再拆成 Logic 型 Service(如
WithdrawLogicService),违反分层红线。 - 不要一次性改 Controller 注入多个 Logic,你已选 facade,保持对外稳定。
- 不要把 BetService/WinService 的业务编排再搬回 Logic 后又复制一份——子 Logic 只做事务、幂等、流水、MQ,核心算法继续调用现有 Service。
预期收益
- 单文件从 ~1900 行降至 门面 ~150 行 + 各子 Logic 200–500 行。
- 改动 bet 不再误触 recharge 事务代码,Review 范围清晰。
- 与
GrantLogic风格统一,新人可按域定位代码。 - 对外 API、
WalletLogic::run()签名、SDK 调用路径 零破坏。
风险与缓解
| 风险 | 缓解 |
|---|---|
| 拆分引入行为回归 | 每 Phase 独立 PR;优先复制代码再删旧代码,不做顺手重构 |
$requestDTO 可变状态 |
基类 bindRequest() + 子 Logic 不跨用例复用实例 |
| Webman 构造注入 | 若无 DI,Phase 1 先在 WalletLogic 内 new 子 Logic,后续再接线 |
| Trial Pool 跨 Recharge/Trial | Phase 3 完成 Recharge 后再动 Trial;必要时抽 TrialPoolDeductionSupport trait 供 Recharge 专用 |
涉及文件
新建(均在 slot-wallet/app/api/logic/):
AbstractWalletMutationLogic.phpWalletQueryLogic.phpWalletRegisterLogic.phpWalletBetWinLogic.phpWalletRechargeLogic.phpWalletWithdrawLogic.phpWalletTrialLogic.php
修改:
WalletLogic.php— 瘦身为门面README.md— 更新入口索引(可选.cursor/rules/slot-wallet-prd-and-money.mdc一行指向)
不改:
WalletController.php- 现有
app/service/wallet/*Service.php