开发扩展

Dcat Admin支持安装扩展工具来帮助丰富你的后台功能。

需要注意的是,Laravel Admin原有的扩展无法直接在Dcat Admin中使用,但大部分扩展只需要做一些微小的调整就可以正常使用了,有兴趣的同学可以自行移植。

如果大家在使用的过程中有在Dcat Admin的基础上添加一些自己的功能或者组件,不妨做成一个Dcat Admin扩展,这样可以给其它Dcat Admin使用者提供帮助,并且在其它人的使用反馈中的提升扩展的质量。

这篇文档将会以开发一个 操作日志扩展 为例,一步一步的教大家开发一个扩展,并且发布给他人使用,最终的效果参考操作日志扩展

开始之前

在开始开发扩展之前,如果是linux环境,请先手动在项目根目录创建一个dcat-admin-extensions目录,并设置可读可写权限,扩展文件将会被安装在dcat-admin-extensions目录,请保证拥有以下几个目录的读写权限

  1. 项目目录/dcat-admin-extensions 扩展的安装目录,可以根据配置参数 admin.extensions.dir 进行更改
  2. public/vendor 扩展静态资源发布目录
  3. resources/lang 语言包目录

1.创建扩展

Dcat Admin的扩展是一个标准的composer扩展包,可以通过composer安装,也可以通过系统内部的本地安装功能直接安装。我们可以通过命令或界面创建一个新的扩展,下面分别简单介绍一下命令和界面创建的方法

1.通过命令创建扩展

  1. php artisan admin:ext-make 扩展包名 --namespace=命名空间 --theme

命令参数说明

  • name 扩展包名称,扩展的名称是一个标准的composer包名,请统一使用小写字母 + 中划线(-)的风格命名,标准的格式如 dcat-admin/operation-log,前面一部分可以是个人名称,后面一部分可以是对扩展包功能的概括词语
  • --namespace= 扩展包命名空间,默认会根据包名自动生成,例如你的包名是jiangqh/operation-log,那么默认的命名空间是Jiangqh/OperationLog
  • --theme 是否为主题扩展

那么在当前这个例子中我们运行一下命令生成扩展包

  1. # `--namespace`
  2. php artisan admin:ext-make dcat-admin/operation-log --namespace="Dcat\Admin\OperationLog"

2.通过管理页面创建扩展

打开扩展管理页面http://localhost/admin/auth/extensions,然后点击表格下面第一行的快速创建,然后输入扩展包名和命名空间即可,在实际开发中也更推荐大家使用界面创建扩展,这样更方便

扩展创建完成之后可以看到扩展文件夹下多了个dcat-admin/extensions/dcat-admin/operation-log目录,目录结构如下

  1. ├── README.md
  2. ├── composer.json # composer配置文件
  3. ├── version.php # 扩展包版本管理文件
  4. ├── logo.png # logo
  5. ├── updates # 扩展包每个版本对应的表迁移文件
  6. ├── resources
  7. ├── lang # 语言包
  8. ├── assets # 静态资源
  9. ├── css
  10. └── index.css # css示例文件
  11. └── js
  12. └── index.js # js示例文件
  13. └── views
  14. └── index.blade.php # 视图示例文件
  15. └── src
  16. ├── OperationLogServiceProvider.php # 扩展包服务提供者
  17. ├── Setting.php # 扩展设置表单
  18. ├── Models # 模型目录
  19. └── Http
  20. ├── routes.php # 扩展包路由文件
  21. ├── Middleware # 扩展包中间件文件夹
  22. └── Controllers # 扩展包控制器
  23. └── OperationLogController.php

然后你还可以设置扩展的logo以及扩展名称,设置之后会在扩展管理页面展示,让你的扩展更具容易被人记住!

扩展logo

扩展logo必须放在扩展的根目录,并且文件名必须是logo.png,尺寸建议是100x100

扩展名称

扩展名称需要修改composer.json里面的alias参数,如果不设置则默认展示包名

2.启用扩展

扩展创建成功之后就可以在管理页面http://localhost/admin/auth/extensions 看到新创建的扩展了,效果如下

