简介
本指南面向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 与各中间件。