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 function ErrorNo()
00289 {
00290 if ($this->_dbat < 0) return -9999;
00291 $db = $this->DB();
00292
00293 return (int) $db->ErrorNo();
00294 }
00295
00296
00297
00298 function &DB()
00299 {
00300 global $_ADODB_ACTIVE_DBS;
00301
00302 if ($this->_dbat < 0) {
00303 $false = false;
00304 $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
00305 return $false;
00306 }
00307 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00308 $db =& $activedb->db;
00309 return $db;
00310 }
00311
00312
00313 function &TableInfo()
00314 {
00315 global $_ADODB_ACTIVE_DBS;
00316
00317 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00318 $table =& $activedb->tables[$this->_tableat];
00319 return $table;
00320 }
00321
00322
00323 function Set(&$row)
00324 {
00325 $db =& $this->DB();
00326
00327 if (!$row) {
00328 $this->_saved = false;
00329 return false;
00330 }
00331
00332 $this->_saved = true;
00333
00334 $table =& $this->TableInfo();
00335 if (sizeof($table->flds) != sizeof($row)) {
00336 $this->Error("Table structure of $this->_table has changed","Load");
00337 return false;
00338 }
00339
00340 $cnt = 0;
00341 foreach($table->flds as $name=>$fld) {
00342 $this->$name = $row[$cnt];
00343 $cnt += 1;
00344 }
00345 $this->_original = $row;
00346 return true;
00347 }
00348
00349
00350 function LastInsertID(&$db,$fieldname)
00351 {
00352 if ($db->hasInsertID)
00353 $val = $db->Insert_ID($this->_table,$fieldname);
00354 else
00355 $val = false;
00356
00357 if (is_null($val) || $val === false) {
00358
00359 return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
00360 }
00361 return $val;
00362 }
00363
00364
00365 function doquote(&$db, $val,$t)
00366 {
00367 switch($t) {
00368 case 'D':
00369 case 'T':
00370 if (empty($val)) return 'null';
00371
00372 case 'C':
00373 case 'X':
00374 if (is_null($val)) return 'null';
00375
00376 if (strncmp($val,"'",1) != 0 && substr($val,strlen($val)-1,1) != "'") {
00377 return $db->qstr($val);
00378 break;
00379 }
00380 default:
00381 return $val;
00382 break;
00383 }
00384 }
00385
00386
00387 function GenWhere(&$db, &$table)
00388 {
00389 $keys = $table->keys;
00390 $parr = array();
00391
00392 foreach($keys as $k) {
00393 $f = $table->flds[$k];
00394 if ($f) {
00395 $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
00396 }
00397 }
00398 return implode(' and ', $parr);
00399 }
00400
00401
00402
00403
00404 function Load($where,$bindarr=false)
00405 {
00406 $db =& $this->DB(); if (!$db) return false;
00407 $this->_where = $where;
00408
00409 $save = $db->SetFetchMode(ADODB_FETCH_NUM);
00410 $row = $db->GetRow("select * from ".$this->_table.' WHERE '.$where,$bindarr);
00411 $db->SetFetchMode($save);
00412
00413 return $this->Set($row);
00414 }
00415
00416
00417 function Save()
00418 {
00419 if ($this->_saved) $ok = $this->Update();
00420 else $ok = $this->Insert();
00421
00422 return $ok;
00423 }
00424
00425
00426 function Insert()
00427 {
00428 $db =& $this->DB(); if (!$db) return false;
00429 $cnt = 0;
00430 $table =& $this->TableInfo();
00431
00432 $valarr = array();
00433 $names = array();
00434 $valstr = array();
00435
00436 foreach($table->flds as $name=>$fld) {
00437 $val = $this->$name;
00438 if(!is_null($val) || !array_key_exists($name, $table->keys)) {
00439 $valarr[] = $val;
00440 $names[] = $name;
00441 $valstr[] = $db->Param($cnt);
00442 $cnt += 1;
00443 }
00444 }
00445
00446 if (empty($names)){
00447 foreach($table->flds as $name=>$fld) {
00448 $valarr[] = null;
00449 $names[] = $name;
00450 $valstr[] = $db->Param($cnt);
00451 $cnt += 1;
00452 }
00453 }
00454 $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
00455 $ok = $db->Execute($sql,$valarr);
00456
00457 if ($ok) {
00458 $this->_saved = true;
00459 $autoinc = false;
00460 foreach($table->keys as $k) {
00461 if (is_null($this->$k)) {
00462 $autoinc = true;
00463 break;
00464 }
00465 }
00466 if ($autoinc && sizeof($table->keys) == 1) {
00467 $k = reset($table->keys);
00468 $this->$k = $this->LastInsertID($db,$k);
00469 }
00470 }
00471
00472 $this->_original = $valarr;
00473 return !empty($ok);
00474 }
00475
00476 function Delete()
00477 {
00478 $db =& $this->DB(); if (!$db) return false;
00479 $table =& $this->TableInfo();
00480
00481 $where = $this->GenWhere($db,$table);
00482 $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
00483 $ok = $db->Execute($sql);
00484
00485 return $ok ? true : false;
00486 }
00487
00488
00489 function &Find($whereOrderBy,$bindarr=false,$pkeysArr=false)
00490 {
00491 $db =& $this->DB(); if (!$db || empty($this->_table)) return false;
00492 $arr =& $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr);
00493 return $arr;
00494 }
00495
00496
00497 function Replace()
00498 {
00499 global $ADODB_ASSOC_CASE;
00500
00501 $db =& $this->DB(); if (!$db) return false;
00502 $table =& $this->TableInfo();
00503
00504 $pkey = $table->keys;
00505
00506 foreach($table->flds as $name=>$fld) {
00507 $val = $this->$name;
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518 if (is_null($val) && !empty($fld->auto_increment)) {
00519 continue;
00520 }
00521 $t = $db->MetaType($fld->type);
00522 $arr[$name] = $this->doquote($db,$val,$t);
00523 $valarr[] = $val;
00524 }
00525
00526 if (!is_array($pkey)) $pkey = array($pkey);
00527
00528
00529 if ($ADODB_ASSOC_CASE == 0)
00530 foreach($pkey as $k => $v)
00531 $pkey[$k] = strtolower($v);
00532 elseif ($ADODB_ASSOC_CASE == 0)
00533 foreach($pkey as $k => $v)
00534 $pkey[$k] = strtoupper($v);
00535
00536 $ok = $db->Replace($this->_table,$arr,$pkey);
00537 if ($ok) {
00538 $this->_saved = true;
00539 if ($ok == 2) {
00540 $autoinc = false;
00541 foreach($table->keys as $k) {
00542 if (is_null($this->$k)) {
00543 $autoinc = true;
00544 break;
00545 }
00546 }
00547 if ($autoinc && sizeof($table->keys) == 1) {
00548 $k = reset($table->keys);
00549 $this->$k = $this->LastInsertID($db,$k);
00550 }
00551 }
00552
00553 $this->_original =& $valarr;
00554 }
00555 return $ok;
00556 }
00557
00558
00559 function Update()
00560 {
00561 $db =& $this->DB(); if (!$db) return false;
00562 $table =& $this->TableInfo();
00563
00564 $where = $this->GenWhere($db, $table);
00565
00566 if (!$where) {
00567 $this->error("Where missing for table $table", "Update");
00568 return false;
00569 }
00570 $valarr = array();
00571 $neworig = array();
00572 $pairs = array();
00573 $i = -1;
00574 $cnt = 0;
00575 foreach($table->flds as $name=>$fld) {
00576 $i += 1;
00577 $val = $this->$name;
00578 $neworig[] = $val;
00579
00580 if (isset($table->keys[$name])) {
00581 continue;
00582 }
00583
00584 if (is_null($val)) {
00585 if (isset($fld->not_null) && $fld->not_null) {
00586 if (isset($fld->default_value) && strlen($fld->default_value)) continue;
00587 else {
00588 $this->Error("Cannot set field $name to NULL","Update");
00589 return false;
00590 }
00591 }
00592 }
00593
00594 if (isset($this->_original[$i]) && $val == $this->_original[$i]) {
00595 continue;
00596 }
00597 $valarr[] = $val;
00598 $pairs[] = $name.'='.$db->Param($cnt);
00599 $cnt += 1;
00600 }
00601
00602
00603 if (!$cnt) return -1;
00604 $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
00605 $ok = $db->Execute($sql,$valarr);
00606 if ($ok) {
00607 $this->_original =& $neworig;
00608 return 1;
00609 }
00610 return 0;
00611 }
00612
00613 function GetAttributeNames()
00614 {
00615 $table =& $this->TableInfo();
00616 if (!$table) return false;
00617 return array_keys($table->flds);
00618 }
00619
00620 };
00621
00622 ?>