ThinikPhp 将数据库模型的增、删、改操作写入日志
Thinkphp中的模型可以对数据库字段进行验证规则的设置和设置一些字段的默认值(比如字段为当前时间)以及在操作数据时的的一些回调方法等
基本上每一个模型都需要设置一些验证规则和字段默认值的设置,而大部分都存在着重复的工作
特别是像需要将数据库操作记录到日志系统的,这就导致我们需要在每个模型中反复处理
针对此问题我定义一个父类模型,所以模型都继承自此类即可解决以上两个问题
父类就完成了以下两件工作:
- 记录增、删、改等操作到日志系统
- 定义一些大部分数据库都需要验证的规则(子类可覆盖或自定义)或者需要自动生成的字段(如每个数据库都有一个记录当前时间的字段create_time)
<?php /* * * 公共模型 */ namespace Common\Model; use Think\Model; class CommonModel extends Model { /** * @Author: HTL * @Email: Huangyuan413026@163.com * @DateTime: 2016-04-08 12:22:19 * @Description: 验证字段,子类可以覆盖或移出 */ protected $_validate = array( array('code','require','{%ERROR_NOT_PAST}'),//必须 array('name','require','{%ERROR_NOT_PAST}'),//必须 ); /** * @Author: HTL * @Email: Huangyuan413026@163.com * @DateTime: 2016-04-08 12:08:38 * @Description: 所有继承的子类字段create_time自动生成当前时间 */ protected $_auto = array ( array ('create_time', 'mGetDate', 1, 'callback' ), // 增加的时候调用回调函数 ); /** * @Author: HTL * @Email: Huangyuan413026@163.com * @DateTime: 2016-04-08 15:52:40 * @Description: 返回该类的自动验证信息,用于在子类中合并该验证信息(不能在子类中定义此$_validate属性否则会被覆盖,如果不需要在子类中合并则可以可忽略此方法) */ protected function get_validate() { return $this->_validate; } /** * @Author: HTL * @Email: Huangyuan413026@163.com * @DateTime: 2016-04-08 12:06:03 * @Description: 获取当前时间 */ protected function mGetDate() { return date ( 'Y-m-d H:i:s' ); } /** * @Author: HTL * @Email: Huangyuan413026@163.com * @DateTime: 2016-04-08 10:50:20 * @Description: 更新成功后的回调方法 */ protected function _after_update($data,$options) { //区分会员登录和更改操作 if( $options['model']=="Users" && $data['last_login_ip'] && $data['last_login_time'] && count($data)==3 ) { $this->after_write("login",$data,$options); } else{ $this->after_write("update",$data,$options); } } /** * @Author: HTL * @Email: Huangyuan413026@163.com * @DateTime: 2016-04-08 10:50:27 * @Description: 插入成功后的回调方法 */ protected function _after_insert($data,$options) { $this->after_write("insert",$data,$options); } /** * @Author: HTL * @Email: Huangyuan413026@163.com * @DateTime: 2016-04-08 11:56:12 * @Description: 删除成功后的回调方法 */ protected function _after_delete($data,$options) { $this->after_write("delete",$data,$options); } /** * @Author: HTL * @Email: Huangyuan413026@163.com * @DateTime: 2016-04-08 11:03:18 * @Description: 更新或插入成功后和删除前写入系统日志 */ function after_write($type,$data,$options) { $db_name = C('DB_PREFIX')."system_log"; //日志表 //如果是系统日志表则不处理,防止循环调用此方法 if(!$this->_is_array($data) || !$this->_is_array($options) || strcasecmp($options['table'],$db_name)==0) return ; $model = M("SystemLog"); //日志表 $new_value = json_encode($data); // 去除前缀的表名 $_data['log_table'] = str_replace(C('DB_PREFIX'), "",$options['table']); //更改时如果原数据未更改则不进行记录,防止重复记录 if("update" === $type){ //表主健 $_data['t_id'] = $data['id']; // 主健名称不是id // 获取主健对应的数据 if($_data['id']){ $tablename = $options['table']; $_data['t_id'] = $data[M($tablename)->getPk()]; } // 如果最后一条的值没有更改则不记录 if($model->where($_data)->order("id desc")->getField("new_value")===$new_value) return; } $_data['log_type'] = $type; $_data['new_value'] = $new_value; $_data['log_user'] = $_SESSION['ADMIN_ID']; $_data['create_time'] = date('Y-m-d H:i:s'); $_data['ip_address'] = get_client_ip(0,true); $_data['user_agent'] = $_SERVER['HTTP_USER_AGENT']; try { $model->add($_data); } catch (Exception $e) { \Think\Log::write('写入系统日志时发生错误,错误信息:'.$e->getMessage(),'WARN'); } } /** * @Author: HTL * @Email: Huangyuan413026@163.com * @DateTime: 2016-04-08 11:04:40 * @Description: 是否是数组 */ function _is_array($array) { return ($array && is_array($array) && count($array)>0); } }
定义一个数据库模型并继承自CommonModel即可
<?php /** * @Author: HTL * @Email: Huangyuan413026@163.com * @DateTime: 2016-04-08 12:03:57 * @Description: 基础价格Model */ namespace Common\Model; use Common\Model\CommonModel; class PriceModel extends CommonModel { /** * @Author: HTL * @Email: Huangyuan413026@163.com * @DateTime: 2016-04-08 15:01:46 * @Description: 自动验证,合并父类验证规则 */ function _initialize() { //自定义验证规则 $_val = array( array('cost','/^[-0-9]{1,}$/','{%ERROR_ONLY_INTEGER}'), array('price','/^[-0-9]{1,}$/','{%ERROR_ONLY_INTEGER}'), ); //合并父类的规则 //验证父类code、name字段 //当前模型的create_time字段自动填充 $this->_validate = array_merge (parent::get_validate(),$_val); // 移出父类的Code唯一性验证 //foreach ($this->_validate as $key => $value) { // if($value[0]=='code' && $value[4]=='unique'){ // unset($this->_validate[$key]); // } //} //覆盖父类验证规则 $this->_validate = $_val; } }
数据库结构
CREATE TABLE `tp_system_log` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `log_type` VARCHAR(50) NOT NULL COMMENT '操作类别', `log_table` VARCHAR(100) NOT NULL COMMENT '操作的表', `log_user` VARCHAR(100) NOT NULL COMMENT '操作的用户', `t_id` VARCHAR(50) NOT NULL COMMENT '操作的表的主健ID', `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '操作的时间', `new_value` TEXT NOT NULL COMMENT '操作后的新值', `ip_address` VARCHAR(20) NOT NULL COMMENT 'Ip地址', `user_agent` VARCHAR(500) NULL DEFAULT NULL COMMENT 'User-Agent:', PRIMARY KEY (`id`), INDEX `id` (`id`) )
参考: