文档目录
服务层设计

引言

本文件面向 DouPHP 前台服务层的开发者,系统阐述服务层的设计理念、职责边界与实现模式。重点覆盖业务逻辑封装、数据处理、外部服务调用、事务管理、接口设计与版本兼容策略,并通过产品、订单、用户等典型服务给出可操作的开发指引与排障建议。

项目结构

前台服务层位于 front/service 下,按领域划分(product、order、user 等),每个服务类聚焦单一业务域,通过构造函数注入共享能力(定价、钱包、优惠券资格、联系人查询等)。前台启动流程由 Init 统一编排,负责语言、模块、视图、会话、安全与站点状态初始化,并将关键服务注册到容器供后续控制器与服务使用。

graph TB
A["前台入口<br/>front/init/Init.php"] --> B["服务基类<br/>core/service/BaseService.php"]
A --> C["产品服务<br/>front/service/product/ProductService.php"]
A --> D["购物车服务<br/>front/service/order/CartService.php"]
A --> E["结算服务<br/>front/service/order/CheckoutService.php"]
A --> F["登录服务<br/>front/service/user/LoginService.php"]
A --> G["资料服务<br/>front/service/user/ProfileService.php"]
C --> H["定价服务/Markdown/排序构建器"]
D --> I["核心订单服务/定价服务"]
E --> J["钱包服务/定价服务/联系人查询/优惠券资格"]
F --> K["用户认证/联系人查询/审计日志"]
G --> L["统计/等级/联系人查询/展示构建"]

核心组件

  • 服务基类 BaseService:定义服务层约定,强调通过门面与 helper 就近获取依赖,避免在 Service 中直接耦合 Request/Session;读多写少,复杂查询下沉到专用 Reader/Core。
  • 前台初始化 Init:完成会话、时区、语言、站点配置、主题、视图引擎、导航与消息响应器等基础设施装配,并挂载可选模块(如 user、favorites、coupon)的能力。
  • 领域服务:
    • ProductService:商品列表与详情数据组装、属性价格联动、型号关联、品牌信息聚合。
    • CartService:加购、改数量、删条目,含规格校验、库存校验、跨模块/积分清空策略。
    • CheckoutService:结算页数据、运费重算、优惠券试算与核销、下单事务(含价格防篡改、地址快照、优惠券明细、零元单自动支付)。
    • LoginService:账号密码与手机验证码登录校验、IP 限流、账户锁定、历史哈希升级、审计日志。
    • ProfileService:会员资料更新、昵称占用检测、会员中心首页数据装配、等级成长进度与推广二维码生成。

架构总览

前台请求经路由进入控制器后,交由对应服务处理。服务之间通过构造函数注入共享能力(定价、钱包、优惠券资格、联系人查询等),保持低耦合与高内聚。Init 在启动阶段将关键服务与门面注册至容器,确保运行时按需解析。

sequenceDiagram
participant Client as "客户端"
participant Controller as "前台控制器"
participant Init as "前台初始化<br/>Init"
participant Svc as "领域服务"
participant Core as "核心服务(定价/钱包/优惠券)"
participant DB as "数据库"
Client->>Controller : "HTTP 请求"
Controller->>Init : "复用已启动的容器与环境"
Controller->>Svc : "调用具体服务方法"
Svc->>Core : "调用定价/钱包/优惠券资格等"
Core->>DB : "读取/写入数据"
DB-->>Core : "结果集"
Core-->>Svc : "计算结果"
Svc-->>Controller : "业务结果"
Controller-->>Client : "响应"

详细组件分析

产品服务(ProductService)

  • 职责边界:商品列表与详情页的数据组装、属性价格联动、型号关联、品牌信息聚合。不直接处理 HTTP 输入输出。
  • 关键流程:
    • 列表:根据分类、品牌、归档区间、排序规则进行分页查询,批量加载分类与附件,计算收藏状态与售价。
    • 详情:取发布态商品,格式化价格与内容,加载画廊、品牌、收藏状态与型号列表。
    • API 属性:根据选中属性动态调整价格与积分换算。
flowchart TD
Start(["buildProductListData"]) --> Parse["参数校验与默认值"]
Parse --> BuildSort["构建排序选项"]
BuildSort --> Query["构造查询(分类/归档/品牌/排序)"]
Query --> Paginate["分页获取列表"]
Paginate --> Enrich["批量填充收藏/附件/价格"]
Enrich --> Return["返回 product_list/pager/sort_list/brand"]

购物车服务(CartService)

  • 职责边界:加购、改数量、删除条目;负责规格校验、库存校验、跨模块/积分兑换清空策略。
  • 关键流程:
    • 加购:校验商品存在性,必要时清空购物车(跨模块或积分兑换/立即购买),校验规格与库存,插入或合并条目。
    • 改数量:仅对普通商品且非一键购买生效,重新校验库存并计算小计与总价。
    • 删除:按用户与条目删除。
