# 数据库开发完整指南
# 📋 概述
本指南涵盖了 OMS 系统中数据库开发的完整流程,包括数据库结构文件(dbschema)格式、数据库更新机制、文件命名规范等内容。
适用范围:所有OMS系统开发人员
重要性:⭐⭐⭐⭐⭐(必须掌握)
# 🚨 重要提醒
数据库结构文件是 PHP 格式,不是 XML 格式!
# 📋 基本格式
# 文件位置
app/{应用名}/dbschema/{表名}.php
# 文件结构
<?php
/**
* {表注释}
*/
$db['{表名}'] = array(
'columns' => array(
// 字段定义
),
'index' => array(
// 索引定义
),
'comment' => '{表注释}',
'engine' => 'innodb',
'version' => '$Rev: $',
);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 📝 字段定义
# 基本字段格式
'字段名' => array(
'type' => '字段类型',
'required' => true/false,
'default' => '默认值',
'label' => '字段标签',
'width' => 宽度,
'in_list' => true/false,
'default_in_list' => true/false,
'comment' => '字段注释',
),
2
3
4
5
6
7
8
9
10
# 常用字段类型
# 1. 整数类型
// 自增主键
'id' => array(
'type' => 'int unsigned',
'required' => true,
'pkey' => true,
'extra' => 'auto_increment',
'label' => 'ID',
),
// 普通整数
'quantity' => array(
'type' => 'int',
'default' => 0,
'label' => '数量',
),
// 小整数
'status' => array(
'type' => 'tinyint(1)',
'default' => 1,
'label' => '状态',
),
// 大整数
'amount' => array(
'type' => 'bigint',
'default' => 0,
'label' => '金额',
),
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
# 2. 字符串类型
// varchar
'name' => array(
'type' => 'varchar(100)',
'required' => true,
'label' => '名称',
),
// text
'description' => array(
'type' => 'text',
'label' => '描述',
),
// char
'code' => array(
'type' => 'char(10)',
'label' => '编码',
),
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 3. 小数类型
'price' => array(
'type' => 'decimal(20,3)',
'required' => true,
'label' => '价格',
),
2
3
4
5
# 4. 布尔类型
'is_active' => array(
'type' => 'bool',
'default' => 'false',
'label' => '是否启用',
),
2
3
4
5
# 5. 时间类型
// 时间戳
'created' => array(
'type' => 'time',
'default' => 0,
'label' => '创建时间',
),
// 自动更新的时间
'last_modified' => array(
'type' => 'last_modify',
'label' => '最后更新时间',
),
// TIMESTAMP 类型
'at_time' => array(
'type' => 'TIMESTAMP',
'label' => '创建时间',
'default' => 'CURRENT_TIMESTAMP',
),
// TIMESTAMP 自动更新
'up_time' => array(
'type' => 'TIMESTAMP',
'label' => '更新时间',
'default' => 'CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP',
),
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
# 6. 关联表类型
// 关联其他表
'cat_id' => array(
'type' => 'table:basic_material_cat@material',
'required' => false,
'default' => 0,
'label' => '分类',
),
2
3
4
5
6
7
# 🔑 索引定义
# 普通索引
'index' => array(
'ind_name' => array(
'columns' => array(
0 => 'column_name',
),
),
),
2
3
4
5
6
7
# 唯一索引
'index' => array(
'uni_name' => array(
'columns' => array(
0 => 'column_name',
),
'prefix' => 'UNIQUE',
),
),
2
3
4
5
6
7
8
# 复合索引
'index' => array(
'ind_multi' => array(
'columns' => array(
0 => 'column1',
1 => 'column2',
),
),
),
2
3
4
5
6
7
8
# 📄 完整示例
# 示例1:商品分类表
<?php
/**
* 商品分类数据结构
*/
$db['goods_category'] = array(
'columns' => array(
'category_id' => array(
'type' => 'int unsigned',
'required' => true,
'pkey' => true,
'extra' => 'auto_increment',
'label' => '分类ID',
'width' => 80,
'in_list' => true,
'default_in_list' => true,
),
'name' => array(
'type' => 'varchar(100)',
'required' => true,
'label' => '分类名称',
'width' => 200,
'in_list' => true,
'default_in_list' => true,
),
'parent_id' => array(
'type' => 'int unsigned',
'default' => 0,
'label' => '父分类ID',
'width' => 80,
),
'sort_order' => array(
'type' => 'int unsigned',
'default' => 0,
'label' => '排序',
'width' => 80,
'in_list' => true,
),
'status' => array(
'type' => 'varchar(10)',
'default' => 'enabled',
'label' => '状态',
'width' => 80,
'in_list' => true,
'default_in_list' => true,
),
'created' => array(
'type' => 'time',
'default' => 0,
'label' => '创建时间',
'width' => 150,
'in_list' => true,
),
'last_modified' => array(
'type' => 'last_modify',
'label' => '最后更新时间',
'width' => 150,
'in_list' => true,
'default_in_list' => true,
),
),
'index' => array(
'ind_parent_id' => array(
'columns' => array(
0 => 'parent_id',
),
),
'ind_status' => array(
'columns' => array(
0 => 'status',
),
),
),
'comment' => '商品分类表',
'engine' => 'innodb',
'version' => '$Rev: $',
);
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
# 示例2:经销商品价格表
<?php
/**
* 经销商品价格数据结构
*/
$db['goods_price'] = array(
'columns' => array(
'id' => array(
'type' => 'int',
'required' => true,
'pkey' => true,
'extra' => 'auto_increment',
'label' => 'ID',
'in_list' => true,
'default_in_list' => true,
'width' => 50,
),
'bs_id' => array(
'type' => 'table:business@dealer',
'required' => true,
'label' => '经销商编码',
'width' => 120,
'in_list' => true,
'default_in_list' => true,
'order' => 10,
),
'bm_id' => array(
'type' => 'table:basic_material@material',
'required' => true,
'label' => '基础物料编码',
'width' => 120,
'in_list' => true,
'default_in_list' => true,
'order' => 20,
),
'price' => array(
'type' => 'decimal(20,3)',
'required' => true,
'label' => '采购价',
'in_list' => true,
'default_in_list' => true,
'order' => 30,
),
'price_unit' => array(
'type' => 'varchar(10)',
'label' => '价格单位',
'in_list' => true,
'default_in_list' => true,
'order' => 35,
'default' => '',
),
'start_time' => array(
'type' => 'time',
'label' => '生效时间',
'in_list' => true,
'default_in_list' => true,
'filtertype' => 'date',
'filterdefault' => true,
'order' => 40,
),
'end_time' => array(
'type' => 'time',
'label' => '过期时间',
'in_list' => true,
'default_in_list' => true,
'filtertype' => 'date',
'filterdefault' => true,
'order' => 50,
),
'at_time' => array(
'type' => 'TIMESTAMP',
'label' => '创建时间',
'default' => 'CURRENT_TIMESTAMP',
'width' => 150,
'in_list' => true,
'default_in_list' => true,
'order' => 60,
),
'up_time' => array(
'type' => 'TIMESTAMP',
'label' => '更新时间',
'default' => 'CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP',
'width' => 150,
'in_list' => true,
'default_in_list' => true,
'order' => 70,
),
),
'index' => array(
'ind_bs_bm' => array(
'columns' => array(
0 => 'bs_id',
1 => 'bm_id',
),
),
'ind_bs_id' => array(
'columns' => array(
0 => 'bs_id',
),
),
'ind_bm_id' => array(
'columns' => array(
0 => 'bm_id',
),
),
),
'comment' => '经销商品价格管理',
'engine' => 'innodb',
'version' => '$Rev: $',
);
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
98
99
100
101
102
103
104
105
106
107
108
109
110
# 🎯 字段属性说明
# 列表展示相关
'in_list' => true, // 是否在列表中显示
'default_in_list' => true, // 默认是否显示
'width' => 120, // 列宽度
'order' => 10, // 显示顺序
'hidden' => true, // 是否隐藏
2
3
4
5
# 筛选相关
'filtertype' => 'normal', // 筛选类型
'filterdefault' => true, // 默认是否显示筛选
'searchtype' => 'has', // 搜索类型
2
3
# 编辑相关
'editable' => false, // 是否可编辑
'required' => true, // 是否必填
'is_title' => true, // 是否是标题字段
2
3
# 筛选类型(filtertype)
normal- 普通下拉选择fuzzy_search- 模糊搜索(单选)fuzzy_search_multiple- 模糊搜索(多选)date- 日期范围选择time- 时间范围选择yes- 是/否选择textarea- 文本域输入
# 搜索类型(searchtype)
has- 包含搜索head- 前缀搜索equal- 精确匹配nequal- 不等于
# ⚠️ 常见错误
# 错误1:使用XML格式
❌ 错误:
app/material/dbschema/goods_category.xml
✅ 正确:
app/material/dbschema/goods_category.php
2
3
4
5
# 错误2:忘记执行更新
❌ 错误:
创建文件后不执行 php cmd update
✅ 正确:
创建或修改 dbschema 文件后立即执行 php cmd update
2
3
4
5
# 🔄 数据库更新机制
# ⚠️ 重要原则
只有在修改了数据库结构定义或XML配置文件时,才需要执行update命令。
纯PHP代码逻辑的修改不需要执行update命令,修改后直接生效。
# 需要执行update的情况
# 1. 修改了dbschema文件
当你修改了任何 app/[应用名]/dbschema/*.php 文件时:
具体场景:
- ✅ 新增表字段
- ✅ 修改字段类型、长度、默认值
- ✅ 删除表字段
- ✅ 新增、修改、删除索引
- ✅ 修改表注释
- ✅ 新增数据表文件
- ✅ 修改字段的
in_list、default_in_list、order等配置
示例:
// 修改了这样的字段定义就需要update
'price' => array(
'type' => 'decimal(20,3)', // 修改了类型
'required' => true,
'label' => '采购价格', // 修改了标签
'in_list' => true, // 修改了列表显示
'default_in_list' => true,
'order' => 30, // 修改了排序
),
2
3
4
5
6
7
8
9
# 2. 修改了XML配置文件
当你修改了任何XML配置文件时:
具体场景:
- ✅
app/[应用名]/desktop.xml- 菜单、权限配置 - ✅
app/[应用名]/services.xml- 服务注册配置 - ✅
app/[应用名]/app.xml- 应用配置 - ✅ 新增菜单项
- ✅ 修改菜单权限
- ✅ 新增权限定义
- ✅ 修改服务类注册
示例:
<!-- 修改了这样的配置就需要update -->
<menu controller='admin_goods_price' action='index'
permission='dealer_goods_price' display='true' order='6001040'>
经销商品价格管理
</menu>
<permission id="dealer_goods_price" show='ome_roles:show_dealer'>
经销商品价格管理
</permission>
<service id="desktop_finder.dealer_mdl_goods_price">
<class>dealer_finder_goods_price</class>
</service>
2
3
4
5
6
7
8
9
10
11
12
13
# ❌ 不需要执行update的情况
# 1. 修改PHP代码文件
- ❌
app/[应用名]/model/*.php- 模型文件 - ❌
app/[应用名]/controller/*.php- 控制器文件 - ❌
app/[应用名]/lib/*.php- 业务逻辑文件 - ❌
app/[应用名]/view/*.html- 视图模板文件
# 2. 修改文档文件
- ❌
docs/*.md- 文档文件 - ❌
README.md- 说明文件
# 3. 纯逻辑修改
- ❌ Bug修复
- ❌ 功能优化
- ❌ 代码重构
- ❌ 新增方法和函数
- ❌ 修改业务逻辑
示例(这些修改不需要update):
// 修改了模型中的方法逻辑
public function modifier_start_time($data)
{
return $data ? date('Y-m-d H:i:s', $data) : ''; // 修改了格式化逻辑
}
// 新增了验证方法
public function validatePrice($price)
{
return is_numeric($price) && $price >= 0; // 新增方法
}
// 修改了控制器逻辑
public function exportTemplate()
{
$data = array(
array('经销商编码', '基础物料编码', '采购价'), // 修改了模板数据
);
// ...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 🔧 执行update命令
# 命令格式
# 方式1:通过docker执行(推荐)
docker exec -it php82 bash -c "cd /var/www/html/erp/oms-yjdf && php app/base/cmd update"
# 方式2:进入容器后执行
docker exec -it php82 bash
cd /var/www/html/erp/oms-yjdf
php app/base/cmd update
2
3
4
5
6
7
# 执行时机
- ✅ 完成dbschema文件修改后立即执行
- ✅ 完成XML配置文件修改后立即执行
- ✅ 部署到新环境时执行
- ❌ 每次修改PHP代码后不需要执行
# 执行结果
成功执行后会看到类似输出:
Scanning local Applications... ok.
Updating base_application_dbtable@dealer.
Applications database and services is up-to-date, ok.
2
3
# 📝 总结
记住这个简单的判断规则:
- 改数据库结构 = 需要update
- 改XML配置 = 需要update
- 改PHP代码 = 不需要update
- 改文档 = 不需要update
当不确定时,可以先尝试不执行update,如果功能不正常再考虑是否需要update。
# 错误3:字段类型错误
❌ 错误:
'created' => array(
'type' => 'datetime', // 不支持这个类型
),
✅ 正确:
'created' => array(
'type' => 'time', // 使用 time 类型
'default' => 0,
),
2
3
4
5
6
7
8
9
10
# 错误4:索引命名不规范
❌ 错误:
'index' => array(
'parent_id' => array( // 直接用字段名
...
),
),
✅ 正确:
'index' => array(
'ind_parent_id' => array( // 使用 ind_ 前缀
...
),
),
2
3
4
5
6
7
8
9
10
11
12
13
# 📚 参考资料
# 实际案例
app/material/dbschema/basic_material.php- 复杂字段示例app/dealer/dbschema/goods_price.php- 关联表示例app/ome/dbschema/orders.php- 大表结构示例
# 📁 文件命名规范
# Model文件命名规则
在OMS系统中,Model文件的命名遵循特定的目录结构规则:
# 基本规则
对于数据表 sdb_[应用名]_[表名],对应的Model文件路径和类名:
文件路径:app/[应用名]/model/[表名去掉应用名前缀].php
类名:[应用名]_mdl_[表名去掉应用名前缀]
# 具体示例
简单表名
数据表:sdb_dealer_goods_price 文件路径:app/dealer/model/goods/price.php 类名:dealer_mdl_goods_price1
2
3带ops后缀的关联表
数据表:sdb_organization_organization_ops 文件路径:app/organization/model/organization/ops.php 类名:organization_mdl_organization_ops1
2
3其他复合表名
数据表:sdb_ome_group_ops 文件路径:app/ome/model/group/ops.php 类名:ome_mdl_group_ops1
2
3
# 目录结构规则
- 如果表名包含多个下划线分隔的部分,需要创建对应的子目录
- 最后一个部分作为文件名(.php)
- 前面的部分作为目录路径
# 常见错误示例
❌ 错误:app/organization/model/organization_ops.php
✅ 正确:app/organization/model/organization/ops.php
❌ 错误:app/dealer/model/goods_price.php
✅ 正确:app/dealer/model/goods/price.php
2
3
4
5
重要提醒:违反命名规则会导致 Call to undefined method 错误,因为框架的自动加载机制无法找到正确的Model文件。
# Lib文件命名规则
在OMS系统中,Lib文件的命名也遵循特定的目录结构规则:
# 基本规则
对于 kernel::single('[应用名]_[目录名]_[文件名]'),对应的Lib文件路径和类名:
文件路径:app/[应用名]/lib/[目录名]/[文件名].php
类名:[应用名]_[目录名]_[文件名]
# 具体示例
简单Lib文件
调用:kernel::single('organization_organization_permission') 文件路径:app/organization/lib/organization/permission.php 类名:organization_organization_permission1
2
3多层目录结构
调用:kernel::single('ome_finder_extend_filter_branch_product') 文件路径:app/ome/lib/finder/extend/filter/branch/product.php 类名:ome_finder_extend_filter_branch_product1
2
3业务逻辑Lib
调用:kernel::single('console_receipt_inventory') 文件路径:app/console/lib/receipt/inventory.php 类名:console_receipt_inventory1
2
3
# 目录结构规则
- 下划线分隔的部分对应目录结构
- 最后一个部分作为文件名(.php)
- 前面的部分作为目录路径
# 常见错误示例
❌ 错误:app/organization/lib/organization_permission.php
✅ 正确:app/organization/lib/organization/permission.php
❌ 错误:app/ome/lib/finder_extend_filter_branch_product.php
✅ 正确:app/ome/lib/finder/extend/filter/branch/product.php
2
3
4
5
重要提醒:违反命名规则会导致 Class not found 错误,因为框架的自动加载机制无法找到正确的Lib文件。
# 📋 前端开发规范
# 下拉列表搜索实现标准
在OMS系统中,下拉列表默认都应该支持搜索功能,使用以下标准实现方式:
# 基本模板
<{input type='select' issearch="fuzzy-search" required="required" name='field_name' options=$optionsData}>
# JavaScript初始化
tail.select('select[issearch="fuzzy-search"]', {
search: true,
width: 300,
height: 300,
searchMinLength: 0
});
2
3
4
5
6
# PHP数据格式
// 使用array_column生成options格式
$data = $model->getList('id,name', $filter);
$this->pagedata['optionsData'] = array_column($data, 'name', 'id');
2
3
# 参数说明
issearch="fuzzy-search"- 启用模糊搜索search: true- 开启搜索功能width: 300- 下拉框宽度height: 300- 下拉框高度searchMinLength: 0- 最小搜索长度(0表示无限制)
# 使用场景
- ✅ 门店选择下拉框
- ✅ 仓库选择下拉框
- ✅ 商品选择下拉框
- ✅ 用户选择下拉框
- ✅ 任何需要从大量选项中快速定位的场景
# 注意事项
- 数据量较大时,建议添加适当的过滤条件
- 搜索功能对用户体验提升明显,特别是选项超过10个时
- 保持与系统其他页面的一致性
# 📚 开发流程建议
# 1. 新功能开发流程
1. 设计数据表结构 → 创建dbschema文件 → 执行update
2. 配置菜单权限 → 修改desktop.xml → 执行update
3. 注册服务类 → 修改services.xml → 执行update
4. 开发业务逻辑 → 编写model/controller/lib → 不需要update
5. 测试功能 → 修改bug → 不需要update
2
3
4
5
# 2. 功能修改流程
1. 如果需要修改表结构 → 修改dbschema → 执行update
2. 如果需要修改菜单权限 → 修改desktop.xml → 执行update
3. 如果只是修改业务逻辑 → 修改PHP代码 → 不需要update
2
3
# ⚠️ 注意事项
# 1. 数据安全
- 在生产环境执行update前务必备份数据库
- 新增字段建议设置合理的默认值
- 删除字段前确认不会影响现有功能
# 2. 团队协作
- 修改dbschema或XML文件后及时通知团队成员
- 提交代码时在提交信息中标明是否需要执行update
- 代码评审时重点检查数据库结构变更
# 3. 错误处理
如果update执行失败:
- 检查语法错误(XML格式、PHP语法)
- 检查权限问题
- 检查数据库连接
- 查看错误日志定位问题
# 📚 参考资料
# 实际案例
app/material/dbschema/basic_material.php- 复杂字段示例app/dealer/dbschema/goods_price.php- 关联表示例app/ome/dbschema/orders.php- 大表结构示例
# 相关文档
最后更新:2025年 版本:1.0