文档目录
基础控制器BaseController

简介

本技术文档聚焦 DouPHP 前台基础控制器 BaseController,系统阐述其设计理念、通用能力(请求处理、数据验证、错误处理、视图渲染)、生命周期管理、中间件集成与安全机制,并通过真实控制器示例展示如何正确继承与使用。读者可据此快速掌握在自定义控制器中复用 Base 能力的标准做法。

项目结构

DouPHP 将“三端共享”的控制器基类放在 core 层,前台专属能力集中在 front/controller/BaseController.php;业务控制器位于 front/controller/模块名/下,统一继承前台 BaseController。

graph TB
A["core/controller/BaseController.php<br/>三端共享基础能力"] --> B["front/controller/BaseController.php<br/>前台扩展:view()/layoutVars()/respond()"]
B --> C["front/controller/index/IndexController.php"]
B --> D["front/controller/user/UserController.php"]
B --> E["front/controller/product/ProductController.php"]
B --> F["front/controller/user/AuthController.php"]

核心组件

  • 三端共享基类(Core):提供 JSON、通用响应、重定向等通用构造方法,约束 HTTP 输入注入约定,确保跨端一致性与可测试性。
  • 前台基类(Front):在 Core 基础上提供前台模板渲染 view()、布局变量 layoutVars()、POST 成功分流 respond()、会员中心导航 buildLinkUserCenter()。
  • 业务控制器:通过构造函数注入服务(如 IndexService、ProductService、NavigationBuilder、SeoResolver 等),在 action 中组合数据并返回 view()/json()/response()/redirect()。

架构总览

前台控制器的典型调用链:路由解析 → 控制器实例化(依赖注入)→ action 执行业务逻辑 → 调用 Base 提供的响应构造方法 → 框架输出响应。

sequenceDiagram
participant R as "路由"
participant C as "业务控制器"
participant B as "前台BaseController"
participant V as "模板渲染器"
participant S as "服务/门面"
R->>C : 调用 action(Request $request)
C->>S : 获取业务数据/导航/SEO
C->>B : view('模板', $data)
B->>V : 合并 layoutVars() + $data 并渲染
V-->>B : ViewResponse
B-->>C : ViewResponse
C-->>R : Response

详细组件分析

前台 BaseController 能力详解

  • view($template, $data = [], $statusCode = 200)
    • 作用:构造前台视图响应,自动合并 layoutVars() 作为公共变量,action 数据优先覆盖。
    • 关键点:仅当真正渲染时才执行 layoutVars(),避免不必要的计算开销。
  • respond(Request $request, $redirectUrl, array $data = [], $message = '')
    • 作用:统一 POST 成功出口。JSON 请求返回带 redirect_url 的成功信封;普通表单提交走 303 重定向,保证渐进增强。
    • 关键点:显式接收 Request,内部不调用 request helper,便于测试与解耦。
  • layoutVars()
    • 作用:返回每个 action 渲染时自动叠加的公共变量(如导航、SEO、当前模块标记等)。
    • 关键点:默认空数组,子类按需重写并叠加自身键。
  • buildLinkUserCenter($currentModule = '')
    • 作用:构建会员中心子导航 ViewModel;未登录或 Builder 未注册时返回空结构。
    • 关键点:懒加载容器中的 FrontUserCenterNavBuilder。

三端共享 BaseController 能力

  • json($data, $statusCode = 200, $encodeOptions = 0)
    • 作用:构造 JSON 响应对象,API 端建议优先使用 ApiResponse 封装。
  • response($content = '', $statusCode = 200, array $headers = [])
    • 作用:构造通用响应(文本/HTML片段/XML/二进制)。
  • redirect($url, $statusCode = 302)
    • 作用:构造重定向响应。

继承与使用示例(来自真实控制器)

  • 首页控制器 IndexController
    • 通过构造函数注入 IndexService、NavigationBuilder、SeoResolver。
    • index() 组装页面数据后调用 view('index.dwt', [...]),并在 layoutVars() 中注入 SEO 与导航。
  • 用户中心 UserController
    • index() 校验登录态并重定向;area() 输出地区 JSON;filebox()/filedel() 演示上传与删除流程。
    • layoutVars() 注入 post 回显、SEO、导航、cur 标记与 link_user_center。
  • 商品控制器 ProductController
    • index()/show() 使用 RouteId、Util、Service 组装列表与详情,结合 BreadcrumbBuilder 与 SchemaService 生成面包屑与结构化数据。
    • layoutVars() 注入顶部与底部导航。
  • 认证控制器 AuthController
    • 登录/注册/找回密码/退出等动作统一通过 FormRequest 校验、Honeypot/Captcha 防护、Session 状态管理,最终调用 respond() 完成 JSON 或重定向分流。

关键流程图:POST 成功分流 respond()

