🔌 插件注册

ThinkAdmin 提供完善的插件注册服务机制,基于 ThinkPHP 的服务层,使每个插件能够像独立的子应用一样运作。

🚀 主要功能

  • 独立运行: 每个插件像独立的子应用一样运作
  • 服务层集成: 基于 ThinkPHP 服务层机制
  • 自动初始化: 通过 Service 类完成全局初始化
  • 配置管理: 支持 composer.json 配置文件
  • 依赖管理: 自动管理插件依赖关系
  • 灵活扩展: 提供灵活的插件扩展机制

📋 插件类型

1. 本地插件

  • 存储方式: 直接放置在本地目录
  • 配置文件: 根目录需要包含 composer.json 文件
  • 版本要求: 必需指定版本号为 dev-master 或其他开发分支
  • 自动加载: 需要配置 autoload 自动加载规则

2. 开放插件

  • 发布平台: 发布到 Composer 管理平台
  • 安装方式: 通过 composer require vendor/package 安装
  • 版本管理: 支持版本控制和更新管理
  • 依赖解析: 自动解析和安装依赖

3. 私有插件

  • 专属平台: 上传到 ThinkAdmin 专属平台
  • Token 认证: 通过插件中心登录生成 token
  • 安装方式: 与开放插件相同的安装方式
  • 状态: 目前未上线

⚙️ 配置要求

必需文件

  • composer.json: 插件元数据和依赖配置
  • Service 类: 插件服务注册类
  • 自动加载: 配置 autoload 自动加载规则

初始化机制

  • 普通模块: 使用 sys.php 进行全局初始化
  • 插件模块: 依赖 Service 类完成全局初始化
  • 服务注册: 通过 Service 类注册插件服务

插件的三种类型

  1. 本地插件,插件直接放置在本地某个目录,其根目录需要包含 composer.json 文件;
  2. 开放插件,将插件发布到 Composer 管理平台,通过 composer require vendor/package 安装;
  3. 私有插件,将插件上传到 ThinkAdmin 专属平台,通过插件中心登录生成 token,同上面的安装方式 ( 未上线 );
1. 本地插件特性

本地插件是基于 Composerrepositories.typepath 实现,参数 url 指向到插件根目录。

项目根 composer.json 配置 repositories 对象并设置插件所在位置,本地插件必需指定版本号为 dev-master 或其他开发分支。

注意事项:

  1. 需要在插件的 composer.json 配置 autoload 自动加载规则,否则无法实现自动加载 Class 类;
  2. 本地插件不建议使用 ThinkAdmin 插件的自毁机制 ( clear ),有可能造成原插件目录被意外删除;

以下项目根 composer.json 的配置案例中 zoujingli/think-plugs-admin 为插件包名,需要替换为你自己的包名。

{
  "type": "project",
  "require": {
    "zoujingli/think-plugs-admin": "dev-master"
  },
  "repositories": {
    "ThinkAdminPlugs": {
      "type": "path",
      "url": "../think-plugs-admin"
    }
  },
  "autoload": {
    "psr-0": {
      "": "extend"
    },
    "psr-4": {
      "app\\": "app"
    }
  }
}
2. 开放插件特性:

将应用插件发布到 Composer 平台,使用 composer require plugs-package-name 安装。

3. 私有插件特性:

私有插件与线上插件一致,区别在于发布的平台不同,后期会针对此类型详细描述!

插件的配置参数

