📦 插件安装

ThinkAdmin 通过 Composer 管理插件包,并通过 zoujingli/think-install 处理 type=think-admin-plugin 的安装规则。安装过程分为两层:Composer 负责下载、依赖解析和自动加载,ThinkInstall 负责执行 extra.plugin 中的文件初始化、复制、清理和安装事件。

📚 基础概念

什么是插件?

插件是扩展 ThinkAdmin 功能的独立模块,可以提供后台模块、业务插件、基础服务或开发辅助能力。

常见用途:

  • 功能扩展:如账号、支付、商城、微信、一物一码等业务能力。
  • 模块复用:把后台、微信等模块按包管理,便于复用和分发。
  • 资源初始化:复制数据库迁移、静态资源、配置模板等文件。
  • 服务注册:通过 ThinkPHP 服务机制注册命令、路由、事件或中间件。

安装流程

# 在项目根目录执行
composer require zoujingli/think-plugs-account

执行安装时通常会经历以下步骤:

  1. Composer 解析依赖并下载插件包。
  2. think-install 识别 type=think-admin-plugin 的包。
  3. 安装器执行插件 composer.json 中的 extra.plugin 规则。
  4. Composer 触发 post-autoload-dump,ThinkInstall 会调用 php think xadmin:publish --migrate
  5. xadmin:publish 汇总服务、插件展示信息,并按需执行迁移脚本。

触发发布前,ThinkInstall 会先确保 vendor/services.php 至少包含 think\migration\Servicethink\admin\Library,并写入 vendor/binarys.php 记录 PHP、Composer 和当前环境标识,供后续命令和授权相关流程读取。随后执行的 xadmin:publish 会重新按 vendor/composer/installed.json 汇总服务列表,因此基础服务仍需要由对应包的 extra.think.services 声明。

🚀 安装能力

  • 插件识别:只处理 Composer 类型为 think-admin-plugin 的包。
  • 初始化文件:通过 extra.plugin.init 初始化不存在的文件。
  • 文件复制:通过 extra.plugin.copy 复制或替换文件、目录。
  • 安装清理:通过 extra.plugin.clear 清理 vendor 下的插件安装目录。
  • 安装事件:通过 extra.plugin.event 执行 onInstall() / onRemove()
  • 服务发布:通过 xadmin:publish 生成 vendor/services.phpvendor/versions.php
  • 环境信息:安装器激活时会生成 vendor/binarys.php,记录当前 PHP 执行文件、Composer 命令及环境标识。

📋 插件类型

ThinkAdmin 项目中常见两类应用插件,区别主要在代码最终存放位置。

普通应用插件

普通插件保留在 vendor 目录,通过插件自己的 PSR-4 自动加载规则加载类文件。

适用场景:

  • 支付插件 think-plugs-payment
  • 账号插件 think-plugs-account
  • 分销商城插件 think-plugs-wemall
  • Workerman 服务插件 think-plugs-worker
  • 一物一码插件 think-plugs-wuma

典型配置:

{
  "type": "think-admin-plugin",
  "name": "zoujingli/think-plugs-account",
  "autoload": {
    "psr-4": {
      "plugin\\account\\": "src"
    }
  },
  "extra": {
    "think": {
      "services": [
        "plugin\\account\\Service"
      ]
    },
    "plugin": {
      "copy": {
        "stc/database": "database/migrations"
      }
    }
  }
}

安装后的特点:

  • 插件源代码保留在 vendor/zoujingli/think-plugs-account
  • 数据库迁移按 extra.plugin.copy 复制到项目 database/migrations
  • 服务类通过 extra.think.services 发布到 vendor/services.php 后加载。
  • 卸载包不会自动删除已复制的迁移文件、静态资源或业务数据表。

模块插件

模块插件会把代码复制到 app 目录,并通常配置 clear: true 清理 vendor 下的原始安装目录。

适用场景:

  • 后台管理模块 think-plugs-admin
  • 微信管理模块 think-plugs-wechat

典型配置:

