文档目录
控制器层设计

简介

本设计文档聚焦 DouPHP 框架的控制器层,围绕 BaseController 基类的设计模式与职责、三端(前台 front、后台 admin、API)控制器的继承关系与差异化实现、HTTP 请求处理流程、参数注入机制、响应生成方式展开。同时说明依赖注入容器在控制器中的作用,以及不同端侧控制器的特定功能实现,并通过具体示例展示控制器如何与中间件、服务层协作。

项目结构

DouPHP 将控制器按“端”划分:

  • 核心基类 core/controller/BaseController.php:提供三端共享的基础能力(JSON/通用响应/重定向)。
  • 前台 base front/controller/BaseController.php:提供 view()、layoutVars()、respond() 等前台专属能力。
  • 后台 base admin/controller/BaseController.php:提供 view()、layoutVars()、AI 工具栏注入、删除结果分流、布尔切换响应等后台专属能力。
  • API base api/controller/BaseController.php:提供 buildLinkUserCenter() 复用前台导航构建器。

路由调度通过 core/web/routing/DelegatingRouter.php 统一代理三端 Router;认证由各自中间件完成(如 admin/middleware/AuthMiddleware.php、api/middleware/UserAuthMiddleware.php)。

graph TB
subgraph "核心"
CoreBC["core/controller/BaseController.php"]
Delegator["core/web/routing/DelegatingRouter.php"]
end
subgraph "前台"
FrontBC["front/controller/BaseController.php"]
FrontIndex["front/controller/index/IndexController.php"]
end
subgraph "后台"
AdminBC["admin/controller/BaseController.php"]
AdminIndex["admin/controller/index/IndexController.php"]
AdminAuth["admin/middleware/AuthMiddleware.php"]
end
subgraph "API"
ApiBC["api/controller/BaseController.php"]
ApiIndex["api/controller/index/IndexController.php"]
ApiAuth["api/middleware/UserAuthMiddleware.php"]
end
Delegator --> FrontIndex
Delegator --> AdminIndex
Delegator --> ApiIndex
FrontIndex --> FrontBC
AdminIndex --> AdminBC
ApiIndex --> ApiBC
AdminIndex --> AdminAuth
ApiIndex --> ApiAuth
FrontBC --> CoreBC
AdminBC --> CoreBC
ApiBC --> CoreBC

核心组件

  • 核心基类 BaseController(core):定义 json()/response()/redirect() 三种基础响应构造方法,并约定 HTTP 输入必须通过 Request/FormRequest 形参注入,避免在 helper 中直接访问全局 request。
  • 前台 BaseController(front):重写 view() 合并 layoutVars(),提供 respond() 统一成功分流(JSON 携带 redirect_url,普通表单走 303),并提供 buildLinkUserCenter() 复用前台导航构建器。
  • 后台 BaseController(admin):重写 view() 合并 layoutVars(),注入 AI 创作工具栏、绝对化 page_actions/page_sub_actions 链接、normalizeFlashes 归一化 flash、respondDeleteResult() 删除结果分流、respondToggle() 行内开关响应、buildLinkUserCenter() 使用后台导航构建器。
  • API BaseController(api):不重写 view(),提供 buildLinkUserCenter() 复用前台导航构建器(Api\Init 以相同类名注册到容器)。

架构总览

控制器层采用“核心基类 + 端侧扩展”的分层设计:

  • 核心基类负责跨端通用的响应构造与输入注入约定。
  • 各端 BaseController 封装端侧差异:视图渲染、布局变量、用户中心导航、业务响应分流。
  • 路由调度通过 DelegatingRouter 统一代理三端 Router,中间件在控制器之前完成鉴权与安全策略。
  • 控制器通过构造函数依赖注入服务层对象,遵循单一职责,仅编排调用与组装响应。