sequenceDiagram
participant C as "控制器"
participant CS as "CartService"
participant OS as "OrderCore"
participant PS as "PricingService"
participant DB as "数据库"
C->>CS : "addToCart(userId,module,itemId,number,mode,action,att)"
CS->>DB : "校验商品存在"
alt 跨模块/积分/立即购买
CS->>OS : "clearCart(userId)"
end
CS->>DB : "规格属性校验"
CS->>OS : "checkStock(module,itemId,number)"
alt 库存不足
CS-->>C : "错误 : stock_error"
else 成功
CS->>DB : "插入/合并购物车条目"
CS-->>C : "ok=true + mode/module/action"
end

结算服务(CheckoutService)

  • 职责边界:结算页数据装配、运费重算、优惠券试算与核销、下单事务(含价格防篡改、地址快照、优惠券明细、零元单自动支付)。
  • 关键流程:
    • 获取结算数据:读取购物车、运费配置、默认收货人、可用优惠券、配送方式。
    • 运费重算:按配送插件配置与金额阈值计算运费。
    • 优惠券试算:校验归属与可用性,计算抵扣金额并缓存至 Session。
    • 创建订单(事务):库存校验、价格防篡改、积分扣减(若积分兑换)、优惠券核销、运费计算、分销奖励比例、写入订单/订单项/地址快照/优惠券明细,清理购物车;零元单自动标记为已支付。
sequenceDiagram
participant Ctrl as "控制器"
participant CS as "CheckoutService"
participant OS as "OrderCore"
participant WS as "WalletService"
participant CE as "CouponEligibility"
participant DB as "数据库"
Ctrl->>CS : "createOrder(userId, form)"
CS->>OS : "getCart(userId)"
alt 购物车为空
CS-->>Ctrl : "cart_empty"
end
CS->>DB : "校验库存/商品存在"
CS->>WS : "积分兑换扣减(可选)"
CS->>CE : "优惠券资格判定与抵扣计算"
CS->>DB : "开启事务"
DB->>DB : "写入 order / order_item / order_address / order_coupon"
DB-->>CS : "提交事务"
CS->>OS : "clearCart(userId)"
alt 零元单
CS->>OS : "changeStatus(PAID)"
end
CS-->>Ctrl : "ok=true + order_sn/amount/mode"

登录服务(LoginService)

  • 职责边界:凭据校验(账号密码/手机验证码),包含 IP 限流、账户锁定、历史哈希升级、审计日志;不写 session/cookie,登录态写入由调用方完成。
  • 关键流程:
    • 账号密码:识别字段类型(邮箱/手机),查库、锁定检查、密码校验(md5/bcrypt 兼容)、状态检查、失败计数与审计、成功计数与审计。
    • 手机验证码:校验验证码与时效,命中则自动创建用户并登记推广关系,随后走成功路径。
flowchart TD
Start(["validateLoginCredentials"]) --> Rate["IP 限流检查"]
Rate --> |触发| LogFail["记录失败日志"] --> ReturnErr["返回错误"]
Rate --> |未触发| Identify["识别字段(email/mobile)"]
Identify --> Query["查询用户"]
Query --> Lock{"是否锁定"}
Lock --> |是| LogLock["记录锁定日志"] --> ReturnErr
Lock --> |否| Verify["密码校验(md5/bcrypt)"]
Verify --> Status{"状态允许登录?"}
Status --> |否| LogStatus["记录状态异常"] --> ReturnErr
Status --> |是| Success["记录成功日志"] --> ReturnOk["返回用户"]

资料服务(ProfileService)

  • 职责边界:会员资料更新、昵称占用检测、会员中心首页数据装配;不触碰模板与 Session。
  • 关键流程:
    • 更新资料:拆分收货 8 字段写入默认联系人行,其余字段更新用户表,记录审计日志。
    • 昵称占用:排除自身后判断是否存在冲突。
    • 首页数据:合并联系人快照、头像 URL、最近登录、积分/余额/优惠券/收藏/消费统计、等级成长进度、推广二维码等。

依赖关系分析

  • 服务间依赖:
    • ProductService 依赖定价服务、Markdown 渲染、排序构建器、附件服务、品牌模型。
    • CartService 依赖核心订单服务、定价服务。
    • CheckoutService 依赖核心订单服务、钱包服务、定价服务、联系人查询、优惠券资格。
    • LoginService 依赖用户认证服务、联系人查询、审计日志。
    • ProfileService 依赖统计服务、等级服务、联系人查询、展示构建。
  • 启动期依赖:Init 在 bootCore 中注册导航、面包屑、消息响应器、SEO 解析器、排序选项构建器等,并在 loadLanguageAndModules 中按需注册用户中心导航构建器与 Auth 门面。
