文档目录
业务逻辑模式

简介

本指南面向 DouPHP 后台服务层,系统化阐述业务逻辑封装模式与设计原则。围绕单一职责、依赖注入、接口抽象、领域模型、业务流程编排与状态管理等主题,结合用户、订单、商品等典型模块的服务类实现,给出高质量服务类的编写范式、参数验证、返回值处理、事务与异常策略、以及与服务层协作的控制器与模型层边界。文末提供单元测试与调试建议,帮助构建可维护、可扩展的业务逻辑。

项目结构

DouPHP 后台采用分层组织:

  • Shell 层(admin):路由、控制器、请求校验、视图响应
  • Service 层(admin/service + core/service):业务编排、领域规则、跨表聚合、外部能力协调
  • Model/ORM:数据访问与关系映射,通过静态门面在 Service 中调用
  • 基础设施:配置、日志、审计、附件、支付、定价、Markdown 渲染等
graph TB
subgraph "后台Shell"
C["控制器 BaseController"]
RQ["表单请求 UserFormRequest"]
end
subgraph "服务层"
BS["BaseService"]
US["UserService"]
OS["OrderService"]
PS["ProductService"]
end
subgraph "领域与基础设施"
M["Model/ORM(静态门面)"]
PMS["PaymentService"]
PRS["PricingService"]
MD["MarkdownRenderer"]
AUD["审计/日志"]
end
C --> US
C --> OS
C --> PS
US --> M
OS --> M
PS --> M
OS --> PMS
PS --> PRS
PS --> MD
US --> AUD
OS --> AUD
PS --> AUD

