Subversion Repositories svnkaklik

Rev

Blame | Last modification | View Log | Download

<?php
/*

@version V4.80 8 Mar 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
  Latest version is available at http://adodb.sourceforge.net
 
  Released under both BSD license and Lesser GPL library license. 
  Whenever there is any discrepancy between the two licenses, 
  the BSD license will take precedence.
  
  Active Record implementation. Superset of Zend Framework's.
  
  Version 0.02
*/

global $_ADODB_ACTIVE_DBS;

// array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat
$_ADODB_ACTIVE_DBS = array();


class ADODB_Active_DB {
        var $db; // ADOConnection
        var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename
}

class ADODB_Active_Table {
        var $name; // table name
        var $flds; // assoc array of adofieldobjs, indexed by fieldname
        var $keys; // assoc array of primary keys, indexed by fieldname
}

// returns index into $_ADODB_ACTIVE_DBS
function ADODB_SetDatabaseAdapter(&$db)
{
        global $_ADODB_ACTIVE_DBS;
        
                foreach($_ADODB_ACTIVE_DBS as $k => $d) {
                        if ($d->db == $db) return $k;
                }
                
                $obj = new ADODB_Active_DB();
                $obj->db =& $db;
                $obj->tables = array();
                
                $_ADODB_ACTIVE_DBS[] = $obj;
                
                return sizeof($_ADODB_ACTIVE_DBS)-1;
}

class ADODB_Active_Record {
        var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
        var $_table; // tablename
        var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
        var $_where; // where clause set in Load()
        var $_saved = false; // indicates whether data is already inserted.
        var $_lasterr = false; // last error message
        
        // should be static
        function SetDatabaseAdapter(&$db) 
        {
                return ADODB_SetDatabaseAdapter($db);
        }
        
        // php4 constructor
        function ADODB_Active_Record($table = false, $pkeyarr=false, $db=false)
        {
                ADODB_Active_Record::__construct($table,$pkeyarr,$db);
        }
        