{
  "type": "think-admin-plugin",
  "name": "zoujingli/think-plugs-admin",
  "autoload": {
    "psr-4": {
      "app\\admin\\": "src"
    }
  },
  "extra": {
    "think": {
      "services": [
        "app\\admin\\Service"
      ]
    },
    "plugin": {
      "copy": {
        "src": "!app/admin",
        "stc/database": "database/migrations"
      },
      "clear": true
    }
  }
}

安装后的特点:

  • src 会复制到 app/admin,成为项目应用代码的一部分。
  • !app/admin 表示目标存在时先删除目标,再复制源内容。
  • clear: true 会在安装目录位于 vendor 下时清理原插件目录。
  • 后续修改 app/admin 属于项目本地修改,卸载 Composer 包不会自动删除这些文件。

静态资源插件

think-plugs-static 也是 think-admin-plugin,但它没有 autoloadextra.think.services。它只通过安装器复制入口文件、静态资源、配置模板和默认控制器。

{
  "type": "think-admin-plugin",
  "name": "zoujingli/think-plugs-static",
  "extra": {
    "plugin": {
      "copy": {
        "stc/think": "!think",
        "stc/public/index.php": "!public/index.php",
        "stc/public/static/admin.js": "!public/static/admin.js"
      },
      "init": {
        "stc/.env.example": ".env.example",
        "stc/config/app.php": "config/app.php"
      },
      "clear": true
    }
  }
}

静态资源插件中的 stc/public/static/admin.js 是源码包维护的标准文件,安装器会把它强制发布为项目 public/static/admin.js。因此核心脚本的通用修复应进入插件源码包,项目侧个性化脚本应放在 public/static/extra/script.js,个性化样式应放在 public/static/extra/style.css;这两个 extra 文件通过 init 初始化,正常更新不会覆盖已存在文件。

⚙️ 安装器规则

ThinkInstall 的安装规则来自插件 composer.jsonextra.plugin。这些规则只在根项目是 Composer project 时执行。

path - 安装路径

当根包类型为 project 且插件配置了 extra.plugin.path 时,安装器会使用该路径作为插件安装路径;否则使用 Composer 默认安装路径。

当前项目插件主要使用默认安装路径,通常不需要配置 path

init - 初始化文件

init 用于初始化文件,目标文件已存在时不会覆盖。

真实行为:

  • 配置格式为 源文件 => 目标文件
  • 源必须是插件包内的文件,不处理目录。
  • 目标文件不存在时才复制。
  • 会自动创建目标文件的上级目录。

示例:

{
  "plugin": {
    "init": {
      "stc/worker.php": "config/worker.php"
    }
  }
}

适用场景:

  • 初始化配置文件。
  • 初始化可由项目后续自行维护的模板文件。
  • 避免覆盖用户已经修改过的配置。

copy - 复制文件或目录

copy 用于复制插件包内的文件或目录到项目目录。

真实行为:

  • 配置格式为 源路径 => 目标路径
  • 源路径不存在时跳过。
  • 普通目标会执行复制;相同文件内容会跳过。
  • 目标以 ! 开头时,如果目标已存在,会先删除目标再复制。
  • 如果目标目录或目标父目录存在 ignore 文件,会跳过该条复制。

普通复制示例:

{
  "plugin": {
    "copy": {
      "stc/database": "database/migrations"
    }
  }
}

绝对复制示例:

{
  "plugin": {
    "copy": {
      "src": "!app/admin"
    }
  }
}

! 模式适合需要保持目标目录与插件源目录一致的模块代码或核心静态资源。使用前应确认目标目录没有需要保留的本地修改。

ignore - 跳过复制

复制前安装器会检查两个位置:

  • dirname(目标路径)/ignore
  • 目标路径/ignore

任一文件存在时,该条 copy 规则会跳过。

示例:

# 跳过复制数据库迁移目录
touch database/migrations/ignore

clear - 清理插件安装目录

clear: true 表示安装器完成 init / copy 后清理当前插件安装目录。

真实行为:

  • 只有插件安装路径位于 vendor 目录下时才会执行清理。
  • 本地 path 仓库或非 vendor 路径会跳过清理。
  • 清理的是插件包安装目录,不会清理已复制到 apppublicconfigdatabase 的文件。
  • 对启用 clear 的包,安装器会把 Composer 的已安装判断直接视为已安装;因此包目录被清理后,Composer 仍可能认为该包处于安装状态。

