# 插件开发指南

<cite>
**本文引用的文件**
- [Swagger 插件入口类](file://public/plugins/swagger/SwaggerPlugin.php)
- [Swagger 控制器（前台）](file://public/plugins/swagger/controller/IndexController.php)
- [Swagger 控制器（后台）](file://public/plugins/swagger/controller/AdminIndexController.php)
- [Swagger 服务类](file://public/plugins/swagger/service/OpenApi.php)
- [Swagger 公共注解与安全方案](file://public/plugins/swagger/swagger/OpenApiSpec.php)
- [Swagger 视图模板（前台页面）](file://public/plugins/swagger/view/swagger.html)
- [Swagger 视图模板（后台导入结果页）](file://public/plugins/swagger/view/widget.html)
- [Swagger 视图模板（后台公共头部）](file://public/plugins/swagger/view/public/head.html)
- [Swagger 视图模板（后台公共脚本）](file://public/plugins/swagger/view/public/scripts.html)
- [Swagger 插件 Composer 配置](file://public/plugins/swagger/composer.json)
- [系统信息插件入口类](file://public/plugins/system_info/SystemInfoPlugin.php)
- [天地图插件入口类](file://public/plugins/tianditu/TiandituPlugin.php)
- [天地图插件配置项定义](file://public/plugins/tianditu/config.php)
- [插件基类（Plugin）](file://vendor/thinkcmf/cmf/src/lib/Plugin.php)
</cite>

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

## 简介
本指南面向 ThinkCMF 插件开发者，提供从项目初始化到最终发布的完整流程说明。以 Swagger 插件为实际案例，讲解插件目录结构、控制器与服务类的职责划分、视图模板的组织方式、插件配置文件的编写规范、安装与卸载逻辑、以及测试、调试与部署的最佳实践。同时对比系统信息与天地图两个插件，帮助理解不同类型的插件实现差异。

## 项目结构
ThinkCMF 插件遵循“按插件命名空间独立目录”的约定，插件根目录位于 public/plugins/<插件名>。每个插件通常包含以下子目录：
- controller：存放插件的控制器类，区分前台与后台两类控制器
- service：存放插件的服务类，封装业务逻辑或第三方 SDK 调用
- swagger：存放 OpenAPI 注解文件，用于统一生成 API 文档
- view：存放插件视图模板，支持前台页面与后台管理页面
- 根目录：插件入口类、Composer 配置、配置项定义等

```mermaid
graph TB
A["public/plugins/<插件名>/"] --> B["controller/"]
A --> C["service/"]
A --> D["swagger/"]
A --> E["view/"]
A --> F["<插件名>Plugin.php"]
A --> G["composer.json"]
A --> H["config.php(可选)"]
B --> B1["前台控制器<br/>如 IndexController.php"]
B --> B2["后台控制器<br/>如 AdminIndexController.php"]
C --> C1["服务类<br/>如 OpenApi.php"]
D --> D1["OpenAPI 注解文件<br/>如 OpenApiSpec.php"]
E --> E1["前台视图<br/>如 swagger.html"]
E --> E2["后台视图<br/>如 widget.html"]
```

图表来源
- [Swagger 插件入口类](file://public/plugins/swagger/SwaggerPlugin.php)
- [Swagger 控制器（前台）](file://public/plugins/swagger/controller/IndexController.php)
- [Swagger 控制器（后台）](file://public/plugins/swagger/controller/AdminIndexController.php)
- [Swagger 服务类](file://public/plugins/swagger/service/OpenApi.php)
- [Swagger 公共注解与安全方案](file://public/plugins/swagger/swagger/OpenApiSpec.php)
- [Swagger 视图模板（前台页面）](file://public/plugins/swagger/view/swagger.html)
- [Swagger 视图模板（后台导入结果页）](file://public/plugins/swagger/view/widget.html)
- [Swagger 插件 Composer 配置](file://public/plugins/swagger/composer.json)
- [天地图插件入口类](file://public/plugins/tianditu/TiandituPlugin.php)
- [天地图插件配置项定义](file://public/plugins/tianditu/config.php)

章节来源
- [Swagger 插件入口类](file://public/plugins/swagger/SwaggerPlugin.php)
- [Swagger 插件 Composer 配置](file://public/plugins/swagger/composer.json)

## 核心组件
- 插件入口类：继承插件基类，声明插件元数据、是否具备后台管理界面、安装与卸载钩子等
- 控制器：处理前台与后台请求，负责渲染视图或返回 JSON 数据
- 服务类：封装复杂逻辑，如扫描 API、生成 OpenAPI 规范、调用外部 SDK
- 视图模板：提供页面展示，支持前台文档页与后台管理页
- 配置文件：定义插件的配置项（如第三方密钥），供后台配置表单使用
- 注解文件：集中定义 OpenAPI 的 Info、Server、SecurityScheme、通用参数与响应等

章节来源
- [Swagger 插件入口类](file://public/plugins/swagger/SwaggerPlugin.php)
- [Swagger 控制器（前台）](file://public/plugins/swagger/controller/IndexController.php)
- [Swagger 控制器（后台）](file://public/plugins/swagger/controller/AdminIndexController.php)
- [Swagger 服务类](file://public/plugins/swagger/service/OpenApi.php)
- [Swagger 公共注解与安全方案](file://public/plugins/swagger/swagger/OpenApiSpec.php)
- [Swagger 视图模板（前台页面）](file://public/plugins/swagger/view/swagger.html)
- [Swagger 视图模板（后台导入结果页）](file://public/plugins/swagger/view/widget.html)
- [天地图插件配置项定义](file://public/plugins/tianditu/config.php)

## 架构总览
下图展示了 Swagger 插件在 ThinkCMF 中的整体交互：浏览器请求进入前台或后台控制器，控制器根据需要调用服务类生成 OpenAPI 规范，随后渲染视图；后台管理页还提供一键导入接口到权限系统的功能。

```mermaid
graph TB
subgraph "浏览器"
U["用户"]
end
subgraph "ThinkCMF 应用"
FC["前台控制器<br/>IndexController"]
AC["后台控制器<br/>AdminIndexController"]
S["服务类<br/>OpenApi"]
V1["视图模板<br/>swagger.html"]
V2["视图模板<br/>widget.html"]
P["插件入口类<br/>SwaggerPlugin"]
end
U --> FC
U --> AC
FC --> S
FC --> V1
AC --> P
P --> S
S --> V1
P --> V2
```

图表来源
- [Swagger 控制器（前台）](file://public/plugins/swagger/controller/IndexController.php)
- [Swagger 控制器（后台）](file://public/plugins/swagger/controller/AdminIndexController.php)
- [Swagger 服务类](file://public/plugins/swagger/service/OpenApi.php)
- [Swagger 视图模板（前台页面）](file://public/plugins/swagger/view/swagger.html)
- [Swagger 视图模板（后台导入结果页）](file://public/plugins/swagger/view/widget.html)
- [Swagger 插件入口类](file://public/plugins/swagger/SwaggerPlugin.php)

## 详细组件分析

### 插件入口类（SwaggerPlugin）
- 职责：声明插件元数据（名称、标题、描述、作者、版本、演示链接、作者链接）、是否具备后台管理界面、安装与卸载钩子
- 安装/卸载：返回布尔值表示安装/卸载是否成功
- 后台管理方法：提供一个导入后台接口列表的方法，扫描 OpenAPI 并写入数据库，再渲染后台导入结果页

```mermaid
classDiagram
class Plugin {
<<抽象>>
+install()
+uninstall()
}
class SwaggerPlugin {
+info
+hasAdmin
+install()
+uninstall()
+adminApiImportView()
}
SwaggerPlugin --|> Plugin : "继承"
```

图表来源
- [Swagger 插件入口类](file://public/plugins/swagger/SwaggerPlugin.php)
- [插件基类（Plugin）](file://vendor/thinkcmf/cmf/src/lib/Plugin.php)

章节来源
- [Swagger 插件入口类](file://public/plugins/swagger/SwaggerPlugin.php)

### 前台控制器（IndexController）
- 职责：处理前台 Swagger 文档页请求，支持在调试模式或后台登录状态下访问；提供 JSON 配置接口，返回 OpenAPI 规范
- 权限控制：通过应用调试状态或当前管理员 ID 判断访问权限
- 输出：渲染视图或抛出 JSON 响应

```mermaid
sequenceDiagram
participant Browser as "浏览器"
participant Ctrl as "IndexController"
participant Service as "OpenApi 服务类"
participant View as "swagger.html"
Browser->>Ctrl : 访问 /swagger
Ctrl->>Ctrl : 检查调试或管理员登录
alt 可访问
Ctrl->>Service : generate()
Service-->>Ctrl : OpenAPI 规范对象
Ctrl->>View : 渲染文档页
View-->>Browser : HTML 页面
else 不可访问
Ctrl-->>Browser : 提示信息
end
```

图表来源
- [Swagger 控制器（前台）](file://public/plugins/swagger/controller/IndexController.php)
- [Swagger 服务类](file://public/plugins/swagger/service/OpenApi.php)
- [Swagger 视图模板（前台页面）](file://public/plugins/swagger/view/swagger.html)

章节来源
- [Swagger 控制器（前台）](file://public/plugins/swagger/controller/IndexController.php)

### 后台控制器（AdminIndexController）
- 职责：提供后台管理菜单入口，渲染 Swagger 文档页
- 初始化：注入当前管理员 ID 到视图
- 菜单注解：通过注解声明后台菜单项的父级、显示顺序、图标、备注等

```mermaid
sequenceDiagram
participant Admin as "后台管理员"
participant Ctrl as "AdminIndexController"
participant View as "swagger.html"
Admin->>Ctrl : 访问 Swagger 菜单项
Ctrl->>Ctrl : initialize() 注入管理员信息
Ctrl->>View : 渲染文档页
View-->>Admin : HTML 页面
```

图表来源
- [Swagger 控制器（后台）](file://public/plugins/swagger/controller/AdminIndexController.php)
- [Swagger 视图模板（前台页面）](file://public/plugins/swagger/view/swagger.html)

章节来源
- [Swagger 控制器（后台）](file://public/plugins/swagger/controller/AdminIndexController.php)

### 服务类（OpenApi）
- 职责：扫描 API 路径，聚合所有可用的控制器与注解，生成 OpenAPI 规范
- 扫描范围：内置 API 应用、扩展 API 应用、已启用插件的控制器与 swagger 目录
- 生成策略：调用 OpenAPI 生成器，指定别名、验证开关与版本

```mermaid
flowchart TD
Start(["开始"]) --> Paths["收集扫描路径<br/>内置/扩展 API 应用<br/>已启用插件控制器与swagger目录"]
Paths --> Apps["遍历应用与插件"]
Apps --> Scan["调用生成器扫描并生成 OpenAPI 规范"]
Scan --> Return["返回规范对象"]
Return --> End(["结束"])
```

图表来源
- [Swagger 服务类](file://public/plugins/swagger/service/OpenApi.php)

章节来源
- [Swagger 服务类](file://public/plugins/swagger/service/OpenApi.php)

### 视图模板（swagger.html）
- 职责：前台文档页，加载 Swagger UI 资源，通过配置接口动态拉取 OpenAPI 规范
- 资源：引入样式与脚本，设置布局与授权持久化

```mermaid
graph TB
V["swagger.html"] --> R1["样式资源"]
V --> R2["脚本资源"]
V --> C["配置接口<br/>cmf_plugin_url('Swagger://Index/config')"]
```

图表来源
- [Swagger 视图模板（前台页面）](file://public/plugins/swagger/view/swagger.html)

章节来源
- [Swagger 视图模板（前台页面）](file://public/plugins/swagger/view/swagger.html)

### 视图模板（widget.html）
- 职责：后台导入结果页，提示导入成功
- 适用场景：后台执行导入接口后跳转展示

```mermaid
graph TB
W["widget.html"] --> T["导入成功提示"]
```

图表来源
- [Swagger 视图模板（后台导入结果页）](file://public/plugins/swagger/view/widget.html)

章节来源
- [Swagger 视图模板（后台导入结果页）](file://public/plugins/swagger/view/widget.html)

### OpenAPI 注解文件（OpenApiSpec.php）
- 职责：集中定义 OpenAPI 的基本信息、服务器地址、安全方案、通用参数与响应等
- 作用：作为全局注解，被扫描器识别，统一生成文档

```mermaid
classDiagram
class OpenApiSpec {
<<注解类>>
+Info
+Server
+SecurityScheme
+Parameter
+Response
}
```

图表来源
- [Swagger 公共注解与安全方案](file://public/plugins/swagger/swagger/OpenApiSpec.php)

章节来源
- [Swagger 公共注解与安全方案](file://public/plugins/swagger/swagger/OpenApiSpec.php)

### 配置文件（config.php）
- 职责：定义插件后台配置表单的字段、类型、默认值与提示信息
- 示例：天地图插件的地图密钥配置项

```mermaid
flowchart TD
Define["定义配置项数组"] --> Render["后台渲染表单"]
Render --> Save["保存配置到数据库"]
Save --> Use["插件运行时读取配置"]
```

图表来源
- [天地图插件配置项定义](file://public/plugins/tianditu/config.php)

章节来源
- [天地图插件配置项定义](file://public/plugins/tianditu/config.php)

### 其他插件示例
- 系统信息插件：在后台仪表盘挂载小部件，读取系统信息并渲染视图
- 天地图插件：无后台管理界面，提供弹窗地图视图，支持配置项

章节来源
- [系统信息插件入口类](file://public/plugins/system_info/SystemInfoPlugin.php)
- [天地图插件入口类](file://public/plugins/tianditu/TiandituPlugin.php)

## 依赖关系分析
- 插件入口类依赖插件基类，实现安装/卸载与后台管理方法
- 控制器依赖服务类生成 OpenAPI 规范，依赖视图模板渲染页面
- 服务类依赖 OpenAPI 生成器与数据库查询，扫描多处路径
- 视图模板依赖静态资源与插件 URL 辅助函数
- 配置文件为后台配置表单提供数据源

```mermaid
graph TB
P["SwaggerPlugin"] --> B["Plugin 基类"]
C1["IndexController"] --> S["OpenApi 服务类"]
C2["AdminIndexController"] --> P
S --> O["OpenAPI 生成器"]
C1 --> V1["swagger.html"]
P --> V2["widget.html"]
P --> DB["数据库(admin_api/auth_rule)"]
```

图表来源
- [Swagger 插件入口类](file://public/plugins/swagger/SwaggerPlugin.php)
- [Swagger 控制器（前台）](file://public/plugins/swagger/controller/IndexController.php)
- [Swagger 控制器（后台）](file://public/plugins/swagger/controller/AdminIndexController.php)
- [Swagger 服务类](file://public/plugins/swagger/service/OpenApi.php)
- [Swagger 视图模板（前台页面）](file://public/plugins/swagger/view/swagger.html)
- [Swagger 视图模板（后台导入结果页）](file://public/plugins/swagger/view/widget.html)

章节来源
- [Swagger 插件入口类](file://public/plugins/swagger/SwaggerPlugin.php)
- [Swagger 控制器（前台）](file://public/plugins/swagger/controller/IndexController.php)
- [Swagger 控制器（后台）](file://public/plugins/swagger/controller/AdminIndexController.php)
- [Swagger 服务类](file://public/plugins/swagger/service/OpenApi.php)

## 性能考虑
- 扫描范围优化：仅扫描已启用插件与内置/扩展 API 应用，避免不必要的目录
- 缓存策略：建议在生产环境对生成的 OpenAPI 规范进行缓存，减少重复扫描与序列化开销
- 资源加载：前端资源尽量使用 CDN 或合并打包，降低首屏渲染时间
- 权限控制：在控制器层尽早判断访问权限，避免无效计算

## 故障排查指南
- 安装/卸载失败：检查插件入口类的 install/uninstall 返回值是否为布尔型且符合预期
- OpenAPI 未生成：确认扫描路径是否包含目标控制器与注解目录，检查生成器别名与版本配置
- 后台导入异常：核对数据库中 admin_api 与 auth_rule 表的写入逻辑，确保标签与 URL 规则正确
- 权限访问受限：确认前台控制器的调试模式或管理员登录判断逻辑
- 配置项不生效：检查后台配置表单渲染与保存流程，确保读取配置的键名一致

章节来源
- [Swagger 插件入口类](file://public/plugins/swagger/SwaggerPlugin.php)
- [Swagger 控制器（前台）](file://public/plugins/swagger/controller/IndexController.php)
- [Swagger 插件入口类](file://public/plugins/swagger/SwaggerPlugin.php)

## 结论
通过 Swagger 插件的完整实现，可以清晰地把握 ThinkCMF 插件开发的关键要素：插件入口类的元数据与生命周期、控制器与服务类的职责边界、视图模板的组织方式、注解文件的统一规范，以及安装/卸载与后台管理的实现要点。结合系统信息与天地图插件的差异实现，开发者可以根据自身需求选择合适的插件类型与实现方式。

## 附录

### 插件创建流程（从零到发布）
- 创建目录：在 public/plugins 下新建插件目录，按需创建 controller、service、swagger、view 子目录
- 编写入口类：继承插件基类，填写 info 数组与 hasAdmin，实现 install/uninstall
- 编写控制器：分别创建前台与后台控制器，处理请求与渲染视图
- 实现服务类：封装业务逻辑，如扫描 API、生成 OpenAPI 规范
- 开发视图模板：设计前台文档页与后台管理页
- 配置插件：在根目录添加 composer.json，定义依赖与类型；如有后台配置，添加 config.php
- 测试与调试：在调试模式下验证文档页与配置接口，检查后台导入逻辑
- 部署与发布：打包插件目录，上传至生产环境，执行安装流程

章节来源
- [Swagger 插件入口类](file://public/plugins/swagger/SwaggerPlugin.php)
- [Swagger 插件 Composer 配置](file://public/plugins/swagger/composer.json)
- [Swagger 控制器（前台）](file://public/plugins/swagger/controller/IndexController.php)
- [Swagger 控制器（后台）](file://public/plugins/swagger/controller/AdminIndexController.php)
- [Swagger 服务类](file://public/plugins/swagger/service/OpenApi.php)
- [Swagger 视图模板（前台页面）](file://public/plugins/swagger/view/swagger.html)
- [Swagger 视图模板（后台导入结果页）](file://public/plugins/swagger/view/widget.html)
- [天地图插件配置项定义](file://public/plugins/tianditu/config.php)