        // php5 constructor
        function __construct($table = false, $pkeyarr=false, $db=false)
        {
        global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
        
                if ($db == false && is_object($pkeyarr)) {
                        $db = $pkeyarr;
                        $pkeyarr = false;
                }
                
                if (!$table) $table = $this->_pluralize(get_class($this));
                
                if ($db) {
                        $this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
                } else
                        $this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1;
                
                
                if ($this->_dbat < 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
                
                $this->_table = $table;
                $this->_tableat = $table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
                $this->UpdateActiveTable($pkeyarr);
        }
        
        function _pluralize($table)
        {
                $ut = strtoupper($table);
                $len = strlen($table);
                $lastc = $ut[$len-1];
                $lastc2 = substr($ut,$len-2);
                switch ($lastc) {
                case 'S':
                        return $table.'es';     
                case 'Y':
                        return substr($table,0,$len-1).'ies';
                case 'X':       
                        return $table.'es';
                case 'H': 
                        if ($lastc2 == 'CH' || $lastc2 == 'SH')
                                return $table.'es';
                default:
                        return $table.'s';
                }
        }
        
        //////////////////////////////////
        
        // update metadata
        function UpdateActiveTable($pkeys=false,$forceUpdate=false)
        {
        global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
        
                $activedb =& $_ADODB_ACTIVE_DBS[$this->_dbat];

                $table = $this->_table;
                $tables = $activedb->tables;
                $tableat = $this->_tableat;
                if (!$forceUpdate && !empty($tables[$tableat])) {
                        $tobj =& $tables[$tableat];
                        foreach($tobj->flds as $name => $fld) 
                                $this->$name = null;
                        return;
                }
                
                $activetab = new ADODB_Active_Table();
                $activetab->name = $table;
                
                $db =& $activedb->db;
                
                $cols = $db->MetaColumns($table);
                if (!$cols) {
                        $this->Error("Invalid table name: $table",'UpdateActiveTable'); 
                        return false;
                }
                $fld = reset($cols);
                if (!$pkeys) {
                        if (isset($fld->primary_key)) {
                                $pkeys = array();
                                foreach($cols as $name => $fld) {
                                        if (!empty($fld->primary_key)) $pkeys[] = $name;
                                }
                        } else  
                                $pkeys = $this->GetPrimaryKeys($db, $table);
                }
                if (empty($pkeys)) {
                        $this->Error("No primary key found for table $table",'UpdateActiveTable');
                        return false;
                }
                
                $attr = array();
                $keys = array();
                
                switch($ADODB_ASSOC_CASE) {
                case 0:
                        foreach($cols as $name => $fldobj) {
                                $name = strtolower($name);
                                $this->$name = null;
                                $attr[$name] = $fldobj;
                        }
                        foreach($pkeys as $k => $name) {
                                $keys[strtolower($name)] = strtolower($name);
                        }
                        break;
                        
                case 1: 
                        foreach($cols as $name => $fldobj) {
                                $name = strtoupper($name);
                                $this->$name = null;
                                $attr[$name] = $fldobj;
                        }
                        
                        foreach($pkeys as $k => $name) {
                                $keys[strtoupper($name)] = strtoupper($name);
                        }
                        break;
                default:
                        foreach($cols as $name => $fldobj) {
                                $name = ($name);
                                $this->$name = null;
                                $attr[$name] = $fldobj;
                        }
                        foreach($pkeys as $k => $name) {
                                $keys[$name] = ($name);
                        }
                        break;
                }
                
                $activetab->keys = $keys;
                $activetab->flds = $attr;
                $activedb->tables[$table] = $activetab;
        }
        
        function GetPrimaryKeys(&$db, $table)
        {
                return $db->MetaPrimaryKeys($table);
        }
        
        // error handler for both PHP4+5. 
        function Error($err,$fn)
        {
        global $_ADODB_ACTIVE_DBS;
        
                $fn = get_class($this).'::'.$fn;
                $this->_lasterr = $fn.': '.$err;
                
                if ($this->_dbat < 0) $db = false;
                else {
                        $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
                        $db =& $activedb->db;
                }
                
                if (function_exists('adodb_throw')) {   
                        if (!$db) adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
                        else adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
                } else
                        if (!$db || $db->debug) ADOConnection::outp($this->_lasterr);
                
        }
        
        // return last error message
        function ErrorMsg()
        {
                if (!function_exists('adodb_throw')) {
                        if ($this->_dbat < 0) $db = false;
                        else $db = $this->DB();
                
                        // last error could be database error too
                        if ($db && $db->ErrorMsg()) return $db->ErrorMsg();
                }
                return $this->_lasterr;
        }
        
        // retrieve ADOConnection from _ADODB_Active_DBs
        function &DB()
        {
        global $_ADODB_ACTIVE_DBS;
        
                if ($this->_dbat < 0) {
                        $false = false;
                        $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
                        return $false;
                }
                $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
                $db =& $activedb->db;
                return $db;
        }
        
        // retrieve ADODB_Active_Table
        function &TableInfo()
        {
        global $_ADODB_ACTIVE_DBS;
        
                $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
                $table =& $activedb->tables[$this->_tableat];
                return $table;
        }
        
        // set a numeric array (using natural table field ordering) as object properties
        function Set(&$row)
        {
                $db =& $this->DB();
                
                if (!$row) {
                        $this->_saved = false;          
                        return false;
                }
                
                $this->_saved = true;
                
                $table =& $this->TableInfo();
                if (sizeof($table->flds) != sizeof($row)) {
                        $this->Error("Table structure of $this->_table has changed","Load");
                        return false;
                }
                
                $cnt = 0;
                foreach($table->flds as $name=>$fld) {
                        $this->$name = $row[$cnt];
                        $cnt += 1;
                }
                #$this->_original =& $row;
                return true;
        }
        
        // get last inserted id for INSERT
        function LastInsertID(&$db,$fieldname)
        {
                if ($db->hasInsertID)
                        $val = $db->Insert_ID($this->_table,$fieldname);
                else
                        $val = false;
                        
                if (is_null($val) || $val === false) {
                        // this might not work reliably in multi-user environment
                        return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
                }
                return $val;
        }
        
        // quote data in where clause
        function doquote(&$db, $val,$t)
        {
                switch($t) {
                case 'D':
                case 'T':
                        if (empty($val)) return 'null';
                        
                case 'C':
                case 'X':
                        if (is_null($val)) return 'null';
                        
                        if (strncmp($val,"'",1) != 0 && substr($val,strlen($val)-1,1) != "'") { 
                                return $db->qstr($val);
                                break;
                        }
                default:
                        return $val;
                        break;
                }
        }
        
        // generate where clause for an UPDATE/SELECT
        function GenWhere(&$db, &$table)
        {
                $keys = $table->keys;
                $parr = array();
                
                foreach($keys as $k) {
                        $f = $table->flds[$k];
                        if ($f) {
                                $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
                        }
                }
                return implode(' and ', $parr);
        }
        
        
        //------------------------------------------------------------ Public functions below
        
        function Load($where,$bindarr=false)
        {
                $db =& $this->DB(); if (!$db) return false;
                $this->_where = $where;
                
                $save = $db->SetFetchMode(ADODB_FETCH_NUM);
                $row = $db->GetRow("select * from ".$this->_table.' WHERE '.$where,$bindarr);
                $db->SetFetchMode($save);
                
                return $this->Set($row);
        }
        
        // false on error
        function Save()
        {
                if ($this->_saved) $ok = $this->Update();
                else $ok = $this->Insert();
                
                return $ok;
        }
        
        // false on error
        function Insert()
        {
                $db =& $this->DB(); if (!$db) return false;
                $cnt = 0;
                $table =& $this->TableInfo();

                foreach($table->flds as $name=>$fld) {
                        $val = $this->$name;
                        /*
                        if (is_null($val)) {
                                if (isset($fld->not_null) && $fld->not_null) {
                                        if (isset($fld->default_value) && strlen($fld->default_value)) continue;
                                        else $this->Error("Cannot insert null into $name","Insert");
                                }
                        }*/
                        
                        $valarr[] = $val;
                        $names[] = $name;
                        $valstr[] = $db->Param($cnt);
                        $cnt += 1;
                }
                
                $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
                $ok = $db->Execute($sql,$valarr);
                
                if ($ok) {
                        $this->_saved = true;
                        $autoinc = false;
                        foreach($table->keys as $k) {
                                if (is_null($this->$k)) {
                                        $autoinc = true;
                                        break;
                                }
                        }
                        if ($autoinc && sizeof($table->keys) == 1) {
                                $k = reset($table->keys);
                                $this->$k = $this->LastInsertID($db,$k);
                        }
                }
                
                #$this->_original =& $valarr;
                return !empty($ok);
        }
        
        function Delete()
        {
                $db =& $this->DB(); if (!$db) return false;
                $table =& $this->TableInfo();
                
                $where = $this->GenWhere($db,$table);
                $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
                $db->Execute($sql);
        }
        
        
        // returns 0 on error, 1 on update, 2 on insert
        function Replace()
        {
        global $ADODB_ASSOC_CASE;
                
                $db =& $this->DB(); if (!$db) return false;
                $table =& $this->TableInfo();
                
                $pkey = $table->keys;
                
                foreach($table->flds as $name=>$fld) {
                        $val = $this->$name;
                        /*
                        if (is_null($val)) {
                                if (isset($fld->not_null) && $fld->not_null) {
                                        if (isset($fld->default_value) && strlen($fld->default_value)) continue;
                                        else {
                                                $this->Error("Cannot update null into $name","Replace");
                                                return false;
                                        }
                                }
                        }*/
                        $t = $db->MetaType($fld->type);
                        $arr[$name] = $this->doquote($db,$val,$t);
                        $valarr[] = $val;
                }
                
                if (!is_array($pkey)) $pkey = array($pkey);
                
                
                if ($ADODB_ASSOC_CASE == 0) 
                        foreach($pkey as $k => $v)
                                $pkey[$k] = strtolower($v);
                elseif ($ADODB_ASSOC_CASE == 0) 
                        foreach($pkey as $k => $v)
                                $pkey[$k] = strtoupper($v);
                                
                $ok = $db->Replace($this->_table,$arr,$pkey);
                if ($ok) {
                        $this->_saved = true; // 1= update 2=insert
                        if ($ok == 2) {
                                $autoinc = false;
                                foreach($table->keys as $k) {
                                        if (is_null($this->$k)) {
                                                $autoinc = true;
                                                break;
                                        }
                                }
                                if ($autoinc && sizeof($table->keys) == 1) {
                                        $k = reset($table->keys);
                                        $this->$k = $this->LastInsertID($db,$k);
                                }
                        }
                        
                        #$this->_original =& $valarr;
                } 
                return $ok;
        }

        // returns false on error
        function Update()
        {
                $db =& $this->DB(); if (!$db) return false;
                $table =& $this->TableInfo();
                
                $where = $this->GenWhere($db, $table);
                
                if (!$where) {
                        $this->error("Where missing for table $table", "Update");
                        return false;
                }
                $cnt = 0;
                foreach($table->flds as $name=>$fld) {
                        if (isset($table->keys[$name])) continue;
                        
                        $val = $this->$name;
                        
                        if (is_null($val)) {
                                if (isset($fld->not_null) && $fld->not_null) {
                                        if (isset($fld->default_value) && strlen($fld->default_value)) continue;
                                        else {
                                                $this->Error("Cannot set field $name to NULL","Update");
                                                return false;
                                        }
                                }
                        }
                        $valarr[] = $val;
                        $pairs[] = $name.'='.$db->Param($cnt);
                        $cnt += 1;
                }
                
                #$this->_original =& $valarr;
                
                $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
                $ok = $db->Execute($sql,$valarr);
                
                return !empty($ok);
        }
        
        function GetAttributeNames()
        {
                $table =& $this->TableInfo();
                if (!$table) return false;
                return array_keys($table->flds);
        }
        
};

?>