开发扩展 - 图1

然后我们分别点击扩展对应的 更新至1.0.0版本 以及 启用 按钮,就可以使这个扩展生效了。 新创建的扩展会生成一个默认的控制器,在这个例子中,我们可以尝试访问http://localhost:8000/admin/operation-log,如果可以正常访问则说明扩展启用成功。

3.功能开发

这个扩展的功能主要是用来记录用户的操作记录,然后提供一个查看记录的页面,然后我们可以把默认创建的扩展文件中用不到的给清理掉,清理后的目录结构如下

  1. ├── README.md
  2. ├── composer.json # composer配置文件
  3. ├── version.php # 扩展包版本管理文件
  4. ├── logo.png # logo
  5. ├── updates # 扩展包每个版本对应的表迁移文件
  6. ├── resources
  7. └── lang # 语言包
  8. └── src
  9. ├── OperationLogServiceProvider.php # 扩展包服务提供者
  10. ├── Setting.php # 扩展设置表单
  11. ├── Models # 模型目录
  12. └── Http
  13. ├── routes.php # 扩展包路由文件
  14. ├── Middleware # 扩展包中间件文件夹
  15. └── Controllers # 扩展包控制器
  16. └── OperationLogController.php

接下来就正式进入功能开发部分

创建迁移文件 (migration)

首先我们需要创建一个表迁移文件,运行命令 php artisan make:migration CreateOperationLogTable,然后写入文件内容如下

  1. <?php
  2. use Illuminate\Database\Migrations\Migration;
  3. use Illuminate\Database\Schema\Blueprint;
  4. use Illuminate\Support\Facades\Schema;
  5. class CreateOperationLogTable extends Migration
  6. {
  7. // 这里可以指定你的数据库连接
  8. public function getConnection()
  9. {
  10. return config('database.connection') ?: config('database.default');
  11. }
  12. public function up()
  13. {
  14. if (! Schema::hasTable('admin_operation_log')) {
  15. Schema::create('admin_operation_log', function (Blueprint $table) {
  16. $table->bigIncrements('id')->unsigned();
  17. $table->bigInteger('user_id');
  18. $table->string('path');
  19. $table->string('method', 10);
  20. $table->string('ip');
  21. $table->text('input');
  22. $table->index('user_id');
  23. $table->timestamps();
  24. });
  25. }
  26. }
  27. public function down()
  28. {
  29. Schema::dropIfExists('admin_operation_log');
  30. }
  31. }

然后把文件移动到 扩展目录/updates 目录,并重命名为 create_opration_log_table.php。最后我们需要修改扩展的版本管理文件 扩展目录/version.php,写入迁移文件的文件名,最终内容如下

  1. <?php
  2. return [
  3. '1.0.0' => [
  4. '版本变化描述1',
  5. '版本变化描述2',
  6. 'create_opration_log_table.php', // 迁移文件名称,安装或更新版本时会自动执行
  7. ],
  8. ];

关于扩展的版本管理更详细的介绍,请前往扩展 - 版本管理章节查看。

模型、控制器和路由

创建模型文件 扩展目录/src/Models/OperationLog,模型内容点击OperationLog.php查看;

然后修改我们的控制器扩展目录/src/Http/Controllers/OperationLogController.php,控制器内容点击LogController.php查看;

最后需要修改我们的路由文件,尽量让你的路由不与其他路由产生冲突

  1. use Dcat\Admin\OperationLog\Http\Controllers;
  2. use Illuminate\Support\Facades\Route;
  3. Route::get('auth/operation-logs', Controllers\OperationLogController::class.'@index')->name('dcat-admin.operation-log.index');
  4. Route::delete('auth/operation-logs/{id}', Controllers\OperationLogController::class.'@destroy')->name('dcat-admin.operation-log.destroy');

语言包

在控制器中,我们可以让一些文本描述支持语言包翻译功能,在这个例子中我们以en以及zh_CN两种语言为例,在扩展包/resources/lang目录下分别创建en/log.phpzh_CN/log.php文件,并写入以下内容

  1. // en
  2. return [
  3. 'title' => 'Operation Log',
  4. 'setting_title' => 'Operation Log',
  5. ];
  6. // zh_CN
  7. return [
  8. 'title' => '操作日志',
  9. 'setting_title' => '操作日志',
  10. ];

