简介
本文件面向 DouPHP 插件开发者,系统化说明插件系统的架构设计、生命周期、钩子机制、依赖管理、安装启用流程、插件间通信与安全控制等。文档基于仓库中的插件实现与后台插件管理能力进行提炼,并给出可操作的开发规范与最佳实践。
更新 本次更新重点反映了扩展系统的重大重构,包括排序机制的现代化改造(sortByCount→listOrderClause)、字段命名标准化(unique_id→slug、name→title、cat_id→category_id)以及 ExtendRoot 映射系统的增强,这些变更显著提升了系统的兼容性和可维护性。
项目结构
DouPHP 的插件以"目录即插件"的方式组织在根目录 plugin 下,每个插件包含描述元数据、Provider/Service 实现以及可选 SDK/资源。后台通过统一的控制器与服务对插件进行发现、注册、配置、启用/禁用与删除。
graph TB
A["admin/controller/plugin/PluginController"] --> B["admin/service/plugin/PluginService"]
B --> C["PaymentPluginRegistry"]
B --> D["ConnectPluginRegistry"]
B --> E["ShippingPluginRegistry"]
C --> F["plugin/*/manifest.php"]
C --> G["plugin/*/XxxProvider.php"]
D --> F
E --> F
H["ExtendRoot"] --> I["扩展服务映射"]
I --> J["字段映射: cat_id→category_id, unique_id→slug, name→title"]
K["listOrderClause"] --> L["差异化排序策略"]
L --> M["template: sort ASC, created_at DESC"]
L --> N["module: sort ASC, count DESC"]
L --> O["其他: id DESC"]
核心组件
- 插件清单 manifest.php:声明插件分组与 Provider 类名,供 Registry 扫描注册。
- Provider:统一抽象能力入口,暴露 meta、start/notify/finish/query/status 等方法,对接业务 Service。
- Service:封装具体第三方 SDK 调用、回调处理、查询与轮询逻辑。
- 后台 PluginService/PluginController:负责插件列表构建、启用/编辑/禁用/删除、云市场集成等。
- 增强 ExtendRoot:扩展顶级分类新旧协议映射,维护客户端协议标识与新库 slug 的双向转换,并提供差异化排序策略。
架构总览
插件系统采用"清单 + 提供者 + 服务"的分层模式:
- 清单 manifest.php 提供最小元信息,便于 Registry 发现。
- Provider 作为对外契约,屏蔽底层差异,向上提供统一方法。
- Service 专注第三方交互细节,保持 Provider 简洁稳定。
- 后台通过 Registry 聚合三类插件(支付、连接、物流),统一管理与展示。
- 增强 ExtendRoot 映射系统确保客户端协议与新数据库结构的兼容性,并提供智能排序策略。
classDiagram
class PaymentPluginRegistry {
+allMeta() array
+provider(slug) Provider
}
class ConnectPluginRegistry {
+allMeta() array
+provider(slug) Provider
}
class ShippingPluginRegistry {
+allMeta() array
+provider(slug) Provider
}
class AlipayProvider {
+pluginId() string
+meta() array
+start(request) string
+notify(payload) string
+finish(payload) string
+query(request) result
}
class WxpayProvider {
+pluginId() string
+meta() array
+start(request) string
+notify(payload) string
+finish(payload) string
+status(payload) string
+query(request) result
}
class PluginService {
+buildPluginListData() array
+loadPluginDefinition(slug, row) array
+insert(data) void
+update(data) void
+disable(uniqueId) void
+delete(uniqueId, post) array
}
class ExtendRoot {
+toDbSlug(clientRoot) string
+toClientRoot(dbSlug) string
+isImageLayout(clientRoot) bool
+listOrderClause(dbSlug) string
}
PaymentPluginRegistry --> AlipayProvider : "解析"
PaymentPluginRegistry --> WxpayProvider : "解析"
PluginService --> PaymentPluginRegistry : "读取元数据"
PluginService --> ConnectPluginRegistry : "读取元数据"
PluginService --> ShippingPluginRegistry : "读取元数据"
ExtendRoot --> PluginService : "字段映射与排序支持"
详细组件分析
支付插件:支付宝 Provider
- 职责:实现支付相关接口,委托 Service 完成下单、通知、完成、查询。
- 关键能力:
- meta:定义名称、版本、允许客户端、配置项表单字段。
- start/notify/finish/query:与系统支付流程对齐。
- 支持主动对账(Reconcilable)。
sequenceDiagram
participant 前端 as "订单系统"
participant 平台 as "DouPHP 支付网关"
participant 提供商 as "AlipayProvider"
participant 服务 as "AlipayService"
participant 三方 as "支付宝网关"
前端->>平台 : 发起支付
平台->>提供商 : start(PaymentRequest)
提供商->>服务 : start(request)
服务->>三方 : 创建订单
三方-->>服务 : 返回支付参数
服务-->>提供商 : 支付参数
提供商-->>平台 : 重定向/表单
平台-->>前端 : 跳转至支付页
三方-->>平台 : 异步通知 notify
平台->>提供商 : notify(PaymentCallbackPayload)
提供商->>服务 : notify(payload)
服务->>三方 : 验签/查询状态
三方-->>服务 : 结果
服务-->>提供商 : 处理结果
提供商-->>平台 : 响应
支付插件:微信支付 Provider
- 职责:实现扫码 Native 轮询、JSAPI/H5 支付、通知与查询。
- 关键能力:
- 同时实现 Reconcilable 与 Pollable 接口,支持主动对账与状态轮询。
- status:用于 Native 扫码场景的轮询查询。
sequenceDiagram
participant 前端 as "小程序/移动端"
participant 平台 as "DouPHP 支付网关"
participant 提供商 as "WxpayProvider"
participant 服务 as "WxpayService"
participant 三方 as "微信支付"
前端->>平台 : 发起支付
平台->>提供商 : start(PaymentRequest)
提供商->>服务 : start(request)
服务->>三方 : 创建支付
三方-->>服务 : 返回支付参数/二维码
服务-->>提供商 : 支付参数
提供商-->>平台 : 返回给前端
前端->>平台 : 轮询 status
平台->>提供商 : status(PaymentCallbackPayload)
提供商->>服务 : status(payload)
服务->>三方 : 查询交易状态
三方-->>服务 : 状态
服务-->>提供商 : 状态
提供商-->>平台 : 状态
平台-->>前端 : 更新结果
三方-->>平台 : 异步通知 notify
平台->>提供商 : notify(payload)
提供商->>服务 : notify(payload)
服务->>三方 : 验签/确认
三方-->>服务 : 确认结果
服务-->>提供商 : 处理结果
提供商-->>平台 : 响应
社交登录插件:Amazon 示例
- 入口 login.php 负责引导用户授权,inc.plugin.php 加载初始化与回调地址。
- 典型流程:未绑定则生成 state 并跳转授权;已登录且已绑定则直接回跳。
flowchart TD
Start(["进入登录入口"]) --> Check["检查是否已登录或已绑定"]
Check --> |未绑定| GenState["生成 state 并存入会话"]
GenState --> Redirect["跳转到第三方授权页面"]
Check --> |已绑定| Return["直接返回目标地址"]
Redirect --> Callback["回调处理(由 return_url 完成)"]
Callback --> End(["结束"])
Return --> End
扩展系统现代化:字段映射与差异化排序
重大更新 扩展系统经历了重大重构,引入了标准化的字段映射规则和智能化的排序机制,确保客户端协议与新数据库结构的完美兼容。
字段映射标准化
cat_id→category_id:分类ID字段统一命名unique_id→slug:唯一标识符使用slug格式name→title:名称字段统一为title
ExtendRoot 映射系统增强
ExtendRoot 类现在提供更强大的双向映射功能:
- 客户端协议:theme / module / plugin / miniprogram / mobile
- 新库 slug:template / module / plugins / mp
- 双向转换:toDbSlug() 和 toClientRoot() 方法
- 新增 listOrderClause() 方法实现差异化排序策略
差异化排序策略
新的排序机制根据不同类型的扩展提供最优排序:
- 模板(template):人工置顶(sort)后按发布/入库时间倒序,新模板靠前
- 模块(module):人工置顶后按下载量倒序
- 其他类型:按 id 倒序
flowchart LR
A["客户端请求"] --> B["ExtendRoot.toDbSlug()"]
B --> C["数据库查询(category_id, slug, title)"]
C --> D["ExtendService/ExtendListService"]
D --> E["ExtendRoot.listOrderClause()"]
E --> F["差异化排序应用"]
F --> G["ExtendRoot.toClientRoot()"]
G --> H["标准API响应"]
后台插件管理:安装、启用、配置、禁用、删除
- 列表:合并三类 Registry 的元数据,标记是否已启用。
- 启用:根据 slug 加载 Provider 的 meta 与默认配置,提交入库。
- 编辑:从数据库读取已保存配置,与 schema 合并渲染表单。
- 禁用:删除数据库记录。
- 删除:二次确认后删除插件目录,并刷新云市场缓存。
sequenceDiagram
participant 管理员 as "管理员"
participant 控制器 as "PluginController"
participant 服务 as "PluginService"
participant 注册表 as "三大Registry"
participant 存储 as "数据库/文件系统"
管理员->>控制器 : 访问插件列表
控制器->>服务 : buildPluginListData()
服务->>注册表 : allMeta()
注册表-->>服务 : 元数据集合
服务-->>控制器 : 列表数据
控制器-->>管理员 : 渲染列表
管理员->>控制器 : 启用插件(create/store)
控制器->>服务 : insert(data)
服务->>存储 : 写入配置
存储-->>服务 : 成功
服务-->>控制器 : 成功
控制器-->>管理员 : 跳转编辑页
管理员->>控制器 : 编辑(update)
控制器->>服务 : update(data)
服务->>存储 : 更新配置
存储-->>服务 : 成功
服务-->>控制器 : 成功
控制器-->>管理员 : 提示成功
管理员->>控制器 : 禁用(disable)
控制器->>服务 : disable(slug)
服务->>存储 : 删除记录
存储-->>服务 : 成功
服务-->>控制器 : 成功
管理员->>控制器 : 删除(destroy)
控制器->>服务 : delete(slug, post)
服务->>存储 : 删除目录/刷新云缓存
存储-->>服务 : 成功
服务-->>控制器 : 返回结果
依赖关系分析
- 插件与系统解耦:通过 manifest.php 声明 provider,由 Registry 动态加载,避免硬编码耦合。
- 后台与插件解耦:PluginService 仅依赖 Registry 提供的元数据与 Provider 实例,不感知具体实现。
- 支付流程解耦:Provider 仅暴露统一方法,具体 SDK 调用下沉到 Service,便于替换与测试。
- 增强 扩展服务解耦:ExtendRoot 提供统一的字段映射和排序策略,避免业务逻辑中散落映射代码。
graph LR
M["manifest.php"] --> R["Registry"]
R --> P["Provider"]
P --> S["Service"]
S --> T["第三方SDK/网关"]
Admin["后台管理"] --> R
Admin --> DB["数据库/文件系统"]
ER["ExtendRoot"] --> ES["扩展服务"]
ES --> FM["字段映射与排序"]
FM --> DB
性能与扩展性
- 元数据缓存:Registry 建议对 allMeta 结果做进程内缓存,减少重复 IO。
- 懒加载:Provider/Service 按需实例化,避免启动时全量加载。
- 并发安全:支付回调需幂等处理,结合唯一订单号与状态机避免重复入账。
- 可扩展点:新增插件类型只需实现对应 Registry 的 provider 解析与 meta 结构即可接入。
- 增强 字段映射优化:ExtendRoot 使用静态映射数组,避免运行时计算开销;差异化排序策略提升查询性能。
故障排查指南
- 插件未显示:检查 manifest.php 的 plugin_group 与 provider 路径是否正确;确认 Registry 能扫描到该目录。
- 启用失败:核对 Provider::meta 中的 config 字段与后台表单一致;确保数据库写入成功。
- 支付回调无效:校验签名与商户密钥;确认回调地址与白名单配置正确。
- 轮询无结果:检查 status 接口调用频率与第三方限流;确认订单号与状态码映射正确。
- 删除后仍显示:清理缓存并刷新云市场同步;确认目录已物理删除。
- 增强 扩展数据异常:检查 ExtendRoot 映射配置;确认字段映射是否正确(category_id vs cat_id, slug vs unique_id, title vs name);验证排序策略是否符合预期。
结论
DouPHP 插件系统通过清单+提供者+服务的分层设计,实现了高内聚、低耦合的扩展机制。支付与社交登录等插件遵循统一契约,后台提供完整的生命周期管理。重大更新 扩展系统的现代化改造显著提升了系统的兼容性和可维护性,标准化的字段映射和智能化的排序策略确保了数据的一致性和查询的高效性。按本文档规范开发插件,可快速接入并稳定运行于生产环境。
附录:开发规范与示例
插件目录与配置文件
- 目录结构建议
- 插件根目录:slug(如 alipay、wxpay)
- manifest.php:声明 plugin_group 与 provider
- XxxProvider.php:实现统一接口
- XxxService.php:封装第三方 SDK 调用
- sdk/:第三方 SDK(如有)
- 其他资源:图片、脚本等
- manifest.php 必填键
- plugin_group:payment/connect/shipping
- provider:Provider 类的完整命名空间
接口定义与生命周期
- Provider 必须实现的方法
- pluginId:插件唯一标识
- meta:插件元信息与配置表单
- start:发起支付/请求
- notify:第三方异步通知处理
- finish:完成回调处理
- query:主动查询(可选)
- status:轮询状态(可选,如微信 Native)
- 数据对象
- PaymentRequest/PaymentCallbackPayload/PaymentQueryRequest/PaymentQueryResult:由系统注入,Provider 直接使用
开发示例:支付插件
- 步骤
- 创建 manifest.php,填写 plugin_group=payment 与 provider
- 实现 XxxProvider,委托 XxxService 完成 SDK 调用
- 实现 start/notify/finish/query/status(按需)
- 在后台启用并配置密钥等参数
- 参考实现
- 支付宝:AlipayProvider.php
- 微信支付:WxpayProvider.php
开发示例:物流插件
- 建议结构
- manifest.php:plugin_group=shipping
- XxxProvider:实现 shipping 相关接口(如运费计算、轨迹查询)
- XxxService:封装物流公司 API
- 接入方式:与支付插件相同,通过 Registry 注册并在后台启用
开发示例:社交登录插件
- 步骤
- 创建 login.php 与 return_url.php,处理授权与回调
- 使用 inc.plugin.php 加载初始化与回调地址
- 将插件归类为 connect,并在后台启用
- 参考实现
- Amazon 示例:login.php、inc.plugin.php
安装、启用、配置与管理流程
- 安装:从云市场拉取或手动上传至 plugin 目录
- 启用:后台选择插件,填写配置并提交入库
- 编辑:修改配置项,保存后即时生效
- 禁用:移除数据库记录,停止调用
- 删除:二次确认后删除目录并刷新云缓存
插件间通信、数据共享与事件订阅
- 推荐方式
- 通过系统服务与模型共享数据,避免直接耦合
- 使用事件总线或消息队列进行异步通信
- 利用配置中心统一管理跨插件共享配置
- 注意事项
- 避免循环依赖
- 明确数据所有权与读写边界
- 对敏感配置加密存储
安全机制、权限控制与版本兼容性
- 安全
- 所有外部输入严格校验与白名单过滤
- 回调接口必须验签与防重放
- 密钥等敏感信息加密存储
- 权限
- 后台操作需鉴权,审计日志记录关键动作
- 兼容性
- Provider 接口保持稳定,向后兼容升级
- 在 meta 中标明最低系统版本要求
扩展系统现代化:字段映射与排序最佳实践
重大更新 在使用扩展服务时,应遵循以下最新的字段映射与排序最佳实践:
数据库查询规范
- 使用
category_id而非cat_id - 使用
slug而非unique_id - 使用
title而非name
API 响应规范
- 所有扩展数据响应统一使用标准化字段名
- 通过 ExtendRoot 进行客户端协议标识转换
- 保持向后兼容性,支持旧字段名的自动转换
差异化排序策略
- 模板类型:
sort ASC, created_at DESC, id DESC- 优先人工置顶,其次按发布时间倒序 - 模块类型:
sort ASC, count DESC, id DESC- 优先人工置顶,其次按下载量倒序 - 其他类型:
id DESC- 按ID倒序排列
URL 构建器增强
- UrlBuilder 已支持
category_slug和slug占位符 - 短地址模块自动处理分类别名链
- 分类段取顶级祖先别名或完整分类链