# :-: 开发配置管理
*****
#
# 场景
* * *
## 配置
主要针对一些取**单值**的场景,比如购物订单的过期时间,网站的站点名,快递查询的秘钥...等等,这些**单一**,**零散**,**不重复**,**却又需既能动态修改的又要能存储的数据****,作为写关键逻辑时取出使用**。这样的场景就可以使用配置实现。
## 数据组
主要针对一些取**多值**的场景,比如轮播图和首页展示图标,**这些数据的特点是数据量有限(比如轮播图可能就只有5~6条数据,图标一般就十来个),数据形式多变(比如轮播图可能需要能单机跳转,这就需要至少一张图和一个跳转连接)**。这样的数据如果正常存取就需要创建相关的数据表来存储,但是它的数据量又很少,一个应用中类似的结构数据有很多,如果都用数据表来实现会导致表数量庞大且每张表的数据量又很少。这样的场景就可以考虑使用数据组,创建自己需要的数据组,每个数据组的字段都可以自由添加和自定义,他们都统一存储在同一张表里,不需要创建多余的表。
## 架构
![](https://img.kancloud.cn/0f/1d/0f1d88261211049ba8eadb4c187ddee5_1442x572.jpg)
因为saas涉及到多租户,这就意味着saas系统下的配置名是可能存在重复的**(考虑一个场景是在多租户环境下,一个商城应用使用了一个叫做首页图标的配置,假设对应的配置叫icon\_name** **。多租户就意味着可能有几十个租户都买了这一个应用。那么意味着每个租户都可以配置自己的首页图标配置,这是个性化的,这就是说每个租户都拥有一个配置名为****icon\_name****的首****页图标配置****)**理解这点有助于理解本系统中为什么后台配置会有**租户**和**平****台**之分。
# 配置
* * *
##
## 添加配置
**总后台** **配置管理**\->**配置分类**
**添加配置流程**:**选择配置分类(没有需先创建)** -> **添加配置**
![](https://img.kancloud.cn/91/25/912550326db821be7fc5760bbe0daac4_746x331.png)
### 添加配置分类
添加配置必须先有配置分类,在配置分类的基础上添加配置,所以需要先创建配置分类
![](https://img.kancloud.cn/b5/50/b550450b2dbeadb1b5348be368626880_746x366.png)
#### 配置范围
**平台**
选择平台则跟大多单应用管理系统的配置是一样的,即**一项配置只对应一个值**,比如假设一个配置是框架版本号,作为给框架使用的配置数据自然没有租户之分,全系统使用这一个值(全局唯一)
**租户**
在 **场景** 章节中有介绍,saas是多租户,每个租户都有应用,自然也需要有租户配置,即**一项配置对应多个值,**比如每个租户的**提现手续费**和**提现最低额度**都是不一样的,虽然配置名都是**extract\_money\_fee**和**extract\_money\_min**但是配置值却各是各的,有几个租户就有几个**extract\_money\_fee**和**extract\_money\_min**
**应用配置**
如果选择**应用配置**,**意味着不同应用之间是允许配置字段重复的**,**但是在展示时需要传额外的参数加以区分获取的是哪个应用的配置,**这在 **后台展示和修改配置** 中的 **路由** 章节会详细说明**。**
比如创建一个应用配置分类是手机商城应用的订单配置,又创建一个应用配置分类是家电商城应用的订单配置,里面就有可能配置分类和配置名重复,这种配置分类,在创建时就需要选择**应用配置**。
![](https://img.kancloud.cn/aa/67/aa678d1eca122d6bbb287bf0e17f5fa2_746x364.png)
### 添加配置
配置可以选择多种类型,目前支持的有 :**文本,数字,浮点数,颜色,富文本 , 多行文本,单选,下拉单选,多选,单图,多图 ,单文件** 。
![](https://img.kancloud.cn/e7/42/e742cb8b258f2336ca8680715076c399_746x364.png)
**懒插入**
懒插入只会在租户第一次设置配置值时才在数据库插入租户配置,否则在租户创建时就会给该租户插入这项配置,默认懒插入
**在配置列表中可以查看配置分类下的相关配置**
![](https://img.kancloud.cn/48/bf/48bf4ce3105039e122882bb33e4ee9d7_746x316.png)
#### 平台配置分类下的配置列表
![](https://img.kancloud.cn/2c/6b/2c6b030ba007bfc381ef68efda420715_746x368.png)
#### 租户配置分类下的配置列表
需要注意的是,如果配置范围是 **租户 则如下图结构** ,会跟 **平台** 的配置列表有所区别,因为**租户是每项配置对应每个租户值都不同,所以每个租户配置都拥有对应每个租户的多条记录**,可编辑修改**每个租户的配置或批量编辑所有租户**
![](https://img.kancloud.cn/4a/d6/4ad6633239b87e788a37413399e08e30_746x342.png)
##
##
## 后台展示和修改配置
### 展示页面
不管是在总平台还是在租户平台展示,展示形式都是一样的,如下图
![](https://img.kancloud.cn/28/e6/28e6fdb019248f5c10b4652255d334bb_746x346.png)
### 路由
#### 路由规则
展示的地方有总平台和租户后台两个后台,平台的配置在总后台展示,租户的配置只在租户后台展示,所以对应的路由也分为总平台路由地址和路由地址
**总平台 **
~~~
/manage/config/showconfig //无可变参数,直接系统配置全部展示出来
~~~
**租户**
~~~
/manage/member/config/showMemberConfig/<type>/<tab_name?>/<config_ids?>/<app?>
//必填url参数 <type> 配置大分类: 0为不限制类型 1系统 2插件 3应用
//选填url参数 <tab_name?> 配置分类[标识/ID]: 0为不限制分类 传了则只展示该配置分类的配置
//选填url参数 <config_ids?> 配置[标识/ID]: 0为不限制配置 传了则只展示该配置
//选填url参数 <app?> 应用[标识]: 传入应用对应dir目录则只查询该应用的配置
~~~
#### 租户配置示例
上图的配置是通过可变url不同的传参动态生成的配置展示页面,也就是说你完全可以定义不同的配置展示页面,又因为本框架是通过添加菜单节点来生出不同管理页面的,如下1,2图:
![](https://img.kancloud.cn/dc/6b/dc6b6c88688ff1182c19c419a50bd466_746x181.png)
![](https://img.kancloud.cn/a9/5e/a95edc9f606a61fb1c98cea66c645a35_746x196.png)
所以只要想,完全可以建立不同的菜单节点,根据路由参数的不同,展示不同的配置。
**需要注意的是,如果是应用配置,且展示的配置分类标识有重复,就必须传入参数的应用标识加以区分**
**例子:**
~~~
/manage/member/config/showMemberConfig/0/integral_config/0/bwmall
//展示bwmall应用的integral_config积分配置
/manage/member/config/showMemberConfig/0/integral_config/0/taotao
//展示taotao应用的integral_config积分配置
//上面的例子中刚好两个应用的配置分类名是一致的,这时就需要在末尾传入应用标识加以区分显示的配置
~~~
## 使用配置
###
### 使用方法
添加的配置是用来使用的,**以使用场景来说,可能你是在租户后台的代码段中调用,或是在总后台的代码段中调用,当然也可能是在api接口的代码段中调用**
你调用的配置既有**平台配置**,也有**租户配置**或是**租户某个应用的配置**
不同的使用环境均调用统一的方法,且大部分情况下,一般用法即满足需求。
**取配置函数**
~~~
/**
*取租户和总后台配置
*@param $name 配置名
*@param $default 配置默认值
*@param $member_id 租户id 如果是[租户后台代码段]或者[api接口代码段]中调用,则无需传参也能识别配置来源
*@param $dir 应用标识
*@return array|null|string|float|int
**/
function bw_config($name, $default = null, $member_id = null,$dir = null)
~~~
在**租户后台代码段** 和**接口代码段**中,无需任何传参也能根据参数名和登录信息识别出你调用的租户配置或是平台配置并取出对应的值。
#### 一般用法
~~~
bw_config('site_name','Tom');//实例:取某个配置 ,第一个传参是参数标识,第二传参是参数默认值
~~~
#### 配置示例
![](https://img.kancloud.cn/e4/73/e473b8b180a1af4653b57b99803c5640_746x421.png)
**例子 1 : 取出某一项配置(可使用bw\_config(\[ 配置分类名 . 配置名 \]) 和bw\_config( \[** **配置名** **\])两种取法,只是写法区别)**
~~~
bw_config('web_config.web_name');//取出站点名称
bw_config('web_name');//取出站点名称
~~~
**结果**
~~~
布网科技saas //结果一样,都是取站点名称
~~~
**例子 2 : 取出某个配置分类的全部配置(可使用bw\_config(\[ 配置分类****名** **\]))**
~~~
bw_config('web_config');//取出站点配置分类下的所有配置
~~~
**结果**
~~~
array(14) {
["web_name"]=> string(16) "布网科技saas"
["web_title"]=> string(16) "布网科技saas"
["web_url"]=> string(27) "https://mall.buwangkeji.com"
["web_logo"]=> array(4) {
["name"]=> string(59) "wdseller308105433-209d00000170a997a2f70a21348d_1176_828.jpg"
["size"]=> int(0)
["type"]=> string(10) "image/jpeg"
["src"]=> string(74) "http://www.bwsaas.com/upload/20201116/42c3a21176a7193e49b10775ac908940.jpg"
}
["web_keywords"]=> string(12) "布网科技"
["web_description"]=> string(12) "布网科技"
["web_icp"]=> string(22) "豫ICP备18042703号-1"
["web_contacts"]=> int(15098745674)
["web_address"]=> string(13) "东方经典1"
["copyright"]=> string(37) "©版权所有 2015-2020 布网科技"
["backstage_top_title"]=> string(9) "控制台"
["backstage_top_url"]=> string(23) "/manage/admin/dashboard"
["member_top_title"]=> string(6) "首页"
["member_top_url"]=> string(24) "/manage/member/dashboard"
}
~~~
#### $member\_id参数
在特殊情况下,你可能会想取出某个租户的租户配置,而不是从当前的登录信息中自动获取的租户信息中取(**如果是用户登录,可以从登录request-app头字段中取租户信息,如果是租户后台登录,则可以直接取到**),比如在总平台,你想取出【租户1】的充值配置和【租户2】的充值配置,因为【租户1】和【租户2】的充值配置标识都一样,为了取出不同租户的同名配置,需要传入租户ID($member\_id)作为第三个参数。
**假设租户1的ID是1,租户2的ID是2,则:**
~~~
bw_config('rechange_min',20,1);//例子: 取出租户ID为 1 的租户充值金额配置
bw_config('rechange_min',20,2);//例子: 取出租户ID为 2 的租户充值金额配置
~~~
### 扩展
...
# 数据组
* * *
## 创建数据组
**总后台** **配置管理**\->**组合配置**\->**组合分类**
**添加数据组流程**:**添加数据组** -> **添加数据组数据**
![](https://img.kancloud.cn/0d/22/0d22e8479b05c73b6a62e65d2a786be9_746x316.png)
### 添加数据组
在**使用场景**章节中说过,组合数据是类似轮播图和图标等这类数据存取的一种实现方法,所以他有与CRUD操作数据表类似的功能,所以创建一个组合数据的过程跟创建一张数据表的过程是一样的,都要创建自己的字段。
![](https://img.kancloud.cn/eb/5f/eb5f75084aae1cfc847c14976366d35f_746x356.png)
#### 配置范围
**平台**
选择平台则跟大多单应用管理系统一样,即**一项组合数据只对应一个数据组**,比如假设一个数据组是saas总平台登录页面壁纸组,作为给框架使用的**数据组**自然没有租户之分,全系统使用这一个**数据组**(全局唯一)
**租户**
在 **场景** 章节中有介绍,saas是多租户,每个租户都有应用,自然也需要有租户的数据组,即**一项数据组对应多个租户各自有不同的数据组数据,**比如每个租户都有自己的**充值套餐设置**recharge\_select,用数据组来实现意味着名为**充值套餐设置**的数据组recharge\_select每个租户的设置都各不相同,虽然数据组名一样,但他们的数据是相互独立的
**应用**
如果选择**应用**,**意味着不同应用之间是允许数据组名重复的**,**但是在展示时需要传额外的参数加以区分获取的是哪个应用的数据组,**这在 **后台展示和修改配置** 中的 **路由** 章节会详细说明**。**
比如**创建一个家电商城应用的轮播图数据组和一个宠物商城的首页轮播图****数据组,他们的数据组名都想叫home\_banner**,这种数据组,在创建时就需要选择**应用配置**。
![](https://img.kancloud.cn/e8/98/e8981863cf672727f862e5fffdd373fe_746x350.png)
字段的添加和配置的添加页面类似,目前支持的有 :**文本,数字,浮点数,颜色,富文本 , 多行文本,单选,下拉单选,多选,单图,多图 ,单文件** 。
![](https://img.kancloud.cn/86/57/8657af44541b450c72993b1aaeb353c8_746x317.png)
**添加好字段后提交,这就相当于是创建好了一张空白的数据表,再来就是填数据了**
####
###
### 添加数据组数据
#### 初始化数据
初始化数据是针对租户数据组的,在bwsaas框架,每一个租户在创建时就会根据配置和数据组初始化数据(默认数据),比如商城图标,如果没有初始化数据(默认数据),那每一个租户使用前都需要先添加一遍数据才能使用,那就太恶心了。so,可以根据需求添加初始化数据(默认数据)
![](https://img.kancloud.cn/f0/6a/f06a0a8c77f9cf91d81523a315c84c0b_746x325.png)
## 后台展示和修改数据组
数据组创建后会生成类似数据表的管理页面,里面会有增删改查,通过特定的路由模板渲染而成,展示的地方有总平台和租户后台两个后台,平台的数据组在总后台展示,租户的配数据组只在租户后台展示,所以对应的路由也分为总平台路由地址和路由地址
![](https://img.kancloud.cn/7f/49/7f49f30ea1ed788677536f3b7b79ac00_746x374.png)
![](https://img.kancloud.cn/41/16/4116c79407fdac80820c5486ea7f4d69_746x385.png)
### 路由
#### 路由规则
####
**总平台 **
~~~
/manage/groupData/<id>
//必填url参数 <id> 数据组[标识/ID] 展示当前数据组对应的管理页面
~~~
**租户**
~~~
/manage/member/groupData/<type>/<app?>
//必填url参数 <type> 数据组[标识/ID]:展示当前数据组对应的管理页面
//选填url参数 <app?> 应用[标识]: 传入应用对应dir目录则只查询该应用的数据组2
~~~
#### 租户数据组示例
上图的数据组是通过可变url不同的传参动态生成的数据组展示页面,也就是说你完全可以定义不同的数据组展示页面,又因为本框架是通过添加菜单节点来生出不同管理页面的,如下1,2图:
![](https://img.kancloud.cn/95/e4/95e423f183586e7c126b4e4f35f03e54_746x270.png)
![](https://img.kancloud.cn/01/23/0123f1ddf5a6aacb641676caa41678b8_746x225.png)
平台数据组也是一样的效果,就不演示了
所以只要想,完全可以建立不同的菜单节点,根据路由参数的不同,展示不同的数据组。
##
##
## 使用数据组
###
### 使用方法
添加的数据组是用来使用的,**以使用场景来说,可能你是在租户后台的代码段中调用,或是在总后台的代码段中调用,当然也可能是在api接口的代码段中调用**
你调用的数据组既有**平台**,也有**租户**或是**租户某个应用的数据组**
不同的使用环境均调用统一的方法。
**取数据组函数**
~~~
/** 返回组合数据对象
* @param int|array|string $groupName 选填 传数字或字符串标识则查该项组合数据 传数组则 格式为:[ '数据组ID或字符串标识','租户ID','应用标识'] 表示只查某个租户(租户ID=0 为总后台)
* @param int|boolean|string $id 选填 传数字则只查单条组合数据 传false则返回组合数据对象,自己写查询条件。
* @param int $page 选填 页数
* @param int $limit 选填 条数
* @param string $sort 选填 排序条件
*/
function bw_data($groupName = '', $id = 0, $where = ['status' => 1], $page = null, $limit = null, $sort = 'sort desc,id desc')
~~~
在**租户后台代码段** 和**接口代码段**中,无需任何传参也能根据参数名和登录信息识别出你调用的租户数据组或是平台数据组并取出对应的值。大部分情况下,**例子 1** 即满足需求。
####
####
#### 使用示例
示例数据来源
![](https://img.kancloud.cn/32/54/3254b3e6d23418033a42f4ca90b96ff8_746x332.png)
![](https://img.kancloud.cn/39/ce/39ce590b75caecd7fe733a5c139a8412_746x245.png)
**例子 1 : 在****租户后台****或****应用接口****中取出当前租户的充值套餐****数据组(可使用bw\_data(\[ 数据组名 or** **数据组****id \])** **)**
~~~
$recharge_select = bw_data('recharge_select');//实例:取充值套餐数据组 ,传入数据组标识
$recharge_select = bw_data(85);//实例:取充值套餐数据组 ,传入数据组id
~~~
**租户ID****参数**
在特殊情况下,你可能会想取出某个租户的租户数据组,而不是从当前的登录信息中自动获取的租户信息中取(**如果是用户登录,可以从登录request-app头字段中取租户信息,如果是租户后台登录,则可以直接取到**),比如在总平台,你想取出【租户1】的充值套餐和【租户2】的充值套餐,因为【租户1】和【租户2】的充值套餐标识都一样,为了取出不同租户的同名数据组,需要传入租户ID作为参数。
**例子 2 : 在****总平台****或****未登录环境****中取出某个租户的充值套餐****数据组(可使用bw\_data(****\[ '数据组ID或字符串标识','租户ID','应用标识'\]****)** **)**
~~~
$recharge_select = bw_data(['recharge_select',65]);//实例:取租户ID为65充值套餐数据组 ,传入数据组标识,租户ID
$recharge_select = bw_data([85,65]);//实例:取租户ID为65充值套餐数据组 ,传入数据组ID,租户ID
$recharge_select = bw_data(['recharge_select',65,'bwmall']);//实例:取租户ID为65的应用为bwmall的充值套餐数据组 ,传入数据组标识,租户ID
~~~
**结果(数组)**
~~~
//return $recharge_select
[
{
"id": 331, //数据id
"group_id": 85, //数据组id
"add_time": 1601296083, //添加时间
"sort": 0, //排序
"status": 1, //是否有效
"member_id": 2, //租户id
"scopes": "member",
"config_name": "recharge_select", //数据组标识
"dir": "bwmall", //应用标识
"price": "1000", //自定义字段1
"give": "300" //自定义字段2
},
{
"id": 257,
"group_id": 85,
"add_time": 1600670096,
"sort": 0,
"status": 1,
"member_id": 2,
"scopes": "member",
"config_name": "recharge_select",
"dir": "bwmall",
"price": "0.01",
"give": "0"
},
{
"id": 256,
"group_id": 85,
"add_time": 1600509716,
"sort": 0,
"status": 1,
"member_id": 2,
"scopes": "member",
"config_name": "recharge_select",
"dir": "bwmall",
"price": "800",
"give": "100"
},
{
"id": 255,
"group_id": 85,
"add_time": 1600509706,
"sort": 0,
"status": 1,
"member_id": 2,
"scopes": "member",
"config_name": "recharge_select",
"dir": "bwmall",
"price": "500",
"give": "50"
},
{
"id": 254,
"group_id": 85,
"add_time": 1600509678,
"sort": 0,
"status": 1,
"member_id": 2,
"scopes": "member",
"config_name": "recharge_select",
"dir": "bwmall",
"price": "50",
"give": "5"
},
{
"id": 253,
"group_id": 85,
"add_time": 1600509671,
"sort": 0,
"status": 1,
"member_id": 2,
"scopes": "member",
"config_name": "recharge_select",
"dir": "bwmall",
"price": "30",
"give": "3"
},
{
"id": 252,
"group_id": 85,
"add_time": 1600509664,
"sort": 0,
"status": 1,
"member_id": 2,
"scopes": "member",
"config_name": "recharge_select",
"dir": "bwmall",
"price": "20",
"give": "2"
}
]
~~~
**例子 3 :** **取出某个租户的充值套餐****数据组中的某一项套餐(可使用bw\_data(****\[ '数据组ID或字符串标识','租户ID','应用标识'\],\[数据ID\]****)** **)**
~~~
$recharge_select = bw_data('recharge_select',331);//实例:取租户充值套餐数据组中ID为331的套餐 ,传入数据组标识,数据ID
~~~
**结果(数组)**
~~~
//return $recharge_select
[
"id": 331, //数据id
"group_id": 85, //数据组id
"add_time": 1601296083, //添加时间
"sort": 0, //排序
"status": 1, //是否有效
"member_id": 2, //租户id
"scopes": "member",
"config_name": "recharge_select", //数据组标识
"dir": "bwmall", //应用标识
"price": "1000", //自定义字段1
"give": "300" //自定义字段2
]
~~~
### 扩展
...