最后在控制器中可以通过下面的方法访问语言包内容,关于多语言的更多用法可以参考laravel官方文档

  1. use Dcat\Admin\OperationLog\OperationLogServiceProvider;
  2. OperationLogServiceProvider:trans('log.title');
  3. OperationLogServiceProvider:trans('log.setting_title');

定义菜单

接下来我们还需要给我们的扩展生成菜单,打开扩展目录/src/OperationLogServiceProvider.php,然后修改内容如下

  1. class OperationLogServiceProvider extends ServiceProvider
  2. {
  3. // 定义菜单
  4. protected $menu = [
  5. [
  6. 'title' => 'Operation Log',
  7. 'uri' => 'auth/operation-logs',
  8. 'icon' => '', // 图标可以留空
  9. ],
  10. ];
  11. public function settingForm()
  12. {
  13. return new Setting($this);
  14. }
  15. }

如果你想注册带有层级关系的菜单,可以通过下面这种方式注册

  1. // 注册菜单
  2. protected $menu = [
  3. [
  4. 'title' => 'Operation Log',
  5. 'uri' => '',
  6. 'icon' => 'feather icon-x',
  7. ],
  8. [
  9. 'parent' => 'Operation Log', // 指定父级菜单
  10. 'title' => 'List',
  11. 'uri' => 'auth/operation-logs',
  12. ],
  13. ];

测试扩展

上面的步骤都完成之后,我们可以先开始测试一下上面的功能,验证下是否有错误,然后再进行后续的开发。

由于刚开始创建扩展的时候,我们已经安装并启用了这个扩展,所以此处我们要先卸载当前扩展,再重新更新到1.0.0版本,这样数据表和菜单才会被创建。

{tip} 卸载功能会删除扩展的数据或数据表,请谨慎操作,以免造成数据丢失!!!

打开扩展管理页面http://域名/admin/auth/extensions,找到当前扩展,鼠标移动到扩展行,点击 卸载 按钮并确认,然后重新点击更新至1.0.0版本 以及 启用 按钮, 最后 F5 刷新浏览器即可看到新创建的菜单,点击菜单可访问操作日志管理页面admin/auth/operation-logs

注册中间件

现在我们的扩展还需要一个中间件来记录用户的操作,创建文件 扩展目录/src/Http/Middleware/LogOperation.php,文件内容点击LogOperation.php查看。

然后我们需要注册这个中间件,让这个中间件生效,打开扩展目录/src/OperationLogServiceProvider.php,然后修改内容如下

  1. class OperationLogServiceProvider extends ServiceProvider
  2. {
  3. protected $middleware = [
  4. 'middle' => [ // 注册中间件
  5. LogOperation::class,
  6. ],
  7. ];
  8. protected $menu = [
  9. [
  10. 'title' => 'Operation Log',
  11. 'uri' => 'auth/operation-logs',
  12. ],
  13. ];
  14. public function settingForm()
  15. {
  16. return new Setting($this);
  17. }
  18. }

$middleware属性中注册的中间件最后会合并到配置参数admin.route.middleware中,中间件注册支持以下三种类型注册

  1. before 中间件会在最前面,也就是最先执行
  2. middle 中间件会在admin.auth(登陆鉴权中)和admin.permission(权限判断)两个中间件之间执行
  3. after 中间件会在最后执行

在这个例子中,操作日志记录用户操作时显然需要记录登陆用户的信息,所以中间件必须在 admin.auth 中间件之后执行,这样才能拿到登陆用户数据; 并且无权限的操作也需要记录,所以必须在 admin.permission 中间件之前执行,所以只有注册为 middle 类型的中间件才能满足上述要求!

注册完中间件之后,我们随意访问一下系统中的其他页面(除了操作日志管理页面),然后再访问操作日志管理页面,就可以看到用户的操作日志了,到这里插件基本开发完毕。

