| [ Index ] |
PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008] |
[Summary view] [Print] [Text view]
1 <?php 2 /* 3 4 @version V4.98 13 Feb 2008 (c) 2000-2008 John Lim (jlim#natsoft.com.my). All rights reserved. 5 Latest version is available at http://adodb.sourceforge.net 6 7 Released under both BSD license and Lesser GPL library license. 8 Whenever there is any discrepancy between the two licenses, 9 the BSD license will take precedence. 10 11 Active Record implementation. Superset of Zend Framework's. 12 13 Version 0.09 14 15 See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord 16 for info on Ruby on Rails Active Record implementation 17 */ 18 19 global $_ADODB_ACTIVE_DBS; 20 global $ADODB_ACTIVE_CACHESECS; // set to true to enable caching of metadata such as field info 21 global $ACTIVE_RECORD_SAFETY; // set to false to disable safety checks 22 global $ADODB_ACTIVE_DEFVALS; // use default values of table definition when creating new active record. 23 24 // array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat 25 $_ADODB_ACTIVE_DBS = array(); 26 $ACTIVE_RECORD_SAFETY = true; 27 $ADODB_ACTIVE_DEFVALS = false; 28 29 class ADODB_Active_DB { 30 var $db; // ADOConnection 31 var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename 32 } 33 34 class ADODB_Active_Table { 35 var $name; // table name 36 var $flds; // assoc array of adofieldobjs, indexed by fieldname 37 var $keys; // assoc array of primary keys, indexed by fieldname 38 var $_created; // only used when stored as a cached file 39 } 40 41 // returns index into $_ADODB_ACTIVE_DBS 42 function ADODB_SetDatabaseAdapter(&$db) 43 { 44 global $_ADODB_ACTIVE_DBS; 45 46 foreach($_ADODB_ACTIVE_DBS as $k => $d) { 47 if (PHP_VERSION >= 5) { 48 if ($d->db === $db) return $k; 49 } else { 50 if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database) 51 return $k; 52 } 53 } 54 55 $obj = new ADODB_Active_DB(); 56 $obj->db =& $db; 57 $obj->tables = array(); 58 59 $_ADODB_ACTIVE_DBS[] = $obj; 60 61 return sizeof($_ADODB_ACTIVE_DBS)-1; 62 } 63 64 65 class ADODB_Active_Record { 66 var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat] 67 var $_table; // tablename, if set in class definition then use it as table name 68 var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat] 69 var $_where; // where clause set in Load() 70 var $_saved = false; // indicates whether data is already inserted. 71 var $_lasterr = false; // last error message 72 var $_original = false; // the original values loaded or inserted, refreshed on update 73 74 // should be static 75 function UseDefaultValues($bool=null) 76 { 77 global $ADODB_ACTIVE_DEFVALS; 78 if (isset($bool)) $ADODB_ACTIVE_DEFVALS = $bool; 79 return $ADODB_ACTIVE_DEFVALS; 80 } 81 82 // should be static 83 function SetDatabaseAdapter(&$db) 84 { 85 return ADODB_SetDatabaseAdapter($db); 86 } 87 88 // php4 constructor 89 function ADODB_Active_Record($table = false, $pkeyarr=false, $db=false) 90 { 91 ADODB_Active_Record::__construct($table,$pkeyarr,$db); 92 } 93 94 // php5 constructor 95 function __construct($table = false, $pkeyarr=false, $db=false) 96 { 97 global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS; 98 99 if ($db == false && is_object($pkeyarr)) { 100 $db = $pkeyarr; 101 $pkeyarr = false; 102 } 103 104 if (!$table) { 105 if (!empty($this->_table)) $table = $this->_table; 106 else $table = $this->_pluralize(get_class($this)); 107 } 108 if ($db) { 109 $this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db); 110 } else 111 $this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1; 112 113 114 if ($this->_dbat < 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor'); 115 116 $this->_table = $table; 117 $this->_tableat = $table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future 118 $this->UpdateActiveTable($pkeyarr); 119 } 120 121 function __wakeup() 122 { 123 $class = get_class($this); 124 new $class; 125 } 126 127 function _pluralize($table) 128 { 129 $ut = strtoupper($table); 130 $len = strlen($table); 131 $lastc = $ut[$len-1]; 132 $lastc2 = substr($ut,$len-2); 133 switch ($lastc) { 134 case 'S': 135 return $table.'es'; 136 case 'Y': 137 return substr($table,0,$len-1).'ies'; 138 case 'X': 139 return $table.'es'; 140 case 'H': 141 if ($lastc2 == 'CH' || $lastc2 == 'SH') 142 return $table.'es'; 143 default: 144 return $table.'s'; 145 } 146 } 147 148 ////////////////////////////////// 149 150 // update metadata 151 function UpdateActiveTable($pkeys=false,$forceUpdate=false) 152 { 153 global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS; 154 global $ADODB_ACTIVE_DEFVALS; 155 156 $activedb =& $_ADODB_ACTIVE_DBS[$this->_dbat]; 157 158 $table = $this->_table; 159 $tables = $activedb->tables; 160 $tableat = $this->_tableat; 161 if (!$forceUpdate && !empty($tables[$tableat])) { 162 $tobj =& $tables[$tableat]; 163 foreach($tobj->flds as $name => $fld) { 164 if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) 165 $this->$name = $fld->default_value; 166 else 167 $this->$name = null; 168 } 169 return; 170 } 171 172 $db =& $activedb->db; 173 $fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache'; 174 if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) { 175 $fp = fopen($fname,'r'); 176 @flock($fp, LOCK_SH); 177 $acttab = unserialize(fread($fp,100000)); 178 fclose($fp); 179 if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) { 180 // abs(rand()) randomizes deletion, reducing contention to delete/refresh file 181 // ideally, you should cache at least 32 secs 182 $activedb->tables[$table] = $acttab; 183 184 //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname"); 185 return; 186 } else if ($db->debug) { 187 ADOConnection::outp("Refreshing cached active record file: $fname"); 188 } 189 } 190 $activetab = new ADODB_Active_Table(); 191 $activetab->name = $table; 192 193 194 $cols = $db->MetaColumns($table); 195 if (!$cols) { 196 $this->Error("Invalid table name: $table",'UpdateActiveTable'); 197 return false; 198 } 199 $fld = reset($cols); 200 if (!$pkeys) { 201 if (isset($fld->primary_key)) { 202 $pkeys = array(); 203 foreach($cols as $name => $fld) { 204 if (!empty($fld->primary_key)) $pkeys[] = $name; 205 } 206 } else 207 $pkeys = $this->GetPrimaryKeys($db, $table); 208 } 209 if (empty($pkeys)) { 210 $this->Error("No primary key found for table $table",'UpdateActiveTable'); 211 return false; 212 } 213 214 $attr = array(); 215 $keys = array(); 216 217 switch($ADODB_ASSOC_CASE) { 218 case 0: 219 foreach($cols as $name => $fldobj) { 220 $name = strtolower($name); 221 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) 222 $this->$name = $fldobj->default_value; 223 else 224 $this->$name = null; 225 $attr[$name] = $fldobj; 226 } 227 foreach($pkeys as $k => $name) { 228 $keys[strtolower($name)] = strtolower($name); 229 } 230 break; 231 232 case 1: 233 foreach($cols as $name => $fldobj) { 234 $name = strtoupper($name); 235 236 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) 237 $this->$name = $fldobj->default_value; 238 else 239 $this->$name = null; 240 $attr[$name] = $fldobj; 241 } 242 243 foreach($pkeys as $k => $name) { 244 $keys[strtoupper($name)] = strtoupper($name); 245 } 246 break; 247 default: 248 foreach($cols as $name => $fldobj) { 249 $name = ($fldobj->name); 250 251 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) 252 $this->$name = $fldobj->default_value; 253 else 254 $this->$name = null; 255 $attr[$name] = $fldobj; 256 } 257 foreach($pkeys as $k => $name) { 258 $keys[$name] = $cols[$name]->name; 259 } 260 break; 261 } 262 263 $activetab->keys = $keys; 264 $activetab->flds = $attr; 265 266 if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) { 267 $activetab->_created = time(); 268 $s = serialize($activetab); 269 if (!function_exists('adodb_write_file')) include (ADODB_DIR.'/adodb-csvlib.inc.php'); 270 adodb_write_file($fname,$s); 271 } 272 $activedb->tables[$table] = $activetab; 273 } 274 275 function GetPrimaryKeys(&$db, $table) 276 { 277 return $db->MetaPrimaryKeys($table); 278 } 279 280 // error handler for both PHP4+5. 281 function Error($err,$fn) 282 { 283 global $_ADODB_ACTIVE_DBS; 284 285 $fn = get_class($this).'::'.$fn; 286 $this->_lasterr = $fn.': '.$err; 287 288 if ($this->_dbat < 0) $db = false; 289 else { 290 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat]; 291 $db =& $activedb->db; 292 } 293 294 if (function_exists('adodb_throw')) { 295 if (!$db) adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false); 296 else adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db); 297 } else 298 if (!$db || $db->debug) ADOConnection::outp($this->_lasterr); 299 300 } 301 302 // return last error message 303 function ErrorMsg() 304 { 305 if (!function_exists('adodb_throw')) { 306 if ($this->_dbat < 0) $db = false; 307 else $db = $this->DB(); 308 309 // last error could be database error too 310 if ($db && $db->ErrorMsg()) return $db->ErrorMsg(); 311 } 312 return $this->_lasterr; 313 } 314 315 function ErrorNo() 316 { 317 if ($this->_dbat < 0) return -9999; // no database connection... 318 $db = $this->DB(); 319 320 return (int) $db->ErrorNo(); 321 } 322 323 324 // retrieve ADOConnection from _ADODB_Active_DBs 325 function &DB() 326 { 327 global $_ADODB_ACTIVE_DBS; 328 329 if ($this->_dbat < 0) { 330 $false = false; 331 $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB"); 332 return $false; 333 } 334 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat]; 335 $db =& $activedb->db; 336 return $db; 337 } 338 339 // retrieve ADODB_Active_Table 340 function &TableInfo() 341 { 342 global $_ADODB_ACTIVE_DBS; 343 344 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat]; 345 $table =& $activedb->tables[$this->_tableat]; 346 return $table; 347 } 348 349 // set a numeric array (using natural table field ordering) as object properties 350 function Set(&$row) 351 { 352 global $ACTIVE_RECORD_SAFETY; 353 354 $db =& $this->DB(); 355 356 if (!$row) { 357 $this->_saved = false; 358 return false; 359 } 360 361 $this->_saved = true; 362 363 $table =& $this->TableInfo(); 364 if ($ACTIVE_RECORD_SAFETY && sizeof($table->flds) != sizeof($row)) { 365 $bad_size = TRUE; 366 if (sizeof($row) == 2 * sizeof($table->flds)) { 367 // Only keep string keys 368 $keys = array_filter(array_keys($row), 'is_string'); 369 if (sizeof($keys) == sizeof($table->flds)) 370 $bad_size = FALSE; 371 } 372 if ($bad_size) { 373 $this->Error("Table structure of $this->_table has changed","Load"); 374 return false; 375 } 376 } 377 else 378 $keys = array_keys($row); 379 380 reset($keys); 381 $this->_original = array(); 382 foreach($table->flds as $name=>$fld) { 383 $value = $row[current($keys)]; 384 $this->$name = $value; 385 $this->_original[] = $value; 386 next($keys); 387 } 388 # </AP> 389 return true; 390 } 391 392 // get last inserted id for INSERT 393 function LastInsertID(&$db,$fieldname) 394 { 395 if ($db->hasInsertID) 396 $val = $db->Insert_ID($this->_table,$fieldname); 397 else 398 $val = false; 399 400 if (is_null($val) || $val === false) { 401 // this might not work reliably in multi-user environment 402 return $db->GetOne("select max(".$fieldname.") from ".$this->_table); 403 } 404 return $val; 405 } 406 407 // quote data in where clause 408 function doquote(&$db, $val,$t) 409 { 410 switch($t) { 411 case 'D': 412 case 'T': 413 if (empty($val)) return 'null'; 414 415 case 'C': 416 case 'X': 417 if (is_null($val)) return 'null'; 418 419 if (strncmp($val,"'",1) != 0 && substr($val,strlen($val)-1,1) != "'") { 420 return $db->qstr($val); 421 break; 422 } 423 default: 424 return $val; 425 break; 426 } 427 } 428 429 // generate where clause for an UPDATE/SELECT 430 function GenWhere(&$db, &$table) 431 { 432 $keys = $table->keys; 433 $parr = array(); 434 435 foreach($keys as $k) { 436 $f = $table->flds[$k]; 437 if ($f) { 438 $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type)); 439 } 440 } 441 return implode(' and ', $parr); 442 } 443 444 445 //------------------------------------------------------------ Public functions below 446 447 function Load($where,$bindarr=false) 448 { 449 $db =& $this->DB(); if (!$db) return false; 450 $this->_where = $where; 451 452 $save = $db->SetFetchMode(ADODB_FETCH_NUM); 453 $row = $db->GetRow("select * from ".$this->_table.' WHERE '.$where,$bindarr); 454 $db->SetFetchMode($save); 455 456 return $this->Set($row); 457 } 458 459 // false on error 460 function Save() 461 { 462 if ($this->_saved) $ok = $this->Update(); 463 else $ok = $this->Insert(); 464 465 return $ok; 466 } 467 468 // false on error 469 function Insert() 470 { 471 $db =& $this->DB(); if (!$db) return false; 472 $cnt = 0; 473 $table =& $this->TableInfo(); 474 475 $valarr = array(); 476 $names = array(); 477 $valstr = array(); 478 479 foreach($table->flds as $name=>$fld) { 480 $val = $this->$name; 481 if(!is_null($val) || !array_key_exists($name, $table->keys)) { 482 $valarr[] = $val; 483 $names[] = $name; 484 $valstr[] = $db->Param($cnt); 485 $cnt += 1; 486 } 487 } 488 489 if (empty($names)){ 490 foreach($table->flds as $name=>$fld) { 491 $valarr[] = null; 492 $names[] = $name; 493 $valstr[] = $db->Param($cnt); 494 $cnt += 1; 495 } 496 } 497 $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')'; 498 $ok = $db->Execute($sql,$valarr); 499 500 if ($ok) { 501 $this->_saved = true; 502 $autoinc = false; 503 foreach($table->keys as $k) { 504 if (is_null($this->$k)) { 505 $autoinc = true; 506 break; 507 } 508 } 509 if ($autoinc && sizeof($table->keys) == 1) { 510 $k = reset($table->keys); 511 $this->$k = $this->LastInsertID($db,$k); 512 } 513 } 514 515 $this->_original = $valarr; 516 return !empty($ok); 517 } 518 519 function Delete() 520 { 521 $db =& $this->DB(); if (!$db) return false; 522 $table =& $this->TableInfo(); 523 524 $where = $this->GenWhere($db,$table); 525 $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where; 526 $ok = $db->Execute($sql); 527 528 return $ok ? true : false; 529 } 530 531 // returns an array of active record objects 532 function &Find($whereOrderBy,$bindarr=false,$pkeysArr=false) 533 { 534 $db =& $this->DB(); if (!$db || empty($this->_table)) return false; 535 $arr =& $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr); 536 return $arr; 537 } 538 539 // returns 0 on error, 1 on update, 2 on insert 540 function Replace() 541 { 542 global $ADODB_ASSOC_CASE; 543 544 $db =& $this->DB(); if (!$db) return false; 545 $table =& $this->TableInfo(); 546 547 $pkey = $table->keys; 548 549 foreach($table->flds as $name=>$fld) { 550 $val = $this->$name; 551 /* 552 if (is_null($val)) { 553 if (isset($fld->not_null) && $fld->not_null) { 554 if (isset($fld->default_value) && strlen($fld->default_value)) continue; 555 else { 556 $this->Error("Cannot update null into $name","Replace"); 557 return false; 558 } 559 } 560 }*/ 561 if (is_null($val) && !empty($fld->auto_increment)) { 562 continue; 563 } 564 $t = $db->MetaType($fld->type); 565 $arr[$name] = $this->doquote($db,$val,$t); 566 $valarr[] = $val; 567 } 568 569 if (!is_array($pkey)) $pkey = array($pkey); 570 571 572 if ($ADODB_ASSOC_CASE == 0) 573 foreach($pkey as $k => $v) 574 $pkey[$k] = strtolower($v); 575 elseif ($ADODB_ASSOC_CASE == 1) 576 foreach($pkey as $k => $v) 577 $pkey[$k] = strtoupper($v); 578 579 $ok = $db->Replace($this->_table,$arr,$pkey); 580 if ($ok) { 581 $this->_saved = true; // 1= update 2=insert 582 if ($ok == 2) { 583 $autoinc = false; 584 foreach($table->keys as $k) { 585 if (is_null($this->$k)) { 586 $autoinc = true; 587 break; 588 } 589 } 590 if ($autoinc && sizeof($table->keys) == 1) { 591 $k = reset($table->keys); 592 $this->$k = $this->LastInsertID($db,$k); 593 } 594 } 595 596 $this->_original =& $valarr; 597 } 598 return $ok; 599 } 600 601 // returns 0 on error, 1 on update, -1 if no change in data (no update) 602 function Update() 603 { 604 $db =& $this->DB(); if (!$db) return false; 605 $table =& $this->TableInfo(); 606 607 $where = $this->GenWhere($db, $table); 608 609 if (!$where) { 610 $this->error("Where missing for table $table", "Update"); 611 return false; 612 } 613 $valarr = array(); 614 $neworig = array(); 615 $pairs = array(); 616 $i = -1; 617 $cnt = 0; 618 foreach($table->flds as $name=>$fld) { 619 $i += 1; 620 $val = $this->$name; 621 $neworig[] = $val; 622 623 if (isset($table->keys[$name])) { 624 continue; 625 } 626 627 if (is_null($val)) { 628 if (isset($fld->not_null) && $fld->not_null) { 629 if (isset($fld->default_value) && strlen($fld->default_value)) continue; 630 else { 631 $this->Error("Cannot set field $name to NULL","Update"); 632 return false; 633 } 634 } 635 } 636 637 if (isset($this->_original[$i]) && $val == $this->_original[$i]) { 638 continue; 639 } 640 $valarr[] = $val; 641 $pairs[] = $name.'='.$db->Param($cnt); 642 $cnt += 1; 643 } 644 645 646 if (!$cnt) return -1; 647 $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where; 648 $ok = $db->Execute($sql,$valarr); 649 if ($ok) { 650 $this->_original =& $neworig; 651 return 1; 652 } 653 return 0; 654 } 655 656 function GetAttributeNames() 657 { 658 $table =& $this->TableInfo(); 659 if (!$table) return false; 660 return array_keys($table->flds); 661 } 662 663 }; 664 665 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Jan 14 11:33:29 2009 | Cross-referenced by PHPXref 0.7 |