插件开发

Masterlab插件可以让我们在不修改 Masterlab 核心的前提下,为 Masterlab 添加很多我们需要的功能。
Masterlab插件开发可以很简单,也可以很复杂,这取决于我们的需求是什么。最简单的插件是一个 PHP 文件。
比如输出“ Hello Word “,这个插件只包含了 插件头, 一些 PHP 函数, 和一些用来把插件函数添加到 Masterlab 中的钩子(Hooks)。

注:插件和Api功能在3.0版本中还处于测试阶段,部分功能可能存在bug和不足,敬请谅解

Masterlab插件有三大组件:

核心: Masterlab 根的app/ 和 public/ 目录下的所有文件。
插件: 位于根目录plugin 目录下,用来增强或改变Masterlab 的功能。
其他资源: 如根目录下的test,lib,storage,这些也是运行Masterlab的重要组成

要求

Masterlab插件目前只支持使用PHP和Javascript语言进行开发,待Api接口完善后可以使用任意web编程语言进行开发

配置开发环境

首先下载最新的masterlab代码,并进行安装 安装 Masterlab 参考文档:"私有部署"章节

Masterlab及插件目录结构说明

项目目录

masterlab
|--  vendor             为composer的第三方类库
|--  lib                为非vendor的第三方类库
|--  app                测试相关目录 
|--  public             为网站访问到目录,入口文件在此,可存放静态文件
|--  storage            为存储目录,可存放临时文件 上传文件 日志等
|--  test               测试相关目录 
|--  plugin             为插件目录,每个插件拥有一个目录
      |--   document    插件实例 :文档管理
      |--   webhook      插件实例 :webhook
      |--   activity     插件实例 :活动日志
      |--   ...          其他插件目录
      |--   ...          其他插件目录

活动日志activity插件目录和文件说明

activity
|--  ctrl                              插件的控制器代码
|----   ...                        
|----   ...              
|--  event                             插件的事件监听处理代码
      |--   IssueSubscriber.php        接收事项的事件
      |--   ProjectSubscriber.php      接收项目的事件
      |--   OrgSubscriber.php          接收组织的事件
      |--   ...                        接收其他事件
      |--   ...                         
|--  view                               活动日志的视图文件 
      |--   ...                        
      |--   ...              
|--  log                                插件日志存放目录
|--  index.php                          插件的入口文件,当运行插件时首先执行到这里
|--  install.sql                        插件安装时执行的sql语句
|--  plugin.json                        插件的配置文件
|--  PluginSubscriber.php               可接收插件安装或卸载的事件

插件创建

要创建一个新的 Masterlab 插件,请按照以下步骤进行。

  1. 以管理员身份登录,在"管理"/"插件管理"页面
    plugin-create-example.png

  2. 输入插件信息,提交后服务器会在plugin目录下创建初始插件文件
    plugin-example-dir.png

  3. 在插件列表页面,点击安装插件
    plugin-list.png

  4. 进入到刚才创建的插件目录,基于此目录进行开发

    根据不同的插件类型,插件的入口方式不同,这里选择的类型是"应用模块",那么在项目列表的到顶部模块导航会出现 一项"example"的插件入口链接,同时项目模板中的初始化系统中的也会多出"example"选项。

plugin-example-link.png

plugin-example-index.png

  1. 使用php进行开发时,可以参考系统已经自带的插件实例进行开发,如可直接访问数据库,事件处理等
    操作数据库例子,在 index.php的pageIndex方法中直接实例化一个model,该model绑定一个数据库实例的db属性,
    该db属性是 \Doctrine\DBAL 的实例,详细用户用法可参见 https://www.doctrine-project.org/projects/doctrine-dbal/en/2.12/index.html

下面是example插件首页的数据库使用示例,请查看 pageIndex 方法:

<?php

namespace main\plugin\example;

use main\app\classes\UserAuth;
use main\app\model\PluginModel;
use main\app\model\user\UserModel;
use main\app\model\issue\IssueModel;
use main\plugin\BasePluginCtrl;

/**
 *
 *   插件的入口类
 * @package main\plugin\example
 */
class Index extends BasePluginCtrl
{

    public $pluginInfo = [];

    public $dirName = '';

    public $pluginMethod = 'pageIndex';

    public function __construct()
    {
        parent::__construct();

        // 当前插件目录名
        $this->dirName = basename(pathinfo(__FILE__)['dirname']);

        // 当前插件的配置信息
        $pluginModel = new PluginModel();
        $this->pluginInfo = $pluginModel->getByName($this->dirName);

        $pluginMethod = isset($_GET['_target'][3])? $_GET['_target'][3] :'';
        if($pluginMethod=="/" || $pluginMethod=="\\" || $pluginMethod==''){
            $pluginMethod = "pageIndex";
        }
        if(method_exists($this,$pluginMethod)){
            $this->pluginMethod = $pluginMethod;
            $this->$pluginMethod();
        }
    }

