文档目录
服务层

简介

本指南面向DouPHP后台服务层的开发者,聚焦于服务层的职责边界、业务逻辑封装原则与可维护性实践。内容覆盖:

  • 服务层职责划分与分层协作(控制器/请求校验/服务/模型)
  • 数据验证机制(表单规则、自定义校验器、批量数据校验)
  • 事务处理最佳实践(开启、提交、回滚)
  • 缓存策略(设置、获取、失效管理)
  • 开发示例(高质量服务类、复杂业务编排、数据导出导入)
  • 横切关注点(错误处理、日志记录、性能监控)

项目结构

后台入口位于 admin 目录,采用“路由 -> 中间件 -> 控制器 -> 服务 -> 模型”的分层组织;核心能力由 core 提供(如服务基类、校验工具、门面等)。

graph TB
A["admin/index.php"] --> B["admin/foundation/routing/Router.php"]
B --> C["admin/foundation/routing/AdminResolver.php"]
C --> D["admin/middleware/*"]
D --> E["admin/controller/*"]
E --> F["admin/service/*"]
F --> G["admin/model/*"]
F --> H["core/service/BaseService.php"]
F --> I["core/support/Check.php"]
F --> J["core/facade/*"]

图示来源

  • Router.php
  • AdminResolver.php
  • BaseService.php
  • Check.php

核心组件

  • 服务基类 BaseService:定义服务层统一约定与依赖解析方式(通过门面/辅助函数),强调“Model不入参”,写操作优先 create,读操作使用 with 关联查询。
  • 通用校验 Check:提供丰富的静态校验方法,用于输入消毒与格式校验,支持批量ID归一化等场景。
  • 路由与中间件:Router/AdminResolver 负责解析路由到控制器;Auth/Permission/Csrf/SecurityHeaders 中间件保障安全与权限。
  • HTTP响应:AdminMessageResponder 统一消息返回格式。

架构总览

后台请求从路由进入,经中间件完成鉴权、CSRF与安全头处理后到达控制器;控制器将参数交由服务层处理,服务层通过ORM门面访问数据库,必要时调用缓存、存储、邮件等外部能力。

sequenceDiagram
participant Client as "客户端"
participant Router as "路由/解析器"
participant MW as "中间件(鉴权/权限/CSRF)"
participant Ctrl as "控制器"
participant Svc as "服务(BaseService子类)"
participant ORM as "ORM门面"
participant Cache as "缓存"
participant DB as "数据库"
Client->>Router : HTTP请求
Router->>MW : 分发至中间件链
MW-->>Router : 通过/拒绝
Router->>Ctrl : 调用控制器动作
Ctrl->>Svc : 执行业务方法(入参已清洗)
Svc->>Cache : 读取/写入缓存(可选)
Svc->>ORM : 读写数据(create/find/update/paginate)
ORM->>DB : SQL执行
DB-->>ORM : 结果集
ORM-->>Svc : 模型/集合
Svc-->>Ctrl : 业务结果
Ctrl-->>Client : 响应(统一消息体)

图示来源

  • Router.php
  • AdminResolver.php
  • AuthMiddleware.php
  • PermissionMiddleware.php
  • CsrfMiddleware.php
  • SecurityHeadersMiddleware.php
  • BaseService.php

详细组件分析

服务基类与依赖约定

  • 职责边界:服务层专注业务编排与领域规则,不直接读取HTTP上下文;上下文由shell层(admin/front/api)提取后作为方法参数传入。
  • 依赖解析:通过门面/辅助函数就近获取(DB、语言、安全、视图、存储、模块等)。
  • ORM约定:写走 create,更新走 find+fill+save 或 whereKey+update;读走 with 预加载关系;复杂查询下沉到 Reader/Core 服务。
classDiagram
class BaseService {
<<abstract>>
+依赖通过门面/辅助函数解析
+ORM写 : create / update
+ORM读 : with(...)->find/get/paginate
}
class ArticleService {
+publish(payload)
+detail(id)
}
BaseService <|-- ArticleService

图示来源

  • BaseService.php

数据验证机制

  • 表单验证规则:在控制器/Request层进行字段级校验,使用 Check 提供的静态方法进行类型与格式校验(数字、邮箱、手机号、URL、域名、日期、时间戳等)。
  • 自定义验证器:基于 Check 扩展业务规则(如组合校验、跨字段校验),保持无状态纯函数风格。
  • 批量数据验证:使用 intIds 对批量勾选的原始值进行去重、转整型、过滤非法项,确保后续批量操作安全。
flowchart TD
Start(["接收表单数据"]) --> Validate["逐字段调用 Check.* 校验"]
Validate --> Valid{"全部通过?"}
Valid -- 否 --> Error["返回校验错误(含字段/原因)"]
Valid -- 是 --> Normalize["批量字段归一化(intIds等)"]
Normalize --> BuildPayload["组装业务载荷"]
BuildPayload --> End(["交给服务层处理"])

图示来源

  • Check.php

