在MixMVC中,model代表具体是数据逻辑封装,其中包括数据库访问、外部接口访问[外部web service、memcached、smtp]等,一切跟数据有关的逻辑都会封装到Model里面,最常用的当时数据库访问的封装了。
Model结构
在MixMVC中,如果需要使用数据库相关的接口,我们需要model继承MST_DBO,MST_DBO 封装了常用的CRUD操作API。配合不同的MST_DBC后端,可以实现对不同的数据库的操作,暂时已经实现的DBC只支持MySQL及Oracle。
PS: 有兴趣的同学可以继续向下研究。
更快捷的方式是,到 http://192.168.33.6/mvctools 使用这个生成工具,直接生成相关的Model php文件。
当我们继承了MST_DBO后,我们首页需要建立Model与数据表之间的映射,我们需要在继承类中设置一下静态变量:
一个Model文件的基本模板:
//所有model一般都是有关于操作数据库的,所以一般我们都会继承自MST_DBO。 //这里的类名是使用的pear风格的命名规范,其中Edm_Admin 是命名空间(namespace), //该文件会放到application/models/edm/admin/Session.php //注意文件夹的命名都是小写的,而类名(ClassName)中是首字母大写的,而已文件名就跟类名(ClassName)一样是首字母大写的。 class Edm_Admin_Session extends MST_DBO { protected static //$columns数组,所有继承于MST_DBO的类,必须包含的定义,用于定义具体的字段参数。 //数组中包含多个配置定义,分别用于自动生成form组件,及数据验证时使用。 //基本格式为 $key => array($type, 'title' => $title) $key 字段在数据库中的名称, //$type form组件类型会根据此值生成相关的input[text/datepicker/radiogroup等] //$title 关于该字段的文字描述, 其他选项会有专门相关的文章说明。 $columns = array( 'sess_id' => array('text', 'title' => 'Sess ID', 'require' => 1), 'value' => array('text', 'title' => 'Value', 'require' => 1), 'created_at' => array('datetime', 'title' => 'Created Time', 'require' => 1), 'created_ip' => array('text', 'title' => 'Created Ip', 'require' => 1), 'updated_at' => array('datetime', 'title' => 'Updated Time', 'require' => 1), 'expired_at' => array('text', 'title' => 'Expired At', 'require' => 1), 'user_id' => array('text', 'title' => 'User ID', 'require' => 1), ), //$stuct 默认new model的时候包含的字段 $struct = array('sess_id','value','created_at','created_ip','updated_at','expired_at','user_id'), //$defaultSelect 默认使用find方法时返回的数据字段 $defaultSelect = 'id,sess_id,value,created_at,created_ip,updated_at,expired_at,user_id'; //钩子回调函数,当新建数据之前是触发 protected function beforeCreate(& $data) { $data['created_at'] = time(); } //钩子回调函数,当数据更新之前触发 protected function beforeUpdate(& $data) { $data['updated_at'] = time(); } //默认的必须实现的接口方法,配合grid组件使用,用于生成列表头部 static public function getGridHeads() { $heads = self::getAllColumnOptions(); return $heads; } //默认必须实现的接口方法,配合dbo_form组件使用,用于获取字段信息,生成相关表单(form) public function getFormColumns() { $columns = self::$columns; return $columns; } }
上面模板中都有相关的注释说明其意义,$columns的具体参数项请看这个文章,然后我们说一下模板中没有表现出来的地方。
默认回调函数
Model中预定于了若干回调函数,用于在流程插入自定义的逻辑操作。例如在上面的模板中,我们就通过beforeCreate 与beforeUpdate连个预定义回调函数,在插入之前及更新之前的时候,把相关字段的默认值+上。
所有的预定义回调函数如下:
//数据验证前触发,一般在此加入自定义的数据库验证判断逻辑,可以通过return false中断流程 public function beforeValidate(& $data, $args) {} //创建数据前触发,一般在此+入创建时间戳 public function beforeCreate(& $data, $args) {} //数据更新前触发,一般在此+入更新时间戳 public function beforeUpdate(& $data, $args) {} //数据保存前触发,此回调会在创建和更新的时候都会触发 public function beforeSave(& $data, $args) {} //数据创建后触发,一般用于关联项目的更新及插入操作,状态判断请使用isNews()方法 public function afterCreate(& $data, $args) {} //数据更新后触发,一般用于关联项目的更新及插入操作,状态判断请使用isNews()方法 public function afterUpdate(& $data, $args) {} //数据保存后触发,在更新及创建后都会触发该回调,一般用于关联项目的更新及插入操作,状态判断请使用isNews()方法 public function afterSave(& $data, $args) {}
Model常用函数
查找相关:
//单条记录最简单方法 $admin_session = Admin_Session::find($id); //使用isNew方法判断是否查询成功 $admin_session-&gt;isNew(); //单条记录完整查询模式,基本上使用array生成SQL,SQL语法就不在叙说了 $admin_session = Admin_Session::find(Admin_Session::FIRST, array( 'select' => '*', 'join' => 'LEFT JOIN *** on admin_session.id=***.**', 'group' => 'admin_session.id', 'order' => 'id desc', 'limit' => 1, 'having' => array('id' => array('=', 1)) //having 聚合条件查询,eg:array('id' => array('>', 1))/array('id' => array('<', 1)), 'in' => array('id' => array(1,2,3,)), // sql in 条件查询 'where' => array('id=?', $id) //条件查询使用dbo风格,?代替变量
&nbsp;&nbsp;&nbsp;&nbsp; )); //多条记录完整查询模式 $list = Admin_Session::find(Admin_Session::ALL, array( 'select' => '*', 'join' => 'LEFT JOIN *** on admin_session.id=***.**', 'group' => 'admin_session.id', 'order' => 'id desc', 'limit' => 1, 'having' => array('id' => array('=', 1)) //having 聚合条件查询,eg:array('id' => array('>', 1))/array('id' => array('<', 1)), 'in' => array('id' => array(1,2,3,)), // sql in 条件查询 'where' => array('id=?', $id)//条件查询使用dbo风格,?代替变量 )); //由于DBO继承自MST_DBO_DataSet, 使用isEmpty方法判断返回的list是否为空, //然后可以直接使用foreach迭代DBO数据,不需要再转成数组! if (!$list->isEmpty()) { foreach($list as $row) { //code } }
数据添加/更新/删除
//最常用的插入方法,直接new一个Model $admin_session = new Admin_Session(); //使用assign方法填充数据 $admin_session->assign(array( 'created_at' => time(), 'updated_at' => time(), 'user_id' => $user_id, )); //使用upgrade方法保存数据,返回操作结果 $admin_session->upgrade(); //使用isNew判断操作是否成功 if ($admin_session->isNew()) { //code } //一般更新数据之前,我们会先查询 $admin_session = Admin_Session::find($id); //也可以使用直接赋值的方法填充数据 $admin_session['user_id'] = $user_id; //使用upgrade方法保存数据,返回操作结果 $admin_session->upgrade(); //使用静态方法update更新,第一个参数是条件,可以直接使用id //第二个参数是需要更新的数据 Admin_Session::update($id, array( 'user_id' => $user_id, )); //也可以使用自定义条件更新数据,一般用于批量操作 Admin_Session::update(array( 'where' => array('id=?', $id) ), array( 'user_id' => $user_id, )); //最简单的删除数据方法,直接传id,返回操作结果 Admin_Session::delete($id); //使用自定义条件进行删除操作,一般用于批量操作 Admin_Session::delete(array( 'where' => array('user_id=?', $user_id), ));
以上就是有关Model部分的基本描述。
Update 2015-08-21: 增加 in条件/having条件的例子。
//一般更新数据之前,我们会先查询
$admin_session = Admin_Session::find($id);
//也可以使用直接赋值的方法填充数据
$admin_session[‘user_id’] = $user_id;
//使用upgrade方法保存数据,返回操作结果
$admin_session->upgrade();
上述解释中,用upgrade()更新数据时,有个情况,就是如果能find出$id,即查到有记录对象返回,那样更新是没问题,但是,要是find不到这$id,那情况就不同了,会变成向数据表插入一条记录,这显然不是想要的结果。而用update(),哪怕是没有查到相应的条件,但它只是返回一条查询的SQL语句,所以用静态的update更新数据记录更为妥当!
isNew()和isEmpty()的疑问
$id = 272990;
$db = self::find(self::FIRST, array(
‘where’ => array(‘id >= ?’, $id)
));
var_dump($db->isEmpty());
var_dump($db->isNew());
上述代码中,当find方法中第一个参数是FIRST时,无论条件是否找到,能正常执行,而当第一个参数是ALL时,isEmpty能正常执行,而isNew会报错,那么按测试如果用find时,不管第一个参数是FIRST还是ALL,我们执行后都用isEmpty,不更为妥当?
DBO::find 方法的会根据第一个参数的,return不同的类型。
如果是传$id, 如model::find($id) 或者 model::find(model::FIRST, array(…)), 会返回一个model对象。
而如果是查询list,如model::find(model::ALL, array(…)),就会返回MST_DBO_DataSet。
由于model 继承自 MST_DBO,而MST_DBO又继承自 MST_DBO_DataSet,所以两个返回的对象中都可以找到 isEmpty()方法[该方式来自MST_DBO_DataSet的父类MST_DataSet],用于判断集合(list)是否为空。而isNew()方式是来自MST_DBO,用于判断对象是否填充数据。
由于model::find返回的对象不同,所以使用的时候需要注意,正确理解返回的是什么对象。