文档目录
控制器开发模式

简介

本文件面向 DouPHP 的控制器层,总结后台、前台、API 三端控制器的通用开发模式与最佳实践。内容覆盖请求处理流程、参数验证、错误处理、响应格式、日志与提示、模板渲染、路由映射与 URL 生成、与模型/服务/视图的交互方式,以及性能优化、安全注意事项和调试方法。通过商品模块的示例,展示如何以统一模式高效开发控制器。

项目结构

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

  • 核心基类:core/controller/BaseController.php,提供 JSON、Response、Redirect 等通用能力。
  • 端侧基类:
    • admin/controller/BaseController.php:后台 view()、layoutVars()、删除二次确认分流、AJAX 切换开关响应、AI 工具栏注入等。
    • front/controller/BaseController.php:前台 view()、layoutVars()、成功响应分流(JSON 返回 redirect_url,表单提交走 303)。
    • api/controller/BaseController.php:API 端会员中心导航构建复用前台实现。
  • 业务控制器:以 product 为例,分别位于 admin/front/api 三个端。
  • 请求校验:admin/request/Product/ProductFormRequest.php 定义字段白名单与规则。
  • 路由声明:admin/route/product.php 使用 Route::resource 声明资源路由并挂载额外动作。
graph TB
subgraph "核心"
CoreBC["core/controller/BaseController.php"]
end
subgraph "后台"
AdminBC["admin/controller/BaseController.php"]
AdminPC["admin/controller/product/ProductController.php"]
AdminReq["admin/request/Product/ProductFormRequest.php"]
AdminRoute["admin/route/product.php"]
end
subgraph "前台"
FrontBC["front/controller/BaseController.php"]
FrontPC["front/controller/product/ProductController.php"]
end
subgraph "API"
ApiBC["api/controller/BaseController.php"]
ApiPC["api/controller/product/ProductController.php"]
end
CoreBC --> AdminBC
CoreBC --> FrontBC
CoreBC --> ApiBC
AdminBC --> AdminPC
FrontBC --> FrontPC
ApiBC --> ApiPC
AdminPC --> AdminReq
AdminPC --> AdminRoute

图示来源

  • core/controller/BaseController.php:21-84
  • admin/controller/BaseController.php:45-245
  • front/controller/BaseController.php:37-133
  • api/controller/BaseController.php:38-60
  • admin/controller/product/ProductController.php:41-291
  • front/controller/product/ProductController.php:44-279
  • api/controller/product/ProductController.php:35-154
  • admin/request/Product/ProductFormRequest.php:27-101
  • admin/route/product.php:31-38

章节来源

  • core/controller/BaseController.php:21-84
  • admin/controller/BaseController.php:45-245
  • front/controller/BaseController.php:37-133
  • api/controller/BaseController.php:38-60

核心组件

  • 核心控制器基类
    • 提供 json()/response()/redirect() 三类基础响应构造器;所有端共享。
    • 约定:Action 外部输入一律通过方法签名注入 Request 或 FormRequest,helper 内部不直接调用 request()。
  • 后台控制器基类
    • view():合并 layoutVars() 与 action data,自动注入 AI 工具栏与页面按钮绝对地址。
    • layoutVars():默认注入 flashes、page_actions、page_sub_actions、面包屑等公共变量。
    • respondDeleteResult():删除结果分流(二次确认页 vs 302+flash)。
    • respondToggle():行内布尔切换统一响应(AJAX 返回 JSON,普通请求 302+flash)。
  • 前台控制器基类
    • view():合并 layoutVars() 与 action data。
    • respond():成功响应分流(JSON 携带 redirect_url,表单提交 303)。
    • layoutVars():默认空,子类按需叠加导航、SEO 等公共数据。
  • API 控制器基类
    • 无模板相关逻辑,仅扩展会员中心导航构建。

章节来源

  • core/controller/BaseController.php:21-84
  • admin/controller/BaseController.php:45-371
  • front/controller/BaseController.php:37-133
  • api/controller/BaseController.php:38-60

架构总览

控制器作为请求入口,遵循“薄控制器、厚服务”的分层原则:

  • 接收与校验:通过 Request/FormRequest 获取并校验输入。
  • 业务编排:调用 Service 完成领域逻辑,必要时组合多个服务。
  • 数据准备:从 Model/Service 取数,组装视图数据或 API 响应体。
  • 响应输出:根据端特性选择 ViewResponse/JsonResponse/RedirectResponse。
sequenceDiagram
participant C as "客户端"
participant R as "路由"
participant BC as "端侧 BaseController"
participant AC as "业务 Controller"
participant S as "Service"
participant M as "Model"
participant V as "视图/模板"
C->>R : HTTP 请求
R->>AC : 解析到 Action
AC->>AC : 读取/校验输入(Request/FormRequest)
AC->>S : 执行业务(读/写/聚合)
S->>M : 数据访问
M-->>S : 数据
S-->>AC : 结果
alt 后台/前台
AC->>BC : view()/respond()/redirect()
BC->>V : 渲染模板
V-->>C : HTML
else API
AC->>BC : ApiResponse : : success/error
BC-->>C : JSON
end

图示来源

  • admin/controller/product/ProductController.php:77-291
  • front/controller/product/ProductController.php:88-279
  • api/controller/product/ProductController.php:48-154
  • front/controller/BaseController.php:52-85
  • admin/controller/BaseController.php:60-68

详细组件分析

后台控制器模式(以商品为例)

  • 列表/创建/编辑/更新/删除/批量操作/辅助接口
  • 参数校验:通过 ProductFormRequest 集中定义 rules(),支持场景化(store/update),失败抛出 DomainException。
  • 错误处理:非法 ID、不存在的数据直接抛 DomainException,由框架统一处理。
  • 响应策略:
    • 新增/更新:redirect()->with('success', message, back_url, back_text)。
    • 删除:调用 respondDeleteResult() 分流(二次确认或 302+flash)。
    • AJAX 辅助接口:直接 response() 返回片段或 JSON。
  • 视图数据:通过 view() 传入模板变量,包含 page_actions/rec/业务数据等。
  • 布局变量:重写 layoutVars() 注入 cur 等上下文。
flowchart TD
Start(["进入 Action"]) --> Validate["参数校验(FormRequest)"]
Validate --> |失败| ThrowErr["抛出 DomainException"]
Validate --> |通过| Biz["调用 Service 执行业务"]
Biz --> Result{"是否需二次确认?"}
Result --> |是| Confirm["respondDeleteResult -> dou_msg.htm"]
Result --> |否| Redirect["redirect()->with('success', ...)"]
ThrowErr --> End(["结束"])
Confirm --> End
Redirect --> End

图示来源

  • admin/controller/product/ProductController.php:146-291
  • admin/request/Product/ProductFormRequest.php:62-99
  • admin/controller/BaseController.php:315-330

章节来源

  • admin/controller/product/ProductController.php:41-291
  • admin/request/Product/ProductFormRequest.php:27-101
  • admin/controller/BaseController.php:315-330

前台控制器模式(以商品为例)

  • 列表/详情:通过 RouteId 解析分类/文章 ID,结合归档时间参数;分页大小来自配置。
  • SEO:统一通过 SeoResolver/BreadcrumbBuilder/SchemaService 生成标题、关键词、描述、面包屑与结构化数据。
  • 视图数据:view() 传入 rec/page_title/nav/breadcrumb 等,模板负责渲染。
  • 成功响应:表单提交后 respond() 在 JSON 模式下返回 redirect_url,HTML 模式 303 跳转。
sequenceDiagram
participant U as "用户浏览器"
participant F as "前台控制器"
participant S as "前台服务"
participant T as "模板引擎"
U->>F : GET /product/category?id=...
F->>F : 解析路由参数/归档/分页
F->>S : buildProductListData(...)
S-->>F : 列表数据/分页
F->>T : view("product_category.dwt", 数据)
T-->>U : HTML

图示来源

  • front/controller/product/ProductController.php:88-160
  • front/controller/BaseController.php:52-85

