# 模块入门开发教程

# 模块开发步骤

# 第一步、准备工作

# 1.1) 安装模块开发助手

模块开发助手可以极大效率的提高开发效率,在 系统管理 → 模块管理 安装 模块开发助手 (opens new window)

# 第二步、模块开发

# 2.1) 创建模块

访问 系统管理 → 模块开发助手,通过常用工具创建模块

模块创建

# 2.2) 安装启用模块

访问 系统管理 → 模块管理 → 本地模块,安装并启用模块。

# 2.3) 完成模块代码开发

第二步会根据填写的模块基本信息完成模块的创建,并且生成一些示例代码,通过修改和完善模块代码,完成模块的功能开发

开发示例程序: https://modstart.com/m/Demo (opens new window)

# 第三步、模块发布分享

# 3.1) 账户信息认证

  1. 注册ModStart账号:访问 https://modstart.com (opens new window) 完成账号注册
  2. 实名认证:在用户中心完成用户实名认证

# 3.2) 在平台创建信息模块

个人中心 → 开发者 → 开发者中心 创建模块,填写基础模块信息完成创建。

创建模块

# 3.3) 模块打包上传到模块市场

进入 系统管理 → 模块开发助手 ,使用相同的 ModStart 账号登录,对于拥有的模块操作栏会出现发布按钮,点击发布一键发布到模块市场。

模块打包上传

发布成功后,需要后台审核模块,完成审核后模块即可显示在模块市场。

# 模块文件介绍

# 目录结构

module/Xxx
├─ Admin/                          → 后台管理
│    ├─ Controller/
│    │    ├─ ...... 
│    │    └─ ConfigController.php  → 后台配置开发Controller
│    └─ routes.php                 → 路由
├─ Api/                            → API接口
│    ├─ Controller
│    │    └─ ......
│    └─ routes.php                 → 路由
├─ Asset/                          → 模块资源文件,安装后会复制到 public/vendor/Xxx
│    └─ ......
├─ Core/
│    └─ ModuleServiceProvider.php  → 模块核心注册器
├─ Docs/                           → 模块文档
│    ├─ doc/                       → 模块使用文档,发布模块时会自动发布到模块使用文档
│    │    └─ .......               
│    ├─ module/
│    │    ├─ content.md            → 模块介绍,发布时自动更新到模块介绍
│    │    ├─ demo.md               → 模块演示,发布时自动更新到模块演示
│    │    ├─ mobilePreview.md      → 模块手机预览图,每行一个支持多个,发布时自动更新
│    │    └─ preview.md            → 模块电脑端预览图,每行一个支持多个,发布时自动更新
│    └─ release.md                 → 模块发布日志,发布时自动更新到模块发布日志
├─ Migrate/                        → 模块数据库迁移文件
│    └─ ......
├─ Model/                          → 模型
│    └─ ......
├─ resources/                      → 前端资源文件,适合vue等需要构建的前端框架
│    └─ ......
├─ Util/                           → 工具类
│    └─ ......
├─ View/                           → 模块视图主目录
│    ├─ pc/                        → 电脑端视图
│    │    └─ ......
│    ├─ m/                         → 手机端视图
│    │    └─ ......
│    └─ admin/                     → 后台管理视图
│         └─ ......
├─ Web/                            → Web前台
│    ├─ Controller/
│    │    └─ ......
│    └─ routes.php                 → 路由
└─ config.json                     → 模块配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

# 其他目录介绍

这些目录并不常用,因此模块骨架代码不包含这些目录,如果需要使用这些目录,可以自行创建。

  • module/Xxx/ROOT/:系统文件,模块安装时会被原样复制到网站根目录,文件已存在时会覆盖已有文件。如 ROOT/aa/bb/cc.txt 会被复制到 网站根目录/aa/bb/cc.txt |

# 模块配置文件 config.json

配置文件是一个合法的JSON,请勿在JSON中包含注释,以下为了参数含义会在JSON中包含注释

