天天看點

ThinikPhp 将資料庫模型的增、删、改操作寫入日志

Thinkphp中的模型可以對資料庫字段進行驗證規則的設定和設定一些字段的預設值(比如字段為目前時間)以及在操作資料時的的一些回調方法等

基本上每一個模型都需要設定一些驗證規則和字段預設值的設定,而大部分都存在着重複的工作

特别是像需要将資料庫操作記錄到日志系統的,這就導緻我們需要在每個模型中反複處理

針對此問題我定義一個父類模型,是以模型都繼承自此類即可解決以上兩個問題

父類就完成了以下兩件工作:

  1. 記錄增、删、改等操作到日志系統
  2. 定義一些大部分資料庫都需要驗證的規則(子類可覆寫或自定義)或者需要自動生成的字段(如每個資料庫都有一個記錄目前時間的字段create_time)
<?php
/* * 
 * 公共模型
 */
namespace Common\Model;
use Think\Model;
class CommonModel extends Model {
     /**
     * @Author:      HTL
     * @Email:       [email protected]
     * @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:       [email protected]
     * @DateTime:    2016-04-08 12:08:38
     * @Description: 所有繼承的子類字段create_time自動生成目前時間
     */
    protected $_auto = array (
        array ('create_time', 'mGetDate', 1, 'callback' ),    // 增加的時候調用回調函數
    );
     /**
     * @Author:      HTL
     * @Email:       [email protected]
     * @DateTime:    2016-04-08 15:52:40
     * @Description: 傳回該類的自動驗證資訊,用于在子類中合并該驗證資訊(不能在子類中定義此$_validate屬性否則會被覆寫,如果不需要在子類中合并則可以可忽略此方法)
     */
    protected function get_validate()
    {
        return $this->_validate;
    }
    /**
    * @Author:      HTL
    * @Email:       [email protected]
    * @DateTime:    2016-04-08 12:06:03
    * @Description: 擷取目前時間
    */
    protected function mGetDate() {
        return date ( 'Y-m-d H:i:s' );
    }
   
     /**
     * @Author:      HTL
     * @Email:       [email protected]
     * @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:       [email protected]
     * @DateTime:    2016-04-08 10:50:27
     * @Description: 插入成功後的回調方法
     */
    protected function _after_insert($data,$options) {
        $this->after_write("insert",$data,$options);
    }
   
    /**
    * @Author:      HTL
    * @Email:       [email protected]
    * @DateTime:    2016-04-08 11:56:12
    * @Description: 删除成功後的回調方法
    */
    protected function _after_delete($data,$options) {
        $this->after_write("delete",$data,$options);
    }
     /**
     * @Author:      HTL
     * @Email:       [email protected]
     * @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:       [email protected]
     * @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:       [email protected]
 * @DateTime:    2016-04-08 12:03:57
 * @Description: 基礎價格Model
 */
namespace Common\Model;
use Common\Model\CommonModel;
class PriceModel extends CommonModel
{	
    /**
    * @Author:      HTL
    * @Email:       [email protected]
    * @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`)
)
      

參考:

TP3.2開發手冊 自動驗證

TP3.1開發手冊 模型擴充

From WizNote