章节来源

  • front/controller/product/ProductController.php:44-279
  • front/controller/BaseController.php:52-85

API 控制器模式(以商品为例)

  • 列表/详情/属性列表:统一通过 ApiResponse::success() 返回标准 JSON 包。
  • 参数校验:对必要参数进行合法性检查,非法时抛出 DomainException。
  • 模块开关:通过 Module::make() 动态加载可选模块(如评论、优惠券)。
sequenceDiagram
participant App as "小程序/第三方"
participant A as "API 控制器"
participant S as "前台服务"
participant R as "响应封装"
App->>A : GET /api/product?category_slug=...
A->>S : buildProductShowData(id, userId)
S-->>A : 商品数据
A->>R : ApiResponse : : success(data)
R-->>App : {code,message,data}

图示来源

  • api/controller/product/ProductController.php:48-154

章节来源

  • api/controller/product/ProductController.php:35-154

路由与 URL 生成

  • 资源路由:使用 Route::resource 声明 CRUD 动作,并通过 ->post([...]) 挂载额外动作。
  • 子资源:通过 prefix/sub 组织二级资源(如 product/category)。
  • URL 生成:模板与控制器中统一使用 route() 生成名称化 URL,避免硬编码路径。
flowchart LR
RouteDef["admin/route/product.php<br/>Route::resource(...)"] --> Map["路由表"]
Map --> Ctrl["ProductController"]
Ctrl --> Actions["index/create/edit/update/destroy/thumb/model/action"]

图示来源

  • admin/route/product.php:31-38
  • admin/controller/product/ProductController.php:77-291

章节来源

  • admin/route/product.php:31-38

请求验证与参数白名单

  • 使用 FormRequest 集中定义 rules(),同时作为 validated() 的白名单键集合。
  • 场景化规则:store 需要 draft_token,update 需要 id;slug 唯一性随功能开关变化。
  • 校验失败抛出异常,避免在 Action 中散落 if/else。

章节来源

  • admin/request/Product/ProductFormRequest.php:27-101

错误处理与提示

  • 非法参数/不存在数据:抛出 DomainException,由框架统一捕获并返回友好页面或错误码。
  • 后台删除:通过 respondDeleteResult() 统一处理二次确认与成功跳转。
  • 前台成功:通过 respond() 区分 JSON/HTML 两种响应形态。

章节来源

  • admin/controller/product/ProductController.php:161-291
  • front/controller/BaseController.php:77-85
  • admin/controller/BaseController.php:315-330

模板渲染与布局变量

  • 后台:view() 自动合并 layoutVars(),注入 flashes、page_actions、page_sub_actions、AI 工具栏等。
  • 前台:view() 合并 layoutVars(),子类可注入导航、SEO 等公共数据。
  • 建议:尽量在 layoutVars() 中放置跨页面公共数据,减少重复代码。

章节来源

  • admin/controller/BaseController.php:60-68
  • admin/controller/BaseController.php:235-245
  • front/controller/BaseController.php:52-59
  • front/controller/BaseController.php:110-113

控制器与模型/服务/视图的交互

  • 控制器职责:接收请求、校验参数、编排服务、组装响应。
  • 服务职责:封装领域逻辑、聚合多数据源、返回领域对象或 DTO。
  • 模型职责:数据访问与实体映射。
  • 视图职责:只负责展示,不承载业务逻辑。

章节来源

  • admin/controller/product/ProductController.php:41-291
  • front/controller/product/ProductController.php:44-279
  • api/controller/product/ProductController.php:35-154

依赖关系分析

  • 控制器依赖服务:通过构造函数注入 ProductService、NavigationBuilder、SeoResolver 等。
  • 控制器依赖基类:继承对应端的 BaseController,复用 view()/respond()/redirect() 等能力。
  • 路由到控制器:通过 Route::resource 将 URL 映射到具体 Controller::action。
  • 请求到验证:FormRequest 在 Action 前完成校验与白名单过滤。
