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