    /**
     * 插件首页方法
     * @throws \Exception
     */
    public function pageIndex()
    {
        $data = [];
        $data['title'] = '插件首页';
        $data['nav_links_active'] = 'plugin';
        $data['current_user']  = UserModel::getInstance()->getByUid(UserAuth::getId());

        $issueModel = new IssueModel();
        $sql = "select * from issue_main limit 10";
        $issueArr = $issueModel->db->fetchAll($sql);
        print_r($issueArr);

        $this->phpRender('index.php', $data);
    }


}

前端开发

插件首页的pageIndex引入了一个view/index.php视图,在这个视图中可以任意添加你的前端代码,比如是跳转到其他的系统iframe

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>插件的首页</title>
</head>
<body>

<?php

//print_r($current_user);
$iframe_url = 'https://www.masterlab.vip/product/agile';
?>

 <div class="content" id="content-body">
        <iframe width="100%" frameborder=no  height="900px" src="<?=iframe_url?>"></iframe>
    </div>


</body>
</html>
Masterlab - 404
404
您所访问的页面不存在或出错了
help->pageIndex no found;
debug
Sql:
Array
(
)
TRACE:
Array
(
)
GET:
Array
(
    [md] => plugin
    [_target] => Array
        (
            [0] => help
        )

)
POST:
Array
(
)
FILES:
Array
(
)
Include: 113
Array
(
    [0] => /data/www/masterlab-site/public/index.php
    [1] => /data/www/masterlab-site/app/globals.php
    [2] => /data/www/masterlab-site/vendor/autoload.php
    [3] => /data/www/masterlab-site/vendor/composer/autoload_real.php
    [4] => /data/www/masterlab-site/vendor/composer/ClassLoader.php
    [5] => /data/www/masterlab-site/vendor/composer/autoload_static.php
    [6] => /data/www/masterlab-site/vendor/ralouphie/getallheaders/src/getallheaders.php
    [7] => /data/www/masterlab-site/vendor/guzzlehttp/promises/src/functions_include.php
    [8] => /data/www/masterlab-site/vendor/guzzlehttp/promises/src/functions.php
    [9] => /data/www/masterlab-site/vendor/guzzlehttp/psr7/src/functions_include.php
    [10] => /data/www/masterlab-site/vendor/guzzlehttp/psr7/src/functions.php
    [11] => /data/www/masterlab-site/vendor/symfony/polyfill-mbstring/bootstrap.php
    [12] => /data/www/masterlab-site/vendor/guzzlehttp/guzzle/src/functions_include.php
    [13] => /data/www/masterlab-site/vendor/guzzlehttp/guzzle/src/functions.php
    [14] => /data/www/masterlab-site/vendor/adbario/php-dot-notation/src/helpers.php
    [15] => /data/www/masterlab-site/vendor/symfony/polyfill-php80/bootstrap.php
    [16] => /data/www/masterlab-site/vendor/danielstjules/stringy/src/Create.php
    [17] => /data/www/masterlab-site/vendor/symfony/polyfill-ctype/bootstrap.php
    [18] => /data/www/masterlab-site/vendor/mtdowling/jmespath.php/src/JmesPath.php
    [19] => /data/www/masterlab-site/vendor/songshenzong/support/src/StringsHelpers.php
    [20] => /data/www/masterlab-site/vendor/songshenzong/support/src/BashEchoHelpers.php
    [21] => /data/www/masterlab-site/vendor/hornet/framework/src/framework/bootstrap.php
    [22] => /data/www/masterlab-site/vendor/hornet/framework/src/framework/function.php
    [23] => /data/www/masterlab-site/vendor/hornet/framework/src/framework/FilterSqlInject.php
    [24] => /data/www/masterlab-site/vendor/hornet/framework/src/framework/HornetCoreException.php
    [25] => /data/www/masterlab-site/vendor/hornet/framework/src/framework/HornetLogicException.php
    [26] => /data/www/masterlab-site/vendor/hornet/framework/src/framework/ErrorHandler.php
    [27] => /data/www/masterlab-site/vendor/hornet/framework/src/framework/HornetEngine.php
    [28] => /data/www/masterlab-site/vendor/hornet/framework/src/framework/protocol/Iprotocol.php
    [29] => /data/www/masterlab-site/vendor/hornet/framework/src/framework/protocol/Api.php
    [30] => /data/www/masterlab-site/vendor/hornet/framework/src/framework/protocol/Ajax.php
    [31] => /data/www/masterlab-site/app/function/autoload.php
    [32] => /data/www/masterlab-site/app/function/array.php
    [33] => /data/www/masterlab-site/app/function/common.php
    [34] => /data/www/masterlab-site/app/function/cryptojs-aes.php
    [35] => /data/www/masterlab-site/app/function/sql.php
    [36] => /data/www/masterlab-site/app/function/string.php
    [37] => /data/www/masterlab-site/app/function/system.php
    [38] => /data/www/masterlab-site/app/function/time.php
    [39] => /data/www/masterlab-site/app/function/upload_image.php
    [40] => /data/www/masterlab-site/app/function/web.php
    [41] => /data/www/masterlab-site/app/function/response_error.php
    [42] => /data/www/masterlab-site/app/function/excel.php
    [43] => /data/www/masterlab-site/vendor/symfony/yaml/Yaml.php
    [44] => /data/www/masterlab-site/vendor/symfony/yaml/Parser.php
    [45] => /data/www/masterlab-site/vendor/symfony/yaml/Inline.php
    [46] => /data/www/masterlab-site/vendor/symfony/yaml/Unescaper.php
    [47] => /data/www/masterlab-site/app/config/app.cfg.php
    [48] => /data/www/masterlab-site/app/constants.php
    [49] => /data/www/masterlab-site/app/config/common.cfg.php
    [50] => /data/www/masterlab-site/app/config/session.cfg.php
    [51] => /data/www/masterlab-site/app/ctrl/Help.php
    [52] => /data/www/masterlab-site/app/ctrl/BaseCtrl.php
    [53] => /data/www/masterlab-site/vendor/symfony/event-dispatcher/EventDispatcher.php
    [54] => /data/www/masterlab-site/vendor/symfony/event-dispatcher/EventDispatcherInterface.php
    [55] => /data/www/masterlab-site/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php
    [56] => /data/www/masterlab-site/app/model/SettingModel.php
    [57] => /data/www/masterlab-site/app/model/BaseDictionaryModel.php
    [58] => /data/www/masterlab-site/app/model/CacheModel.php
    [59] => /data/www/masterlab-site/app/model/DbModel.php
    [60] => /data/www/masterlab-site/app/model/BaseModel.php
    [61] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/DriverManager.php
    [62] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Configuration.php
    [63] => /data/www/masterlab-site/vendor/doctrine/event-manager/lib/Doctrine/Common/EventManager.php
    [64] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDO/MySQL/Driver.php
    [65] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php
    [66] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php
    [67] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver.php
    [68] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/ExceptionConverterDriver.php
    [69] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/VersionAwarePlatformDriver.php
    [70] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php
    [71] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Connection.php
    [72] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/TransactionIsolationLevel.php
    [73] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/ParameterType.php
    [74] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/FetchMode.php
    [75] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php
    [76] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDO/Connection.php
    [77] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php
    [78] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/ServerInfoAwareConnection.php
    [79] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOQueryImplementation.php
    [80] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDO/Statement.php
    [81] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php
    [82] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Statement.php
    [83] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/ResultStatement.php
    [84] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Result.php
    [85] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatementImplementations.php
    [86] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Events.php
    [87] => /data/www/masterlab-site/lib/MyRedis.php
    [88] => /data/www/masterlab-site/vendor/doctrine/dbal/lib/Doctrine/DBAL/SQLParserUtils.php
    [89] => /data/www/masterlab-site/app/classes/UserAuth.php
    [90] => /data/www/masterlab-site/app/ctrl/Resource.php
    [91] => /data/www/masterlab-site/lib/parsedown/Parsedown.php
    [92] => /data/www/masterlab-site/app/view/help.php
    [93] => /data/www/masterlab-site/app/view/common/header-meta.php
    [94] => /data/www/masterlab-site/app/view/common/header-style.php
    [95] => /data/www/masterlab-site/app/view/common/header-script.php
    [96] => /data/www/masterlab-site/app/view/common/body-header.php
    [97] => /data/www/masterlab-site/app/view/common/common-footer.php
    [98] => /data/www/masterlab-site/app/view/common/siteFooter.php
    [99] => /data/www/masterlab-site/app/view/modal/login.php
    [100] => /data/www/masterlab-site/app/view/modal/signup.php
    [101] => /data/www/masterlab-site/app/view/modal/get-started.php
    [102] => /data/www/masterlab-site/app/view/modal/try.php
    [103] => /data/www/masterlab-site/app/view/modal/trial.php
    [104] => /data/www/masterlab-site/app/view/modal/buy-premium.php
    [105] => /data/www/masterlab-site/app/view/modal/loading.php
    [106] => /data/www/masterlab-site/app/view/modal/signup-failed.php
    [107] => /data/www/masterlab-site/app/view/modal/existing-account.php
    [108] => /data/www/masterlab-site/app/view/modal/unsupported-browser.php
    [109] => /data/www/masterlab-site/app/view/modal/calculate.php
    [110] => /data/www/masterlab-site/app/view/modal/sso-signup.php
    [111] => /data/www/masterlab-site/app/view/modal/i18n.php
    [112] => /data/www/masterlab-site/app/view/exception.php
)