示例:

{
  "plugin": {
    "clear": true
  }
}

本地插件开发时不建议开启 clear,避免调试目录被意外清理。

event - 安装与卸载事件

event 用于声明安装或卸载时加载的事件脚本。

真实行为:

  • 配置格式为 源文件 => 类名
  • 安装完成并执行完 installPlugin() 后,若类存在且有 onInstall() 方法,会调用该方法。
  • 卸载前,若类存在且有 onRemove() 方法,会调用该方法。
  • 源文件路径相对于插件安装路径。
  • 普通更新流程主要重新执行 initcopyclear;只有安装路径不存在并回退到安装流程时,才会按安装流程触发 onInstall()

Worker 插件示例:

{
  "plugin": {
    "init": {
      "stc/worker.php": "config/worker.php"
    },
    "event": {
      "src/Script.php": "plugin\\worker\\Script"
    }
  }
}

对应事件类:

<?php

namespace plugin\worker;

abstract class Script
{
    public static function onRemove()
    {
        @unlink('config/worker.php');
    }
}

Wuma 插件同样使用 event 配置:

{
  "plugin": {
    "copy": {
      "stc/database": "database/migrations"
    },
    "event": {
      "src/Script.php": "plugin\\wuma\\Script"
    }
  }
}

🔄 发布流程

ThinkInstall 会在 Composer post-autoload-dump 阶段触发:

php think xadmin:publish --migrate

xadmin:publish 的实际工作包括:

  • 清理运行缓存。
  • vendor/composer/installed.json 汇总 extra.think.services 并重新生成 vendor/services.php
  • extra.config 和包元信息汇总插件展示信息到 vendor/versions.php
  • 处理 extra.think.config,按 vendor/{包名}/{源文件} 查找源文件,仅在目标配置不存在时复制到 config 目录。
  • 遍历 ModuleService::getModules() 读取到的本地应用目录,将每个应用下的 configpublicdatabase 发布到项目根目录。
  • --migrate 时执行 php think migrate:run

发布应用资源时,configdatabase 默认不覆盖已有文件,public 会强制复制;使用 --force 后,configdatabase 也会允许覆盖。发布数据库迁移前会清理同一迁移后缀但时间戳已变化的旧脚本及其数据目录。

手动发布命令:

# 发布服务、版本信息和应用资源
php think xadmin:publish

# 发布后执行数据库迁移
php think xadmin:publish --migrate

# 发布应用 config/database 资源时允许覆盖
php think xadmin:publish --force

📋 完整配置示例

普通插件配置

{
  "type": "think-admin-plugin",
  "name": "zoujingli/think-plugs-account",
  "description": "Multi-terminal account and JWT authentication plugin for ThinkAdmin",
  "require": {
    "php": ">7.1",
    "ext-gd": "*",
    "ext-curl": "*",
    "ext-json": "*",
    "zoujingli/think-install": "^1.0|@dev",
    "zoujingli/think-library": "^6.1|@dev"
  },
  "autoload": {
    "psr-4": {
      "plugin\\account\\": "src"
    }
  },
  "extra": {
    "think": {
      "services": [
        "plugin\\account\\Service"
      ]
    },
    "plugin": {
      "copy": {
        "stc/database": "database/migrations"
      }
    },
    "config": {
      "type": "plugin",
      "name": "用户账号管理",
      "document": "https://thinkadmin.top/plugin/think-plugs-account.html",
      "license": [
        "VIP"
      ]
    }
  }
}

说明:

  • 代码保留在 vendor 目录。
  • 迁移文件复制到 database/migrations
  • 服务类发布到 vendor/services.php 后参与 ThinkPHP 启动。
  • 插件展示信息发布到 vendor/versions.php 后供插件中心读取。

模块插件配置

