简介
本文件面向前端开发者,系统化说明 DouPHP 前台应用的架构与开发方式。内容涵盖控制器层、服务层、模型层的职责分离;DWT 模板系统的使用(语法、继承、组件复用);前台业务交互模式(用户交互、数据展示、SEO);新增页面/功能/主题定制流程;响应式与多语言支持;以及缓存、压缩、CDN 等性能优化建议。
项目结构
前台应用采用“入口引导 + 路由分发 + 控制器 + 服务 + 模型 + 视图”的分层组织:
- 入口与引导:根入口 index.php 负责加载引导程序 core/bootstrap.php,设置路由委托、解析语言前缀并启动 Init,随后进行路由调度与响应输出。
- 路由:front/route 下按模块划分路由定义文件,将 URL 映射到具体控制器方法。
- 控制器:front/controller 下按模块组织控制器,统一继承 BaseController,提供 view() 渲染与 respond() 成功分流。
- 服务:front/service 封装领域逻辑,控制器通过依赖注入调用服务。
- 模型:front/model 以 ORM 风格访问数据库,供服务层使用。
- 视图:theme/default 下的 .dwt 模板文件,配合 inc 片段实现组件复用。
graph TB
A["入口 index.php"] --> B["引导 core/bootstrap.php"]
B --> C["路由 front/route/*"]
C --> D["控制器 front/controller/*"]
D --> E["服务 front/service/*"]
E --> F["模型 front/model/*"]
D --> G["视图 theme/default/*.dwt"]
G --> H["片段 theme/default/inc/*"]
核心组件
- 入口与引导
- 入口 index.php:注册路由委托、解析语言前缀、执行 Init、调度路由、统一异常处理与 JSON/HTML 响应。
- 引导 bootstrap.php:定义路径常量、加载配置、注册自动加载、门面别名、DI 容器、Request/Route 单例、全局助手与事件注册器。
- 控制器基类 BaseController
- 提供 view() 合并布局公共变量、respond() 根据请求类型返回 JSON 或 303 重定向、layoutVars() 注入导航/SEO 等公共数据。
- 首页示例 IndexController/IndexService
- 控制器通过服务组装首页数据,注入 SEO、导航与模板变量;服务层聚合产品、文章、展示位等数据。
- 模板系统
- 基于 .dwt 模板,使用 {include} 复用头部、底部、轮播等片段;通过 meta 标签与变量完成 SEO 基础信息。
架构总览
前台遵循 MVC 分层与“控制器薄、服务厚”的设计:
- 控制器:接收请求、参数校验、调用服务、渲染视图或返回 JSON/重定向。
- 服务:封装领域规则、组合多个模型查询、计算展示数据、生成结构化数据(如 Schema)。
- 模型:ORM 访问数据库,提供查询构造与关联。
- 视图:仅负责展示,通过模板变量与片段拼装页面。
sequenceDiagram
participant U as "浏览器"
participant I as "入口 index.php"
participant R as "路由 front/route/*"
participant C as "控制器"
participant S as "服务"
participant M as "模型"
participant V as "模板 *.dwt"
U->>I : HTTP 请求
I->>R : 解析语言前缀并调度
R->>C : 匹配控制器方法
C->>S : 调用服务获取数据
S->>M : 查询/聚合数据
M-->>S : 数据集
S-->>C : 业务结果
C->>V : 渲染模板(含片段)
V-->>U : HTML 响应
详细组件分析
控制器层:BaseController 与 IndexController
- BaseController
- view(): 渲染模板时自动合并 layoutVars(),便于注入导航、SEO 等公共变量。
- respond(): 对期望 JSON 的请求返回标准成功信封并附带 redirect_url;普通表单提交走 303 重定向,保证无 JS 可用。
- layoutVars(): 默认空,子类可叠加导航、关键词、描述等。
- IndexController
- 通过构造函数注入 IndexService、NavigationBuilder、SeoResolver。
- index() 调用服务构建首页数据,并返回模板变量(标题、骨架、推荐商品、最新文章、分类等)。
- layoutVars() 注入 keywords、description、多级导航列表。
classDiagram
class BaseController {
+view(template, data, statusCode)
+respond(request, redirectUrl, data, message)
#layoutVars() array
#buildLinkUserCenter(currentModule) array
}
class IndexController {
-indexService
-nav
-seo
+index() Response
#layoutVars() array
}
BaseController <|-- IndexController
服务层:IndexService
- 职责:聚合首页所需数据,包括“关于”页摘要、展示位、推荐/新品、文章、产品分类、头部代码片段等。
- 关键点:
- 读取配置项控制分页数量与功能开关(如 features.product/article)。
- 通过 SchemaService 生成结构化数据,并与站点自定义 head 代码拼接。
- 使用 ORM 模型 Product、Article、Show、ProductCategory 进行查询与关联。
flowchart TD
Start(["进入 buildIndexData"]) --> LoadAbout["读取关于页并本地化"]
LoadAbout --> BuildIndexObj["组装 index 对象"]
BuildIndexObj --> ReadCfg["读取分页与功能开关"]
ReadCfg --> GenSchema["生成结构化数据"]
GenSchema --> MergeHead["合并 code_head"]
MergeHead --> QueryData["查询展示/商品/文章/分类"]
QueryData --> Return["返回数组给控制器"]
视图模板系统:DWT 语法、继承与组件复用
- 模板文件:theme/default/*.dwt,例如 index.dwt。
- 常用语法
- 变量输出:{$page_title}、{$keywords}、{$description} 等。
- 条件判断:<!-- {if $features.product} --> ... <!-- {/if} -->。
- 片段复用:{include file="inc/header.tpl"}、{include file="inc/footer.tpl"} 等。
- 模板继承
- 当前默认模板未显式使用继承机制,但可通过 inc 片段实现“头/尾/通用区块”的复用,达到类似继承的效果。
- SEO 与元信息
- 在模板中通过 meta 标签输出 keywords/description,title 由控制器传入 page_title。
- 移动端适配
- 模板包含 viewport 设置与 Bootstrap 样式,具备基础响应式能力。
graph LR
T["index.dwt"] --> H["inc/header.tpl"]
T --> SLIDE["inc/slide_show.tpl"]
T --> ABOUT["inc/about.tpl"]
T --> REC_PROD["inc/recommend_product.tpl"]
T --> REC_ART["inc/recommend_article.tpl"]
T --> LINK["inc/link.tpl"]
T --> FOOTER["inc/footer.tpl"]
路由与控制器绑定
- 路由文件位于 front/route,每个模块一个文件,例如 product.php、article.php、user.php。
- 入口 index.php 通过 Route::setDelegate 指定路由解析器,并在 boot 后执行 Route::dispatch() 将请求分派到对应控制器方法。
- 语言前缀解析:入口在 Init 之前解析 route 参数中的语言标识,写入 Request,确保后续流程能正确识别语言环境。
sequenceDiagram
participant B as "浏览器"
participant I as "入口 index.php"
participant L as "LangPrefixParser"
participant R as "路由"
participant C as "控制器"
B->>I : GET /?route=...
I->>L : 解析语言前缀
L-->>I : langSign + routeString
I->>R : dispatch()
R->>C : 匹配控制器方法
C-->>B : 返回视图或JSON
业务交互模式:用户交互、数据展示、SEO
- 用户交互
- 表单提交:控制器使用 respond() 统一处理成功后的 JSON/重定向,避免重复提交与状态不一致。
- CSRF:模板中注入 csrf-token,后端通过 Csrf 门面保护写操作。
- 数据展示
- 控制器从服务获取数据,再传递给模板;服务层负责复杂查询与聚合。
- SEO
- 控制器注入 page_title、keywords、description;服务层可生成结构化数据(Schema)增强搜索引擎理解。
新增页面/功能的开发步骤
- 新建路由:在 front/route 下新增或扩展模块路由文件,定义 URL 到控制器方法的映射。
- 新建控制器:在 front/controller/<module> 下创建控制器,继承 BaseController,实现 action 方法。
- 编写服务:在 front/service/<module> 中封装业务逻辑,必要时组合多个模型查询。
- 编写模型:在 front/model/<module> 中定义 ORM 模型与查询作用域。
- 编写模板:在 theme/default 下新增 .dwt 模板,并通过 {include} 复用 inc 片段。
- 注入公共数据:如需导航/SEO,重写 layoutVars() 或在控制器中直接赋值。
- 测试验证:通过浏览器访问路由,检查 JSON/HTML 响应与页面渲染。
自定义主题
- 复制默认主题目录 theme/default 为新主题目录(如 newtheme),按需修改 .dwt 模板与静态资源。
- 通过后台或配置切换主题(若平台提供该能力)。
- 保持 inc 片段命名一致,以便复用通用区块。
响应式设计、移动端适配与多语言
- 响应式
- 模板引入 Bootstrap 与 viewport 设置,具备基础响应式能力。
- 移动端适配
- 结合媒体查询与 Bootstrap 栅格,优化小屏体验。
- 多语言
- 入口在 Init 之前解析语言前缀并写入 Request;服务层使用 language()->langBox() 对内容进行本地化。
- 模块开关与菜单显示可通过 config/module.php 控制。
依赖关系分析
- 入口与引导
- index.php 依赖 core/bootstrap.php 完成常量、配置、自动加载、门面、容器、Request/Route 初始化。
- 控制器与服务
- 控制器通过依赖注入使用服务;服务依赖模型与配置。
- 模板与片段
- 模板通过 {include} 引用 inc 片段,形成松耦合的组件化结构。
graph TB
subgraph "入口与引导"
IDX["index.php"]
BOOT["core/bootstrap.php"]
end
subgraph "路由与控制器"
RT["front/route/*"]
CTRL["front/controller/*"]
end
subgraph "服务与模型"
SVC["front/service/*"]
MOD["front/model/*"]
end
subgraph "视图"
TPL["theme/default/*.dwt"]
INC["theme/default/inc/*"]
end
IDX --> BOOT
IDX --> RT
RT --> CTRL
CTRL --> SVC
SVC --> MOD
CTRL --> TPL
TPL --> INC
性能考虑
- 缓存策略
- 对读多写少的数据(如首页推荐、分类树、展示位)在服务层加入缓存(如 Redis/Memcached),减少数据库压力。
- 利用配置项控制分页数量与功能开关,降低不必要的数据加载。
- 资源压缩与合并
- 在生产环境启用 CSS/JS 压缩与合并,减少请求数与体积。
- 图片使用 WebP/AVIF 格式,合理尺寸与懒加载。
- CDN 集成
- 将静态资源(CSS/JS/图片)托管至 CDN,提升全球访问速度。
- 模板中通过变量或配置替换静态资源域名。
- 数据库优化
- 为高频查询字段建立索引;使用 with() 预加载关联,避免 N+1 查询。
- 模板渲染
- 尽量复用 inc 片段,减少重复渲染开销。
- 避免在模板中进行复杂计算,将逻辑下沉到服务层。
故障排查指南
- 未安装跳转
- 若 storage/install.lock 不存在且非安装路径,入口会跳转到安装程序。请确认已安装并生成锁文件。
- 异常处理
- 入口捕获 DomainException、HttpResponseException、RedirectException 及通用 Exception/Throwable,按 site.debug 与请求类型输出调试页或 JSON 错误。
- 未捕获异常会记录日志并根据环境输出友好提示或 API 500。
- 常见问题定位
- 检查路由是否正确映射到控制器方法。
- 检查服务层是否抛出业务异常(如参数非法、权限不足)。
- 检查模板变量是否缺失导致渲染异常。
结论
DouPHP 前台应用采用清晰的分层架构与模块化设计,控制器聚焦请求处理与视图渲染,服务层承载业务逻辑,模型负责数据访问,模板通过片段复用实现高内聚低耦合。借助入口的统一引导与异常处理、路由的语言前缀解析、以及 BaseController 的响应分流,开发者可以高效地新增页面与功能,同时具备良好的 SEO、多语言与响应式支持。在生产环境中,结合缓存、压缩与 CDN 可进一步提升性能与用户体验。
附录
- 配置要点
- 数据库与应用常量:config/config.php。
- 模块开关与菜单可见性:config/module.php。
- 参考文件
- 入口与引导:index.php、core/bootstrap.php
- 控制器基类与首页示例:front/controller/BaseController.php、front/controller/index/IndexController.php
- 首页服务:front/service/index/IndexService.php
- 模板与片段:theme/default/index.dwt
- 路由示例:front/route/product.php、front/route/article.php、front/route/user.php