flowchart TD
Start(["进入 respond"]) --> CheckJson{"是否期望 JSON?"}
CheckJson --> |是| BuildPayload["合并 redirect_url 与 data"]
BuildPayload --> ThrowSuccess["抛出成功信封 ApiResponse::throwSuccess"]
CheckJson --> |否| DoRedirect["执行 303 重定向"]
ThrowSuccess --> End(["结束"])
DoRedirect --> End

关键流程图:视图渲染与布局变量合并

flowchart TD
Enter(["进入 view"]) --> CallLayout["调用 layoutVars()"]
CallLayout --> MergeData["$data + layoutVars()<br/>左操作数优先"]
MergeData --> Render["创建 ViewResponse 并渲染"]
Render --> Exit(["返回响应"])

依赖关系分析

  • 前台 BaseController 依赖:
    • 模板渲染器:通过容器解析 TemplateRendererInterface。
    • 响应类型:ViewResponse、ApiResponse、RedirectResponse。
    • 会话与语言:通过 helper/facade(如 language()、user()、auth('front'))。
  • 业务控制器依赖:
    • 服务层:IndexService、ProductService、ProfileService、LoginService、RegistrationService 等。
    • 导航与SEO:NavigationBuilder、BreadcrumbBuilder、SeoResolver、SchemaService。
    • 安全与校验:FormRequest、Captcha、Honeypot、Session。
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() array
+buildLinkUserCenter(currentModule) array
}
class IndexController {
+index()
+layoutVars() array
}
class UserController {
+index()
+area(request)
+filebox(request)
+filedel(request)
+layoutVars() array
}
class ProductController {
+index(request)
+show(request)
+layoutVars() array
}
class AuthController {
+register(request)
+registerPost(formRequest, request)
+login(request)
+loginPost(formRequest, request)
+loginPhone(request)
+loginPhonePost(formRequest, request)
+passwordReset(request)
+passwordResetPost(formRequest, request)
+logout()
+layoutVars() array
}
FrontBaseController --|> CoreBaseController : "继承"
IndexController --|> FrontBaseController : "继承"
UserController --|> FrontBaseController : "继承"
ProductController --|> FrontBaseController : "继承"
AuthController --|> FrontBaseController : "继承"

性能考量

  • 视图渲染延迟:layoutVars() 仅在调用 view() 时执行,避免 JSON/重定向路径上的不必要计算。
  • 数据合并策略:使用 PHP 数组“+”合并,action 数据优先,减少重复赋值。
  • 依赖注入:通过构造函数注入服务,避免全局查找,提升可测试性与运行效率。
  • 请求分流:respond() 对 JSON 与普通表单分别处理,减少分支判断成本。

故障排查指南

  • 已登录用户访问登录/注册页被重定向
    • 现象:访问 user/login 或 user/register 被跳转至会员中心。
    • 原因:AuthController 内置 redirectIfLoggedIn() 检测已登录态。
    • 处理:确认 auth('front')->check() 状态;如需强制显示登录页,调整前置检查逻辑。
  • 验证码/短信校验失败
    • 现象:登录/注册/找回密码时报错或提示过期。
    • 原因:Captcha 或 Session 中的 verification 数据不匹配或超时。
    • 处理:检查 captcha()->verify()/ontime() 与 Session::arr('verification') 的一致性;注意防爆破清理策略。
  • 文件上传/删除异常
    • 现象:filebox/filedel 无效果或回显为空。
    • 原因:草稿 token 与 item_id 混用导致查询条件不一致。
    • 处理:区分 useDraft 场景,按 draft_token 回显剩余草稿;确保存储路径与权限配置正确。
  • 页面 404/错误页
    • 现象:产品列表/详情抛 DomainException 并跳转到 HOME_URL。
    • 原因:RouteId 解析失败或资源不存在。
    • 处理:检查路由参数与 ID 映射;必要时记录日志定位。

结论

BaseController 为前台控制器提供了统一的视图渲染、POST 成功分流、布局变量注入与会员中心导航构建能力;配合三端共享的 Core BaseController,形成清晰的分层与职责边界。业务控制器只需关注领域逻辑与服务编排,即可快速获得一致的请求处理、错误处理与响应构造体验。遵循依赖注入、FormRequest 校验、Honeypot/Captcha 防护与 respond() 分流的最佳实践,可显著提升代码质量与可维护性。

附录:最佳实践与常见模式

  • 始终通过构造函数注入服务,避免在 action 内直接调用全局 helper。
  • 使用 FormRequest 进行输入校验,将错误集中抛出,保持 action 简洁。
  • 使用 respond() 统一处理 POST 成功后的 JSON/重定向分流,减少重复分支。
  • 在 layoutVars() 中注入导航、SEO、cur/rec 等公共变量,保持模板一致性。
  • 对敏感操作启用 Honeypot 与 Captcha,并对验证码失败做防爆破处理。
  • 使用 RouteId/Util/BreadcrumbBuilder/SchemaService 等工具统一 URL、归档、面包屑与结构化数据。
  • 对可能缺失的资源(如模块未安装、Builder 未注册)做防御性判断,返回空结构或降级处理。
添加日期:2026-10-05