ecmall 框架系统分析-对于ecmall数据库关系模型的分析
对于ecmall数据库关系模型的分析,我觉得需要从两个函数说起:
- //获取一个模型
- function &m($model_name, $params = array(), $is_new = false)
- {
- static $models = array();
- $model_hash = md5($model_name . var_export($params, true));
- if ($is_new || !isset($models[$model_hash]))
- {
- $model_file = ROOT_PATH . ‘/includes/models/’ . $model_name .
- ‘.model.php’;
- if (!is_file($model_file))
- {
- /* 不存在该文件,则无法获取模型 */
- return false;
- }
- include_once($model_file);
- $model_name = ucfirst($model_name) . ‘Model’;
- if ($is_new)
- {
- return new $model_name($params, db());
- }
- $models[$model_hash] = new $model_name($params, db());
- }
- return $models[$model_hash];
- }
- //获取一个业务模型
- function &bm($model_name, $params = array(), $is_new = false)
- {
- static $models = array();
- $model_hash = md5($model_name . var_export($params, true));
- if ($is_new || !isset($models[$model_hash]))
- {
- $model_file = ROOT_PATH . ‘/includes/models/’ . $model_name .
- ‘.model.php’;
- if (!is_file($model_file))
- {
- /* 不存在该文件,则无法获取模型 */
- return false;
- }
- include_once($model_file);
- $model_name = ucfirst($model_name) . ‘BModel’;
- if ($is_new)
- {
- return new $model_name($params, db());
- }
- $models[$model_hash] = new $model_name($params, db());
- }
- return $models[$model_hash];
- }
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 |
//获取一个模型 function &m($model_name, $params = array(), $is_new = false) { static $models = array(); $model_hash = md5($model_name . var_export($params, true)); if ($is_new || !isset($models[$model_hash])) { $model_file = ROOT_PATH . '/includes/models/' . $model_name . '.model.php'; if (!is_file($model_file)) { /* 不存在该文件,则无法获取模型 */ return false; } include_once($model_file); $model_name = ucfirst($model_name) . 'Model'; if ($is_new) { return new $model_name($params, db()); } $models[$model_hash] = new $model_name($params, db()); } return $models[$model_hash]; } //获取一个业务模型 function &bm($model_name, $params = array(), $is_new = false) { static $models = array(); $model_hash = md5($model_name . var_export($params, true)); if ($is_new || !isset($models[$model_hash])) { $model_file = ROOT_PATH . '/includes/models/' . $model_name . '.model.php'; if (!is_file($model_file)) { /* 不存在该文件,则无法获取模型 */ return false; } include_once($model_file); $model_name = ucfirst($model_name) . 'BModel'; if ($is_new) { return new $model_name($params, db()); } $models[$model_hash] = new $model_name($params, db()); } return $models[$model_hash]; } |
所谓模型,则是一个一个的数据实体,换句话说就是一个数据表,你可以基于这个模
型,调用model.base.php中的数据库操作函数来 对数据进行增、删、改、查的操作。
这里的业务模型,是在实体模型基础上,再继承一次,然后对一些方法进行重写。
系统中只有三个实体有业务模型:
推荐类型 recommend;商品数据模型 goods;商品分类业务模型 gcategory;
具体操作例子:
- //物品表的操作:
- $model_goods = & m(‘goods’);
- $goods_info = $model_goods->get($goods_id);
1 2 3 |
//物品表的操作: $model_goods = & m('goods'); $goods_info = $model_goods->get($goods_id); |
这里需要解释一下对于数据模型的操作是怎样的一个函数调用过程:
首先:$model_goods = &m(‘goods’);
我 们看一下&m()函数的代码,其中var_export()函数则是将传进来的实体,返回相应的实体类对象,因为所有的model都继承至 model.base.php中的BaseModel类,这个类中定义了基本所有的操作函数,因此$model_goods对象可以对数据库进行相应的操 作。
而我们再看看goods.model.php中的GoodsModel的代码:
- class GoodsModel extends BaseModel
- {
- var $table = ‘goods’;
- var $prikey = ‘goods_id’;
- var $alias = ‘g’;//缩写
- var $_name = ‘goods’;
- var $temp; // 临时变量
- var $_relation = array(
- // 一个商品对应一条商品统计记录
- ‘has_goodsstatistics’ => array(
- ‘model’ => ‘goodsstatistics’,
- ‘type’ => HAS_ONE,
- ‘foreign_key’ => ‘goods_id’,
- ‘dependent’ => true
- ),
- // 一个商品对应多个规格
- ‘has_goodsspec’ => array(
- ‘model’ => ‘goodsspec’,
- ‘type’ => HAS_MANY,
- ‘foreign_key’ => ‘goods_id’,
- ‘dependent’ => true
- ),
- // 一个商品对应一个默认规格
- ‘has_default_spec’ => array(
- ‘model’ => ‘goodsspec’,
- ‘type’ => HAS_ONE,
- ‘refer_key’ => ‘default_spec’,
- ‘foreign_key’ => ‘spec_id’,
- ),
- // 一个商品对应多个属性
- ‘has_goodsattr’ => array(
- ‘model’ => ‘goodsattr’,
- ‘type’ => HAS_MANY,
- ‘foreign_key’ => ‘goods_id’,
- ‘dependent’ => true
- ),
- // 一个商品对应多个图片
- ‘has_goodsimage’ => array(
- ‘model’ => ‘goodsimage’,
- ‘type’ => HAS_MANY,
- ‘foreign_key’ => ‘goods_id’,
- ‘dependent’ => true
- ),
- // 一个商品只能属于一个店铺
- ‘belongs_to_store’ => array(
- ‘model’ => ‘store’,
- ‘type’ => BELONGS_TO,
- ‘foreign_key’ => ‘store_id’,
- ‘reverse’ => ‘has_goods’,
- ),
- // 商品和分类是多对多的关系
- ‘belongs_to_gcategory’ => array(
- ‘model’ => ‘gcategory’,
- ‘type’ => HAS_AND_BELONGS_TO_MANY,
- ‘middle_table’ => ‘category_goods’,
- ‘foreign_key’ => ‘goods_id’,
- ‘reverse’ => ‘has_goods’,
- ),
- // 商品和会员是多对多的关系(会员收藏商品)
- ‘be_collect’ => array(
- ‘model’ => ‘member’,
- ‘type’ => HAS_AND_BELONGS_TO_MANY,
- ‘middle_table’ => ‘collect’,
- ‘foreign_key’ => ‘item_id’,
- ‘ext_limit’ => array(‘type’ => ‘goods’),
- ‘reverse’ => ‘collect_goods’,
- ),
- // 商品和推荐类型是多对多的关系 todo
- ‘be_recommend’ => array(
- ‘model’ => ‘recommend’,
- ‘type’ => HAS_AND_BELONGS_TO_MANY,
- ‘middle_table’ => ‘recommended_goods’,
- ‘foreign_key’ => ‘goods_id’,
- ‘reverse’ => ‘recommend_goods’,
- ),
- );
- var $_autov = array(
- ‘goods_name’ => array(
- ‘required’ => true,
- ‘filter’ => ‘trim’,
- ),
- );
- }
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 |
class GoodsModel extends BaseModel { var $table = 'goods'; var $prikey = 'goods_id'; var $alias = 'g';//缩写 var $_name = 'goods'; var $temp; // 临时变量 var $_relation = array( // 一个商品对应一条商品统计记录 'has_goodsstatistics' => array( 'model' => 'goodsstatistics', 'type' => HAS_ONE, 'foreign_key' => 'goods_id', 'dependent' => true ), // 一个商品对应多个规格 'has_goodsspec' => array( 'model' => 'goodsspec', 'type' => HAS_MANY, 'foreign_key' => 'goods_id', 'dependent' => true ), // 一个商品对应一个默认规格 'has_default_spec' => array( 'model' => 'goodsspec', 'type' => HAS_ONE, 'refer_key' => 'default_spec', 'foreign_key' => 'spec_id', ), // 一个商品对应多个属性 'has_goodsattr' => array( 'model' => 'goodsattr', 'type' => HAS_MANY, 'foreign_key' => 'goods_id', 'dependent' => true ), // 一个商品对应多个图片 'has_goodsimage' => array( 'model' => 'goodsimage', 'type' => HAS_MANY, 'foreign_key' => 'goods_id', 'dependent' => true ), // 一个商品只能属于一个店铺 'belongs_to_store' => array( 'model' => 'store', 'type' => BELONGS_TO, 'foreign_key' => 'store_id', 'reverse' => 'has_goods', ), // 商品和分类是多对多的关系 'belongs_to_gcategory' => array( 'model' => 'gcategory', 'type' => HAS_AND_BELONGS_TO_MANY, 'middle_table' => 'category_goods', 'foreign_key' => 'goods_id', 'reverse' => 'has_goods', ), // 商品和会员是多对多的关系(会员收藏商品) 'be_collect' => array( 'model' => 'member', 'type' => HAS_AND_BELONGS_TO_MANY, 'middle_table' => 'collect', 'foreign_key' => 'item_id', 'ext_limit' => array('type' => 'goods'), 'reverse' => 'collect_goods', ), // 商品和推荐类型是多对多的关系 todo 'be_recommend' => array( 'model' => 'recommend', 'type' => HAS_AND_BELONGS_TO_MANY, 'middle_table' => 'recommended_goods', 'foreign_key' => 'goods_id', 'reverse' => 'recommend_goods', ), ); var $_autov = array( 'goods_name' => array( 'required' => true, 'filter' => 'trim', ), ); } |
这里贴出了实体goods模型类中的内容,先是表格的属性,再就是goods与其它实体之间的关联关系的定义。然后我们再看看这个函数,它是 BaseModel构造函数里调用的方法,对对象中的基础变量进行初使化:
- function BaseModel($params, $db)
- {
- $this->db =& $db;
- !$this->alias && $this->alias = $this->table;
- $this->_prefix = DB_PREFIX;
- $this->table = $this->_prefix . $this->table;
- if (!emptyempty($params))
- {
- foreach ($params as $key => $value)
- {
- $this->$key = $value;
- }
- }
- }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function BaseModel($params, $db) { $this->db =& $db; !$this->alias && $this->alias = $this->table; $this->_prefix = DB_PREFIX; $this->table = $this->_prefix . $this->table; if (!empty($params)) { foreach ($params as $key => $value) { $this->$key = $value; } } } |
大家已经看出$_relation 中间是此实体的关联信息,然后在BaseModel类中的一个函数:
- function _getJoinString($relation_info)
- {
- switch ($relation_info[‘type’])
- {
- case HAS_ONE://
- $model =& m($relation_info[‘model’]);
- /* 联合限制 */
- $ext_limit = ”;
- $relation_info[‘ext_limit’] && $ext_limit = ‘ AND ‘ . $this->_getExtLimit($relation_info[‘ext_limit’]);
- /* 获取参考键,默认是本表主键(直接拥有),否则为间接拥有 */
- $refer_key = isset($relation_info[‘refer_key’]) ? $relation_info[‘refer_key’] : $this->prikey;
- /* 本表参考键=外表外键 */
- return ” LEFT JOIN {$model->table} {$model->alias} ON {$this->alias}.{$refer_key}={$model->alias}.{$relation_info[‘foreign_key’]}{$ext_limit}”;
- break;
- case BELONGS_TO:
- /* 属于关系与拥有是一个反向的关系 */
- $model =& m($relation_info[‘model’]);
- $be_related = $model->getRelation($relation_info[‘reverse’]);
- if (emptyempty($be_related))
- {
- /* 没有找到反向关系 */
- $this->_error(‘no_reverse_be_found’, $relation_info[‘model’]);
- return ”;
- }
- $ext_limit = ”;
- !emptyempty($relation_info[‘ext_limit’]) && $ext_limit = ‘ AND ‘ . $this->_getExtLimit($relation_info[‘ext_limit’], $this->alias);
- /* 获取参考键,默认是外表主键 */
- $refer_key = isset($be_related[‘refer_key’]) ? $be_related[‘refer_key’] :$model->prikey ;
- /* 本表外键=外表参考键 */
- return ” LEFT JOIN {$model->table} {$model->alias} ON {$this->alias}.{$be_related[‘foreign_key’]} = {$model->alias}.{$refer_key}{$ext_limit}”;
- break;
- case HAS_AND_BELONGS_TO_MANY:
- /* 连接中间表,本表主键=中间表外键 */
- $malias = isset($relation_info[‘alias’]) ? $relation_info[‘alias’] : $relation_info[‘middle_table’];
- $ext_limit = ”;
- $relation_info[‘ext_limit’] && $ext_limit = ‘ AND ‘ . $this->_getExtLimit($relation_info[‘ext_limit’], $malias);
- return ” LEFT JOIN {$this->_prefix}{$relation_info[‘middle_table’]} {$malias} ON {$this->alias}.{$this->prikey} = {$malias}.{$relation_info[‘foreign_key’]}{$ext_limit}”;
- break;
- }
- }
- /* 模型相关常量定义 */
- define(‘HAS_ONE’, 1); //一对一关联
- define(‘BELONGS_TO’, 2); //属于关联
- define(‘HAS_MANY’, 3); //一对多关联
- define(‘HAS_AND_BELONGS_TO_MANY’, 4); //多对多关联
- define(‘DROP_CONDITION_TRUNCATE’, ‘TRUNCATE’); // 清空
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 |
function _getJoinString($relation_info) { switch ($relation_info['type']) { case HAS_ONE:// $model =& m($relation_info['model']); /* 联合限制 */ $ext_limit = ''; $relation_info['ext_limit'] && $ext_limit = ' AND ' . $this->_getExtLimit($relation_info['ext_limit']); /* 获取参考键,默认是本表主键(直接拥有),否则为间接拥有 */ $refer_key = isset($relation_info['refer_key']) ? $relation_info['refer_key'] : $this->prikey; /* 本表参考键=外表外键 */ return " LEFT JOIN {$model->table} {$model->alias} ON {$this->alias}.{$refer_key}={$model->alias}.{$relation_info['foreign_key']}{$ext_limit}"; break; case BELONGS_TO: /* 属于关系与拥有是一个反向的关系 */ $model =& m($relation_info['model']); $be_related = $model->getRelation($relation_info['reverse']); if (empty($be_related)) { /* 没有找到反向关系 */ $this->_error('no_reverse_be_found', $relation_info['model']); return ''; } $ext_limit = ''; !empty($relation_info['ext_limit']) && $ext_limit = ' AND ' . $this->_getExtLimit($relation_info['ext_limit'], $this->alias); /* 获取参考键,默认是外表主键 */ $refer_key = isset($be_related['refer_key']) ? $be_related['refer_key'] :$model->prikey ; /* 本表外键=外表参考键 */ return " LEFT JOIN {$model->table} {$model->alias} ON {$this->alias}.{$be_related['foreign_key']} = {$model->alias}.{$refer_key}{$ext_limit}"; break; case HAS_AND_BELONGS_TO_MANY: /* 连接中间表,本表主键=中间表外键 */ $malias = isset($relation_info['alias']) ? $relation_info['alias'] : $relation_info['middle_table']; $ext_limit = ''; $relation_info['ext_limit'] && $ext_limit = ' AND ' . $this->_getExtLimit($relation_info['ext_limit'], $malias); return " LEFT JOIN {$this->_prefix}{$relation_info['middle_table']} {$malias} ON {$this->alias}.{$this->prikey} = {$malias}.{$relation_info['foreign_key']}{$ext_limit}"; break; } } /* 模型相关常量定义 */ define('HAS_ONE', 1); //一对一关联 define('BELONGS_TO', 2); //属于关联 define('HAS_MANY', 3); //一对多关联 define('HAS_AND_BELONGS_TO_MANY', 4); //多对多关联 define('DROP_CONDITION_TRUNCATE', 'TRUNCATE'); //清空 |
从这个函数中,我们可以看到,对于不同的关联关系,它会返回不同的关联时的查询语句片断,然后连接上主sql语句,就可以针对实体的关联实体进行相 应的关联操作了。
具体操作例子:
- //物品表的操作:
- $model_goods = & m(‘goods’);
- $goods_info = $model_goods->find(array(
- ‘conditions’ => “if_show=1 and closed=0”,
- ‘fields’ => ‘goods_id,goods_name,s.store_id,s.store_name’,
- ‘join’ => ‘blongs_to_store’
- ));
1 2 3 4 5 6 7 |
//物品表的操作: $model_goods = & m('goods'); $goods_info = $model_goods->find(array( 'conditions' => "if_show=1 and closed=0", 'fields' => 'goods_id,goods_name,s.store_id,s.store_name', 'join' => 'blongs_to_store' )); |
这里的’join’ => ‘blongs_to_store’ ,我们从上面的:
- // 一个商品只能属于一个店铺
- ‘belongs_to_store’ => array(
- ‘model’ => ‘store’,
- ‘type’ => BELONGS_TO,
- ‘foreign_key’ => ‘store_id’,
- ‘reverse’ => ‘has_goods’,
- ),
1 2 3 4 5 6 7 |
// 一个商品只能属于一个店铺 'belongs_to_store' => array( 'model' => 'store', 'type' => BELONGS_TO, 'foreign_key' => 'store_id', 'reverse' => 'has_goods', ), |
这里我们可以知道这是在与store表进行关联查找了。
到这里,读者就可以知道,如果在上面进行二次开发的话,怎样进行数据库操作就已经很 明确的了。
在BaseModel与cls_mysql(mysql.php)中,有很多的有关数据操作的函数,这里就不需要再一一进行解释了,而 在cls_mysql中,有一些更基础的操作函数,还有仿真 Adodb 的函数,可以直接跳过BaseModel中的函数
以上介绍了如何在 ecmall的平台上进行数据库操作,如果操作更加的复杂,这里还有一种更加直接的方法:
- $sql = “select g.goods_id,g.goods_name, from “.DB_PREFIX.”goods g, “.DB_PREFIX.”goods_spec gs , “.DB_PREFIX.”store s where cate_id='”.$cate_id.”‘ AND g.if_show = 1 AND g.closed = 0 and g.goods_id=gs.goods_id and g.store_id=s.store_id and gs.stock>0 and s.state=1 order by g.add_time desc limit 6″;
- $goods_mod =& m(‘goods’);
- $category_goods = $goods_mod->getAll($sql);
- if(!$category_goods){
- $category_goods=array();
- }
- return $category_goods;
1 2 3 4 5 6 7 |
$sql = "select g.goods_id,g.goods_name, from ".DB_PREFIX."goods g, ".DB_PREFIX."goods_spec gs , ".DB_PREFIX."store s where cate_id='".$cate_id."' AND g.if_show = 1 AND g.closed = 0 and g.goods_id=gs.goods_id and g.store_id=s.store_id and gs.stock>0 and s.state=1 order by g.add_time desc limit 6"; $goods_mod =& m('goods'); $category_goods = $goods_mod->getAll($sql); if(!$category_goods){ $category_goods=array(); } return $category_goods; |
就可以直接使用sql语句进行数据操作了。
还可以在BaseModel中定义自己的操作方法,其中可以使用$this->db->(cls_mysql中定义的方法) 来调用cls_mysql中的函数,从而可以添加更加复杂的数据操作函数。