classDiagram
class CoreBaseController
class AdminBaseController
class FrontBaseController
class ApiBaseController
class ProductController_Admin
class ProductController_Front
class ProductController_Api
class ProductFormRequest
CoreBaseController <|-- AdminBaseController
CoreBaseController <|-- FrontBaseController
CoreBaseController <|-- ApiBaseController
AdminBaseController <|-- ProductController_Admin
FrontBaseController <|-- ProductController_Front
ApiBaseController <|-- ProductController_Api
ProductController_Admin --> ProductFormRequest : "使用"

图示来源

  • core/controller/BaseController.php:21-84
  • admin/controller/BaseController.php:45-371
  • front/controller/BaseController.php:37-133
  • api/controller/BaseController.php:38-60
  • admin/controller/product/ProductController.php:41-291
  • front/controller/product/ProductController.php:44-279
  • api/controller/product/ProductController.php:35-154
  • admin/request/Product/ProductFormRequest.php:27-101

章节来源

  • core/controller/BaseController.php:21-84
  • admin/controller/product/ProductController.php:41-291
  • front/controller/product/ProductController.php:44-279
  • api/controller/product/ProductController.php:35-154
  • admin/request/Product/ProductFormRequest.php:27-101

性能注意事项

  • 懒求值:layoutVars() 仅在渲染模板时执行,避免不必要的计算。
  • 条件加载:通过 Module::make() 按需加载可选模块,减少无关开销。
  • 分页与查询:列表页使用合理分页大小,避免一次性拉取过多数据。
  • 缓存与配置:分页大小、功能开关等通过配置中心管理,便于调优。
  • 响应类型:AJAX 请求优先返回轻量 JSON,减少模板渲染成本。

故障排查指南

  • 参数非法/数据不存在:检查是否在入口处抛出 DomainException,并确保路由参数解析正确(RouteId)。
  • 表单校验失败:查看 FormRequest::rules() 与 validationData() 是否正确拼装待校验数据。
  • 删除未生效:确认是否调用 respondDeleteResult(),并检查 confirm_url 分支逻辑。
  • 前台成功跳转异常:确认 respond() 的 wantsJson() 分支与 redirect_url 设置。
  • 路由未命中:核对 admin/route/*.php 中的 Route::resource 与 ->post([...]) 是否完整。

章节来源

  • admin/controller/product/ProductController.php:161-291
  • admin/request/Product/ProductFormRequest.php:39-99
  • front/controller/BaseController.php:77-85
  • admin/route/product.php:31-38

结论

DouPHP 控制器层通过统一的基类与分层设计,实现了后台、前台、API 三端的一致开发体验。遵循“薄控制器、厚服务”的原则,借助 FormRequest 做参数校验,利用基类的 view()/respond()/redirect() 统一响应,配合资源路由与名称化 URL,能够高效、稳定地交付业务功能。建议在新增控制器时严格遵循本文的模式与规范,确保可维护性与一致性。

附录:命名与代码规范

  • 控制器命名
    • 按端分目录:admin/controller/、front/controller/、api/controller/*。
    • 文件名与类名一致,采用驼峰命名,如 ProductController。
  • 方法命名
    • 标准 CRUD:index/create/edit/update/destroy。
    • 额外动作:thumb/model/action 等语义化命名。
  • 请求校验
    • 使用 FormRequest,rules() 集中定义,validationData() 按需拼装。
    • 场景化规则通过 scene 区分(store/update)。
  • 响应规范
    • 后台:删除使用 respondDeleteResult();AJAX 切换使用 respondToggle()。
    • 前台:成功使用 respond(),JSON 模式返回 redirect_url。
    • API:统一 ApiResponse::success/error。
  • 路由与 URL
    • 使用 Route::resource 声明资源路由,->post([...]) 挂载额外动作。
    • 模板与控制器中使用 route() 生成名称化 URL。
  • 依赖注入
    • 通过构造函数注入 Service、工具类等依赖,避免在 Action 中直接实例化。
  • 安全与健壮性
    • 所有外部输入必须经 FormRequest 或显式校验。
    • 敏感操作(删除)提供二次确认或权限校验。
    • 可选模块通过 Module::make() 安全加载。
添加日期:2026-10-05