简介
本文面向 DouPHP 的文章模块,围绕前台、后台与 API 三端的文章控制器展开,系统说明文章列表展示、分类浏览、归档、详情查看、推荐阅读、评论集成、阅读统计等核心特性;并解释内容渲染(Markdown)、图片处理、SEO 优化、缓存策略、安全与版权保护等实现要点。文末提供扩展建议与最佳实践,帮助开发者快速迭代与增强功能。
项目结构
文章模块采用“控制器-服务-模型”的分层组织方式,前后端分离的入口分别由前台控制器、API 控制器与后台控制器承担,统一通过服务层封装业务逻辑,数据访问由模型完成。路由声明式挂载到控制器方法,模板负责页面呈现。
graph TB
subgraph "前端"
FR["前台控制器<br/>front/controller/article/ArticleController.php"]
TR["模板<br/>article.dwt / article_category.dwt"]
end
subgraph "API"
AR["API 控制器<br/>api/controller/article/ArticleController.php"]
end
subgraph "后台"
ACR["后台控制器<br/>admin/controller/article/ArticleController.php"]
end
subgraph "服务层"
FAS["前台服务<br/>front/service/article/ArticleService.php"]
BAS["后台服务<br/>admin/service/article/ArticleService.php"]
end
subgraph "模型层"
AM["文章模型<br/>front/model/article/Article.php"]
AC["分类模型<br/>front/model/article/ArticleCategory.php"]
end
subgraph "路由"
RT["声明式路由<br/>front/route/article.php"]
end
RT --> FR
RT --> AR
FR --> FAS
AR --> FAS
ACR --> BAS
FAS --> AM
FAS --> AC
AM --> AC
FR --> TR
核心组件
- 前台文章控制器:负责文章列表/分类/归档页与详情页的渲染,组装 SEO、面包屑、导航、推荐阅读、评论数据,并记录阅读统计。
- API 文章控制器:对外暴露文章列表与详情的 JSON 接口,复用前台服务进行数据构建。
- 后台文章控制器:提供文章的增删改查与批量操作,结合表单校验与服务层完成数据持久化与审计日志。
- 前台服务:封装文章列表查询、详情渲染(Markdown 转换)、分类信息获取、点击量统计等。
- 后台服务:封装后台列表、新增/更新/删除/批量操作、附件与草稿管理、审计日志。
- 模型:文章与分类模型,定义关联、筛选器、排序、格式化与可导出能力。
- 模板:默认主题下的文章列表与详情模板,承载 SEO 元信息与页面骨架。
架构总览
文章模块遵循 MVC + Service 分层,控制器仅做请求解析与视图装配,服务层聚合业务规则与跨领域调用,模型专注数据访问与格式化。路由以声明式方式将 URL 映射到控制器方法,模板负责最终 HTML 输出。
sequenceDiagram
participant U as "用户/客户端"
participant R as "路由<br/>front/route/article.php"
participant FC as "前台控制器"
participant AS as "前台服务"
participant M as "文章模型"
participant T as "模板"
U->>R : 访问文章列表/详情
R->>FC : 分发到 index/show
FC->>AS : 构建列表/详情数据
AS->>M : 查询已发布文章/分类
M-->>AS : 返回数据含格式化
AS-->>FC : 返回结构化数据
FC->>T : 渲染 article_category.dwt / article.dwt
T-->>U : 返回 HTML
详细组件分析
前台文章控制器
- 列表/分类/归档:解析路由参数(分类、slug、年/月),计算分页大小,调用服务构建列表数据,组装 SEO、面包屑、导航、侧边栏分类树、推荐阅读与分页。
- 详情:解析文章 ID,构建详情数据,记录阅读统计,加载评论模块数据,生成 Schema 与 SEO,渲染详情模板。
- 搜索关键词回填:从请求中读取全站搜索参数 q,校验后回填至侧栏搜索框。
flowchart TD
Start(["进入列表/详情"]) --> Parse["解析路由参数<br/>分类/slug/年/月"]
Parse --> BuildList{"是否列表?"}
BuildList -- 是 --> ListData["调用服务构建列表数据"]
ListData --> SEO["组装 SEO/面包屑/导航"]
SEO --> RenderList["渲染列表模板"]
BuildList -- 否 --> ShowData["调用服务构建详情数据"]
ShowData --> RecordView["记录阅读统计"]
RecordView --> Comment["加载评论数据"]
Comment --> RenderDetail["渲染详情模板"]
API 文章控制器
- 列表:接收 id/category_slug/year/month/page 等参数,复用前台服务构建列表数据,返回统一 JSON 响应。
- 详情:解析文章 ID,构建详情数据,记录阅读统计,附带评论数据,返回 JSON。
sequenceDiagram
participant C as "客户端"
participant ARC as "API 控制器"
participant AS as "前台服务"
participant M as "文章模型"
C->>ARC : GET /api/article (list/detail)
ARC->>AS : 构建列表/详情数据
AS->>M : 查询文章/分类
M-->>AS : 返回数据
AS-->>ARC : 返回结构化数据
ARC-->>C : ApiResponse : : success(data)
后台文章控制器与服务
- 列表:按分类与关键词过滤,分页展示文章基础信息。
- 新增:清理草稿附件,生成草稿令牌,填充默认数据,提交时执行 XSS 清洗、远程图片本地化、主图上传、认领草稿、写入审计日志。
- 编辑/更新:读取原始字段,格式化预览内容,处理主图与正文图片,保存并记录日志。
- 删除/批量:二次确认或批量删除/转移分类,记录审计日志。
flowchart TD
AdminStart(["后台操作入口"]) --> List["列表查询(分类/关键词/分页)"]
AdminStart --> Create["新增表单(清理草稿/令牌/默认数据)"]
Create --> Store["提交新增(XSS/远程图/主图/认领/日志)"]
AdminStart --> Edit["编辑表单(原始字段/预览)"]
Edit --> Update["更新(图片/内容/保存/日志)"]
AdminStart --> Delete["删除(二次确认/实际删除/日志)"]
AdminStart --> Batch["批量(删除/转移分类/日志)"]
模型与数据流
- 文章模型:定义 casts(图片、自定义键值对、时间)、appends(派生字段如摘要、时间、URL、收藏数、分类信息)、translatable(标题/内容/描述/关键词多语言)、prefetchers(预热 URL、多语言、附件)、scope 过滤器(已发布、归档时间窗、默认排序、非空主图)。
- 分类模型:支持分类树与带内容的分类查询,name 多语言预热。
- 服务层使用 with('category') 批量加载分类,避免 N+1 查询;列表项通过模型 accessor 与 appends 生成 Presenter 字段。
classDiagram
class Article {
+table "article"
+casts "image, defined, created_at"
+appends "add_time_short, time, name, description, url, favorites, cate_info"
+translatable "title, content, description, keywords"
+prefetchers "url, language, attachment"
+moduleSchema()
+category()
+findPublishedById(id)
+scopePublished(query)
+scopeFilterByArchive(query, archive)
+scopeImageNotEmpty(query)
+scopeApplyDefaultOrder(query)
}
class ArticleCategory {
+table "article_category"
+translatable "name"
+prefetchers "language"
}
Article --> ArticleCategory : "belongsTo(category_id)"
内容渲染、图片处理与 SEO
- 内容渲染:服务层在详情构建时将 Markdown 转换为 HTML,模板中以 nofilter 输出,确保富文本正确渲染。
- 图片处理:后台新增/更新时对正文中的远程图片进行本地化存储,主图通过附件服务上传并绑定到文章;列表项图片经 casts 转为附件 URL。
- SEO 优化:控制器通过 SEO 解析器生成页面标题、关键词、描述,并注入模板 meta;详情页附加 Schema 标记;面包屑用于结构化数据。
评论、点赞收藏、分享与阅读统计
- 评论:详情控制器动态加载 comment 模块的数据,若模块可用则传入模板渲染。
- 点赞收藏/分享:当前控制器未直接实现,可通过扩展模块或前端交互接入;建议在服务层增加对应行为钩子以便统一处理。
- 阅读统计:详情控制器在服务构建详情后调用记录点击量,并将 click 字段加一并返回给模板显示。
依赖关系分析
- 控制器依赖服务层进行业务编排,服务层依赖模型进行数据访问与格式化。
- 路由以声明式方式将 URL 映射到控制器方法,减少硬编码。
- 模板依赖控制器传递的数据变量,包含 SEO 元信息、列表、详情、评论等。
graph LR
Route["路由"] --> FrontCtrl["前台控制器"]
Route --> ApiCtrl["API 控制器"]
FrontCtrl --> FrontSvc["前台服务"]
ApiCtrl --> FrontSvc
FrontSvc --> ArticleModel["文章模型"]
FrontSvc --> CategoryModel["分类模型"]
FrontCtrl --> Template["模板"]
性能考虑
- 列表查询优化:使用 with('category') 预加载分类,避免 N+1;应用 scope 过滤器限制结果集;分页控制每页数量。
- 内容渲染:Markdown 转换在服务层集中处理,减少重复计算;必要时可对热门文章详情结果进行缓存。
- 图片处理:远程图片本地化仅在后台编辑时触发;列表图片通过 casts 转为 URL,减少运行时转换开销。
- SEO 与结构化数据:按需生成 Schema,避免不必要的计算。
- 缓存策略:可在服务层引入缓存层(如 Redis/Memcached)缓存分类树、热门文章列表与详情片段,注意失效策略与一致性。
故障排查指南
- 页面错误:当路由解析失败或文章不存在时,控制器抛出领域异常并跳转首页;检查路由参数与 ID 合法性。
- 评论缺失:若 comment 模块未启用或未安装,详情不会加载评论;检查模块是否存在与配置。
- 内容渲染异常:确认 Markdown 转换器可用且内容格式正确;后台编辑时注意 XSS 清洗与远程图片本地化流程。
- 图片未显示:检查主图上传是否成功、附件服务是否正常、casts 是否正确转换 URL。
- 统计不更新:确认详情控制器调用了记录点击量方法,数据库字段类型与权限正确。
结论
DouPHP 文章控制器采用清晰的分层架构,前台与 API 共享服务层,后台独立服务层保障管理流程;模型层提供强大的查询与格式化能力;模板承载 SEO 与页面结构。通过 Markdown 渲染、图片本地化、SEO 与结构化数据,实现了高质量的内容展示与检索体验。后续可扩展评论、点赞收藏、分享与智能推荐等功能,并结合缓存与安全策略提升性能与安全性。
附录:扩展与最佳实践
扩展文章功能
- 新增互动功能(点赞、收藏、分享):在服务层增加相应方法,控制器在详情处调用并返回状态;模板中增加交互按钮与反馈。
- 添加新内容类型:在模型中扩展字段与 casts/appends,服务层适配渲染逻辑,模板增加展示分支。
- 集成富文本编辑器:后台编辑表单使用富文本编辑器,提交时通过服务层的 XSS 清洗与远程图片本地化处理;确保模板以 nofilter 输出。
- 实现智能推荐:在服务层基于标签、分类、阅读历史等维度计算推荐列表,并在详情模板中展示。
性能优化
- 列表与详情缓存:对热点分类列表与热门文章详情进行缓存,设置合理过期时间与失效策略。
- 查询优化:合理使用 scope 与 with 预加载,避免 N+1;分页与索引优化查询性能。
- 图片优化:压缩与懒加载,CDN 加速静态资源。
内容安全与版权保护
- 输入校验与 XSS 清洗:后台提交内容必须经过清洗;前台展示时谨慎输出。
- 权限控制:后台操作需鉴权与审计日志;敏感操作二次确认。
- 版权水印与外链保护:对图片添加水印,禁止直接外链;必要时添加防盗链策略。