简介
本设计文档面向 DouPHP 框架的服务层,聚焦其在 MVC 架构中的核心职责与实现方式。服务层负责封装业务逻辑、协调多个模型完成复杂操作、管理事务边界、统一错误处理与日志记录,并通过依赖注入提升可测试性与可维护性。本文以订单、用户、商品等典型领域为例,说明服务类的组织方式、与控制器和模型的职责边界,以及面向扩展的模块化设计。
项目结构
DouPHP 将服务按“核心能力 + 端侧适配”分层组织:
- core/service:跨端共享的核心业务能力(如订单状态机、库存校验、定时任务编排)。
- admin/service:后台管理端业务编排(列表组装、审核、批量操作、审计日志)。
- front/service:前台展示与交互业务(商品列表、详情、价格计算、Markdown 渲染)。
- api/service:API 端轻量编排(支付、初始化、视图数据准备等)。
graph TB
subgraph "核心服务"
CoreBase["BaseService"]
OrderCore["OrderService核心"]
UserCore["UserService核心"]
end
subgraph "后台端"
AdminOrder["OrderService后台"]
AdminUser["UserService后台"]
end
subgraph "前台端"
FrontProduct["ProductService前台"]
end
CoreBase --> OrderCore
CoreBase --> UserCore
AdminOrder --> OrderCore
AdminUser --> UserCore
FrontProduct --> UserCore
核心组件
- 服务基类 BaseService:定义服务层的通用约定与依赖解析方式(通过门面/辅助函数就近获取 DB、语言、安全、存储、模块等),并明确 ORM 访问采用静态门面,避免在 Service 构造中注入具体 Model。
- 核心订单服务 OrderService(核心):薄编排门面,组合购物车、状态机、条目查询、库存守卫、定时任务、结算选项等子服务,对外提供稳定签名。
- 后台订单服务 OrderService(后台):面向后台页面的业务编排,包括列表构建、详情组装、线下付款审核、批量删除/取消、自动化任务触发等。
- 前台商品服务 ProductService:商品列表与详情页数据构建,整合定价、附件、品牌、Markdown 渲染、排序选项等。
- 后台用户服务 UserService:会员列表、编辑、删除、批量操作、等级与分销等级调整日志写入等。
架构总览
服务层在 MVC 中的位置与职责:
- 控制器(Controller):接收请求、参数校验、调用服务、返回响应或跳转。
- 服务层(Service):封装业务规则、协调多模型、管理事务、统一异常与日志。
- 模型(Model):数据访问与实体映射,提供静态门面方法供服务调用。
sequenceDiagram
participant C as "控制器"
participant S as "服务层"
participant M as "模型/ORM"
participant L as "日志/审计"
participant T as "事务"
C->>S : 调用业务方法入参已校验
S->>T : 开启事务必要时
S->>M : 读取/写入数据静态门面
M-->>S : 结果集/影响行数
S->>L : 记录审计/错误日志
S-->>C : 返回结果或抛出领域异常
T-->>S : 提交/回滚
详细组件分析
订单服务(核心):主题域拆分与编排
- 职责:将订单相关能力拆分为购物车、状态机、条目查询、库存守卫、定时任务、结算选项等子服务;对外暴露稳定接口,屏蔽内部变化。
- 设计原则:单一职责、高内聚低耦合、对外签名稳定、对模块特性开关解耦(如分销奖励在未启用时跳过)。
- 关键流程:变更订单状态、生成订单号、重试付款后联动、自动取消/评价/售后标记等。
classDiagram
class OrderService_核心 {
+getCart(user_id)
+clearCart(user_id)
+changeStatus(order_sn, new_status)
+createOrderSn(user_sn)
+distributionReward(order_sn)
+retryPaidEffects(order_sn)
+getOrderItem(order_id, user_id)
+ifCanComment(order_item_id, user_id)
+checkStock(module, item_id, number)
+realTimeStock(module, item_id)
+autoUpdateComment(where_conditions)
+autoUpdateAftersaleStatus(where_conditions)
+autoCancelOrder(where_conditions)
+getPaymentList()
+getShippingList()
+timeLimit(time_limit)
+payTimeLimit(created_at, short, only_number)
+adminRefund(order_id, amount, remark)
}
订单服务(后台):业务编排与事务管理
- 列表与详情:组装筛选条件、分页、地址信息、支付方式名称、优惠券汇总、支付历史等。
- 线下付款审核:查找待审核支付记录,标记成功或失败,并联动订单状态机推进或回退。
- 批量取消:使用数据库事务保证订单及明细、关联模块状态一致更新,失败时回滚并记录日志。
- 自动化任务:在列表入口触发自动取消未付款订单、自动更新售后/评论状态等。
flowchart TD
Start(["开始"]) --> Validate["校验订单ID与存在性"]
Validate --> FindPending{"是否存在待审核支付?"}
FindPending -- 否 --> ThrowErr["抛出领域异常"]
FindPending -- 是 --> MarkSuccess["标记支付成功/失败"]
MarkSuccess --> ChangeStatus{"是否需要变更订单状态?"}
ChangeStatus -- 是 --> UpdateOrder["调用状态机变更订单状态"]
ChangeStatus -- 否 --> End(["结束"])
UpdateOrder --> Verify["验证状态是否生效"]
Verify --> |否| Rollback["抛出异常并提示重试"]
Verify --> |是| Audit["写入审计日志"]
Audit --> End
前台商品服务:数据构建与展示增强
- 列表页:支持分类、品牌、归档区间、排序选项;按需加载收藏状态、缩略图、价格折扣等。
- 详情页:基础信息、价格、画廊、品牌、型号列表、Markdown 内容渲染、多语言字段归一化。
- API 场景:返回结构化数据(销量占比、价格格式化等),便于前端消费。
sequenceDiagram
participant Ctrl as "前台控制器"
participant Svc as "ProductService"
participant ORM as "产品模型"
participant Price as "定价服务"
participant Att as "附件服务"
Ctrl->>Svc : buildProductListData(...)
Svc->>ORM : with('category')->published()->filterByCategory(...)->paginate(...)
ORM-->>Svc : 产品集合
Svc->>Price : salePrice('product', id, userId)
Price-->>Svc : 折扣价信息
Svc->>Att : galleryFirstMap / url(...)
Att-->>Svc : 图片URL
Svc-->>Ctrl : 列表数据+分页+排序选项
后台用户服务:CRUD 与审计
- 列表与编辑:聚合用户资料、联系方式快照、等级/VIP 信息、登录统计等。
- 状态变更:依据状态机允许迁移,写入审计日志。
- 批量操作:删除、导出 Excel;确保输入合法与幂等。
- 等级调整:手工调整等级时写入等级日志表,保留审计轨迹。
flowchart TD
Enter(["进入 setStatus"]) --> CheckId["校验用户ID合法性"]
CheckId --> CheckNew["校验目标状态合法性"]
CheckNew --> ReadCurrent["读取当前状态"]
ReadCurrent --> CanTransit{"是否允许迁移?"}
CanTransit -- 否 --> ThrowErr["抛出领域异常"]
CanTransit -- 是 --> Update["更新用户状态"]
Update --> Audit["写入审计日志"]
Audit --> Exit(["结束"])
依赖关系分析
- 服务基类 BaseService 提供统一的依赖解析约定(DB、语言、安全、存储、模块、ORM 静态门面),避免在 Service 中直接耦合 Request/Session。
- 核心服务通过构造函数注入子服务(如 OrderStatusTransition、OrderStockGuard、PricingService、MarkdownRenderer 等),形成清晰的主题域边界。
- 端侧服务(admin/front/api)仅做编排与展示适配,不重复实现核心业务规则。
graph LR
Base["BaseService"] --> OrderCore["OrderService核心"]
Base --> UserCore["UserService核心"]
OrderCore --> Sub1["OrderStatusTransition"]
OrderCore --> Sub2["OrderStockGuard"]
OrderCore --> Sub3["OrderScheduledTasks"]
UserCore --> USub1["UserProfileQuery"]
UserCore --> USub2["UserMembershipQuery"]
AdminOrder["OrderService后台"] --> OrderCore
AdminUser["UserService后台"] --> UserCore
FrontProduct["ProductService前台"] --> UserCore
性能考量
- 列表查询优化:使用 with 预加载关系、集中取附件缩略图映射、避免 N+1 查询。
- 分页与过滤:在服务层拼装查询条件,结合默认排序与 URL 规范化,减少无效扫描。
- 缓存与模块开关:对可选功能(如收藏、品牌、属性)通过配置开关与 Module::make 懒加载,降低无关开销。
- 批量操作:使用事务与批量 SQL 更新,减少往返次数;失败时及时回滚并记录日志。
故障排查指南
- 常见异常:非法参数、资源不存在、状态迁移非法、支付记录缺失等,均通过领域异常抛出,并附带返回路由以便友好提示。
- 事务回滚:批量取消订单等操作在异常分支中显式 rollback,并记录错误日志,便于定位问题。
- 审计追踪:所有关键写操作(创建、更新、删除、状态变更、退款等)均写入审计日志,支持回溯。
- 调试建议:检查输入校验、状态机允许迁移、支付记录是否存在、模块开关是否启用、ORM 查询条件是否正确。
结论
DouPHP 的服务层通过“核心能力 + 端侧编排”的分层设计,实现了业务逻辑的高内聚与低耦合。服务类以主题域拆分、依赖注入、静态 ORM 门面访问为核心模式,配合统一的事务管理与审计日志,保证了复杂业务的一致性与可追溯性。该设计既提升了代码的可测试性与可维护性,也为后续扩展(新模块、新端)提供了清晰的接入点。
附录:最佳实践清单
- 服务基类约定:通过 BaseService 的注释约定进行依赖解析,避免在服务中直接读取 Request。
- 模型访问:使用 ORM 静态门面进行读写,复杂查询抽取到专用 Reader/Query 服务。
- 事务边界:在涉及多表写操作的场景中显式开启事务,异常时回滚并记录日志。
- 错误处理:统一抛出领域异常,携带提示信息与返回路由,避免静默失败。
- 可测试性:通过构造函数注入子服务,便于单元测试替换依赖。
- 可维护性:按主题域拆分服务,保持对外签名稳定,内部实现可演进。