<?php
namespace imcat;

//数据库操作类,加载了外部的数据库驱动类

class glbDBObj{

    public 
$db NULL// 当前数据库操作对象
    
public $config = array();
    public 
$driver '';
    public 
$sql '';//sql语句,主要用于输出构造成的sql语句
    
public $pre '';//表前缀,主要用于在其他地方获取表前缀
    
public $ext '';//表后缀,主要用于在其他地方获取表后缀
    
public $data = array();// 数据信息
    
public $otps = array(); // 查询表达式参数
    
static $uobj = array(); //实例化的前数据对象

    
function __construct($config=array()){
        
$this->config = empty($config) ? self::getCfg() : $config;
        
$this->otps['field'] = '*';//默认查询字段
        
$this->driver $this->config['db_driver'];
        
$this->pre $this->config['db_prefix'];//数据表前缀
        
$this->ext $this->config['db_suffix'];//数据表后缀
    
}

    
//连接数据库
    
function connect(){ 
        if(!
is_object($this->db)){ //$this->db不是对象,则连接数据库
            
$file 'db'.ucfirst($this->driver);
            require_once 
DIR_IMCAT."/adpt/dbdrv/{$file}.php";
            
$class "\\imcat\\$file";
            
$this->db = new $class();//连接数据库
            
$this->runTimer();
            
$this->db->connect($this->config);
            
$this->runTimer('connect');
        }
    }

    
//执行时间分析
    
function runTimer($mode=0){
        global 
$_cbase;
        if(!
$mode){
            
$_cbase['run']['qstart'] = microtime(1); //记录Start
            
return;
        }else{
            
$run_one microtime(1)-$_cbase['run']['qstart'];
            
$_cbase['run']['qtime'] += $run_one;
            
$_cbase['run']['query']++;
            
$loger $this->runChkbug($mode);
            if(empty(
$loger)) return;
        }
        
$tpl $_cbase['run']['tplname'];
        if(
$_cbase['debug']['db_sql']=='db'){
            
$info basDebug::bugInfo();
            
$sql basReq::in($this->sql); $used 1000*$run_one$run $_cbase['run']; 
            
$kid basKeyid::kidTemp().$_cbase['run']['query'];
            
$vals "'$kid','$sql','$used','{$info['vp']}','$tpl','','{$run['stamp']}'"
            
$this->db->run("INSERT INTO ".$this->table('logs_dbsql',2)."(kid,`sql`,used,page,tpl,tag,atime)VALUES($vals)"); 
        }elseif(!empty(
$_cbase['debug']['db_sql'])){
            
$fmt $_cbase['debug']['db_sql'];
            
$file date($fmt).".dbsql";
            
basDebug::bugLogs('dbobj',$this->sql,$file,'file');
        }
    }