配置参数(设置)

在当前这个例子中,我们需要让用户能配置一些自定义参数(比如配置不需要记录操作日志的路由),所以我们还需要一个 配置表单 让用户能通过页面直接配置相关参数, 我们需要在 OperationLogServiceProvider 类里面的 settingForm 返回这个配置表单的对象

  1. class OperationLogServiceProvider extends ServiceProvider
  2. {
  3. ...
  4. // 返回配置表单对象,如果不需要保存配置参数,则请删除这个方法
  5. public function settingForm()
  6. {
  7. return new Setting($this);
  8. }
  9. }

然后我们需要修改配置表单类 扩展目录/src/Setting.php 如下

  1. namespace Dcat\Admin\OperationLog;
  2. use Dcat\Admin\Extend\Setting as Form;
  3. use Dcat\Admin\OperationLog\Models\OperationLog;
  4. use Dcat\Admin\Support\Helper;
  5. class Setting extends Form
  6. {
  7. // 返回表单弹窗标题
  8. public function title()
  9. {
  10. return $this->trans('log.title');
  11. }
  12. // 格式化待保存的配置参数值
  13. protected function formatInput(array $input)
  14. {
  15. // 转化为数组,注意如果这里保存的时候是数组,那么读取出来的时候也是数组
  16. $input['except'] = Helper::array($input['except']);
  17. $input['allowed_methods'] = Helper::array($input['allowed_methods']);
  18. return $input;
  19. }
  20. public function form()
  21. {
  22. // 定义表单字段
  23. $this->tags('except');
  24. $this->multipleSelect('allowed_methods')
  25. ->options(array_combine(OperationLog::$methods, OperationLog::$methods));
  26. $this->tags('secret_fields');
  27. }
  28. }

以上设置完成之后我们就可以在扩展管理页面保存自定义参数了

开发扩展 - 图2

配置参数读取用法如下,我们可以在中间件 LogOperation 中使用这些参数

  1. use Dcat\Admin\OperationLog\OperationLogServiceProvider;
  2. // 读取配置参数
  3. $except = OperationLogServiceProvider::setting('except');
  4. $allowedMethods = OperationLogServiceProvider::setting('allowed_methods');
  5. $secretFields = OperationLogServiceProvider::setting('secret_fields');

服务注册与初始化

由于当前这个例子中没有使用到服务注册与初始化相关功能,所以这部分内容先略过,有相关需要的同学可以参考扩展 - 服务注册与初始化章节。

视图 (view)

由于当前这个例子中没有使用到自定义静态资源的功能,所以这部分内容先略过,有相关需要的同学可以参考扩展 - 视图章节。

静态资源

由于当前这个例子中没有使用到自定义静态资源的功能,所以这部分内容先略过,有相关需要的同学可以参考扩展 - 静态资源章节。

修改 composer.json & README.md

代码部分完成之后,需要修改composer.json里面的内容,将descriptionkeywordslicenseauthors等内容替换为你的信息,然后不要忘记完善README.md,补充使用文档等相关信息。

发布扩展

上传应用市场

正式版发布后会上线应用市场功能,开发者可以把扩展发布到应用市场,然后用户就可以通过页面直接安装使用,敬请期待…

上传到Github

先登录你的Github,创建一个仓库,然后按照页面上的提示把你的代码push上去

  1. git init
  2. git remote add origin https://github.com/<your-name>/<your-repository>.git
  3. git add .
  4. git commit -am "Initial commit."
  5. git push origin master

发布到Packagist.org

接下来就是发布你的项目到Packagist.org,如果没有账号的话,先注册一个,然后打开顶部导航的Submit, 填入仓库地址提交

默认情况下,当您推送新代码时,Packagist.org不会自动更新,所以,您需要创建一个GitHub服务钩子, 你也可以使用点击页面上的Update按钮手动更新它,但我建议自动执行这个过程

提交之后,由于各地的镜像同步时间的延迟,可能在用 composer 安装的时候,会暂时找不到你的项目,这个时候可能需要等待同步完成

发布完成之后就可以通过 composer 安装你的扩展了