# 插件架构设计

<cite>
**本文引用的文件**
- [README.md](file://README.md)
- [composer.json](file://composer.json)
- [Plugin.php](file://vendor/thinkcmf/cmf/src/lib/Plugin.php)
- [SwaggerPlugin.php](file://public/plugins/swagger/SwaggerPlugin.php)
- [SystemInfoPlugin.php](file://public/plugins/system_info/SystemInfoPlugin.php)
- [TiandituPlugin.php](file://public/plugins/tianditu/TiandituPlugin.php)
- [config.php](file://public/plugins/tianditu/config.php)
- [composer.json](file://public/plugins/swagger/composer.json)
- [widget.html](file://public/plugins/swagger/view/widget.html)
- [widget.html](file://public/plugins/system_info/view/widget.html)
- [plugins.html](file://public/themes/admin_default/admin/hook/plugins.html)
- [hooks.html](file://public/themes/admin_default/admin/plugin/hooks.html)
- [index.html](file://public/themes/admin_default/admin/plugin/index.html)
- [setting.html](file://public/themes/admin_default/admin/plugin/setting.html)
- [functions.html](file://public/themes/admin_default/admin/plugin/functions.html)
</cite>

## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)

## 引言
本文件面向 ThinkCMF 的插件体系，围绕 Plugin 基类展开，系统阐述插件信息配置、生命周期管理、钩子注册与执行顺序、插件状态与数据库记录、插件基本结构与命名规范、以及插件间依赖与执行优先级控制，并结合仓库中的具体插件示例，给出最佳实践与设计模式建议。

## 项目结构
- 插件根目录位于 public/plugins 下，每个插件一个子目录，目录名为“插件英文名”的蛇形小写形式。
- 插件命名空间约定为 plugins\<插件名>\，例如 plugins\swagger\、plugins\system_info\、plugins\tianditu\。
- 插件类文件通常命名为 <插件名>Plugin.php，如 SwaggerPlugin.php、SystemInfoPlugin.php、TiandituPlugin.php。
- 插件配置文件 config.php 位于插件根目录，用于声明后台配置表单项。
- 插件模板视图位于插件目录的 view 子目录中，按主题区分（如 swagger.html、widget.html）。
- 插件可通过 composer.json 声明依赖，ThinkCMF 会在插件初始化时自动加载其 vendor/autoload.php。

```mermaid
graph TB
A["public/plugins/<插件名>/"] --> B["<插件名>Plugin.php"]
A --> C["config.php"]
A --> D["view/"]
D --> E["swagger.html"]
D --> F["widget.html"]
A --> G["composer.json"]
A --> H["vendor/autoload.php"]
```

**图表来源**
- [SwaggerPlugin.php:1-106](file://public/plugins/swagger/SwaggerPlugin.php#L1-L106)
- [SystemInfoPlugin.php:1-85](file://public/plugins/system_info/SystemInfoPlugin.php#L1-L85)
- [TiandituPlugin.php:1-46](file://public/plugins/tianditu/TiandituPlugin.php#L1-L46)
- [config.php:1-17](file://public/plugins/tianditu/config.php#L1-L17)
- [composer.json:1-20](file://public/plugins/swagger/composer.json#L1-L20)

**章节来源**
- [composer.json:46-56](file://composer.json#L46-L56)

## 核心组件
- Plugin 基类：提供插件信息校验、配置加载与缓存、模板引擎初始化与渲染、生命周期抽象方法 install()/uninstall() 等能力。
- 具体插件类：继承 Plugin，实现 install()/uninstall()，并在 info 属性中声明插件元信息；可实现钩子方法以参与系统钩子执行。
- 插件配置表单：通过 config.php 返回表单字段定义，配合后台模板 functions.html 解析生成配置表单。
- 插件钩子管理：后台提供“插件钩子”页面，可设置钩子执行顺序与是否仅执行首个插件。

**章节来源**
- [Plugin.php:19-309](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L19-L309)
- [SwaggerPlugin.php:17-106](file://public/plugins/swagger/SwaggerPlugin.php#L17-L106)
- [SystemInfoPlugin.php:14-85](file://public/plugins/system_info/SystemInfoPlugin.php#L14-L85)
- [TiandituPlugin.php:13-46](file://public/plugins/tianditu/TiandituPlugin.php#L13-L46)
- [config.php:9-17](file://public/plugins/tianditu/config.php#L9-L17)
- [functions.html:1-36](file://public/themes/admin_default/admin/plugin/functions.html#L1-L36)
- [hooks.html:1-43](file://public/themes/admin_default/admin/plugin/hooks.html#L1-L43)
- [plugins.html:1-65](file://public/themes/admin_default/admin/hook/plugins.html#L1-L65)

## 架构总览
ThinkCMF 插件架构由“基类能力 + 插件实现 + 配置与模板 + 后台管理 + 钩子调度”构成。基类负责插件生命周期与运行时环境准备，插件实现业务逻辑与钩子方法，配置文件驱动后台表单，后台页面负责状态管理与钩子顺序设置。

```mermaid
graph TB
subgraph "插件基类层"
P["Plugin 基类<br/>生命周期/配置/模板/钩子"]
end
subgraph "插件实现层"
S["SwaggerPlugin"]
SI["SystemInfoPlugin"]
T["TiandituPlugin"]
end
subgraph "配置与模板"
CFG["config.php"]
V1["view/swagger.html"]
V2["view/widget.html"]
end
subgraph "后台管理"
IDX["插件列表"]
HK["钩子管理"]
ORD["执行顺序设置"]
SET["插件设置"]
end
P --> S
P --> SI
P --> T
S --> CFG
S --> V1
S --> V2
SI --> CFG
SI --> V2
T --> CFG
T --> V2
IDX --> HK
HK --> ORD
IDX --> SET
```

**图表来源**
- [Plugin.php:19-309](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L19-L309)
- [SwaggerPlugin.php:17-106](file://public/plugins/swagger/SwaggerPlugin.php#L17-L106)
- [SystemInfoPlugin.php:14-85](file://public/plugins/system_info/SystemInfoPlugin.php#L14-L85)
- [TiandituPlugin.php:13-46](file://public/plugins/tianditu/TiandituPlugin.php#L13-L46)
- [config.php:9-17](file://public/plugins/tianditu/config.php#L9-L17)
- [widget.html:1-32](file://public/plugins/swagger/view/widget.html#L1-L32)
- [widget.html:1-12](file://public/plugins/system_info/view/widget.html#L1-L12)
- [index.html:26-135](file://public/themes/admin_default/admin/plugin/index.html#L26-L135)
- [hooks.html:1-43](file://public/themes/admin_default/admin/plugin/hooks.html#L1-L43)
- [plugins.html:1-65](file://public/themes/admin_default/admin/hook/plugins.html#L1-L65)
- [setting.html:1-42](file://public/themes/admin_default/admin/plugin/setting.html#L1-L42)

## 详细组件分析

### Plugin 基类设计
- 插件信息与校验
  - info 属性用于存放插件元信息，基类提供 checkInfo() 校验必需字段。
- 生命周期
  - 抽象方法 install()/uninstall() 必须在子类中实现，分别处理安装与卸载逻辑。
- 配置加载与缓存
  - getConfig() 从数据库缓存读取插件配置，若无则回退到默认配置（来自 config.php）。
  - getDefaultConfig() 从插件根目录 config.php 提取默认值。
- 模板引擎与渲染
  - 初始化 View 引擎，设置视图根目录与模板变量替换规则，提供 assign/fetch/display 方法。
  - fetch() 支持相对路径模板名，自动拼接后缀与主题目录。
- Composer 自动加载
  - 插件 vendor/autoload.php 在首次加载时自动引入，确保插件依赖可用。

```mermaid
classDiagram
class Plugin {
+info
+checkInfo() bool
+getConfig() array
+getDefaultConfig() array
+getPluginPath() string
+getThemeRoot() string
+getView() View
+assign(name, value)
+fetch(template) string
+display(content)
<<abstract>>
+install()
+uninstall()
}
```

**图表来源**
- [Plugin.php:19-309](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L19-L309)

**章节来源**
- [Plugin.php:34-42](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L34-L42)
- [Plugin.php:199-207](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L199-L207)
- [Plugin.php:303-308](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L303-L308)
- [Plugin.php:249-274](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L249-L274)
- [Plugin.php:280-301](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L280-L301)
- [Plugin.php:141-154](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L141-L154)
- [Plugin.php:162-165](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L162-L165)
- [Plugin.php:174-177](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L174-L177)
- [Plugin.php:65-72](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L65-L72)

### 插件基本结构与命名规范
- 目录结构
  - public/plugins/<插件名>/：插件根目录，插件名采用“插件英文名”的蛇形小写形式。
  - <插件名>Plugin.php：插件类文件，命名空间 plugins\<插件名>\。
  - config.php：插件配置表单定义。
  - view/：模板视图目录，按主题划分。
  - composer.json：可选，声明插件依赖。
- 命名空间约定
  - 类命名空间 plugins\<插件名>\，类名 <插件名>Plugin，info 中 name 字段与类名一致（不含 Plugin 后缀）。
- 配置文件格式
  - config.php 返回数组，键为表单项标识，值包含 title/type/value/tip 等字段，支持分组与多种表单类型。

**章节来源**
- [SwaggerPlugin.php:10-17](file://public/plugins/swagger/SwaggerPlugin.php#L10-L17)
- [SystemInfoPlugin.php:9-14](file://public/plugins/system_info/SystemInfoPlugin.php#L9-L14)
- [TiandituPlugin.php:9-13](file://public/plugins/tianditu/TiandituPlugin.php#L9-L13)
- [config.php:9-17](file://public/plugins/tianditu/config.php#L9-L17)

### 插件状态管理与数据库记录机制
- 插件状态
  - 插件 info 中 status 字段表示启用/禁用状态；后台插件列表页根据状态显示不同标记。
- 数据库记录
  - 插件配置存储于数据库表 plugin 的 config 字段（JSON），基类通过缓存键 cmf_<插件名>_plugin_config 与 cmf_<插件名>_plugin_config_db 进行缓存与持久化读取。
- 后台设置
  - 插件设置页通过 _parse_plugin_config() 解析 config.php 生成表单，提交后更新数据库记录。

```mermaid
flowchart TD
Start(["进入插件设置"]) --> LoadCfg["读取插件配置<br/>getConfig()"]
LoadCfg --> HasCache{"缓存存在？"}
HasCache --> |是| ReturnCache["返回缓存配置"]
HasCache --> |否| LoadDB["查询数据库 plugin 表 config 字段"]
LoadDB --> Parse["JSON 解析为数组"]
Parse --> SaveCache["写入缓存并返回"]
ReturnCache --> End(["完成"])
SaveCache --> End
```

**图表来源**
- [Plugin.php:253-274](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L253-L274)
- [setting.html:7-24](file://public/themes/admin_default/admin/plugin/setting.html#L7-L24)
- [functions.html:1-36](file://public/themes/admin_default/admin/plugin/functions.html#L1-L36)

**章节来源**
- [Plugin.php:253-274](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L253-L274)
- [index.html:52-56](file://public/themes/admin_default/admin/plugin/index.html#L52-L56)
- [setting.html:7-24](file://public/themes/admin_default/admin/plugin/setting.html#L7-L24)
- [functions.html:1-36](file://public/themes/admin_default/admin/plugin/functions.html#L1-L36)

### 钩子注册机制与执行优先级
- 钩子注册
  - 插件通过实现特定钩子方法（如 adminDashboard、adminDialogMapView、adminApiImportView 等）参与系统钩子。
- 执行顺序
  - 后台“插件钩子”页面列出钩子类型与是否仅执行首个插件；可设置每个钩子下各插件的执行顺序。
- 钩子类型
  - 后台页面支持系统钩子、应用钩子、主题钩子、后台主题钩子四类。

```mermaid
sequenceDiagram
participant Admin as "后台管理"
participant Hooks as "钩子管理页面"
participant Plugin as "插件类"
participant DB as "数据库"
Admin->>Hooks : 打开“插件钩子”页面
Hooks->>DB : 查询钩子与插件绑定及顺序
DB-->>Hooks : 返回绑定与排序
Hooks-->>Admin : 展示可调整顺序的列表
Admin->>Hooks : 修改顺序并保存
Hooks->>DB : 更新排序字段
Note over Admin,DB : 钩子触发时按排序依次执行
```

**图表来源**
- [hooks.html:1-43](file://public/themes/admin_default/admin/plugin/hooks.html#L1-L43)
- [plugins.html:1-65](file://public/themes/admin_default/admin/hook/plugins.html#L1-L65)

**章节来源**
- [hooks.html:6-11](file://public/themes/admin_default/admin/plugin/hooks.html#L6-L11)
- [plugins.html:6-8](file://public/themes/admin_default/admin/hook/plugins.html#L6-L8)
- [SwaggerPlugin.php:44-103](file://public/plugins/swagger/SwaggerPlugin.php#L44-L103)
- [SystemInfoPlugin.php:39-82](file://public/plugins/system_info/SystemInfoPlugin.php#L39-L82)
- [TiandituPlugin.php:38-43](file://public/plugins/tianditu/TiandituPlugin.php#L38-L43)

### 具体插件类实现示例
- SwaggerPlugin
  - 实现 install()/uninstall()，在 adminApiImportView() 中扫描 OpenAPI 并向后台 API 权限表写入或更新记录，最后渲染 widget 页面。
- SystemInfoPlugin
  - 实现 install()/uninstall()，在 adminDashboard() 中收集服务器信息并通过模板渲染仪表盘部件。
- TiandituPlugin
  - 实现 install()/uninstall()，在 adminDialogMapView() 中读取配置并渲染地图部件。

```mermaid
classDiagram
class SwaggerPlugin {
+info
+install() bool
+uninstall() bool
+adminApiImportView() mixed
}
class SystemInfoPlugin {
+info
+install() bool
+uninstall() bool
+adminDashboard() array
}
class TiandituPlugin {
+info
+install() bool
+uninstall() bool
+adminDialogMapView() mixed
}
SwaggerPlugin --|> Plugin
SystemInfoPlugin --|> Plugin
TiandituPlugin --|> Plugin
```

**图表来源**
- [SwaggerPlugin.php:17-106](file://public/plugins/swagger/SwaggerPlugin.php#L17-L106)
- [SystemInfoPlugin.php:14-85](file://public/plugins/system_info/SystemInfoPlugin.php#L14-L85)
- [TiandituPlugin.php:13-46](file://public/plugins/tianditu/TiandituPlugin.php#L13-L46)
- [Plugin.php:303-308](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L303-L308)

**章节来源**
- [SwaggerPlugin.php:32-42](file://public/plugins/swagger/SwaggerPlugin.php#L32-L42)
- [SwaggerPlugin.php:44-103](file://public/plugins/swagger/SwaggerPlugin.php#L44-L103)
- [SystemInfoPlugin.php:27-37](file://public/plugins/system_info/SystemInfoPlugin.php#L27-L37)
- [SystemInfoPlugin.php:39-82](file://public/plugins/system_info/SystemInfoPlugin.php#L39-L82)
- [TiandituPlugin.php:26-36](file://public/plugins/tianditu/TiandituPlugin.php#L26-L36)
- [TiandituPlugin.php:38-43](file://public/plugins/tianditu/TiandituPlugin.php#L38-L43)

### 插件间依赖关系与执行优先级控制
- 依赖声明
  - 插件可通过 composer.json 声明依赖，ThinkCMF 在插件构造时自动加载 vendor/autoload.php。
- 执行优先级
  - 后台“插件钩子”页面允许为每个钩子设置多个插件的执行顺序；“仅首个插件执行”选项可控制是否中断后续插件执行。
- 最佳实践
  - 对于有副作用的钩子（如修改全局状态），建议启用“仅首个插件执行”，避免重复处理。
  - 对于可叠加的钩子（如统计、日志），保持“允许多个插件执行”。

**章节来源**
- [composer.json:12-15](file://public/plugins/swagger/composer.json#L12-L15)
- [Plugin.php:65-72](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L65-L72)
- [hooks.html:18-28](file://public/themes/admin_default/admin/plugin/hooks.html#L18-L28)
- [plugins.html:30-34](file://public/themes/admin_default/admin/hook/plugins.html#L30-L34)

## 依赖关系分析
- 命名空间映射
  - composer.json 将 plugins\ 映射到 public/plugins，便于 PSR-4 自动加载插件类。
- 插件与基类
  - 所有插件类均继承 Plugin 基类，复用其生命周期与运行时能力。
- 插件与模板
  - 插件通过基类的 View 引擎渲染自身模板，模板路径受主题与 CDN 设置影响。
- 插件与数据库
  - 插件配置持久化于 plugin 表，基类提供缓存与读取逻辑。

```mermaid
graph LR
CJ["composer.json<br/>PSR-4: plugins\\ => public/plugins"] --> PL["插件类命名空间"]
PL --> PB["Plugin 基类"]
PB --> TM["模板引擎"]
PB --> DB["数据库 plugin 表"]
```

**图表来源**
- [composer.json:46-56](file://composer.json#L46-L56)
- [Plugin.php:118-126](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L118-L126)
- [Plugin.php:253-274](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L253-L274)

**章节来源**
- [composer.json:46-56](file://composer.json#L46-L56)
- [Plugin.php:118-126](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L118-L126)
- [Plugin.php:253-274](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L253-L274)

## 性能考虑
- 配置缓存
  - 基类对插件配置使用随机 TTL 缓存，减少数据库频繁读取，提升后台设置页与钩子执行性能。
- 模板渲染
  - 模板路径解析与后缀拼接在 fetch() 内部完成，建议插件在钩子中尽量复用已分配变量，避免重复 assign。
- Composer 自动加载
  - 仅在首次加载插件时引入 vendor/autoload.php，避免重复引入带来的性能损耗。

**章节来源**
- [Plugin.php:263-274](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L263-L274)
- [Plugin.php:141-154](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L141-L154)
- [Plugin.php:65-72](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L65-L72)

## 故障排查指南
- 模板不存在
  - fetch() 若模板文件不存在会抛出异常，需检查模板路径与主题设置。
- 配置未生效
  - 确认插件设置页已保存，且缓存键 cmf_<插件名>_plugin_config 已更新；必要时清理缓存后重试。
- 钩子未执行
  - 检查后台“插件钩子”页面中该钩子是否启用、顺序是否正确、是否被“仅首个插件执行”提前中断。
- 插件依赖缺失
  - 确认插件 composer.json 依赖已安装，vendor/autoload.php 可正常加载。

**章节来源**
- [Plugin.php:149-151](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L149-L151)
- [Plugin.php:259-274](file://vendor/thinkcmf/cmf/src/lib/Plugin.php#L259-L274)
- [hooks.html:18-28](file://public/themes/admin_default/admin/plugin/hooks.html#L18-L28)
- [composer.json:12-15](file://public/plugins/swagger/composer.json#L12-L15)

## 结论
ThinkCMF 的插件体系以 Plugin 基类为核心，提供了完善的生命周期、配置与模板渲染能力，并通过后台页面实现插件状态管理与钩子执行顺序控制。遵循命名规范、合理设计 config.php、充分利用钩子与优先级设置，可构建高内聚、低耦合、可扩展的插件生态。

## 附录
- 插件示例页面
  - Swagger 插件导入成功页面：[widget.html:1-32](file://public/plugins/swagger/view/widget.html#L1-L32)
  - 系统信息插件部件页面：[widget.html:1-12](file://public/plugins/system_info/view/widget.html#L1-L12)
- 后台管理页面
  - 插件列表：[index.html:26-135](file://public/themes/admin_default/admin/plugin/index.html#L26-L135)
  - 钩子管理：[hooks.html:1-43](file://public/themes/admin_default/admin/plugin/hooks.html#L1-L43)
  - 插件钩子执行顺序：[plugins.html:1-65](file://public/themes/admin_default/admin/hook/plugins.html#L1-L65)
  - 插件设置表单解析：[functions.html:1-36](file://public/themes/admin_default/admin/plugin/functions.html#L1-L36)