sequenceDiagram
participant Client as "客户端"
participant Router as "DelegatingRouter"
participant MW as "端中间件"
participant Ctrl as "端控制器"
participant Svc as "服务层"
participant Resp as "响应对象"
Client->>Router : "HTTP 请求"
Router->>MW : "分发前执行中间件"
MW-->>Router : "放行或拒绝"
Router->>Ctrl : "调用控制器 action"
Ctrl->>Svc : "调用服务层方法"
Svc-->>Ctrl : "返回数据/结果"
Ctrl->>Resp : "构造 ViewResponse/JsonResponse/RedirectResponse"
Resp-->>Client : "返回响应"

详细组件分析

核心基类 BaseController(core)

  • 职责:提供统一的 JSON、通用响应、重定向构造方法;约束 HTTP 输入必须通过 Request/FormRequest 形参注入,保证可测试性与解耦。
  • 关键点:
    • json()/response()/redirect() 分别返回 JsonResponse、Response、RedirectResponse。
    • 注释明确禁止在 action/helper 中直接调用 request 辅助函数,需显式接收 Request。

前台 BaseController(front)

  • 职责:
    • view():构造 ViewResponse,合并 action data 与 layoutVars()(action 优先覆盖)。
    • respond():统一成功分流,JSON 请求返回包含 redirect_url 的成功信封,非 JSON 走 303 重定向。
    • layoutVars():默认空数组,子类可注入 SEO、导航等公共变量。
    • buildLinkUserCenter():若已登录且容器中存在 FrontUserCenterNavBuilder,则构建会员中心子导航 ViewModel。
  • 典型用法:前台 IndexController 在 index() 中调用服务层获取首页数据,通过 view('index.dwt', $data) 渲染模板,并在 layoutVars() 注入 keywords/description/nav_*。
flowchart TD
Start(["进入前台控制器 action"]) --> CallSvc["调用服务层构建数据"]
CallSvc --> BuildView["调用 view(template, data)"]
BuildView --> MergeLayout["合并 layoutVars() 到 data"]
MergeLayout --> Render["构造 ViewResponse 并返回"]

后台 BaseController(admin)

  • 职责:
    • view():构造 ViewResponse,合并 layoutVars() 与 action data,并对 page_actions/page_sub_actions 中的 href/confirm/attrs 进行绝对地址转换,确保伪静态深路径下链接有效。
    • injectAiToolbar():根据 cur/rec 上下文向页面注入 AI 创作工具栏按钮与配置,支持列表页与表单页挂载 link_ai 模块。
    • layoutVars():注入 flashes、page_actions、page_sub_actions、breadcrumb、cue 等公共变量;flashes 经 normalizeFlashes() 归一化为模板可直接消费的数组。
    • respondDeleteResult():删除结果分流,未确认时跳转 dou_msg.htm 二次确认,确认后 302 + flash。
    • respondToggle():行内布尔切换响应,AJAX 返回 JSON(value),普通请求 302 + flash。
    • buildLinkUserCenter():使用后台 UserCenterNavBuilder 构建会员中心子导航。
  • 典型用法:后台 IndexController 在 index() 中调用服务层获取系统信息、备份、快速开始项等,通过 view('index.htm', $data) 渲染控制台页面。
flowchart TD
A["后台 action 调用 view()"] --> B["合并 layoutVars() 与 action data"]
B --> C{"是否包含 page_actions/page_sub_actions?"}
C -- 是 --> D["绝对化 href/confirm/attrs"]
C -- 否 --> E["跳过"]
D --> F["注入 AI 工具栏可选"]
E --> F
F --> G["构造 ViewResponse 返回"]

API BaseController(api)

  • 职责:
    • 不重写 view(),API 通常返回 JSON 或标准响应。
    • buildLinkUserCenter():复用前台导航构建器(Api\Init 在容器中以相同类名注册),实现前后端一致的会员中心导航。
  • 典型用法:API IndexController 在 index() 中调用服务层构建首页数据,直接返回 ApiResponse::success($data)。

中间件与认证

  • 后台 AuthMiddleware:从 session 恢复管理员登录态,未登录抛出异常并重定向到登录页;免登入口通过路由级 withoutMiddleware 豁免。
  • API UserAuthMiddleware:从 Authorization: Bearer 头提取 token,交由 auth('api') guard 解析登录态;未认证返回 401 JSON,无工作身份返回 403 JSON。