classDiagram
class BaseService
class ProductService {
+buildProductListData(...)
+buildProductShowData(...)
+buildApiAttributeData(...)
}
class CartService {
+addToCart(...)
+updateCartItem(...)
+deleteCartItem(...)
}
class CheckoutService {
+getCheckoutData(...)
+recalculateShipping(...)
+applyCoupon(...)
+createOrder(...)
}
class LoginService {
+validateLoginCredentials(...)
+validatePhoneLogin(...)
}
class ProfileService {
+updateProfile(...)
+nicknameExistsForOtherUser(...)
+getUserInfo(...)
+buildEditableUserInfo(...)
}
ProductService --> BaseService
CartService --> BaseService
CheckoutService --> BaseService
LoginService --> BaseService
ProfileService --> BaseService

性能考虑

  • 批量加载与预取:商品列表使用 with('category') 批量加载分类,减少 N+1 查询;附件与图片采用批量映射。
  • 排序与分页:通过 ListSortOptionBuilder 统一生成排序 SQL 与页面链接,避免重复计算。
  • 价格计算:集中到 PricingService,避免在各处重复计算导致不一致与额外开销。
  • 购物车操作:仅在必要场景清空购物车(跨模块/积分兑换/立即购买),减少不必要写操作。
  • 结算页:运费与优惠券计算缓存至 Session,AJAX 重算时快速返回。
  • 事务最小化:下单事务仅包裹必要的写操作,异常时回滚并记录日志。

故障排查指南

  • 登录失败:
    • 检查 IP 限流与账户锁定状态;查看审计日志中的失败原因(字段无效、密码错误、账户锁定、验证码无效/过期)。
    • 确认历史 md5 哈希已升级为 bcrypt,避免旧密码无法验证。
  • 购物车异常:
    • 规格属性不匹配会导致加购失败;检查 attribute_value 与 item_id 的归属关系。
    • 库存不足会返回 stock_error;确认 checkStock 返回值与实时库存。
  • 下单失败:
    • 价格防篡改:服务端重算金额与前端传入差异超过阈值会拒绝;检查 sale_price 与属性加价。
    • 优惠券不可用:检查 coupon_log 归属与状态、有效期与范围;确认 eligibility 判定逻辑。
    • 事务异常:捕获异常并记录详细上下文(用户、订单号、模块、金额、异常堆栈),便于定位。

结论

DouPHP 前台服务层以“领域服务 + 共享核心服务”的模式组织,职责清晰、依赖明确。通过 Init 统一装配、BaseService 规范约定、以及定价/钱包/优惠券资格等核心服务的解耦,实现了高内聚、低耦合的可维护架构。服务层在事务、价格防篡改、库存校验、审计日志等方面提供了完善保障,适合扩展新的业务服务并保持向后兼容。

附录:开发示例与最佳实践

  • 编写新服务类

    • 继承 BaseService,通过构造函数注入所需核心服务(如 PricingService、WalletService、CouponEligibility)。
    • 方法签名显式传入上下文参数(如 userId、ip),不在服务内部读取 Request/Session。
    • 使用 ORM 静态门面进行读写,复杂查询下沉到 Reader/Core 服务。
  • 处理复杂业务逻辑

    • 将跨模块协调逻辑放入服务方法(如 CheckoutService::createOrder),保证原子性与一致性。
    • 使用事务包裹写操作,异常时回滚并记录日志。
  • 实现事务管理

    • 在 CheckoutService::createOrder 中演示了事务的使用:先准备数据(订单号、用户信息),再执行写操作(订单、订单项、地址快照、优惠券明细),最后提交或回滚。
  • 测试策略

    • 单元测试:针对服务方法输入输出进行断言,模拟核心服务返回(如定价、钱包、优惠券资格)。
    • 集成测试:验证数据库交互(库存、优惠券、订单)与事务行为。
    • 端到端测试:覆盖登录、加购、结算、下单全流程。
  • 性能优化技巧

    • 批量加载与预取(with、批量映射)。
    • 合理分页与排序(ListSortOptionBuilder)。
    • 价格计算集中化(PricingService)。
    • 缓存 Session 中的运费与优惠券信息,减少重复计算。
  • 服务接口设计与版本兼容

    • 服务方法保持向后兼容:新增参数提供默认值,避免破坏现有调用。
    • 对外暴露稳定接口(如 createOrder 的表单键),内部实现可演进。
    • 通过 features 开关控制可选模块能力(如 favorites、attribute、coupon),确保最小化站点可用。
添加日期:2026-10-05