模块架构

    模块帮助文档 Docs/doc/

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

    1. # 帮助文档标题
    2. ---
    3. 帮助文档内容

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

    模块说明文档 content.md

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

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

    模块更新日志文档 release.md

    文档位于 Docs/release.md

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

    1. ## 1.1.0 版本发布说明
    2. - 新增:XXX功能
    3. - 新增:XXX功能
    4. - 优化:XXX功能
    5. - 修复:XXX功能
    6. ---
    7. ## 1.0.0 版本发布说明
    8. - 新增:XXX功能
    9. - 新增:XXX功能
    10. - 优化:XXX功能
    11. - 修复:XXX功能

    后台导航菜单注册

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

    1. AdminMenu::register(function () {
    2. return [
    3. [
    4. 'title' => '一级菜单',
    5. 'icon' => 'tools',
    6. 'sort' => 150,
    7. 'children' => [
    8. [
    9. 'title' => '二级菜单',
    10. 'url' => '\Module\Xxx\Admin\Controller\XxxController@index',
    11. ]
    12. ]
    13. ],
    14. [
    15. 'title' => '一级菜单',
    16. 'icon' => 'tools',
    17. 'sort' => 150,
    18. 'children' => [
    19. [
    20. 'title' => '二级菜单',
    21. 'children' => [
    22. [
    23. 'title' => '三级菜单',
    24. 'url' => '\Module\Xxx\Admin\Controller\XxxController@index',
    25. ],
    26. 'title' => '三级菜单',
    27. 'url' => '\Module\Xxx\Admin\Controller\XxxController@index',
    28. ]
    29. ]
    30. ]
    31. ],
    32. ];
    33. });
    • 一级菜单(title+icon+sort)
    • 二级菜单(title)

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

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

    后台导航菜单使用规范

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

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

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

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

    也可自定义权限标识

    管理员权限标识获取方法

    使用了RBAC标准授权:

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

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

    1. Session::get('_adminRules',[])

    模块生命周期Hook

    1. <?php
    2. namespace Module\Xxx\Core;
    3. class ModuleHook
    4. {
    5. /**
    6. * 安装完成
    7. */
    8. public function hookInstalled() { }
    9. /**
    10. * 已启用
    11. */
    12. public function hookEnabled() { }
    13. /**
    14. * 禁用前
    15. */
    16. public function hookBeforeDisable() { }
    17. /**
    18. * 卸载前
    19. */
    20. public function hookBeforeUninstall() { }
    21. }

    模块管理与操作

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

    常见示例调用如下:

    1. // 列出所有安装并启用的模块
    2. \ModStart\Module\ModuleManager::listAllEnabledModules();
    3. // 判断模块是否安装并启用
    4. \ModStart\Module\ModuleManager::isModuleEnabled('Xxx');
    5. modstart_module_enabled('Xxx');
    6. // 模块 Xxx 是否安装了 >=1.2.0 的版本
    7. modstart_module_enabled('Member','>=1.2.0');

    安装 module-install

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

    卸载 module-uninstall

    1. php artisan modstart:module-uninstall {module}

    启用 module-enable

    1. php artisan modstart:module-disable {module}

    安装全部 module-install-all

    1. php artisan modstart:module-install-all

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

    接口文档注解

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

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

    类注解

    • 接口分组:@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 { }

    工具类注解

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

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

    类注解

    • 工具类分组:@Util 分组
    • 名称:@Util 名称
    • 参数:@param $name string 说明
    • 返回:@return array

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

    第一步,创建 SDK 目录

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

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