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