应用插件 composer.json 具体配置参数如下:

  • 插件类型 ( 固定的 ):think-admin-plugin
  • 插件名称 ( 自定义 ):zouingli/think-plugs-admin
  • 插件信息 ( 自定义 ):可选,配置插件基本信息,展示在插件说明
  • 安装配置 ( 自定义 ):可选,支持安装的规则请阅读《插件安装规则》
  • 插件服务 ( 自定义 ):需要继承 think\admin\Plugin 并在 composer.json 里面注册;
  • 如果是本地插件且未发布到线上,需要增加 version:"dev-master" 配置;
{
  "type": "think-admin-plugin",
  "name": "zoujingli/think-plugs-admin",
  "license": "MIT",
  "homepage": "https://thinkadmin.top",
  "description": "Admin Plugin for ThinkAdmin",
  "authors": [
    {
      "name": "Anyon",
      "email": "zoujingli@qq.com"
    }
  ],
  "require": {
    "php": ">7.1",
    "ext-json": "*",
    "topthink/framework": "^6.0|^8.0",
    "zoujingli/think-library": "^6.1|@dev"
  },
  "autoload": {
    "psr-4": {
      "app\\admin\\": "src"
    }
  },
  "extra": {
    "think": {
      "services": [
        "app\\admin\\Service"
      ]
    },
    "config": {
      "type": "module",
      "name": "系统后台管理",
      "cover": "可选,插件的封面图片,仅支持 https 协议的图片链接",
      "document": "https://thinkadmin.top/plugin/think-plugs-admin.html",
      "platforms": "可选,插件支持的平台,如:['wxapp','wxweb','h5wap','h5web']",
      "description": "后台基础管理模块,系统账号及安全配置管理。",
      "license": "可选,插件授权协议,如:['MIT', 'VIP']"
    },
    "plugin": {
      "copy": {
        "src": "!app/admin",
        "stc/database": "database/migrations"
      },
      "clear": true
    }
  }
}

配置说明:

  • type: 固定为 think-admin-plugin
  • name: 插件包名,格式为 vendor/package-name
  • autoload: PSR-4 自动加载规则,定义插件的命名空间映射
  • extra.think.services: 插件服务注册类,必须指向继承 Plugin 的 Service 类
  • extra.config: 插件基本信息配置
    • type: 插件类型,module 表示模块插件,plugin 表示普通插件
    • name: 插件中文名称
    • document: 插件文档链接
    • description: 插件描述
    • license: 授权协议(数组格式)
  • extra.plugin: 插件安装配置
    • copy: 文件复制规则,! 开头表示绝对复制(先删除再复制)
    • clear: 是否在安装后清理原安装目录

插件服务注册类

插件的服务类需要继承 think\admin\Plugin 类,必须实现静态方法 menu() 来定义插件菜单。

基础属性

在插件的服务类中,可以配置以下属性:

属性类型必填说明
$packagestring插件包名(如:zoujingli/think-plugs-admin
$appCodestring插件编码(自动从命名空间计算,如:adminplugin-account
$appNamestring插件名称(如:系统管理
$appPathstring插件路径(自动计算)
$appAliasstring插件别名(用于路由映射)
$appSpacestring插件命名空间(自动从类命名空间计算)
$appServicestring服务注册类(默认为当前类)

基础示例

<?php
declare(strict_types=1);

namespace app\admin;

use think\admin\Plugin;

/**
 * 插件服务注册
 * @class Service
 * @package app\admin
 */
class Service extends Plugin
{
    /**
     * 定义插件名称
     * @var string
     */
    protected $appName = '系统管理';

    /**
     * 定义安装包名
     * @var string
     */
    protected $package = 'zoujingli/think-plugs-admin';

    /**
     * 定义插件中心菜单
     * @return array
     */
    public static function menu(): array
    {
        return [
            [
                'name' => '系统配置',
                'subs' => [
                    ['name' => '系统参数配置', 'icon' => 'layui-icon layui-icon-set', 'node' => 'admin/config/index'],
                    ['name' => '系统任务管理', 'icon' => 'layui-icon layui-icon-log', 'node' => 'admin/queue/index'],
                    ['name' => '系统日志管理', 'icon' => 'layui-icon layui-icon-form', 'node' => 'admin/oplog/index'],
                    ['name' => '数据字典管理', 'icon' => 'layui-icon layui-icon-code-circle', 'node' => 'admin/base/index'],
                    ['name' => '系统文件管理', 'icon' => 'layui-icon layui-icon-carousel', 'node' => 'admin/file/index'],
                    ['name' => '系统菜单管理', 'icon' => 'layui-icon layui-icon-layouts', 'node' => 'admin/menu/index'],
                ],
            ],
            [
                'name' => '权限管理',
                'subs' => [
                    ['name' => '系统权限管理', 'icon' => 'layui-icon layui-icon-vercode', 'node' => 'admin/auth/index'],
                    ['name' => '系统用户管理', 'icon' => 'layui-icon layui-icon-username', 'node' => 'admin/user/index'],
                ],
            ],
        ];
    }
}

高级示例(带服务注册)

<?php
declare(strict_types=1);

namespace app\wechat;

use app\wechat\command\Auto;
use app\wechat\command\Fans;
use app\wechat\service\AutoService;
use think\admin\Plugin;
use think\Request;

/**
 * 组件注册服务
 * @class Service
 * @package app\wechat
 */
class Service extends Plugin
{
    /**
     * 定义插件名称
     * @var string
     */
    protected $appName = '微信管理';

    /**
     * 定义安装包名
     * @var string
     */
    protected $package = 'zoujingli/think-plugs-wechat';

    /**
     * 注册组件服务
     * @return void
     */
    public function register(): void
    {
        // 注册模块指令
        $this->commands([Fans::class, Auto::class]);

        // 注册事件监听
        $this->app->event->listen('WechatFansSubscribe', static function ($openid) {
            AutoService::register($openid);
        });

        // 注册路由
        $this->app->route->any('/plugin-wxpay-notify/:vars', static function (Request $request) {
            // 处理支付通知
            return PaymentService::notify($data);
        });
    }

    /**
     * 定义插件菜单
     * @return array
     */
    public static function menu(): array
    {
        $code = app(static::class)->appCode;
        return [
            [
                'name' => '微信管理',
                'subs' => [
                    ['name' => '微信接口配置', 'icon' => 'layui-icon layui-icon-set', 'node' => "{$code}/config/options"],
                    ['name' => '微信支付配置', 'icon' => 'layui-icon layui-icon-rmb', 'node' => "{$code}/config/payment"],
                ],
            ],
            [
                'name' => '微信定制',
                'subs' => [
                    ['name' => '微信粉丝管理', 'icon' => 'layui-icon layui-icon-username', 'node' => "{$code}/fans/index"],
                    ['name' => '微信图文管理', 'icon' => 'layui-icon layui-icon-template-1', 'node' => "{$code}/news/index"],
                    ['name' => '微信菜单配置', 'icon' => 'layui-icon layui-icon-cellphone', 'node' => "{$code}/menu/index"],
                ],
            ],
        ];
    }
}

使用 appCode 动态获取插件编码

在菜单定义中,可以使用 app(static::class)->appCode 来动态获取插件编码:

public static function menu(): array
{
    $code = app(static::class)->appCode; // 获取插件编码,如:plugin-account
    return [
        [
            'name' => '用户管理',
            'subs' => [
                ['name' => '用户账号管理', 'node' => "{$code}/master/index"],
                ['name' => '终端账号管理', 'node' => "{$code}/device/index"],
            ],
        ],
    ];
}

合并其他插件菜单

插件可以合并其他插件的菜单,例如支付插件合并账号插件的菜单:

<?php
namespace plugin\payment;

use plugin\account\Service as AccountService;
use think\admin\Plugin;

class Service extends Plugin
{
    protected $appName = '支付管理';
    protected $package = 'zoujingli/think-plugs-payment';

    public static function menu(): array
    {
        $code = app(static::class)->appCode;
        // 合并账号插件的菜单
        return array_merge(AccountService::menu(), [
            [
                'name' => '支付管理',
                'subs' => [
                    ['name' => '支付配置管理', 'node' => "{$code}/config/index"],
                    ['name' => '支付行为管理', 'node' => "{$code}/record/index"],
                ],
            ]
        ]);
    }
}
最近更新:
Contributors: 邹景立, Anyon