{
  "type": "think-admin-plugin",
  "name": "zoujingli/think-plugs-admin",
  "description": "Admin backend module with system, menu, auth, file and queue management for ThinkAdmin",
  "require": {
    "php": ">7.1",
    "ext-json": "*",
    "topthink/framework": "^6.0|^8.0",
    "topthink/think-view": "^1.0|^2.0",
    "zoujingli/ip2region": "^1.0|^2.0|^3.0|@dev",
    "zoujingli/think-install": "^1.0|@dev",
    "zoujingli/think-library": "^6.1|@dev",
    "zoujingli/think-plugs-static": "^1.0|@dev"
  },
  "autoload": {
    "psr-4": {
      "app\\admin\\": "src"
    }
  },
  "extra": {
    "think": {
      "services": [
        "app\\admin\\Service"
      ]
    },
    "config": {
      "type": "module",
      "name": "系统后台管理",
      "document": "https://thinkadmin.top/plugin/think-plugs-admin.html",
      "description": "后台基础管理模块,提供系统配置、任务、日志、字典、文件、菜单、权限和用户管理。"
    },
    "plugin": {
      "copy": {
        "src": "!app/admin",
        "stc/database": "database/migrations"
      },
      "clear": true
    }
  }
}

说明:

  • src 复制到 app/admin
  • stc/database 复制到 database/migrations
  • clear: true 清理 vendor 中的插件目录。
  • 卸载时需要自行处理 app/admin、迁移文件和数据库数据。

服务插件配置

{
  "type": "think-admin-plugin",
  "name": "zoujingli/think-plugs-worker",
  "autoload": {
    "psr-4": {
      "plugin\\worker\\": "src"
    }
  },
  "extra": {
    "think": {
      "services": [
        "plugin\\worker\\Service"
      ]
    },
    "plugin": {
      "init": {
        "stc/worker.php": "config/worker.php"
      },
      "event": {
        "src/Script.php": "plugin\\worker\\Script"
      }
    }
  }
}

说明:

  • init 只在 config/worker.php 不存在时复制默认配置。
  • Service 注册 xadmin:worker 命令。
  • 卸载时 Script::onRemove() 会尝试删除 config/worker.php

🔧 常用命令

标准安装

composer require zoujingli/think-plugs-account

开发版本安装

composer require zoujingli/think-plugs-account dev-master

本地插件调试

{
  "require": {
    "zoujingli/think-plugs-account": "dev-master"
  },
  "repositories": {
    "ThinkAdminPlugs": {
      "type": "path",
      "url": "../think-plugs-account"
    }
  }
}

本地 path 插件调试时应谨慎使用 clear: true。安装器会跳过非 vendor 路径的清理,但发布到真实项目前仍应检查目标路径和复制规则。

手动迁移

php think migrate:run

安装器会在 post-autoload-dump 中触发 xadmin:publish --migrate,但在手动复制迁移文件或排查安装问题时,可以单独执行迁移命令。

插件卸载

普通插件:

composer remove zoujingli/think-plugs-account

模块插件:

composer remove zoujingli/think-plugs-admin

# 按需手动清理复制到项目中的代码和资源
rm -rf app/admin

卸载注意事项:

  • Composer 卸载不会自动删除数据库表和业务数据。
  • 已复制到 configpublicdatabase/migrationsapp 的文件需要按插件说明手动处理。
  • 配置了 event 的插件会在卸载时尝试执行 onRemove(),但清理范围以事件类实现为准。
  • 删除模块代码和数据库表前应先备份项目代码与数据。

⚠️ 常见问题

服务类没有加载

检查插件是否已经发布服务配置:

php think xadmin:publish

再检查 vendor/services.php 是否包含插件 extra.think.services 中声明的服务类。

插件中心没有展示包信息

执行:

php think xadmin:publish

插件中心展示信息来自 vendor/versions.php。该文件由 xadmin:publish 从 Composer 已安装包的 extra.config 与包元信息生成。

文件复制没有生效

按顺序检查:

  1. 插件包是否为 type=think-admin-plugin
  2. 根项目是否是 Composer project
  3. extra.plugin.copy 的源路径在插件包中是否存在。
  4. 目标目录或父目录下是否存在 ignore 文件。
  5. 是否使用了 ! 前缀导致目标目录被先删后复制。

配置文件没有被覆盖

如果配置来自 extra.plugin.initextra.think.config,目标已存在时会跳过复制,这是为了避免覆盖项目本地配置。需要覆盖时请手动比对后处理。

最近更新:
Contributors: 邹景立, Anyon