00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 global $_ADODB_ACTIVE_DBS;
00020 global $ADODB_ACTIVE_CACHESECS;
00021
00022
00023 $_ADODB_ACTIVE_DBS = array();
00024
00025
00026 class ADODB_Active_DB {
00027 var $db;
00028 var $tables;
00029 }
00030
00031 class ADODB_Active_Table {
00032 var $name;
00033 var $flds;
00034 var $keys;
00035 var $_created;
00036 }
00037
00038
00039 function ADODB_SetDatabaseAdapter(&$db)
00040 {
00041 global $_ADODB_ACTIVE_DBS;
00042
00043 foreach($_ADODB_ACTIVE_DBS as $k => $d) {
00044 if (PHP_VERSION >= 5) {
00045 if ($d->db == $db) return $k;
00046 } else {
00047 if ($d->db->_connectionID == $db->_connectionID && $db->database == $d->db->database)
00048 return $k;
00049 }
00050 }
00051
00052 $obj = new ADODB_Active_DB();
00053 $obj->db =& $db;
00054 $obj->tables = array();
00055
00056 $_ADODB_ACTIVE_DBS[] = $obj;
00057
00058 return sizeof($_ADODB_ACTIVE_DBS)-1;
00059 }
00060
00061
00062 class ADODB_Active_Record {
00063 var $_dbat;
00064 var $_table;
00065 var $_tableat;
00066 var $_where;
00067 var $_saved = false;
00068 var $_lasterr = false;
00069 var $_original = false;
00070
00071
00072 function SetDatabaseAdapter(&$db)
00073 {
00074 return ADODB_SetDatabaseAdapter($db);
00075 }
00076
00077
00078 function ADODB_Active_Record($table = false, $pkeyarr=false, $db=false)
00079 {
00080 ADODB_Active_Record::__construct($table,$pkeyarr,$db);
00081 }
00082
00083
00084 function __construct($table = false, $pkeyarr=false, $db=false)
00085 {
00086 global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
00087
00088 if ($db == false && is_object($pkeyarr)) {
00089 $db = $pkeyarr;
00090 $pkeyarr = false;
00091 }
00092
00093 if (!$table) {
00094 if (!empty($this->_table)) $table = $this->_table;
00095 else $table = $this->_pluralize(get_class($this));
00096 }
00097 if ($db) {
00098 $this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
00099 } else
00100 $this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1;
00101
00102
00103 if ($this->_dbat < 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
00104
00105 $this->_table = $table;
00106 $this->_tableat = $table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
00107 $this->UpdateActiveTable($pkeyarr);
00108 }
00109
00110 function __wakeup()
00111 {
00112 $class = get_class($this);
00113 new $class;
00114 }
00115
00116 function _pluralize($table)
00117 {
00118 $ut = strtoupper($table);
00119 $len = strlen($table);
00120 $lastc = $ut[$len-1];
00121 $lastc2 = substr($ut,$len-2);
00122 switch ($lastc) {
00123 case 'S':
00124 return $table.'es';
00125 case 'Y':
00126 return substr($table,0,$len-1).'ies';
00127 case 'X':
00128 return $table.'es';
00129 case 'H':
00130 if ($lastc2 == 'CH' || $lastc2 == 'SH')
00131 return $table.'es';
00132 default:
00133 return $table.'s';
00134 }
00135 }
00136
00138
00139
00140 function UpdateActiveTable($pkeys=false,$forceUpdate=false)
00141 {
00142 global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
00143
00144 $activedb =& $_ADODB_ACTIVE_DBS[$this->_dbat];
00145
00146 $table = $this->_table;
00147 $tables = $activedb->tables;
00148 $tableat = $this->_tableat;
00149 if (!$forceUpdate && !empty($tables[$tableat])) {
00150 $tobj =& $tables[$tableat];
00151 foreach($tobj->flds as $name => $fld)
00152 $this->$name = null;
00153 return;
00154 }
00155
00156 $db =& $activedb->db;
00157 $fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
00158 if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
00159 $fp = fopen($fname,'r');
00160 @flock($fp, LOCK_SH);
00161 $acttab = unserialize(fread($fp,100000));
00162 fclose($fp);
00163 if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) {
00164
00165
00166 $activedb->tables[$table] = $acttab;
00167
00168
00169 return;
00170 } else if ($db->debug) {
00171 ADOConnection::outp("Refreshing cached active record file: $fname");
00172 }
00173 }
00174 $activetab = new ADODB_Active_Table();
00175 $activetab->name = $table;
00176
00177
00178 $cols = $db->MetaColumns($table);
00179 if (!$cols) {
00180 $this->Error("Invalid table name: $table",'UpdateActiveTable');
00181 return false;
00182 }
00183 $fld = reset($cols);
00184 if (!$pkeys) {
00185 if (isset($fld->primary_key)) {
00186 $pkeys = array();
00187 foreach($cols as $name => $fld) {
00188 if (!empty($fld->primary_key)) $pkeys[] = $name;
00189 }
00190 } else
00191 $pkeys = $this->GetPrimaryKeys($db, $table);
00192 }
00193 if (empty($pkeys)) {
00194 $this->Error("No primary key found for table $table",'UpdateActiveTable');
00195 return false;
00196 }
00197
00198 $attr = array();
00199 $keys = array();
00200
00201 switch($ADODB_ASSOC_CASE) {
00202 case 0:
00203 foreach($cols as $name => $fldobj) {
00204 $name = strtolower($name);
00205 $this->$name = null;
00206 $attr[$name] = $fldobj;
00207 }
00208 foreach($pkeys as $k => $name) {
00209 $keys[strtolower($name)] = strtolower($name);
00210 }
00211 break;
00212
00213 case 1:
00214 foreach($cols as $name => $fldobj) {
00215 $name = strtoupper($name);
00216 $this->$name = null;
00217 $attr[$name] = $fldobj;
00218 }
00219
00220 foreach($pkeys as $k => $name) {
00221 $keys[strtoupper($name)] = strtoupper($name);
00222 }
00223 break;
00224 default:
00225 foreach($cols as $name => $fldobj) {
00226 $name = ($fldobj->$name);
00227 $this->$name = null;
00228 $attr[$name] = $fldobj;
00229 }
00230 foreach($pkeys as $k => $name) {
00231 $keys[$name] = $cols[$name]->name;
00232 }
00233 break;
00234 }
00235
00236 $activetab->keys = $keys;
00237 $activetab->flds = $attr;
00238
00239 if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) {
00240 $activetab->_created = time();
00241 $s = serialize($activetab);
00242 if (!function_exists('adodb_write_file')) include(ADODB_DIR.'/adodb-csvlib.inc.php');
00243 adodb_write_file($fname,$s);
00244 }
00245 $activedb->tables[$table] = $activetab;
00246 }
00247
00248 function GetPrimaryKeys(&$db, $table)
00249 {
00250 return $db->MetaPrimaryKeys($table);
00251 }
00252
00253
00254 function Error($err,$fn)
00255 {
00256 global $_ADODB_ACTIVE_DBS;
00257
00258 $fn = get_class($this).'::'.$fn;
00259 $this->_lasterr = $fn.': '.$err;
00260
00261 if ($this->_dbat < 0) $db = false;
00262 else {
00263 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00264 $db =& $activedb->db;
00265 }
00266
00267 if (function_exists('adodb_throw')) {
00268 if (!$db) adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
00269 else adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
00270 } else
00271 if (!$db || $db->debug) ADOConnection::outp($this->_lasterr);
00272
00273 }
00274
00275
00276 function ErrorMsg()
00277 {
00278 if (!function_exists('adodb_throw')) {
00279 if ($this->_dbat < 0) $db = false;
00280 else $db = $this->DB();
00281
00282
00283 if ($db && $db->ErrorMsg()) return $db->ErrorMsg();
00284 }
00285 return $this->_lasterr;
00286 }
00287
00288
00289 function &DB()
00290 {
00291 global $_ADODB_ACTIVE_DBS;
00292
00293 if ($this->_dbat < 0) {
00294 $false = false;
00295 $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
00296 return $false;
00297 }
00298 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00299 $db =& $activedb->db;
00300 return $db;
00301 }
00302
00303
00304 function &TableInfo()
00305 {
00306 global $_ADODB_ACTIVE_DBS;
00307
00308 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00309 $table =& $activedb->tables[$this->_tableat];
00310 return $table;
00311 }
00312
00313
00314 function Set(&$row)
00315 {
00316 $db =& $this->DB();
00317
00318 if (!$row) {
00319 $this->_saved = false;
00320 return false;
00321 }
00322
00323 $this->_saved = true;
00324
00325 $table =& $this->TableInfo();
00326 if (sizeof($table->flds) != sizeof($row)) {
00327 $this->Error("Table structure of $this->_table has changed","Load");
00328 return false;
00329 }
00330
00331 $cnt = 0;
00332 foreach($table->flds as $name=>$fld) {
00333 $this->$name = $row[$cnt];
00334 $cnt += 1;
00335 }
00336 $this->_original = $row;
00337 return true;
00338 }
00339
00340
00341 function LastInsertID(&$db,$fieldname)
00342 {
00343 if ($db->hasInsertID)
00344 $val = $db->Insert_ID($this->_table,$fieldname);
00345 else
00346 $val = false;
00347
00348 if (is_null($val) || $val === false) {
00349
00350 return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
00351 }
00352 return $val;
00353 }
00354
00355
00356 function doquote(&$db, $val,$t)
00357 {
00358 switch($t) {
00359 case 'D':
00360 case 'T':
00361 if (empty($val)) return 'null';
00362
00363 case 'C':
00364 case 'X':
00365 if (is_null($val)) return 'null';
00366
00367 if (strncmp($val,"'",1) != 0 && substr($val,strlen($val)-1,1) != "'") {
00368 return $db->qstr($val);
00369 break;
00370 }
00371 default:
00372 return $val;
00373 break;
00374 }
00375 }
00376
00377
00378 function GenWhere(&$db, &$table)
00379 {
00380 $keys = $table->keys;
00381 $parr = array();
00382
00383 foreach($keys as $k) {
00384 $f = $table->flds[$k];
00385 if ($f) {
00386 $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
00387 }
00388 }
00389 return implode(' and ', $parr);
00390 }
00391
00392
00393
00394
00395 function Load($where,$bindarr=false)
00396 {
00397 $db =& $this->DB(); if (!$db) return false;
00398 $this->_where = $where;
00399
00400 $save = $db->SetFetchMode(ADODB_FETCH_NUM);
00401 $row = $db->GetRow("select * from ".$this->_table.' WHERE '.$where,$bindarr);
00402 $db->SetFetchMode($save);
00403
00404 return $this->Set($row);
00405 }
00406
00407
00408 function Save()
00409 {
00410 if ($this->_saved) $ok = $this->Update();
00411 else $ok = $this->Insert();
00412
00413 return $ok;
00414 }
00415
00416
00417 function Insert()
00418 {
00419 $db =& $this->DB(); if (!$db) return false;
00420 $cnt = 0;
00421 $table =& $this->TableInfo();
00422
00423 $valarr = array();
00424 $names = array();
00425 $valstr = array();
00426
00427 foreach($table->flds as $name=>$fld) {
00428 $val = $this->$name;
00429 if(!is_null($val) || !array_key_exists($name, $table->keys)) {
00430 $valarr[] = $val;
00431 $names[] = $name;
00432 $valstr[] = $db->Param($cnt);
00433 $cnt += 1;
00434 }
00435 }
00436
00437 if (empty($names)){
00438 foreach($table->flds as $name=>$fld) {
00439 $valarr[] = null;
00440 $names[] = $name;
00441 $valstr[] = $db->Param($cnt);
00442 $cnt += 1;
00443 }
00444 }
00445 $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
00446 $ok = $db->Execute($sql,$valarr);
00447
00448 if ($ok) {
00449 $this->_saved = true;
00450 $autoinc = false;
00451 foreach($table->keys as $k) {
00452 if (is_null($this->$k)) {
00453 $autoinc = true;
00454 break;
00455 }
00456 }
00457 if ($autoinc && sizeof($table->keys) == 1) {
00458 $k = reset($table->keys);
00459 $this->$k = $this->LastInsertID($db,$k);
00460 }
00461 }
00462
00463 $this->_original = $valarr;
00464 return !empty($ok);
00465 }
00466
00467 function Delete()
00468 {
00469 $db =& $this->DB(); if (!$db) return false;
00470 $table =& $this->TableInfo();
00471
00472 $where = $this->GenWhere($db,$table);
00473 $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
00474 $ok = $db->Execute($sql);
00475
00476 return $ok ? true : false;
00477 }
00478
00479
00480 function &Find($whereOrderBy,$bindarr=false,$pkeysArr=false)
00481 {
00482 $db =& $this->DB(); if (!$db || empty($this->_table)) return false;
00483 $arr =& $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr);
00484 return $arr;
00485 }
00486
00487
00488 function Replace()
00489 {
00490 global $ADODB_ASSOC_CASE;
00491
00492 $db =& $this->DB(); if (!$db) return false;
00493 $table =& $this->TableInfo();
00494
00495 $pkey = $table->keys;
00496
00497 foreach($table->flds as $name=>$fld) {
00498 $val = $this->$name;
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509 if (is_null($val) && !empty($fld->auto_increment)) {
00510 continue;
00511 }
00512 $t = $db->MetaType($fld->type);
00513 $arr[$name] = $this->doquote($db,$val,$t);
00514 $valarr[] = $val;
00515 }
00516
00517 if (!is_array($pkey)) $pkey = array($pkey);
00518
00519
00520 if ($ADODB_ASSOC_CASE == 0)
00521 foreach($pkey as $k => $v)
00522 $pkey[$k] = strtolower($v);
00523 elseif ($ADODB_ASSOC_CASE == 0)
00524 foreach($pkey as $k => $v)
00525 $pkey[$k] = strtoupper($v);
00526
00527 $ok = $db->Replace($this->_table,$arr,$pkey);
00528 if ($ok) {
00529 $this->_saved = true;
00530 if ($ok == 2) {
00531 $autoinc = false;
00532 foreach($table->keys as $k) {
00533 if (is_null($this->$k)) {
00534 $autoinc = true;
00535 break;
00536 }
00537 }
00538 if ($autoinc && sizeof($table->keys) == 1) {
00539 $k = reset($table->keys);
00540 $this->$k = $this->LastInsertID($db,$k);
00541 }
00542 }
00543
00544 $this->_original =& $valarr;
00545 }
00546 return $ok;
00547 }
00548
00549
00550 function Update()
00551 {
00552 $db =& $this->DB(); if (!$db) return false;
00553 $table =& $this->TableInfo();
00554
00555 $where = $this->GenWhere($db, $table);
00556
00557 if (!$where) {
00558 $this->error("Where missing for table $table", "Update");
00559 return false;
00560 }
00561 $valarr = array();
00562 $neworig = array();
00563 $pairs = array();
00564 $i = -1;
00565 $cnt = 0;
00566 foreach($table->flds as $name=>$fld) {
00567 $i += 1;
00568 $val = $this->$name;
00569 $neworig[] = $val;
00570
00571 if (isset($table->keys[$name])) {
00572 continue;
00573 }
00574
00575 if (is_null($val)) {
00576 if (isset($fld->not_null) && $fld->not_null) {
00577 if (isset($fld->default_value) && strlen($fld->default_value)) continue;
00578 else {
00579 $this->Error("Cannot set field $name to NULL","Update");
00580 return false;
00581 }
00582 }
00583 }
00584
00585 if (isset($this->_original[$i]) && $val == $this->_original[$i]) {
00586 continue;
00587 }
00588 $valarr[] = $val;
00589 $pairs[] = $name.'='.$db->Param($cnt);
00590 $cnt += 1;
00591 }
00592
00593
00594 if (!$cnt) return -1;
00595 $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
00596 $ok = $db->Execute($sql,$valarr);
00597 if ($ok) {
00598 $this->_original =& $neworig;
00599 return 1;
00600 }
00601 return 0;
00602 }
00603
00604 function GetAttributeNames()
00605 {
00606 $table =& $this->TableInfo();
00607 if (!$table) return false;
00608 return array_keys($table->flds);
00609 }
00610
00611 };
00612
00613 ?>