|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 /* 00003 00004 @version V5.14 8 Sept 2011 (c) 2000-2011 John Lim (jlim#natsoft.com). 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.92 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 00020 global $_ADODB_ACTIVE_DBS; 00021 global $ADODB_ACTIVE_CACHESECS; // set to true to enable caching of metadata such as field info 00022 global $ACTIVE_RECORD_SAFETY; // set to false to disable safety checks 00023 global $ADODB_ACTIVE_DEFVALS; // use default values of table definition when creating new active record. 00024 00025 // array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat 00026 $_ADODB_ACTIVE_DBS = array(); 00027 $ACTIVE_RECORD_SAFETY = true; 00028 $ADODB_ACTIVE_DEFVALS = false; 00029 $ADODB_ACTIVE_CACHESECS = 0; 00030 00031 class ADODB_Active_DB { 00032 var $db; // ADOConnection 00033 var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename 00034 } 00035 00036 class ADODB_Active_Table { 00037 var $name; // table name 00038 var $flds; // assoc array of adofieldobjs, indexed by fieldname 00039 var $keys; // assoc array of primary keys, indexed by fieldname 00040 var $_created; // only used when stored as a cached file 00041 var $_belongsTo = array(); 00042 var $_hasMany = array(); 00043 } 00044 00045 // $db = database connection 00046 // $index = name of index - can be associative, for an example see 00047 // http://phplens.com/lens/lensforum/msgs.php?id=17790 00048 // returns index into $_ADODB_ACTIVE_DBS 00049 function ADODB_SetDatabaseAdapter(&$db, $index=false) 00050 { 00051 global $_ADODB_ACTIVE_DBS; 00052 00053 foreach($_ADODB_ACTIVE_DBS as $k => $d) { 00054 if (PHP_VERSION >= 5) { 00055 if ($d->db === $db) return $k; 00056 } else { 00057 if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database) 00058 return $k; 00059 } 00060 } 00061 00062 $obj = new ADODB_Active_DB(); 00063 $obj->db = $db; 00064 $obj->tables = array(); 00065 00066 if ($index == false) $index = sizeof($_ADODB_ACTIVE_DBS); 00067 00068 00069 $_ADODB_ACTIVE_DBS[$index] = $obj; 00070 00071 return sizeof($_ADODB_ACTIVE_DBS)-1; 00072 } 00073 00074 00075 class ADODB_Active_Record { 00076 static $_changeNames = true; // dynamically pluralize table names 00077 static $_quoteNames = false; 00078 00079 static $_foreignSuffix = '_id'; // 00080 var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat] 00081 var $_table; // tablename, if set in class definition then use it as table name 00082 var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat] 00083 var $_where; // where clause set in Load() 00084 var $_saved = false; // indicates whether data is already inserted. 00085 var $_lasterr = false; // last error message 00086 var $_original = false; // the original values loaded or inserted, refreshed on update 00087 00088 var $foreignName; // CFR: class name when in a relationship 00089 00090 static function UseDefaultValues($bool=null) 00091 { 00092 global $ADODB_ACTIVE_DEFVALS; 00093 if (isset($bool)) $ADODB_ACTIVE_DEFVALS = $bool; 00094 return $ADODB_ACTIVE_DEFVALS; 00095 } 00096 00097 // should be static 00098 static function SetDatabaseAdapter(&$db, $index=false) 00099 { 00100 return ADODB_SetDatabaseAdapter($db, $index); 00101 } 00102 00103 00104 public function __set($name, $value) 00105 { 00106 $name = str_replace(' ', '_', $name); 00107 $this->$name = $value; 00108 } 00109 00110 // php5 constructor 00111 function __construct($table = false, $pkeyarr=false, $db=false) 00112 { 00113 global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS; 00114 00115 if ($db == false && is_object($pkeyarr)) { 00116 $db = $pkeyarr; 00117 $pkeyarr = false; 00118 } 00119 00120 if (!$table) { 00121 if (!empty($this->_table)) $table = $this->_table; 00122 else $table = $this->_pluralize(get_class($this)); 00123 } 00124 $this->foreignName = strtolower(get_class($this)); // CFR: default foreign name 00125 if ($db) { 00126 $this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db); 00127 } else if (!isset($this->_dbat)) { 00128 if (sizeof($_ADODB_ACTIVE_DBS) == 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor'); 00129 end($_ADODB_ACTIVE_DBS); 00130 $this->_dbat = key($_ADODB_ACTIVE_DBS); 00131 } 00132 00133 $this->_table = $table; 00134 $this->_tableat = $table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future 00135 00136 $this->UpdateActiveTable($pkeyarr); 00137 } 00138 00139 function __wakeup() 00140 { 00141 $class = get_class($this); 00142 new $class; 00143 } 00144 00145 function _pluralize($table) 00146 { 00147 if (!ADODB_Active_Record::$_changeNames) return $table; 00148 00149 $ut = strtoupper($table); 00150 $len = strlen($table); 00151 $lastc = $ut[$len-1]; 00152 $lastc2 = substr($ut,$len-2); 00153 switch ($lastc) { 00154 case 'S': 00155 return $table.'es'; 00156 case 'Y': 00157 return substr($table,0,$len-1).'ies'; 00158 case 'X': 00159 return $table.'es'; 00160 case 'H': 00161 if ($lastc2 == 'CH' || $lastc2 == 'SH') 00162 return $table.'es'; 00163 default: 00164 return $table.'s'; 00165 } 00166 } 00167 00168 // CFR Lamest singular inflector ever - @todo Make it real! 00169 // Note: There is an assumption here...and it is that the argument's length >= 4 00170 function _singularize($tables) 00171 { 00172 00173 if (!ADODB_Active_Record::$_changeNames) return $table; 00174 00175 $ut = strtoupper($tables); 00176 $len = strlen($tables); 00177 if($ut[$len-1] != 'S') 00178 return $tables; // I know...forget oxen 00179 if($ut[$len-2] != 'E') 00180 return substr($tables, 0, $len-1); 00181 switch($ut[$len-3]) 00182 { 00183 case 'S': 00184 case 'X': 00185 return substr($tables, 0, $len-2); 00186 case 'I': 00187 return substr($tables, 0, $len-3) . 'y'; 00188 case 'H'; 00189 if($ut[$len-4] == 'C' || $ut[$len-4] == 'S') 00190 return substr($tables, 0, $len-2); 00191 default: 00192 return substr($tables, 0, $len-1); // ? 00193 } 00194 } 00195 00196 function hasMany($foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record') 00197 { 00198 $ar = new $foreignClass($foreignRef); 00199 $ar->foreignName = $foreignRef; 00200 $ar->UpdateActiveTable(); 00201 $ar->foreignKey = ($foreignKey) ? $foreignKey : $foreignRef.ADODB_Active_Record::$_foreignSuffix; 00202 $table =& $this->TableInfo(); 00203 $table->_hasMany[$foreignRef] = $ar; 00204 # $this->$foreignRef = $this->_hasMany[$foreignRef]; // WATCHME Removed assignment by ref. to please __get() 00205 } 00206 00207 // use when you don't want ADOdb to auto-pluralize tablename 00208 static function TableHasMany($table, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record') 00209 { 00210 $ar = new ADODB_Active_Record($table); 00211 $ar->hasMany($foreignRef, $foreignKey, $foreignClass); 00212 } 00213 00214 // use when you don't want ADOdb to auto-pluralize tablename 00215 static function TableKeyHasMany($table, $tablePKey, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record') 00216 { 00217 if (!is_array($tablePKey)) $tablePKey = array($tablePKey); 00218 $ar = new ADODB_Active_Record($table,$tablePKey); 00219 $ar->hasMany($foreignRef, $foreignKey, $foreignClass); 00220 } 00221 00222 00223 // use when you want ADOdb to auto-pluralize tablename for you. Note that the class must already be defined. 00224 // e.g. class Person will generate relationship for table Persons 00225 static function ClassHasMany($parentclass, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record') 00226 { 00227 $ar = new $parentclass(); 00228 $ar->hasMany($foreignRef, $foreignKey, $foreignClass); 00229 } 00230 00231 00232 function belongsTo($foreignRef,$foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record') 00233 { 00234 global $inflector; 00235 00236 $ar = new $parentClass($this->_pluralize($foreignRef)); 00237 $ar->foreignName = $foreignRef; 00238 $ar->parentKey = $parentKey; 00239 $ar->UpdateActiveTable(); 00240 $ar->foreignKey = ($foreignKey) ? $foreignKey : $foreignRef.ADODB_Active_Record::$_foreignSuffix; 00241 00242 $table =& $this->TableInfo(); 00243 $table->_belongsTo[$foreignRef] = $ar; 00244 # $this->$foreignRef = $this->_belongsTo[$foreignRef]; 00245 } 00246 00247 static function ClassBelongsTo($class, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record') 00248 { 00249 $ar = new $class(); 00250 $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass); 00251 } 00252 00253 static function TableBelongsTo($table, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record') 00254 { 00255 $ar = new ADOdb_Active_Record($table); 00256 $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass); 00257 } 00258 00259 static function TableKeyBelongsTo($table, $tablePKey, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record') 00260 { 00261 if (!is_array($tablePKey)) $tablePKey = array($tablePKey); 00262 $ar = new ADOdb_Active_Record($table, $tablePKey); 00263 $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass); 00264 } 00265 00266 00274 function __get($name) 00275 { 00276 return $this->LoadRelations($name, '', -1, -1); 00277 } 00278 00286 function LoadRelations($name, $whereOrderBy='', $offset=-1,$limit=-1) 00287 { 00288 $extras = array(); 00289 $table = $this->TableInfo(); 00290 if ($limit >= 0) $extras['limit'] = $limit; 00291 if ($offset >= 0) $extras['offset'] = $offset; 00292 00293 if (strlen($whereOrderBy)) 00294 if (!preg_match('/^[ \n\r]*AND/i',$whereOrderBy)) 00295 if (!preg_match('/^[ \n\r]*ORDER[ \n\r]/i',$whereOrderBy)) 00296 $whereOrderBy = 'AND '.$whereOrderBy; 00297 00298 if(!empty($table->_belongsTo[$name])) 00299 { 00300 $obj = $table->_belongsTo[$name]; 00301 $columnName = $obj->foreignKey; 00302 if(empty($this->$columnName)) 00303 $this->$name = null; 00304 else 00305 { 00306 if ($obj->parentKey) $key = $obj->parentKey; 00307 else $key = reset($table->keys); 00308 00309 $arrayOfOne = $obj->Find($key.'='.$this->$columnName.' '.$whereOrderBy,false,false,$extras); 00310 if ($arrayOfOne) { 00311 $this->$name = $arrayOfOne[0]; 00312 return $arrayOfOne[0]; 00313 } 00314 } 00315 } 00316 if(!empty($table->_hasMany[$name])) 00317 { 00318 $obj = $table->_hasMany[$name]; 00319 $key = reset($table->keys); 00320 $id = @$this->$key; 00321 if (!is_numeric($id)) { 00322 $db = $this->DB(); 00323 $id = $db->qstr($id); 00324 } 00325 $objs = $obj->Find($obj->foreignKey.'='.$id. ' '.$whereOrderBy,false,false,$extras); 00326 if (!$objs) $objs = array(); 00327 $this->$name = $objs; 00328 return $objs; 00329 } 00330 00331 return array(); 00332 } 00334 00335 // update metadata 00336 function UpdateActiveTable($pkeys=false,$forceUpdate=false) 00337 { 00338 global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS; 00339 global $ADODB_ACTIVE_DEFVALS,$ADODB_FETCH_MODE; 00340 00341 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat]; 00342 00343 $table = $this->_table; 00344 $tables = $activedb->tables; 00345 $tableat = $this->_tableat; 00346 if (!$forceUpdate && !empty($tables[$tableat])) { 00347 00348 $acttab = $tables[$tableat]; 00349 foreach($acttab->flds as $name => $fld) { 00350 if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) 00351 $this->$name = $fld->default_value; 00352 else 00353 $this->$name = null; 00354 } 00355 return; 00356 } 00357 $db = $activedb->db; 00358 $fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache'; 00359 if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) { 00360 $fp = fopen($fname,'r'); 00361 @flock($fp, LOCK_SH); 00362 $acttab = unserialize(fread($fp,100000)); 00363 fclose($fp); 00364 if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) { 00365 // abs(rand()) randomizes deletion, reducing contention to delete/refresh file 00366 // ideally, you should cache at least 32 secs 00367 00368 foreach($acttab->flds as $name => $fld) { 00369 if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) 00370 $this->$name = $fld->default_value; 00371 else 00372 $this->$name = null; 00373 } 00374 00375 $activedb->tables[$table] = $acttab; 00376 00377 //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname"); 00378 return; 00379 } else if ($db->debug) { 00380 ADOConnection::outp("Refreshing cached active record file: $fname"); 00381 } 00382 } 00383 $activetab = new ADODB_Active_Table(); 00384 $activetab->name = $table; 00385 00386 $save = $ADODB_FETCH_MODE; 00387 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; 00388 if ($db->fetchMode !== false) $savem = $db->SetFetchMode(false); 00389 00390 $cols = $db->MetaColumns($table); 00391 00392 if (isset($savem)) $db->SetFetchMode($savem); 00393 $ADODB_FETCH_MODE = $save; 00394 00395 if (!$cols) { 00396 $this->Error("Invalid table name: $table",'UpdateActiveTable'); 00397 return false; 00398 } 00399 $fld = reset($cols); 00400 if (!$pkeys) { 00401 if (isset($fld->primary_key)) { 00402 $pkeys = array(); 00403 foreach($cols as $name => $fld) { 00404 if (!empty($fld->primary_key)) $pkeys[] = $name; 00405 } 00406 } else 00407 $pkeys = $this->GetPrimaryKeys($db, $table); 00408 } 00409 if (empty($pkeys)) { 00410 $this->Error("No primary key found for table $table",'UpdateActiveTable'); 00411 return false; 00412 } 00413 00414 $attr = array(); 00415 $keys = array(); 00416 00417 switch($ADODB_ASSOC_CASE) { 00418 case 0: 00419 foreach($cols as $name => $fldobj) { 00420 $name = strtolower($name); 00421 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) 00422 $this->$name = $fldobj->default_value; 00423 else 00424 $this->$name = null; 00425 $attr[$name] = $fldobj; 00426 } 00427 foreach($pkeys as $k => $name) { 00428 $keys[strtolower($name)] = strtolower($name); 00429 } 00430 break; 00431 00432 case 1: 00433 foreach($cols as $name => $fldobj) { 00434 $name = strtoupper($name); 00435 00436 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) 00437 $this->$name = $fldobj->default_value; 00438 else 00439 $this->$name = null; 00440 $attr[$name] = $fldobj; 00441 } 00442 00443 foreach($pkeys as $k => $name) { 00444 $keys[strtoupper($name)] = strtoupper($name); 00445 } 00446 break; 00447 default: 00448 foreach($cols as $name => $fldobj) { 00449 $name = ($fldobj->name); 00450 00451 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) 00452 $this->$name = $fldobj->default_value; 00453 else 00454 $this->$name = null; 00455 $attr[$name] = $fldobj; 00456 } 00457 foreach($pkeys as $k => $name) { 00458 $keys[$name] = $cols[$name]->name; 00459 } 00460 break; 00461 } 00462 00463 $activetab->keys = $keys; 00464 $activetab->flds = $attr; 00465 00466 if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) { 00467 $activetab->_created = time(); 00468 $s = serialize($activetab); 00469 if (!function_exists('adodb_write_file')) include(ADODB_DIR.'/adodb-csvlib.inc.php'); 00470 adodb_write_file($fname,$s); 00471 } 00472 if (isset($activedb->tables[$table])) { 00473 $oldtab = $activedb->tables[$table]; 00474 00475 if ($oldtab) $activetab->_belongsTo = $oldtab->_belongsTo; 00476 if ($oldtab) $activetab->_hasMany = $oldtab->_hasMany; 00477 } 00478 $activedb->tables[$table] = $activetab; 00479 } 00480 00481 function GetPrimaryKeys(&$db, $table) 00482 { 00483 return $db->MetaPrimaryKeys($table); 00484 } 00485 00486 // error handler for both PHP4+5. 00487 function Error($err,$fn) 00488 { 00489 global $_ADODB_ACTIVE_DBS; 00490 00491 $fn = get_class($this).'::'.$fn; 00492 $this->_lasterr = $fn.': '.$err; 00493 00494 if ($this->_dbat < 0) $db = false; 00495 else { 00496 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat]; 00497 $db = $activedb->db; 00498 } 00499 00500 if (function_exists('adodb_throw')) { 00501 if (!$db) adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false); 00502 else adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db); 00503 } else 00504 if (!$db || $db->debug) ADOConnection::outp($this->_lasterr); 00505 00506 } 00507 00508 // return last error message 00509 function ErrorMsg() 00510 { 00511 if (!function_exists('adodb_throw')) { 00512 if ($this->_dbat < 0) $db = false; 00513 else $db = $this->DB(); 00514 00515 // last error could be database error too 00516 if ($db && $db->ErrorMsg()) return $db->ErrorMsg(); 00517 } 00518 return $this->_lasterr; 00519 } 00520 00521 function ErrorNo() 00522 { 00523 if ($this->_dbat < 0) return -9999; // no database connection... 00524 $db = $this->DB(); 00525 00526 return (int) $db->ErrorNo(); 00527 } 00528 00529 00530 // retrieve ADOConnection from _ADODB_Active_DBs 00531 function DB() 00532 { 00533 global $_ADODB_ACTIVE_DBS; 00534 00535 if ($this->_dbat < 0) { 00536 $false = false; 00537 $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB"); 00538 return $false; 00539 } 00540 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat]; 00541 $db = $activedb->db; 00542 return $db; 00543 } 00544 00545 // retrieve ADODB_Active_Table 00546 function &TableInfo() 00547 { 00548 global $_ADODB_ACTIVE_DBS; 00549 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat]; 00550 $table = $activedb->tables[$this->_tableat]; 00551 return $table; 00552 } 00553 00554 00555 // I have an ON INSERT trigger on a table that sets other columns in the table. 00556 // So, I find that for myTable, I want to reload an active record after saving it. -- Malcolm Cook 00557 function Reload() 00558 { 00559 $db =& $this->DB(); if (!$db) return false; 00560 $table =& $this->TableInfo(); 00561 $where = $this->GenWhere($db, $table); 00562 return($this->Load($where)); 00563 } 00564 00565 00566 // set a numeric array (using natural table field ordering) as object properties 00567 function Set(&$row) 00568 { 00569 global $ACTIVE_RECORD_SAFETY; 00570 00571 $db = $this->DB(); 00572 00573 if (!$row) { 00574 $this->_saved = false; 00575 return false; 00576 } 00577 00578 $this->_saved = true; 00579 00580 $table = $this->TableInfo(); 00581 if ($ACTIVE_RECORD_SAFETY && sizeof($table->flds) != sizeof($row)) { 00582 # <AP> 00583 $bad_size = TRUE; 00584 if (sizeof($row) == 2 * sizeof($table->flds)) { 00585 // Only keep string keys 00586 $keys = array_filter(array_keys($row), 'is_string'); 00587 if (sizeof($keys) == sizeof($table->flds)) 00588 $bad_size = FALSE; 00589 } 00590 if ($bad_size) { 00591 $this->Error("Table structure of $this->_table has changed","Load"); 00592 return false; 00593 } 00594 # </AP> 00595 } 00596 else 00597 $keys = array_keys($row); 00598 00599 # <AP> 00600 reset($keys); 00601 $this->_original = array(); 00602 foreach($table->flds as $name=>$fld) { 00603 $value = $row[current($keys)]; 00604 $this->$name = $value; 00605 $this->_original[] = $value; 00606 next($keys); 00607 } 00608 00609 # </AP> 00610 return true; 00611 } 00612 00613 // get last inserted id for INSERT 00614 function LastInsertID(&$db,$fieldname) 00615 { 00616 if ($db->hasInsertID) 00617 $val = $db->Insert_ID($this->_table,$fieldname); 00618 else 00619 $val = false; 00620 00621 if (is_null($val) || $val === false) { 00622 // this might not work reliably in multi-user environment 00623 return $db->GetOne("select max(".$fieldname.") from ".$this->_table); 00624 } 00625 return $val; 00626 } 00627 00628 // quote data in where clause 00629 function doquote(&$db, $val,$t) 00630 { 00631 switch($t) { 00632 case 'L': 00633 if (strpos($db->databaseType,'postgres') !== false) return $db->qstr($val); 00634 case 'D': 00635 case 'T': 00636 if (empty($val)) return 'null'; 00637 00638 case 'B': 00639 case 'N': 00640 case 'C': 00641 case 'X': 00642 if (is_null($val)) return 'null'; 00643 00644 if (strlen($val)>1 && 00645 (strncmp($val,"'",1) != 0 || substr($val,strlen($val)-1,1) != "'")) { 00646 return $db->qstr($val); 00647 break; 00648 } 00649 default: 00650 return $val; 00651 break; 00652 } 00653 } 00654 00655 // generate where clause for an UPDATE/SELECT 00656 function GenWhere(&$db, &$table) 00657 { 00658 $keys = $table->keys; 00659 $parr = array(); 00660 00661 foreach($keys as $k) { 00662 $f = $table->flds[$k]; 00663 if ($f) { 00664 $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type)); 00665 } 00666 } 00667 return implode(' and ', $parr); 00668 } 00669 00670 00671 function _QName($n,$db=false) 00672 { 00673 if (!ADODB_Active_Record::$_quoteNames) return $n; 00674 if (!$db) $db = $this->DB(); if (!$db) return false; 00675 return $db->nameQuote.$n.$db->nameQuote; 00676 } 00677 00678 //------------------------------------------------------------ Public functions below 00679 00680 function Load($where=null,$bindarr=false) 00681 { 00682 global $ADODB_FETCH_MODE; 00683 00684 $db = $this->DB(); if (!$db) return false; 00685 $this->_where = $where; 00686 00687 $save = $ADODB_FETCH_MODE; 00688 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 00689 if ($db->fetchMode !== false) $savem = $db->SetFetchMode(false); 00690 00691 $qry = "select * from ".$this->_table; 00692 00693 if($where) { 00694 $qry .= ' WHERE '.$where; 00695 } 00696 $row = $db->GetRow($qry,$bindarr); 00697 00698 if (isset($savem)) $db->SetFetchMode($savem); 00699 $ADODB_FETCH_MODE = $save; 00700 00701 return $this->Set($row); 00702 } 00703 00704 # useful for multiple record inserts 00705 # see http://phplens.com/lens/lensforum/msgs.php?id=17795 00706 function Reset() 00707 { 00708 $this->_where=null; 00709 $this->_saved = false; 00710 $this->_lasterr = false; 00711 $this->_original = false; 00712 $vars=get_object_vars($this); 00713 foreach($vars as $k=>$v){ 00714 if(substr($k,0,1)!=='_'){ 00715 $this->{$k}=null; 00716 } 00717 } 00718 $this->foreignName=strtolower(get_class($this)); 00719 return true; 00720 } 00721 00722 // false on error 00723 function Save() 00724 { 00725 if ($this->_saved) $ok = $this->Update(); 00726 else $ok = $this->Insert(); 00727 00728 return $ok; 00729 } 00730 00731 00732 // false on error 00733 function Insert() 00734 { 00735 $db = $this->DB(); if (!$db) return false; 00736 $cnt = 0; 00737 $table = $this->TableInfo(); 00738 00739 $valarr = array(); 00740 $names = array(); 00741 $valstr = array(); 00742 00743 foreach($table->flds as $name=>$fld) { 00744 $val = $this->$name; 00745 if(!is_array($val) || !is_null($val) || !array_key_exists($name, $table->keys)) { 00746 $valarr[] = $val; 00747 $names[] = $this->_QName($name,$db); 00748 $valstr[] = $db->Param($cnt); 00749 $cnt += 1; 00750 } 00751 } 00752 00753 if (empty($names)){ 00754 foreach($table->flds as $name=>$fld) { 00755 $valarr[] = null; 00756 $names[] = $name; 00757 $valstr[] = $db->Param($cnt); 00758 $cnt += 1; 00759 } 00760 } 00761 $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')'; 00762 $ok = $db->Execute($sql,$valarr); 00763 00764 if ($ok) { 00765 $this->_saved = true; 00766 $autoinc = false; 00767 foreach($table->keys as $k) { 00768 if (is_null($this->$k)) { 00769 $autoinc = true; 00770 break; 00771 } 00772 } 00773 if ($autoinc && sizeof($table->keys) == 1) { 00774 $k = reset($table->keys); 00775 $this->$k = $this->LastInsertID($db,$k); 00776 } 00777 } 00778 00779 $this->_original = $valarr; 00780 return !empty($ok); 00781 } 00782 00783 function Delete() 00784 { 00785 $db = $this->DB(); if (!$db) return false; 00786 $table = $this->TableInfo(); 00787 00788 $where = $this->GenWhere($db,$table); 00789 $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where; 00790 $ok = $db->Execute($sql); 00791 00792 return $ok ? true : false; 00793 } 00794 00795 // returns an array of active record objects 00796 function Find($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array()) 00797 { 00798 $db = $this->DB(); if (!$db || empty($this->_table)) return false; 00799 $arr = $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr,$extra); 00800 return $arr; 00801 } 00802 00803 // returns 0 on error, 1 on update, 2 on insert 00804 function Replace() 00805 { 00806 global $ADODB_ASSOC_CASE; 00807 00808 $db = $this->DB(); if (!$db) return false; 00809 $table = $this->TableInfo(); 00810 00811 $pkey = $table->keys; 00812 00813 foreach($table->flds as $name=>$fld) { 00814 $val = $this->$name; 00815 /* 00816 if (is_null($val)) { 00817 if (isset($fld->not_null) && $fld->not_null) { 00818 if (isset($fld->default_value) && strlen($fld->default_value)) continue; 00819 else { 00820 $this->Error("Cannot update null into $name","Replace"); 00821 return false; 00822 } 00823 } 00824 }*/ 00825 if (is_null($val) && !empty($fld->auto_increment)) { 00826 continue; 00827 } 00828 00829 if (is_array($val)) continue; 00830 00831 $t = $db->MetaType($fld->type); 00832 $arr[$name] = $this->doquote($db,$val,$t); 00833 $valarr[] = $val; 00834 } 00835 00836 if (!is_array($pkey)) $pkey = array($pkey); 00837 00838 00839 if ($ADODB_ASSOC_CASE == 0) 00840 foreach($pkey as $k => $v) 00841 $pkey[$k] = strtolower($v); 00842 elseif ($ADODB_ASSOC_CASE == 1) 00843 foreach($pkey as $k => $v) 00844 $pkey[$k] = strtoupper($v); 00845 00846 $ok = $db->Replace($this->_table,$arr,$pkey); 00847 if ($ok) { 00848 $this->_saved = true; // 1= update 2=insert 00849 if ($ok == 2) { 00850 $autoinc = false; 00851 foreach($table->keys as $k) { 00852 if (is_null($this->$k)) { 00853 $autoinc = true; 00854 break; 00855 } 00856 } 00857 if ($autoinc && sizeof($table->keys) == 1) { 00858 $k = reset($table->keys); 00859 $this->$k = $this->LastInsertID($db,$k); 00860 } 00861 } 00862 00863 $this->_original = $valarr; 00864 } 00865 return $ok; 00866 } 00867 00868 // returns 0 on error, 1 on update, -1 if no change in data (no update) 00869 function Update() 00870 { 00871 $db = $this->DB(); if (!$db) return false; 00872 $table = $this->TableInfo(); 00873 00874 $where = $this->GenWhere($db, $table); 00875 00876 if (!$where) { 00877 $this->error("Where missing for table $table", "Update"); 00878 return false; 00879 } 00880 $valarr = array(); 00881 $neworig = array(); 00882 $pairs = array(); 00883 $i = -1; 00884 $cnt = 0; 00885 foreach($table->flds as $name=>$fld) { 00886 $i += 1; 00887 $val = $this->$name; 00888 $neworig[] = $val; 00889 00890 if (isset($table->keys[$name]) || is_array($val)) 00891 continue; 00892 00893 if (is_null($val)) { 00894 if (isset($fld->not_null) && $fld->not_null) { 00895 if (isset($fld->default_value) && strlen($fld->default_value)) continue; 00896 else { 00897 $this->Error("Cannot set field $name to NULL","Update"); 00898 return false; 00899 } 00900 } 00901 } 00902 00903 if (isset($this->_original[$i]) && strcmp($val,$this->_original[$i]) == 0) { 00904 continue; 00905 } 00906 $valarr[] = $val; 00907 $pairs[] = $this->_QName($name,$db).'='.$db->Param($cnt); 00908 $cnt += 1; 00909 } 00910 00911 00912 if (!$cnt) return -1; 00913 $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where; 00914 $ok = $db->Execute($sql,$valarr); 00915 if ($ok) { 00916 $this->_original = $neworig; 00917 return 1; 00918 } 00919 return 0; 00920 } 00921 00922 function GetAttributeNames() 00923 { 00924 $table = $this->TableInfo(); 00925 if (!$table) return false; 00926 return array_keys($table->flds); 00927 } 00928 00929 }; 00930 00931 function adodb_GetActiveRecordsClass(&$db, $class, $table,$whereOrderBy,$bindarr, $primkeyArr, 00932 $extra) 00933 { 00934 global $_ADODB_ACTIVE_DBS; 00935 00936 00937 $save = $db->SetFetchMode(ADODB_FETCH_NUM); 00938 $qry = "select * from ".$table; 00939 00940 if (!empty($whereOrderBy)) 00941 $qry .= ' WHERE '.$whereOrderBy; 00942 if(isset($extra['limit'])) 00943 { 00944 $rows = false; 00945 if(isset($extra['offset'])) { 00946 $rs = $db->SelectLimit($qry, $extra['limit'], $extra['offset'],$bindarr); 00947 } else { 00948 $rs = $db->SelectLimit($qry, $extra['limit'],-1,$bindarr); 00949 } 00950 if ($rs) { 00951 while (!$rs->EOF) { 00952 $rows[] = $rs->fields; 00953 $rs->MoveNext(); 00954 } 00955 } 00956 } else 00957 $rows = $db->GetAll($qry,$bindarr); 00958 00959 $db->SetFetchMode($save); 00960 00961 $false = false; 00962 00963 if ($rows === false) { 00964 return $false; 00965 } 00966 00967 00968 if (!class_exists($class)) { 00969 $db->outp_throw("Unknown class $class in GetActiveRecordsClass()",'GetActiveRecordsClass'); 00970 return $false; 00971 } 00972 $arr = array(); 00973 // arrRef will be the structure that knows about our objects. 00974 // It is an associative array. 00975 // We will, however, return arr, preserving regular 0.. order so that 00976 // obj[0] can be used by app developpers. 00977 $arrRef = array(); 00978 $bTos = array(); // Will store belongTo's indices if any 00979 foreach($rows as $row) { 00980 00981 $obj = new $class($table,$primkeyArr,$db); 00982 if ($obj->ErrorNo()){ 00983 $db->_errorMsg = $obj->ErrorMsg(); 00984 return $false; 00985 } 00986 $obj->Set($row); 00987 $arr[] = $obj; 00988 } // foreach($rows as $row) 00989 00990 return $arr; 00991 } 00992 ?>