sequenceDiagram
participant R as "路由"
participant AMW as "Admin 认证中间件"
participant FW as "前台/后台/API 控制器"
R->>AMW : "请求进入"
AMW->>AMW : "restoreFromSession()"
alt 未登录
AMW-->>R : "抛出异常 -> 重定向到登录页"
else 已登录
AMW-->>FW : "放行至控制器"
end

依赖注入容器在控制器中的作用

  • 控制器通过构造函数声明依赖(如服务层、门面),由容器自动解析并注入,实现松耦合与可测试性。
  • 端侧 BaseController 通过 app()->has()/app() 按需解析 Builder(如 UserCenterNavBuilder、AiToolbarBuilder),仅在存在时执行,避免强依赖。
  • 路由调度通过 DelegatingRouter 代理三端 Router,保持当前路由状态与分发逻辑的统一抽象。

依赖关系分析

  • 控制器对服务层的依赖通过构造函数注入,降低耦合度。
  • 控制器对容器的使用集中在端侧 BaseController:按需解析 Builder,避免硬编码依赖。
  • 路由与中间件位于控制器之前,负责鉴权、安全、限流等横切关注点。
classDiagram
class CoreBaseController {
+json(data, statusCode, encodeOptions)
+response(content, statusCode, headers)
+redirect(url, statusCode)
}
class FrontBaseController {
+view(template, data, statusCode)
+respond(request, redirectUrl, data, message)
+layoutVars()
+buildLinkUserCenter(currentModule)
}
class AdminBaseController {
+view(template, data, statusCode)
+layoutVars()
+respondDeleteResult(result)
+respondToggle(request, value, message, backUrl)
+buildLinkUserCenter(currentModule)
}
class ApiBaseController {
+buildLinkUserCenter(currentModule)
}
CoreBaseController <|-- FrontBaseController
CoreBaseController <|-- AdminBaseController
CoreBaseController <|-- ApiBaseController

性能考量

  • 懒求值:前端/后台 layoutVars() 仅在真正渲染模板时执行,避免 JSON/重定向路径上的不必要开销。
  • 轻量前置过滤:后台 AI 工具栏注入前进行模块匹配判断,减少不必要的服务调用。
  • 响应类型选择:API 端优先使用 ApiResponse 统一信封,减少重复包装成本;前台/后台在 AJAX 场景下返回结构化 JSON,避免额外模板渲染。

故障排查指南

  • 后台链接失效:检查 page_actions/page_sub_actions 的 href/confirm/attrs 是否被 absolutizeActionUrls() 处理;确认路由配置与伪静态规则。
  • 删除操作未跳转:确认 service 返回的 confirm_url 是否为空;为空应走 302 + flash,非空应显示 dou_msg.htm 二次确认。
  • 行内开关无效:确认请求是否带 X-Requested-With 或 wantsJson();AJAX 应返回 JSON 携带 value,普通请求应 302 + flash。
  • API 未认证:检查 Authorization: Bearer 是否正确传递;确认 UserAuthMiddleware 能正确解析 token 并 hydrate 登录态。

结论

DouPHP 控制器层通过核心基类与端侧扩展的组合,实现了清晰的职责分离与可扩展性:核心基类提供通用响应与输入注入约定,端侧 BaseController 封装视图渲染、布局变量、用户中心导航与业务响应分流。中间件在控制器之前完成鉴权与安全策略,服务层通过依赖注入接入控制器,形成高内聚、低耦合的请求处理链路。该设计便于在三端间复用能力、扩展新功能,并保持良好的可测试性与可维护性。

附录

  • 最佳实践建议:
    • 控制器只负责编排与响应构造,业务逻辑下沉到服务层。
    • 所有外部输入通过 Request/FormRequest 形参注入,避免直接访问全局 request。
    • 使用端侧 BaseController 提供的 view()/respond()/layoutVars() 等方法,保持一致的响应风格。
    • 在中间件中处理横切关注点(认证、权限、限流、安全头),不在控制器中重复实现。
添加日期:2026-10-05