"TYPO3 4.0.1: typo3_src-4.0.1/typo3/sysext/adodb/adodb/adodb-active-record.inc.php Source File", "datetime" => "Sat Dec 2 19:22:24 2006", "date" => "2 Dec 2006", "doxygenversion" => "1.4.6", "projectname" => "TYPO3 4.0.1", "projectnumber" => "4.0.1" ); get_header($doxygen_vars); ?>
00001 <?php 00002 /* 00003 00004 @version V4.90 8 June 2006 (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved. 00005 Latest version is available at http://adodb.sourceforge.net 00006 00007 Released under both BSD license and Lesser GPL library license. 00008 Whenever there is any discrepancy between the two licenses, 00009 the BSD license will take precedence. 00010 00011 Active Record implementation. Superset of Zend Framework's. 00012 00013 Version 0.04 00014 00015 See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord 00016 for info on Ruby on Rails Active Record implementation 00017 */ 00018 00019 global $_ADODB_ACTIVE_DBS; 00020 global $ADODB_ACTIVE_CACHESECS; // set to true to enable caching of metadata such as field info 00021 00022 // array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat 00023 $_ADODB_ACTIVE_DBS = array(); 00024 00025 00026 class ADODB_Active_DB { 00027 var $db; // ADOConnection 00028 var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename 00029 } 00030 00031 class ADODB_Active_Table { 00032 var $name; // table name 00033 var $flds; // assoc array of adofieldobjs, indexed by fieldname 00034 var $keys; // assoc array of primary keys, indexed by fieldname 00035 var $_created; // only used when stored as a cached file 00036 } 00037 00038 // returns index into $_ADODB_ACTIVE_DBS 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; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat] 00059 var $_table; // tablename, if set in class definition then use it as table name 00060 var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat] 00061 var $_where; // where clause set in Load() 00062 var $_saved = false; // indicates whether data is already inserted. 00063 var $_lasterr = false; // last error message 00064 var $_original = false; // the original values loaded or inserted, refreshed on update 00065 00066 // should be static 00067 function SetDatabaseAdapter(&$db) 00068 { 00069 return ADODB_SetDatabaseAdapter($db); 00070 } 00071 00072 // php4 constructor 00073 function ADODB_Active_Record($table = false, $pkeyarr=false, $db=false) 00074 { 00075 ADODB_Active_Record::__construct($table,$pkeyarr,$db); 00076 } 00077 00078 // php5 constructor 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 // update metadata 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 // abs(rand()) randomizes deletion, reducing contention to delete/refresh file 00154 // ideally, you should cache at least 32 secs 00155 $activedb->tables[$table] = $acttab; 00156 00157 //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname"); 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 // error handler for both PHP4+5. 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 // return last error message 00265 function ErrorMsg() 00266 { 00267 if (!function_exists('adodb_throw')) { 00268 if ($this->_dbat < 0) $db = false; 00269 else $db = $this->DB(); 00270 00271 // last error could be database error too 00272 if ($db && $db->ErrorMsg()) return $db->ErrorMsg(); 00273 } 00274 return $this->_lasterr; 00275 } 00276 00277 // retrieve ADOConnection from _ADODB_Active_DBs 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 // retrieve ADODB_Active_Table 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 // set a numeric array (using natural table field ordering) as object properties 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 // get last inserted id for INSERT 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 // this might not work reliably in multi-user environment 00339 return $db->GetOne("select max(".$fieldname.") from ".$this->_table); 00340 } 00341 return $val; 00342 } 00343 00344 // quote data in where clause 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 // generate where clause for an UPDATE/SELECT 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 //------------------------------------------------------------ Public functions below 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 // false on error 00397 function Save() 00398 { 00399 if ($this->_saved) $ok = $this->Update(); 00400 else $ok = $this->Insert(); 00401 00402 return $ok; 00403 } 00404 00405 // false on error 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 if (is_null($val)) { 00416 if (isset($fld->not_null) && $fld->not_null) { 00417 if (isset($fld->default_value) && strlen($fld->default_value)) continue; 00418 else $this->Error("Cannot insert null into $name","Insert"); 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 // returns an array of active record objects 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 // returns 0 on error, 1 on update, 2 on insert 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 if (is_null($val)) { 00482 if (isset($fld->not_null) && $fld->not_null) { 00483 if (isset($fld->default_value) && strlen($fld->default_value)) continue; 00484 else { 00485 $this->Error("Cannot update null into $name","Replace"); 00486 return false; 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; // 1= update 2=insert 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 // returns 0 on error, 1 on update, -1 if no change in data (no update) 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 ?>