summaryrefslogtreecommitdiff
path: root/framework/3rdParty/adodb/ADOdb_Active_Record.php
diff options
context:
space:
mode:
Diffstat (limited to 'framework/3rdParty/adodb/ADOdb_Active_Record.php')
-rw-r--r--framework/3rdParty/adodb/ADOdb_Active_Record.php579
1 files changed, 579 insertions, 0 deletions
diff --git a/framework/3rdParty/adodb/ADOdb_Active_Record.php b/framework/3rdParty/adodb/ADOdb_Active_Record.php
new file mode 100644
index 00000000..a8e2a75b
--- /dev/null
+++ b/framework/3rdParty/adodb/ADOdb_Active_Record.php
@@ -0,0 +1,579 @@
+<?php
+/*
+
+@version V4.81 3 May 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.03
+
+ See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord
+ for info on Ruby on Rails Active Record implementation
+*/
+
+global $_ADODB_ACTIVE_DBS;
+global $ADODB_ACTIVE_CACHESECS; // set to true to enable caching of metadata such as field info
+
+// array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat
+$_ADODB_ACTIVE_DBS = array();
+
+
+class ADODB_Active_DB {
+ public $db; // ADOConnection
+ public $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename
+}
+
+class ADODB_Active_Table {
+ public $name; // table name
+ public $flds; // assoc array of adofieldobjs, indexed by fieldname
+ public $keys; // assoc array of primary keys, indexed by fieldname
+ public $_created; // only used when stored as a cached file
+}
+
+// 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 {
+ private $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
+ private $_table; // tablename
+ private $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
+ private $_where; // where clause set in Load()
+ private $_saved = false; // indicates whether data is already inserted.
+ private $_lasterr = false; // last error message
+ private $_original = false; // the original values loaded or inserted, refreshed on update
+
+ // should be static
+ function SetDatabaseAdapter($db)
+ {
+ return ADODB_SetDatabaseAdapter($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 , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
+
+ $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;
+ }
+
+ $db =& $activedb->db;
+ $fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
+ if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
+ $fp = fopen($fname,'r');
+ @flock($fp, LOCK_SH);
+ $acttab = unserialize(fread($fp,100000));
+ fclose($fp);
+ if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) {
+ // abs(rand()) randomizes deletion, reducing contention to delete/refresh file
+ // ideally, you should cache at least 32 secs
+ $activedb->tables[$table] = $acttab;
+
+ //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname");
+ return;
+ } else if ($db->debug) {
+ ADOConnection::outp("Refreshing cached active record file: $fname");
+ }
+ }
+ $activetab = new ADODB_Active_Table();
+ $activetab->name = $table;
+
+
+ $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;
+
+ if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) {
+ $activetab->_created = time();
+ $s = serialize($activetab);
+ if (!function_exists('adodb_write_file')) include(ADODB_DIR.'/adodb-csvlib.inc.php');
+ adodb_write_file($fname,$s);
+ }
+ $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;
+ }
+ }
+ }*/
+ if (is_null($val) && !empty($fld->auto_increment)) {
+ continue;
+ }
+ $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 0 on error, 1 on update, -1 if no change in data (no update)
+ 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;
+ }
+ $valarr = array();
+ $neworig = array();
+ $pairs = array();
+ $i = -1;
+ $cnt = 0;
+ foreach($table->flds as $name=>$fld) {
+ $i += 1;
+ $val = $this->$name;
+ $neworig[] = $val;
+
+ if (isset($table->keys[$name])) {
+ continue;
+ }
+
+
+ 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;
+ }
+ }
+ }
+
+ if ( $val == $this->_original[$i]) {
+ continue;
+ }
+ $valarr[] = $val;
+ $pairs[] = $name.'='.$db->Param($cnt);
+ $cnt += 1;
+ }
+
+
+ if (!$cnt) return -1;
+ $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
+ $ok = $db->Execute($sql,$valarr);
+ if ($ok) {
+ $this->_original =& $neworig;
+ return 1;
+ }
+ return 0;
+ }
+
+ function GetAttributeNames()
+ {
+ $table =& $this->TableInfo();
+ if (!$table) return false;
+ return array_keys($table->flds);
+ }
+
+};
+
+?> \ No newline at end of file