    function 
runChkbug($mode){
        global 
$_cbase;
        if(!
strpos($_cbase['debug']['db_acts'],$mode)) return 0;
        
$indefine 0;
        foreach(
$_cbase['debug']['db_area'] as $key){
            if(
defined($key)){
                
$indefine 1;
                break;
            }
        }
        return 
$indefine;
    }

    
//回调方法,连贯操作的实现
    
function __call($method$args) {
        
$method strtolower($method);
        if(
in_array($method,array('field','data','where','groups','having','order','limit','cache'))){
            
$this->otps[$method] = $args[0]; //接收数据
            
return $this//返回对象,连贯查询
        
}else{
            
glbError::show($method.':No Found.');
        }
    }
    
    
//设置表,$nofix为true的时候,不加上默认的表前缀
    
function table($table$nofix=false){
        
$full '`'.$this->pre.$table.$this->ext.'`';
        if(
$nofix===2){ 
            return 
$full;
        }elseif(
$nofix){
            
$this->otps['table'] = '`'.$table.'`';
        }else{
            
$this->otps['bare_tab'] = $table;
            
$this->otps['table'] = $full;
        }
        return 
$this;
    }

    
//执行原生sql语句,如果sql是查询语句,返回二维数组
    
function query($sql){ 
        
$this->sql $sql;
        
//判断当前的sql是否是查询语句
        
if(strpos(trim(strtolower($sql)),'select')===0){
            
$this->runTimer();
            
$data $this->db->arr($this->sql);
            
$this->runTimer('qSelect');
            return 
$data;
        }else{ 
//不是查询条件,执行之后,直接返回
            
$query $this->run($this->sql,'qOther');
            return 
$query;
        }
    }

    
//执行sql语句
    
function run($sql$act=''){ 
        global 
$_cbase;
        
$this->sql $sql;
        
$this->runTimer();
        
$re $this->db->run($this->sql);
        
$this->runTimer($act);
        return 
$re;
    }

    
//统计行数
    
function count(){
        
$table $this->otps['table'];//当前表
        
$field 'count(*)';//查询的字段
        
$where $this->_parseCond();//条件
        
$this->sql="SELECT $field FROM $table $where";
        
$this->runTimer();       
        
$re $this->db->val($this->sql);
        
$this->runTimer('count');
        return 
$re;
    }

    
//只查询一条信息,返回一维数组    
    
function find(){
        
$table $this->otps['table'];//当前表
        
$field $this->otps['field'];//查询的字段
        
$this->otps['limit']=1;//限制只查询一条数据
        
$where $this->_parseCond();//条件
        
$this->otps['field']='*';//设置下一次查询时,字段的默认值
        
$this->sql="SELECT $field FROM $table $where";
        
$data = array();
        
$this->runTimer();
        
$data $this->db->row($this->sql);
        
$this->runTimer('find');
        return 
$data;
    }

    
//查询多条信息,返回数组
    
function select(){
        
$table $this->otps['table'];//当前表
        
$field $this->otps['field'];//查询的字段
        
$where $this->_parseCond();//条件
        
$this->otps['field'] = '*';//设置下一次查询时,字段的默认值
        
$this->sql "SELECT $field FROM $table $where";
        
$data = array();
        
$this->runTimer();
        
$data $this->db->arr($this->sql);
        
$this->runTimer('select');
        return 
$data;
    }

    
//插入数据
    
function insert($log='a') {
        
$table $this->otps['table'];//当前表
        
$data $this->_parseData('add',$log);//要插入的数据
        
$this->sql "INSERT INTO $table $data";
        
$this->run($this->sql,'insert');
        if(
$this->db->affRows){
            
$id $this->db->lastID;
            return empty(
$id)?$this->db->affRows:$id;
        }
        return 
false;
    }

    
//替换数据
    
function replace($log='a') {
        
$table $this->otps['table'];//当前表
        
$data $this->_parseData('add',$log);//要插入的数据
        
$this->sql="REPLACE INTO $table $data;
        
$this->run($this->sql,'replace');
        if(
$this->db->affRows){
            return  
$this->db->lastID;
        }
        return 
false;
    }

    
//修改更新
    
function update($log='e'){ 
        
$table $this->otps['table'];//当前表
        
$data $this->_parseData('save',$log);//要更新的数据
        
$where $this->_parseCond();//更新条件
        
if(empty($where)) return false;    //修改条件为空时,则返回false,避免不小心将整个表数据修改了
        
$this->sql "UPDATE $table SET $data $where;
        
$this->run($this->sql,'update');
        return 
$this->db->affRows;
    }

    
//删除
    
function delete(){
        
$table $this->otps['table'];//当前表
        
$where $this->_parseCond();//条件
        
if(empty($where)) return false;    //删除条件为空时,则返回false,避免数据不小心被全部删除
        
$this->sql "DELETE FROM $table $where";
        
$this->run($this->sql,'delete');
        return 
$this->db->affRows;
    }

    
// 取得数据表的字段信息
    
function fields($tab){
        
$tab is_array($tab) ? $tab[0] : $tab;
        
$this->runTimer();
        
$a $this->db->fields("$this->pre$tab$this->ext");
        
$this->runTimer('fields');
        return 
$a;
    }

    
// 取得数据库的表信息
    
function tables($info=0){
        
$this->runTimer();
        
$a $info $this->db->tabinfo() : $this->db->tables();
        
$this->runTimer('tables'); 
        
$tab = array();
        foreach(
$a as $v){ 
            if(
$info){
                
$v['Name'] = str_replace(array("($this->pre","$this->ext)"),'',"({$v['Name']})");
                if((
$this->pre && strstr($v['Name'],'(')) || ($this->ext && strpos($v['Name'],')'))) continue;
                
$tab[] = $v;
            }else{
                
$table str_replace(array("($this->pre","$this->ext)"),'',"($v)");
                if((
$this->pre && strstr($table,'(')) || ($this->ext && strpos($table,')'))) continue;
                
$tab[] = $table;
            }
        }
        return 
$tab;
    }

    
// 取得创建表sql
    
function create($tab){
        
$this->runTimer();
        
$a $this->db->create("{$this->pre}$tab{$this->ext}");
        
$this->runTimer('create');
        return 
$a;
    }
    
//返回sql语句
    
function getSql(){
        return 
$this->sql;
    }
    
//返回quoteSql语句
    
function quoteSql($sql){
        return 
$this->db->quoteSql($sql);
    }

    
//解析数据,添加数据时$type=add,更新数据时$type=save
    
public function _parseData($type$log='') {
        if(empty(
$this->otps['data'])){
            die(
"Error, Null-Data!");
        }
        
//如果数据是字符串,直接返回
        
if(is_string($this->otps['data'])){
            return 
$this->otps['data'];
        }
        
$arfix = array('advs_','base','bext','coms_','docs_','types','users');
        if(
$log && in_array(substr($this->otps['bare_tab'],0,5), $arfix)){
            
$dlog basSql::logData($log);
            
$this->otps['data'] = array_merge($dlog$this->otps['data']);
        }
        switch(
$type){
            case 
'add':
                
$data=array();
                
$data['key'] = "";
                
$data['value'] = "";
                foreach(
$this->otps['data'] as $key=>$value){
                    
$data['key'] .= "`$key`,";
                    
$data['value'] .= "'$value',";
                }
                
$data['key'] = substr($data['key'], 0,-1);//去除后面的逗号
                
$data['value'] = substr($data['value'], 0,-1);//去除后面的逗号
                
return " (".$data['key'].") VALUES (".$data['value'].") ";
                break;
            case 
'save':
                
$data "";
                foreach(
$this->otps['data'] as $key=>$value){
                    
$data .= "`$key`='$value',";
                }
                
$data substr($data0,-1); //去除后面的逗号
                
return $data;
                break;
            default:
                return 
false;
        }        
    }

    
//解析sql查询条件
    
public function _parseCond() {
        
$cond ""
        
//解析where()方法
        
if(!empty($this->otps['where'])){
            
$cond " WHERE ";
            if(
is_string($this->otps['where'])){
                
$cond .= $this->otps['where'];
            }else if(
is_array($this->otps['where'])){
                    foreach(
$this->otps['where'] as $key=>$value){
                         
$cond .= " `$key`='$value' AND ";
                    }
                    
$cond substr($cond0,-4);
            }else{
                
$cond "";
            }
            unset(
$this->otps['where']);//清空$this->otps['where']数据
        
}
        if(!empty(
$this->otps['groups'])&&is_string($this->otps['groups'])){
            
$cond .= " GROUP BY ".$this->otps['groups'];
            unset(
$this->otps['groups']);
        }
        if(!empty(
$this->otps['having'])&&is_string($this->otps['having'])){
            
$cond .= " HAVING ".$this->otps['having'];
            unset(
$this->otps['having']);
        }
        if(!empty(
$this->otps['order'])&&is_string($this->otps['order'])){
            
$cond .= " ORDER BY ".$this->otps['order'];
            unset(
$this->otps['order']);
        }
        if(!empty(
$this->otps['limit'])&&(is_string($this->otps['limit'])||is_numeric($this->otps['limit']))){
            
$cond .= " LIMIT ".$this->otps['limit'];
            unset(
$this->otps['limit']);
        }
        if(empty(
$cond))
            return 
"";
        return 
$cond;
    }
    
    
// 
    
static function dbObj($config=array(), $catch=0){ 
        
$dbcfg self::getCfg(); 
        if(empty(
$config)){
            
$key 'db0_main';
        }elseif(
is_string($config)){ // `user`
            
$key $config;
            
$config = isset($dbcfg[$key]) ? $dbcfg[$key] : $dbcfg;
            
$key = isset($dbcfg[$key]) ? "db1_$key'db0_main';
        }else{ 
// array()
            
$config array_merge($dbcfg$config);
            
$key 'dba_'.$config['db_host'].'_'.$config['db_name'];
        }
        
$key .= $catch;
        if(empty(
self::$uobj[$key])){
            
$class $catch '\\imcat\\glbDBCache' '\\imcat\\glbDBObj';
            
self::$uobj[$key] = new $class($config); 
            
self::$uobj[$key]->connect($config); 
        }
        return 
self::$uobj[$key];
    }
    
    static function 
getCfg($key=''){
        static 
$dbcfg;
        if(empty(
$dbcfg)){
            require 
DIR_ROOT.'/cfgs/boot/cfg_db.php';
            
$dbcfg $_cfgs;
        }
        return (
$key && isset($dbcfg[$key])) ? $dbcfg[$key] : $dbcfg;
    }

}