{
    // 模块唯一标示,请使用 SomeExampleName 首字母大写的驼峰命名方式
    // 如果模块后期需要发布到模块市场,在开发前请先创建模块,防止与他人冲突
    "name": "Demo",
    // 模块文字说明
    "title": "开发示例程序",
    // 兼容环境,可选值为 laravel5、laravel9 ,默认为 laravel5
    "env": [
        "laravel5",
        "laravel9"
    ],
    // 模块类型,可以包含多个,目前支持以下值
    // PC:        电脑版
    // Mobile:    手机H5
    // App:       手机APP
    // MiniApp:   小程序
    // WxMiniApp: 微信小程序
    // Theme:     主题模块
    // Admin:     后台管理
    // Arch:      基础功能
    "types": [
        "PC",
        "Mobile"
    ],
    "tags": [
        "标签1",
        "标签2"
    ],
    // 当前模块版本号,请使用 主版本号.次版本号.修复版本号 的格式
    // 大的迭代请升级主版本号,常规次二代升级次版本号,Bug修复升级修复版本号
    "version": "1.2.0",
    // 模块依赖,支持多个
    "require": [
        // 依赖 Vendor 模块任何版本
        "Vendor",
        // 依赖 Abc 模块任何版本 
        "Abc:*",
        // 依赖 Abc 模块大于等于1.1.0的版本
        "Abc:>=1.1.0",
        // 依赖 Abc 模块大于1.1.0的版本
        "Abc:>1.1.0",
        // 依赖 Abc 模块小于等于1.1.0的版本 
        "Abc:<=1.1.0",
        // 依赖 Abc 模块小于1.1.0的版本 
        "Abc:<1.1.0",
        // 依赖 Abc 模块1.1.0的版本,其他任何版本都不匹配
        "Abc:==1.1.0"
    ],
    // 推荐模块声明,表示当前模块已适配,推荐安装的模块
    "suggest": [
        "Abc",
        "Abc:*"
    ],
    // 冲突模块声明,表示会和当前模块冲突的模块,禁止同时安装
    "conflicts": [
        "Abc",
        "Abc:*"
    ],
    // 模块依赖的 MSCore 版本,可以通过 \ModStart\ModStart::$version 获取 MSCore 版本号
    "modstartVersion": "*",
    // 模块作者
    "author": "ModStart",
    // 模块描述
    "description": "ModStart开发示例程序",
    // 模块可配置项,可在程序中通过如下方法获取配置信息
    // \ModStart\Module\ModuleManager::getModuleConfig('模块名','配置名')
    "config": {
        // 定义一个名称为 testText 的文本参数
        "testText": [
            [
                "text",
                "文字参数"
            ]
        ],
        // 定义一个名称为 testEnable 的开关
        "testEnable": [
            [
                "switch",
                "功能启用"
            ]
        ],
        // 定义一个名称为 testSelect 的下拉选项,包含两个选项
        "testSelect": [
            [
                "select",
                "下拉选择"
            ],
            [
                "options",
                {
                    "key1": "选项1",
                    "key2": "选项2"
                }
            ]
        ]
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97

# 模块帮助文档 Docs/doc/

模块帮助文档位于 Docs/doc 目录中,每个帮助文档保存为一个 *.md Markdown 文档,格式如下:

# 帮助文档标题

---

帮助文档内容
1
2
3
4
5

使用模块开发助手后台上传模块时,会自动解析 Docs/doc 目录中的帮助文档并上传关联到模块中。

帮助文档使用帮助文档的文件名作为唯一标识,如果有更新会自动更新发布。

# 模块说明文档 content.md

文档位置位于 Docs/module/content.md

模块帮助文档位于 Docs/module/content.md ,使用模块开发助手后台上传模块时,会自动更新到模块说明文档中。

# 模块更新日志文档 release.md

文档位于 Docs/release.md

模块格式严格按照如下,使用模块开发助手后台上传模块时,会自动更新到模块发布更新日志中。

## 1.1.0 版本发布说明

- 新增:XXX功能
- 新增:XXX功能
- 优化:XXX功能
- 修复:XXX功能

---

## 1.0.0 版本发布说明

- 新增:XXX功能
- 新增:XXX功能
- 优化:XXX功能
- 修复:XXX功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

多个版本使用 --- 分割。

# 模块Api接口开发

使用 ModStart 可以很方便的进行接口开发

# 定义接口路由

文件 module/Xxx/Api/routes.php

// 新增以下路由接口
Route::match(['post'], 'xxxx/paginate', 'XxxController@paginate');
Route::match(['post'], 'xxxx/get', 'XxxController@get');
1
2
3

# 开发接口逻辑

文件 module/Xxx/Api/Controller/XxxController.php

<?php
namespace Module\Xxx\Api\Controller;
use Illuminate\Routing\Controller;
use ModStart\Core\Dao\ModelUtil;
use ModStart\Core\Input\InputPackage;
use ModStart\Core\Input\Response;

class XxxController extends Controller
{
    public function paginate()
    {
        $input = InputPackage::buildFromInput();
        $page = $input->getPage();
        $pageSize = $input->getPageSize();
        $option = [];
        $paginateData = ModelUtil::paginate('xxx', $page, $pageSize, $option);
        return Response::generateSuccessData([
            'page' => $page,
            'pageSize' => $pageSize,
            'total' => $paginateData['total'],
            'records' => $paginateData['records'],
        ]);
    }

    public function get()
    {
        $input = InputPackage::buildFromInput();
        $id = $input->getInteger('id');
        $record = ModelUtil::get('xxx', $id);
        return Response::generateSuccessData([
            'record' => $record,
        ]);
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 模块视图文件

模块视图文件均位于 module/Xxx/View

# 在Web模块中引用视图

use ModStart\Module\ModuleBaseController;

class XxxController extends ModuleBaseController{
    // ...
    public function index(){
        // 使用 module/View/Xxx/pc/aaa/bbb.blade.php 视图
        return $this->view('aaa.bbb',[
            // ...
        ]);
    }
    // ...
}
1
2
3
4
5
6
7
8
9
10
11
12

# 在Admin模块中引用视图

use Illuminate\Routing\Controller;

class XxxController extends Controller{
    // ...
    public function index(){
        // 使用 module/View/Xxx/admin/aaa/bbb.blade.php 视图
        return view('module::Xxx.View.admin.aaa.bbb',[
            // ...
        ]);
    }
    // ...
}
1
2
3
4
5
6
7
8
9
10
11
12

# 视图渲染查找顺序

主题的视图文件( .blade.php 结尾)可能出现在多个位置,系统在渲染视图的时候会按照以下优先级查找直到匹配成功:

  1. 启用主题自定义视图目录:如 resources/views/theme/<主题>
  2. 当前主题主题模块视图目录:如 module/<主题模块>/View(这里假设主题模块的主题根目录为 module/<主题模块>/View
  3. 系统默认视图目录:如 resources/views/theme/default
  4. 当前模块视图目录:如 module/Xxx/View

举例说明: 当前系统启用 myTest 主题模块,主题根目录位于 module/MyTest/View,在 Xxx 模块中调用 $this->view('test.list.news') 系统会按照如下顺序进行视图文件的查找,优先使用第一个匹配到的文件:

  1. resources/views/theme/myTest/pc/test/list/news.blade.php
  2. module/MyTest/View/test/list/news.blade.php
  3. resources/views/theme/default/pc/test/list/news.blade.php
  4. module/Xxx/View/pc/test/list/news.blade.php

# 静态资源文件

# 静态资源路径

模块中包含的静态资源文件(如图片、CSS、JS等)该如何处理,保证用户安装主题模块后可以通过链接访问?

模块安装时,静态资源会从 module/Xxx/Asset/ 复制到 public/vendor/Xxx/,因此需要将静态资源文件统一放在主题模块的 Asset 目录中。

blade 文件中引用静态资源时需要使用如下的方式

@asset('vendor/Xxx/js/test.js')
1

# 系统文件复制与覆盖

在模块中创建文件 module/Xxx/ROOT/aaa/bbb/ccc.txt, 在安装时会自动复制到 <根目录>/aaa/bbb/ccc.txt 中。

如系统本身包含了 <根目录>aaa/bbb/ccc.txt 文件,会自动将已有的文件 aaa/bbb/ccc.txt 重命名为 aaa/bbb/ccc.txt._delete_.Xxx并替换为最新的文件。

  • 其中 Xxx 是模块名称,表示是被哪个模块删除掉的
  • 在模块 Xxx 被卸载时,如果发现存在 aaa/bbb/ccc.txt._delete_.Xxx 文件,会自动复原为 aaa/bbb/ccc.txt

提示: 模块开发时,应尽量避免系统文件的复制与覆盖,系统在升级时如果该文件被修改过可能会自动覆盖为最新的文件,会带来不可预知的后果。

# 开发阶段静态资源软连接

系统安装后,静态资源会从 module/Xxx/Asset/ 复制到 public/vendor/Xxx/ ,开发阶段如何处理这个问题?

开发阶段创建一个从 module/Xxx/Asset/public/vendor/Xxx/ 的软连接,这样就可以通过 http://xxx/vendor/Xxx/ 访问到模块静态资源文件了。

  • Linux:运行命令 ln -s module/Xxx/Asset public/vendor/Xxx
  • Windows:手动创建快捷方式

# 后台导航菜单注册

Core/ModuleServiceProvider.php 中配置,通过如下方式注册菜单:

AdminMenu::register(function () {
    return [
        [
            // 菜单标题
            'title' => '一级菜单',
            // 导航图标,可从以下图标 class 值,如 list 或 fa fa-search
            // → 基础图标 https://modstart.com/ui/manual/icon
            // → Font Awesome 图标 https://modstart.com/ui/manual/icon_fa
            'icon' => 'tools',
            // 菜单排序
            'sort' => 150,
            // 菜单子菜单
            'children' => [
                [
                    'title' => '二级菜单',
                    // 菜单链接 Controller 和 Action
                    'url' => '\Module\Xxx\Admin\Controller\XxxController@index',
                ]
            ]
        ],
        [
            'title' => '一级菜单',
            'icon' => 'tools',
            'sort' => 150,
            'children' => [
                [
                    'title' => '二级菜单',
                    'children' => [
                        [
                            'title' => '三级菜单',
                            'url' => '\Module\Xxx\Admin\Controller\XxxController@index',
                        ],
                        [
                            'title' => '三级菜单',
                            'url' => '\Module\Xxx\Admin\Controller\XxxController@index',
                        ]
                    ],
                ]
            ]
        ],
    ];
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

ModStart系统按照如下相同的规则进行菜单合并:

  • 一级菜单(title+icon+sort)
  • 二级菜单(title)

如需要隐藏某一个菜单不显示在菜单栏但出现在权限管理中,只需要给菜单项增加参数,如下

// ...
[
  'title' => '二级菜单',
  'url' => '\Module\Xxx\Admin\Controller\XxxController@index',
  // 增加该参数不会显示在菜单栏
  'hide' => true,
]
// ...
1
2
3
4
5
6
7
8

# 后台导航菜单使用规范

我们强烈建议按照系统推荐的方式组织菜单避免用户安装多个模块后系统菜单变得混乱。

  • 独立的业务功能模块可以插入一级菜单,用于管理模块涉及的业务功能
  • 物料类、工具类的模块使用二级或三级菜单
  • 菜单由上至下应遵循使用频率递减的特性

系统内置了如下的菜单大类组织方式,强烈建议遵守如下约定。

目录内容 排序(sort值) 图标(icon) 说明
用户管理 100 users 用户管理模块
|-- 用户管理
|-- ...
物料管理 200 description 系统基础物料管理
|-- 导航配置
|-- 文章管理
|-- 友情链接
|-- ...
功能设置 300 tools 模块业务功能相关的设置
|-- 用户设置
|-- ...
系统设置 400 cog 技术相关配置
|-- 基础配置
|-- 短信设置
|-- 支付设置
|-- ...
后台权限 500 user-o 管理员、角色、管理日志
|-- 管理角色
|-- 管理账号
|-- 管理日志
运维工具 600 magic-wand 系统运维阶段功能模块
|-- ...
系统管理 700 code-alt 系统功能管理(通常用于开发阶段)
|-- 模块管理

# 后台权限管理

# 权限校验原理

后台权限管理统一在 ModStart\Admin\Middleware\AuthMiddleware.php 管理,匹配规则如下:

  • ① 根据访问路径拼接权限标识,如 \Module\Aaa\Admin\Controller\BbbController@ccc
  • ② 如果管理员权限标识列表中包含第 ① 步拼接的权限标识,则校验权限成功,否则进行第 ③ 步
  • ③ 如果当前控制器定义了静态变量 $PermitMethodMap,对权限标识进行转换,转换表如下
    • currentMethod => checkMethod 使用 当前 Controller 的 checkMethod 检查权限
    • currentMethod => controller@method 使用 Controller@method 检查权限
    • currentMethod => @rule 使用 rule 检查权限
    • currentMethod => * 忽略匹配不到时的权限检查
    • * => * 本 Controller 的所有方法匹配不到时忽略权限检查
  • ④ 查找管理员权限标识中是否拥有权限标识,如果有则校验权限成功,否则权限校验失败

# 权限标识定义方法

在后台导航菜单定义时,默认会 url 作为权限校验标识

// ...
[
  'title' => '二级菜单',
  'url' => '\Module\Xxx\Admin\Controller\XxxController@index',
  // 增加隐藏菜单的参数
  'hide' => true,
]
// ...
1
2
3
4
5
6
7
8

也可自定义权限标识

// ...
[
  'title' => '二级菜单',
  'url' => '\Module\Xxx\Admin\Controller\XxxController@index',
  'rule' => 'MyCustomRule',
  'hide' => true,
]
// ...
1
2
3
4
5
6
7
8

在代码可以使用以下方法判断是否包含某个权限

// 判断是否包含某个权限
\ModStart\Admin\Auth\AdminPermission::permit('\Module\Xxx\Admin\Controller\XxxController@index');
\ModStart\Admin\Auth\AdminPermission::permit('MyCustomRule');
1
2
3

# 管理员权限标识获取方法

使用了RBAC标准授权:

用户表(admin_user) ↔ 角色关联表(admin_user_role) ↔ 角色表(admin_role) ↔ 角色权限表(admin_role_rule)

用户登录后可通过如下方法获取用户角色标识列表

// 获取管理员所有权限标识
Session::get('_adminRules',[])
// 判断是否包含某个权限
\ModStart\Admin\Auth\AdminPermission::permit('Xxx');
1
2
3
4

# 更细粒度的权限控制

根据 权限校验原理 可以看到,默认是基于 Controller 粒度的权限校验。 如果需要对页面的更细粒度的权限控制,需要在 ModuleServiceProvider中注册更多的权限校验规则。

以独立控制后台增删改查权限为例,可以在 ModuleServiceProvider 中注册如下规则,在菜单定义时使用 hide 参数隐藏菜单,但是权限控制出现在角色配置上。

// 通过设置 hide 为 true,隐藏菜单,但是权限控制出现在角色上。
AdminMenu::register(function () {
    return [
        [
            'title' => '内容管理',
            'icon' => 'file',
            'sort' => 150,
            'children' => [
                [
                    'title' => '内容列表',
                    'url' => '\ModStart\Admin\Controller\AdminRoleController@index',
                ],
                [
                    'title' => '内容添加权限',
                    'rule'  => '\ModStart\Admin\Controller\AdminRoleController@add',
                    'hide' => true,
                ],
                [
                    'title' => '内容编辑权限',
                    'rule'  => '\ModStart\Admin\Controller\AdminRoleController@edit',
                    'hide' => true,
                ],
                [
                    'title' => '内容删除权限',
                    'rule'  => '\ModStart\Admin\Controller\AdminRoleController@delete',
                    'hide' => true,
                ],
                [
                    'title' => '内容查看权限',
                    'rule'  => '\ModStart\Admin\Controller\AdminRoleController@show',
                    'hide' => true,
                ],
            ],
        ],
    ];
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

随后再 Grid 中设置操作:

$grid->canAdd(AdminPermission::permit('\ModStart\Admin\Controller\AdminRoleController@add'))
     ->canEdit(AdminPermission::permit('\ModStart\Admin\Controller\AdminRoleController@edit'))
     ->canDelete(AdminPermission::permit('\ModStart\Admin\Controller\AdminRoleController@delete'))
     ->canShow(AdminPermission::permit('\ModStart\Admin\Controller\AdminRoleController@show'));
1
2
3
4

如果需要更详细的控制每一行是否显示某个操作,可以需要定义每行的操作:

$grid->hookItemOperateRendering(function (ItemOperate $itemOperate) {
    // 当前行记录
    $item = $itemOperate->item();
    // 判断是否可编辑
    $itemOperate->canEdit( $item->adminUserId === Admin::id() );
});
1
2
3
4
5
6

同时,需要在 edit 方法中增加权限校验:

public function edit()
{
    $record = ModuleUtil::get('xxx', CRUDUtil::id());
    // 判断是否可编辑
    BizException::throwsIf('无权限', $record['adminUserId'] != Admin::id());
}
1
2
3
4
5
6

# 后台多标签页面

系统在渲染页面时候使用URL中的 _is_tab 来判断是显示在标签 iframe 中或者是正常页面。

如果想在当前页面打开一个新的标签页,可使用 data-tab-open 属性,如下:

<a href="/path/to/tab_page" data-tab-open>打开新标签页</a>  
1

如果当前页面为 Grid 页面,还可以增加 data-refresh-grid-on-close 属性,当新标签页关闭时,自动刷新当前页面的 Grid 数据。

<a href="/path/to/tab_page" data-tab-open data-refresh-grid-on-close>打开新标签页</a>
1

或者也可以使用 JavaScript 调用打开页面

window.parent._pageTabManager.open('/path/to/tab_page', '新标签页面')
1

以上的操作均会自动为连接追加 _is_tab=1 参数,以便在新标签页中正确渲染页面。

# 模块生命周期Hook

需要在模块的安装、启用、禁用、卸载的时机执行代码,可通过创建类 Module/Xxx/Core/ModuleHook 实现。

<?php

namespace Module\Xxx\Core;

class ModuleHook
{
    /**
     * 安装完成
     */
    public function hookInstalled() { }

    /**
     * 已启用
     */
    public function hookEnabled() { }

    /**
     * 禁用前
     */
    public function hookBeforeDisable() { }

    /**
     * 卸载前
     */
    public function hookBeforeUninstall() { }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 模块管理与操作

模块操作相关方法都集中在 ModStart\Module\ModuleManager 类中。

常见示例调用如下:

// 列出所有安装并启用的模块
\ModStart\Module\ModuleManager::listAllEnabledModules();

// 判断模块是否安装并启用
modstart_module_enabled('Xxx');
// 或
modstart_module_enabled('Xxx');

// 模块 Xxx 是否安装了 >=1.2.0 的版本
modstart_module_enabled('Member','>=1.2.0');
1
2
3
4
5
6
7
8
9
10

# 模块数据调用方式

以调用 Demo 模块中的表 demo_user 数据表为例。

假设 demo_user 数据表有如下数据:

id status name age
1 1 张三 20
2 1 李四 21
3 0 王五 22
4 1 赵六 23

首先,创建文件 module/Demo/Util/DemoUserUtil.php,内容如下

<?php
namespace Module\Demo\Util;
use Module\Paper\Model\PaperWare;

class DemoUserUtil
{
    public static function listRecords($limit = 5)
    {
        $records = PaperWare::where([ 'status' => 1])
            ->orderBy('id', 'desc')
            ->limit($limit)
            ->get()->toArray();
        return $records;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

下面就可以在 .blade.php 模板文件中直接调用了,调用代码如下

@foreach(\Module\Demo\Util\DemoUserUtil::listRecords(2) as $r)
    {{$r['name']}} || {{$r['age']}}
@endforeach
1
2
3

调用效果如下

赵六 || 23
李四 || 21
1
2

# 命令行模块管理

# 安装 module-install

php artisan modstart:module-install {module} {--force}
1

# 卸载 module-uninstall

php artisan modstart:module-uninstall {module}
1

# 启用 module-enable

php artisan modstart:module-enable {module}
1

# 禁用 module-disable

php artisan modstart:module-disable {module}
1

# 安装全部 module-install-all

php artisan modstart:module-install-all
1

一条命令安装全部模块,该命令会计算模块的依赖顺序,按照顺序依次安装。

php artisan modstart:module-link-asset {module}
1

该命令会将模块的 public/vendor/{module} 目录软连接到 module/{module}/Asset 目录下,以便在浏览器中访问。

# 接口文档注解

使用注解可以在模块打包时生成接口文档,一个接口文档注解示例如下

/**
 * @Api 新闻
 */
class NewsController extends Controller
{
  /**
   * @Api 新闻分页
   * @ApiBodyParam search.categoryId int 新闻分类ID
   * @ApiResponseData {
   *  "total": 1,
   *  "page" : 1,
   *  "pageSize": 10,
   *  "records": [
   *      {
   *        "id":1,
   *        "categoryId":1,
   *        "title":"标题",
   *        "summary":"摘要",
   *        "content":"内容"
   *      }
   *  ]
   * }
   */
  public function paginate()
  {
     // ...
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 类注解

  • 接口分组:@Api 分组

# 方法注解

  • 接口名称:@Api 名称
  • 接口说明:@ApiDesc 接口说明
  • 接口请求方式:@ApiMethod post|get
  • 接口请求格式:@ApiDataType json|formData
  • 接口请求头:@ApiHeadParam api-token string required 参数说明
  • 接口请求Body参数:@ApiBodyParam bizId int required 企业ID
  • 接口请求Query参数:@ApiQueryParam bizId int required 企业ID
  • 接口返回Code特殊值:@ApiResponseCode 10000 用户未登录
  • 接口返回Data内容格式:@ApiResponseData { }

# 工具类注解

使用注解可以在模块打包时生成工具类使用文档,一个工具类文档注解示例如下

/**
 * Class MCms
 *
 * @Util CMS操作
 */
class TestUtil
{
  /**
   * @Util 获取栏目
   * @param $catUrl string 栏目URL
   * @return array
   */
  public static function getCatByUrl($catUrl)
  {
     // ...
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 类注解

  • 工具类分组:@Util 分组

# 方法注解

  • 名称:@Util 名称
  • 参数:@param $name string 说明
  • 返回:@return array

# 模块手动第三方依赖包

模块开发的重要的原则是要保证模块所有的依赖代码都位于模块目录中 /module/Xxx。 如需要引入第三方依赖,推荐做法是在模块目录中创建 SDK/ 目录,将第三方依赖包放在该目录中,同时使用如下方法引入 namespace

第一步,创建 SDK 目录

引入两个包 package-apackage-b 为例,完成后的目录结构参考

/module/Xxx
└── SDK
    ├── package-a
    │   └── src
    └── package-b
        └── src
1
2
3
4
5
6

第二步,在使用包的地方显示引入

其中 AuthorA\PackageA 表示包A的 namespaceAuthorB\PackageB 表示包B的 namespace

\ModStart\Module\ModuleClassLoader::addNamespace('AuthorA\PackageA', __DIR__ . '/../SDK/package-a/src');
\ModStart\Module\ModuleClassLoader::addNamespace('AuthorB\PackageB', __DIR__ . '/../SDK/package-b/src');
1
2
Last Updated: 12 days ago