事务处理最佳实践

  • 开启:在涉及多表写操作的入口处显式开启事务。
  • 提交:所有写操作成功后统一提交。
  • 回滚:任一环节失败立即回滚,并抛出/返回结构化错误。
  • 建议:将事务边界放在服务层,避免在控制器中直接操作数据库;对于长事务拆分为子步骤,减少锁持有时间。
sequenceDiagram
participant Svc as "服务"
participant DB as "数据库"
Svc->>DB : 开启事务
Svc->>DB : 写操作A
DB-->>Svc : 成功/失败
alt 失败
Svc->>DB : 回滚事务
Svc-->>调用方 : 返回错误
else 成功
Svc->>DB : 写操作B
DB-->>Svc : 成功/失败
alt 失败
Svc->>DB : 回滚事务
Svc-->>调用方 : 返回错误
else 成功
Svc->>DB : 提交事务
Svc-->>调用方 : 返回成功
end
end

缓存策略设计与实现

  • 设置:在服务层对热点读数据进行缓存写入(如配置、字典、统计聚合结果)。
  • 获取:先读缓存,未命中再查库并回填缓存。
  • 失效:写操作成功后主动失效相关缓存键;对过期数据采用TTL或事件驱动失效。
  • 注意:缓存键命名需包含业务域与版本前缀,避免冲突;对一致性要求高的数据谨慎使用缓存。
flowchart TD
Req["读取请求"] --> Hit{"缓存命中?"}
Hit -- 是 --> ReturnCache["返回缓存数据"]
Hit -- 否 --> LoadDB["查询数据库"]
LoadDB --> SaveCache["写入缓存(带TTL)"]
SaveCache --> ReturnDB["返回数据库数据"]

开发示例指引

  • 编写高质量服务类
    • 单一职责:每个服务对应一个业务域(如订单、商品、用户)。
    • 明确入参与返回值:入参来自请求层,返回值仅包含业务结果与必要元信息。
    • 使用ORM门面:遵循 create/find/update/paginate 约定。
    • 复杂查询下沉:抽取 Reader/Core 服务,按DI注入。
  • 复杂业务编排
    • 将跨表/跨服务的步骤拆分到私有方法,保证主流程清晰。
    • 使用事务包裹写路径,异常时统一回滚。
  • 数据导出导入
    • 导出:分页查询大结果集,流式写出到文件/对象存储。
    • 导入:分批读取CSV/Excel,逐批校验与入库,失败行记录日志并继续。

依赖关系分析

  • 路由与中间件:Router/AdminResolver 负责将请求解析到控制器;中间件链保障鉴权、权限、CSRF与安全头。
  • 服务与ORM:服务通过ORM门面访问数据库,避免直接耦合SQL。
  • 配置:系统配置、安全策略、站点开关等通过配置中心统一管理。
graph LR
R["Router/AdminResolver"] --> M["中间件(鉴权/权限/CSRF/安全头)"]
M --> C["控制器"]
C --> S["服务(BaseService子类)"]
S --> O["ORM门面"]
S --> CFG["配置(config/system/security)"]

图示来源

  • Router.php
  • AdminResolver.php
  • AuthMiddleware.php
  • PermissionMiddleware.php
  • CsrfMiddleware.php
  • SecurityHeadersMiddleware.php
  • config.php
  • system.php
  • security.php

性能考虑

  • 查询优化:合理使用 with 预加载,避免N+1;分页查询限制返回字段。
  • 事务范围:尽量缩小事务粒度,减少锁竞争。
  • 缓存命中:热点数据加缓存,合理设置TTL与失效策略。
  • 批量操作:合并写操作,降低往返次数。
  • 日志与监控:对关键路径打点,记录耗时与错误率,便于定位瓶颈。

故障排查指南

  • 常见错误
    • 参数校验失败:检查 Request/控制器中的校验规则与 Check 方法使用是否正确。
    • 权限不足:确认中间件链是否放行,权限策略是否匹配。
    • CSRF校验失败:确认表单是否携带有效令牌。
    • 数据库异常:查看事务边界与回滚逻辑,确认SQL与索引。
  • 定位手段
    • 启用调试日志,记录请求ID、入参、关键步骤耗时。
    • 使用统一消息响应体,便于前端快速定位错误位置。
    • 结合配置开关控制日志级别与输出目标。

结论

DouPHP后台服务层以 BaseService 为契约基础,配合统一的校验工具、ORM门面与中间件体系,形成清晰的分层架构。遵循本文的职责划分、验证、事务、缓存与横切关注点实践,可有效提升代码的可维护性与稳定性。建议在新增功能时严格遵循上述规范,并通过测试与监控持续验证质量。

附录

  • 术语
    • 服务层:封装业务逻辑与领域规则的层级。
    • ORM门面:对数据访问的抽象接口,屏蔽底层实现细节。
    • 中间件:在请求/响应管道中执行的横切逻辑。
  • 参考
    • 服务基类约定与ORM用法参见 BaseService 注释。
    • 校验方法与批量ID归一化参见 Check。
    • 路由与中间件链路参见 Router、AdminResolver 与各中间件。
添加日期:2026-10-05