核心组件

  • BaseService:定义服务基类与约定,明确 ORM 使用方式(静态门面)、依赖解析方式(helper/门面就近获取),并强调“复杂查询/聚合下沉到 Reader/Query/*Core 服务”。
  • UserService:会员管理业务编排,包含列表组装、状态迁移、新增/更新/删除、批量操作、Excel 导出、等级日志记录等。
  • OrderService:订单管理业务编排,包含列表筛选、详情组装、线下付款审核、批量取消、物流发货、自动化任务触发、退款委托等。
  • ProductService:商品管理业务编排,包含列表/编辑数据组装、新增/更新、缩略图重建、型号关联、批量操作等。
  • BaseController:后台控制器基类,统一视图响应、Flash 归一化、删除结果分流、AJAX 切换响应等。
  • UserFormRequest:表单请求校验与白名单,场景化规则(store/update)。

架构总览

服务层作为“业务编排中心”,遵循以下设计原则:

  • 单一职责:每个 Service 聚焦一个业务域(用户、订单、商品),方法粒度按用例划分(如 insert/update/delete/action/build*Data)。
  • 依赖注入:通过构造函数注入领域服务(如 PaymentService、PricingService、MarkdownRenderer)与查询对象(UserLogQuery、UserStatsService 等),避免全局耦合。
  • 接口抽象:复杂查询/聚合下沉为独立服务或 Reader/Query/Core,便于复用与测试。
  • 输入校验前置:由 FormRequest 负责字段类型、唯一性、必填等;Service 专注业务规则与状态机校验。
  • 返回值契约:Service 返回结构化数组或领域对象,控制器负责 HTTP 响应转换(重定向、JSON、消息页)。
  • 异常与事务:非法参数抛 DomainException;批量写操作使用数据库事务保证一致性。
sequenceDiagram
participant Ctrl as "控制器"
participant Svc as "服务层"
participant Model as "Model/ORM"
participant Ext as "外部服务(支付/定价/Markdown)"
participant Aud as "审计/日志"
Ctrl->>Svc : 调用业务方法(如 insert/update/action)
Svc->>Ext : 调用依赖(如 PricingService/MarkdownRenderer)
Svc->>Model : 读写数据(静态门面/聚合查询)
Svc->>Aud : 写入审计日志
Svc-->>Ctrl : 返回结构化结果/抛出异常
Ctrl-->>Ctrl : 转换为HTTP响应(重定向/JSON/消息页)

详细组件分析

用户服务(UserService)

  • 职责边界:会员列表数据组装、状态迁移、新增/更新/删除、批量操作、Excel 导出、等级日志记录。
  • 关键流程:
    • 列表数据:过滤条件解析、分页、关联数据聚合(登录、积分、消费、VIP、等级),构造模板友好结构。
    • 状态迁移:基于状态枚举校验合法迁移,写审计日志。
    • 新增/更新:字段白名单由 Request 承担;Service 做业务校验(邮箱/手机至少其一)、密码哈希、头像上传、联系人 upsert、审计日志。
    • 删除:二次确认分支,实际删除时清理关联数据并记录审计日志。
    • 批量:支持批量删除、Excel 导出全部/选中。
flowchart TD
Start(["进入 insert"]) --> Validate["校验邮箱/手机至少其一"]
Validate --> |不通过| ThrowE["抛出 DomainException"]
Validate --> |通过| BuildInsert["构造插入数据<br/>生成user_sn/密码哈希/时间戳"]
BuildInsert --> Create["创建用户记录"]
Create --> UpsertContact["upsert默认联系人"]
UpsertContact --> UploadAvatar["上传头像并回写"]
UploadAvatar --> Audit["写入管理员审计日志"]
Audit --> ReturnId["返回新ID"]

订单服务(OrderService)

  • 职责边界:订单列表筛选与详情组装、线下付款审核(通过/驳回)、批量取消、物流发货、自动化任务触发、退款委托。
  • 关键流程:
    • 列表数据:解析多条件筛选(用户关键字、状态、单号、收件人分组、时间范围),分页并补齐地址信息。
    • 详情数据:组装支付历史、支付方式展示名、物流公司名、优惠券汇总、是否需支付检查、订单项等。
    • 线下付款审核:查找 pending 支付记录,标记成功/失败,联动订单状态机推进或回退。
    • 批量取消:事务内批量更新订单及明细状态,必要时同步关联模块状态,记录审计日志。
    • 自动化任务:每次列表入口执行自动取消、售后状态更新、评论自动完成等。
sequenceDiagram
participant Ctrl as "控制器"
participant OS as "OrderService"
participant Pay as "PaymentService"
participant Core as "OrderCore"
participant DB as "DB/事务"
Ctrl->>OS : payCheck(order_id)
OS->>Pay : findActivePending(order_id)
alt 找到待审核支付
OS->>Pay : markSucceeded(payment_sn, remark)
Pay-->>OS : 成功/失败
OS-->>Ctrl : 返回详情页URL
else 未找到
OS-->>Ctrl : 抛出异常
end
flowchart TD
A["action(cancel_all)"] --> B{"checkbox有效?"}
B --> |否| E["记录错误并返回false"]
B --> |是| T["开启事务"]
T --> Q["查询待取消订单(PENDING)"]
Q --> U["逐条更新order状态=CANCELLED"]
U --> UI["更新order_item状态与库存解锁"]
UI --> LM{"存在关联模块?"}
LM --> |是| UM["更新关联模块状态"]
LM --> |否| N["继续"]
UM --> N
N --> L["记录审计日志"]
L --> C["提交事务"]
C --> R["返回成功"]

商品服务(ProductService)

  • 职责边界:商品列表/编辑数据组装、新增/更新、缩略图重建、型号关联、批量操作。
  • 关键流程:
    • 列表数据:分类/关键词过滤、分页、价格格式化、会员价档位、图片与排序等。
    • 新增:内容清洗与远程图片本地化、会员价序列化、主图上传、草稿资源认领、审计日志。
    • 编辑:读取记录、图片 URL、型号列表 HTML、Markdown 渲染内容。
    • 缩略图重建:按磁盘配置与站点尺寸逐条生成缩略图,输出进度脚本。
    • 型号关联:add/del 模式维护型号字符串与商品关联,返回最新 HTML 片段。
    • 批量:批量删除、批量移动分类。
classDiagram
class ProductService {
+buildProductListData(catId, keyword, page) array
+buildProductDefaultData(itemId) array
+insert(data, draftToken, adminId) int
+buildProductEditData(id) array|null
+update(data, adminId) void
+buildThumbData(data) array
+thumbFlush(query, maskTag) void
+model(mode, id, action_id) string
+buildProductModelHtml(model, currentId) string
+delete(id, data) array
+action(data) array
}
class PricingService
class MarkdownRenderer
class Storage
ProductService --> PricingService : "依赖注入"
ProductService --> MarkdownRenderer : "依赖注入"
ProductService --> Storage : "磁盘实例"

控制器与服务层协作

  • 控制器职责:接收请求、调用服务、将服务返回的结构化结果转换为 HTTP 响应(重定向+flash、JSON、消息页)。
  • 关键机制:
    • view() 合并布局变量与页面数据,注入 AI 工具栏配置。
    • respondDeleteResult() 根据 service 返回的 confirm_url 决定走 302+flash 还是二次确认消息页。
    • respondToggle() 对 AJAX 与非 AJAX 分别返回 JSON 或重定向。
sequenceDiagram
participant Ctrl as "控制器"
participant Svc as "服务层"
Ctrl->>Svc : delete(id, post)
Svc-->>Ctrl : {message, back_url, timeout?, confirm_url?}
alt 有confirm_url
Ctrl->>Ctrl : message()->respond(...)
else 无confirm_url
Ctrl->>Ctrl : redirect(back_url)->with('success', message)
end

依赖关系分析

  • 服务间解耦:OrderService 依赖 OrderCore/PaymentService,ProductService 依赖 PricingService/MarkdownRenderer,UserService 依赖 UserStatsService/UserLogQuery/UserMembershipQuery/UserContactQuery。
  • ORM 访问:Service 通过静态门面调用 Model 方法,避免将 Model 实例注入 Service 构造函数,降低耦合度。
  • 外部能力:附件存储、图片处理、Markdown 渲染、审计日志、配置等通过 helper/门面就近解析。
graph LR
US["UserService"] --> QS["UserStatsService"]
US --> QL["UserLogQuery"]
US --> MQ["UserMembershipQuery"]
US --> CQ["UserContactQuery"]
OS["OrderService"] --> OC["OrderCore"]
OS --> PS["PaymentService"]
PSvc["ProductService"] --> PRS["PricingService"]
PSvc --> MD["MarkdownRenderer"]

性能与可维护性

  • 列表查询优化:
    • 使用 with/过滤器链式查询减少 N+1 问题。
    • 对大字段或无关字段使用 field() 限制投影。
    • 对复杂筛选(如收件人分组)使用子查询或临时集合,避免全表扫描。
  • 批量操作:
    • 使用事务包裹批量写,确保一致性与可回滚。
    • 对无效 ID 进行过滤,减少无效 SQL。
  • 异步/流式处理:
    • 缩略图重建采用逐条输出与 flush,提升长耗时任务的交互体验。
  • 可维护性:
    • 复杂查询/聚合下沉到 Reader/Query/*Core,保持 Service 方法简洁。
    • 表单校验集中在 Request,Service 专注业务规则。
    • 返回值结构稳定,控制器统一响应转换。

故障排查指南

  • 常见异常:
    • 非法参数:Service 中通过 Check/枚举校验后抛 DomainException,附带回跳 URL。
    • 状态机拒绝:如订单状态回退失败、支付状态机拒绝推进,应记录日志并提示重试。
    • 事务失败:批量取消失败时捕获异常并记录错误日志,确保事务回滚。
  • 定位技巧:
    • 查看审计日志(audit)与系统日志(Log),确认操作上下文与失败点。
    • 对复杂查询打印 SQL 或使用调试工具定位慢查询。
    • 对附件/图片路径使用 attachment()->url() 校验资源可达性。

结论

DouPHP 后台服务层以 BaseService 为约定基础,通过依赖注入、接口抽象与领域服务拆分,实现了高内聚、低耦合的业务编排。控制器专注于 HTTP 响应转换,服务层专注业务规则与流程控制,模型层负责数据访问。配合表单请求校验、审计日志、事务与异常策略,形成了清晰、可测试、可维护的业务逻辑体系。遵循本文规范,可有效避免反模式,提升代码质量与团队协作效率。

附录:编码规范与最佳实践

  • 方法设计:
    • 单一职责:每个方法对应一个用例(如 insert/update/delete/action/build*Data)。
    • 参数校验:优先在 Request 中声明规则;Service 中进行业务规则校验(如状态迁移、必填组合)。
    • 返回值:返回结构化数组或领域对象,避免裸字符串;控制器负责格式化为 HTTP 响应。
  • 依赖注入:
    • 通过构造函数注入领域服务与查询对象,避免在方法体内直接 new 或全局获取。
    • 复杂查询/聚合下沉到 Reader/Query/*Core,提高复用性与可测试性。
  • 数据访问:
    • ORM 使用静态门面,写操作统一 create/fill+save,读操作使用 with/过滤器链式查询。
    • 批量写使用事务,确保一致性与可回滚。
  • 异常与日志:
    • 非法参数抛 DomainException,附带回跳 URL。
    • 关键业务变更写入审计日志,便于追溯。
  • 表单与视图:
    • 表单校验集中在 Request,Service 不关心 HTTP 细节。
    • 视图数据在 Service 中组装为模板友好结构,避免在模板中做复杂计算。
  • 单元测试与调试:
    • 针对 Service 方法编写单元测试,覆盖正常路径与异常路径。
    • 使用 Mock 依赖(如 PaymentService、PricingService)隔离外部影响。
    • 利用审计日志与系统日志定位问题,结合 SQL 调试工具优化查询。
添加日期:2026-10-05