Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]
1 <?php 2 /* 3 4 @version v5.20.16 12-Jan-2020 5 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved. 6 @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community 7 Latest version is available at http://adodb.org/ 8 9 Released under both BSD license and Lesser GPL library license. 10 Whenever there is any discrepancy between the two licenses, 11 the BSD license will take precedence. 12 13 Active Record implementation. Superset of Zend Framework's. 14 15 Version 0.92 16 17 See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord 18 for info on Ruby on Rails Active Record implementation 19 */ 20 21 22 global $_ADODB_ACTIVE_DBS; 23 global $ADODB_ACTIVE_CACHESECS; // set to true to enable caching of metadata such as field info 24 global $ACTIVE_RECORD_SAFETY; // set to false to disable safety checks 25 global $ADODB_ACTIVE_DEFVALS; // use default values of table definition when creating new active record. 26 27 // array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat 28 $_ADODB_ACTIVE_DBS = array(); 29 $ACTIVE_RECORD_SAFETY = true; 30 $ADODB_ACTIVE_DEFVALS = false; 31 $ADODB_ACTIVE_CACHESECS = 0; 32 33 class ADODB_Active_DB { 34 var $db; // ADOConnection 35 var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename 36 } 37 38 class ADODB_Active_Table { 39 var $name; // table name 40 var $flds; // assoc array of adofieldobjs, indexed by fieldname 41 var $keys; // assoc array of primary keys, indexed by fieldname 42 var $_created; // only used when stored as a cached file 43 var $_belongsTo = array(); 44 var $_hasMany = array(); 45 } 46 47 // $db = database connection 48 // $index = name of index - can be associative, for an example see 49 // http://phplens.com/lens/lensforum/msgs.php?id=17790 50 // returns index into $_ADODB_ACTIVE_DBS 51 function ADODB_SetDatabaseAdapter(&$db, $index=false) 52 { 53 global $_ADODB_ACTIVE_DBS; 54 55 foreach($_ADODB_ACTIVE_DBS as $k => $d) { 56 if (PHP_VERSION >= 5) { 57 if ($d->db === $db) { 58 return $k; 59 } 60 } else { 61 if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database) { 62 return $k; 63 } 64 } 65 } 66 67 $obj = new ADODB_Active_DB(); 68 $obj->db = $db; 69 $obj->tables = array(); 70 71 if ($index == false) { 72 $index = sizeof($_ADODB_ACTIVE_DBS); 73 } 74 75 $_ADODB_ACTIVE_DBS[$index] = $obj; 76 77 return sizeof($_ADODB_ACTIVE_DBS)-1; 78 } 79 80 81 class ADODB_Active_Record { 82 static $_changeNames = true; // dynamically pluralize table names 83 static $_quoteNames = false; 84 85 static $_foreignSuffix = '_id'; // 86 var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat] 87 var $_table; // tablename, if set in class definition then use it as table name 88 var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat] 89 var $_where; // where clause set in Load() 90 var $_saved = false; // indicates whether data is already inserted. 91 var $_lasterr = false; // last error message 92 var $_original = false; // the original values loaded or inserted, refreshed on update 93 94 var $foreignName; // CFR: class name when in a relationship 95 96 var $lockMode = ' for update '; // you might want to change to 97 98 static function UseDefaultValues($bool=null) 99 { 100 global $ADODB_ACTIVE_DEFVALS; 101 if (isset($bool)) { 102 $ADODB_ACTIVE_DEFVALS = $bool; 103 } 104 return $ADODB_ACTIVE_DEFVALS; 105 } 106 107 // should be static 108 static function SetDatabaseAdapter(&$db, $index=false) 109 { 110 return ADODB_SetDatabaseAdapter($db, $index); 111 } 112 113 114 public function __set($name, $value) 115 { 116 $name = str_replace(' ', '_', $name); 117 $this->$name = $value; 118 } 119 120 // php5 constructor 121 function __construct($table = false, $pkeyarr=false, $db=false) 122 { 123 global $_ADODB_ACTIVE_DBS; 124 125 if ($db == false && is_object($pkeyarr)) { 126 $db = $pkeyarr; 127 $pkeyarr = false; 128 } 129 130 if (!$table) { 131 if (!empty($this->_table)) { 132 $table = $this->_table; 133 } 134 else $table = $this->_pluralize(get_class($this)); 135 } 136 $this->foreignName = strtolower(get_class($this)); // CFR: default foreign name 137 if ($db) { 138 $this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db); 139 } else if (!isset($this->_dbat)) { 140 if (sizeof($_ADODB_ACTIVE_DBS) == 0) { 141 $this->Error( 142 "No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)", 143 'ADODB_Active_Record::__constructor' 144 ); 145 } 146 end($_ADODB_ACTIVE_DBS); 147 $this->_dbat = key($_ADODB_ACTIVE_DBS); 148 } 149 150 $this->_table = $table; 151 $this->_tableat = $table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future 152 153 $this->UpdateActiveTable($pkeyarr); 154 } 155 156 function __wakeup() 157 { 158 $class = get_class($this); 159 new $class; 160 } 161 162 function _pluralize($table) 163 { 164 if (!ADODB_Active_Record::$_changeNames) { 165 return $table; 166 } 167 168 $ut = strtoupper($table); 169 $len = strlen($table); 170 $lastc = $ut[$len-1]; 171 $lastc2 = substr($ut,$len-2); 172 switch ($lastc) { 173 case 'S': 174 return $table.'es'; 175 case 'Y': 176 return substr($table,0,$len-1).'ies'; 177 case 'X': 178 return $table.'es'; 179 case 'H': 180 if ($lastc2 == 'CH' || $lastc2 == 'SH') { 181 return $table.'es'; 182 } 183 default: 184 return $table.'s'; 185 } 186 } 187 188 // CFR Lamest singular inflector ever - @todo Make it real! 189 // Note: There is an assumption here...and it is that the argument's length >= 4 190 function _singularize($tables) 191 { 192 193 if (!ADODB_Active_Record::$_changeNames) { 194 return $table; 195 } 196 197 $ut = strtoupper($tables); 198 $len = strlen($tables); 199 if($ut[$len-1] != 'S') { 200 return $tables; // I know...forget oxen 201 } 202 if($ut[$len-2] != 'E') { 203 return substr($tables, 0, $len-1); 204 } 205 switch($ut[$len-3]) { 206 case 'S': 207 case 'X': 208 return substr($tables, 0, $len-2); 209 case 'I': 210 return substr($tables, 0, $len-3) . 'y'; 211 case 'H'; 212 if($ut[$len-4] == 'C' || $ut[$len-4] == 'S') { 213 return substr($tables, 0, $len-2); 214 } 215 default: 216 return substr($tables, 0, $len-1); // ? 217 } 218 } 219 220 function hasMany($foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record') 221 { 222 $ar = new $foreignClass($foreignRef); 223 $ar->foreignName = $foreignRef; 224 $ar->UpdateActiveTable(); 225 $ar->foreignKey = ($foreignKey) ? $foreignKey : $foreignRef.ADODB_Active_Record::$_foreignSuffix; 226 $table =& $this->TableInfo(); 227 $table->_hasMany[$foreignRef] = $ar; 228 # $this->$foreignRef = $this->_hasMany[$foreignRef]; // WATCHME Removed assignment by ref. to please __get() 229 } 230 231 // use when you don't want ADOdb to auto-pluralize tablename 232 static function TableHasMany($table, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record') 233 { 234 $ar = new ADODB_Active_Record($table); 235 $ar->hasMany($foreignRef, $foreignKey, $foreignClass); 236 } 237 238 // use when you don't want ADOdb to auto-pluralize tablename 239 static function TableKeyHasMany($table, $tablePKey, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record') 240 { 241 if (!is_array($tablePKey)) { 242 $tablePKey = array($tablePKey); 243 } 244 $ar = new ADODB_Active_Record($table,$tablePKey); 245 $ar->hasMany($foreignRef, $foreignKey, $foreignClass); 246 } 247 248 249 // use when you want ADOdb to auto-pluralize tablename for you. Note that the class must already be defined. 250 // e.g. class Person will generate relationship for table Persons 251 static function ClassHasMany($parentclass, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record') 252 { 253 $ar = new $parentclass(); 254 $ar->hasMany($foreignRef, $foreignKey, $foreignClass); 255 } 256 257 258 function belongsTo($foreignRef,$foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record') 259 { 260 global $inflector; 261 262 $ar = new $parentClass($this->_pluralize($foreignRef)); 263 $ar->foreignName = $foreignRef; 264 $ar->parentKey = $parentKey; 265 $ar->UpdateActiveTable(); 266 $ar->foreignKey = ($foreignKey) ? $foreignKey : $foreignRef.ADODB_Active_Record::$_foreignSuffix; 267 268 $table =& $this->TableInfo(); 269 $table->_belongsTo[$foreignRef] = $ar; 270 # $this->$foreignRef = $this->_belongsTo[$foreignRef]; 271 } 272 273 static function ClassBelongsTo($class, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record') 274 { 275 $ar = new $class(); 276 $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass); 277 } 278 279 static function TableBelongsTo($table, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record') 280 { 281 $ar = new ADOdb_Active_Record($table); 282 $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass); 283 } 284 285 static function TableKeyBelongsTo($table, $tablePKey, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record') 286 { 287 if (!is_array($tablePKey)) { 288 $tablePKey = array($tablePKey); 289 } 290 $ar = new ADOdb_Active_Record($table, $tablePKey); 291 $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass); 292 } 293 294 295 /** 296 * __get Access properties - used for lazy loading 297 * 298 * @param mixed $name 299 * @access protected 300 * @return mixed 301 */ 302 function __get($name) 303 { 304 return $this->LoadRelations($name, '', -1, -1); 305 } 306 307 /** 308 * @param string $name 309 * @param string $whereOrderBy : eg. ' AND field1 = value ORDER BY field2' 310 * @param offset 311 * @param limit 312 * @return mixed 313 */ 314 function LoadRelations($name, $whereOrderBy='', $offset=-1,$limit=-1) 315 { 316 $extras = array(); 317 $table = $this->TableInfo(); 318 if ($limit >= 0) { 319 $extras['limit'] = $limit; 320 } 321 if ($offset >= 0) { 322 $extras['offset'] = $offset; 323 } 324 325 if (strlen($whereOrderBy)) { 326 if (!preg_match('/^[ \n\r]*AND/i', $whereOrderBy)) { 327 if (!preg_match('/^[ \n\r]*ORDER[ \n\r]/i', $whereOrderBy)) { 328 $whereOrderBy = 'AND ' . $whereOrderBy; 329 } 330 } 331 } 332 333 if(!empty($table->_belongsTo[$name])) { 334 $obj = $table->_belongsTo[$name]; 335 $columnName = $obj->foreignKey; 336 if(empty($this->$columnName)) { 337 $this->$name = null; 338 } 339 else { 340 if ($obj->parentKey) { 341 $key = $obj->parentKey; 342 } 343 else { 344 $key = reset($table->keys); 345 } 346 347 $arrayOfOne = $obj->Find($key.'='.$this->$columnName.' '.$whereOrderBy,false,false,$extras); 348 if ($arrayOfOne) { 349 $this->$name = $arrayOfOne[0]; 350 return $arrayOfOne[0]; 351 } 352 } 353 } 354 if(!empty($table->_hasMany[$name])) { 355 $obj = $table->_hasMany[$name]; 356 $key = reset($table->keys); 357 $id = @$this->$key; 358 if (!is_numeric($id)) { 359 $db = $this->DB(); 360 $id = $db->qstr($id); 361 } 362 $objs = $obj->Find($obj->foreignKey.'='.$id. ' '.$whereOrderBy,false,false,$extras); 363 if (!$objs) { 364 $objs = array(); 365 } 366 $this->$name = $objs; 367 return $objs; 368 } 369 370 return array(); 371 } 372 ////////////////////////////////// 373 374 // update metadata 375 function UpdateActiveTable($pkeys=false,$forceUpdate=false) 376 { 377 global $_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS; 378 global $ADODB_ACTIVE_DEFVALS,$ADODB_FETCH_MODE; 379 380 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat]; 381 382 $table = $this->_table; 383 $tables = $activedb->tables; 384 $tableat = $this->_tableat; 385 if (!$forceUpdate && !empty($tables[$tableat])) { 386 387 $acttab = $tables[$tableat]; 388 foreach($acttab->flds as $name => $fld) { 389 if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) { 390 $this->$name = $fld->default_value; 391 } 392 else { 393 $this->$name = null; 394 } 395 } 396 return; 397 } 398 $db = $activedb->db; 399 $fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache'; 400 if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) { 401 $fp = fopen($fname,'r'); 402 @flock($fp, LOCK_SH); 403 $acttab = unserialize(fread($fp,100000)); 404 fclose($fp); 405 if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) { 406 // abs(rand()) randomizes deletion, reducing contention to delete/refresh file 407 // ideally, you should cache at least 32 secs 408 409 foreach($acttab->flds as $name => $fld) { 410 if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) { 411 $this->$name = $fld->default_value; 412 } 413 else { 414 $this->$name = null; 415 } 416 } 417 418 $activedb->tables[$table] = $acttab; 419 420 //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname"); 421 return; 422 } else if ($db->debug) { 423 ADOConnection::outp("Refreshing cached active record file: $fname"); 424 } 425 } 426 $activetab = new ADODB_Active_Table(); 427 $activetab->name = $table; 428 429 $save = $ADODB_FETCH_MODE; 430 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; 431 if ($db->fetchMode !== false) { 432 $savem = $db->SetFetchMode(false); 433 } 434 435 $cols = $db->MetaColumns($table); 436 437 if (isset($savem)) { 438 $db->SetFetchMode($savem); 439 } 440 $ADODB_FETCH_MODE = $save; 441 442 if (!$cols) { 443 $this->Error("Invalid table name: $table",'UpdateActiveTable'); 444 return false; 445 } 446 $fld = reset($cols); 447 if (!$pkeys) { 448 if (isset($fld->primary_key)) { 449 $pkeys = array(); 450 foreach($cols as $name => $fld) { 451 if (!empty($fld->primary_key)) { 452 $pkeys[] = $name; 453 } 454 } 455 } else 456 $pkeys = $this->GetPrimaryKeys($db, $table); 457 } 458 if (empty($pkeys)) { 459 $this->Error("No primary key found for table $table",'UpdateActiveTable'); 460 return false; 461 } 462 463 $attr = array(); 464 $keys = array(); 465 466 switch (ADODB_ASSOC_CASE) { 467 case ADODB_ASSOC_CASE_LOWER: 468 foreach($cols as $name => $fldobj) { 469 $name = strtolower($name); 470 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) { 471 $this->$name = $fldobj->default_value; 472 } 473 else { 474 $this->$name = null; 475 } 476 $attr[$name] = $fldobj; 477 } 478 foreach($pkeys as $k => $name) { 479 $keys[strtolower($name)] = strtolower($name); 480 } 481 break; 482 483 case ADODB_ASSOC_CASE_UPPER: 484 foreach($cols as $name => $fldobj) { 485 $name = strtoupper($name); 486 487 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) { 488 $this->$name = $fldobj->default_value; 489 } 490 else { 491 $this->$name = null; 492 } 493 $attr[$name] = $fldobj; 494 } 495 496 foreach($pkeys as $k => $name) { 497 $keys[strtoupper($name)] = strtoupper($name); 498 } 499 break; 500 default: 501 foreach($cols as $name => $fldobj) { 502 $name = ($fldobj->name); 503 504 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) { 505 $this->$name = $fldobj->default_value; 506 } 507 else { 508 $this->$name = null; 509 } 510 $attr[$name] = $fldobj; 511 } 512 foreach($pkeys as $k => $name) { 513 $keys[$name] = $cols[$name]->name; 514 } 515 break; 516 } 517 518 $activetab->keys = $keys; 519 $activetab->flds = $attr; 520 521 if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) { 522 $activetab->_created = time(); 523 $s = serialize($activetab); 524 if (!function_exists('adodb_write_file')) { 525 include (ADODB_DIR.'/adodb-csvlib.inc.php'); 526 } 527 adodb_write_file($fname,$s); 528 } 529 if (isset($activedb->tables[$table])) { 530 $oldtab = $activedb->tables[$table]; 531 532 if ($oldtab) { 533 $activetab->_belongsTo = $oldtab->_belongsTo; 534 $activetab->_hasMany = $oldtab->_hasMany; 535 } 536 } 537 $activedb->tables[$table] = $activetab; 538 } 539 540 function GetPrimaryKeys(&$db, $table) 541 { 542 return $db->MetaPrimaryKeys($table); 543 } 544 545 // error handler for both PHP4+5. 546 function Error($err,$fn) 547 { 548 global $_ADODB_ACTIVE_DBS; 549 550 $fn = get_class($this).'::'.$fn; 551 $this->_lasterr = $fn.': '.$err; 552 553 if ($this->_dbat < 0) { 554 $db = false; 555 } 556 else { 557 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat]; 558 $db = $activedb->db; 559 } 560 561 if (function_exists('adodb_throw')) { 562 if (!$db) { 563 adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false); 564 } 565 else { 566 adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db); 567 } 568 } else { 569 if (!$db || $db->debug) { 570 ADOConnection::outp($this->_lasterr); 571 } 572 } 573 574 } 575 576 // return last error message 577 function ErrorMsg() 578 { 579 if (!function_exists('adodb_throw')) { 580 if ($this->_dbat < 0) { 581 $db = false; 582 } 583 else { 584 $db = $this->DB(); 585 } 586 587 // last error could be database error too 588 if ($db && $db->ErrorMsg()) { 589 return $db->ErrorMsg(); 590 } 591 } 592 return $this->_lasterr; 593 } 594 595 function ErrorNo() 596 { 597 if ($this->_dbat < 0) { 598 return -9999; // no database connection... 599 } 600 $db = $this->DB(); 601 602 return (int) $db->ErrorNo(); 603 } 604 605 606 // retrieve ADOConnection from _ADODB_Active_DBs 607 function DB() 608 { 609 global $_ADODB_ACTIVE_DBS; 610 611 if ($this->_dbat < 0) { 612 $false = false; 613 $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB"); 614 return $false; 615 } 616 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat]; 617 $db = $activedb->db; 618 return $db; 619 } 620 621 // retrieve ADODB_Active_Table 622 function &TableInfo() 623 { 624 global $_ADODB_ACTIVE_DBS; 625 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat]; 626 $table = $activedb->tables[$this->_tableat]; 627 return $table; 628 } 629 630 631 // I have an ON INSERT trigger on a table that sets other columns in the table. 632 // So, I find that for myTable, I want to reload an active record after saving it. -- Malcolm Cook 633 function Reload() 634 { 635 $db = $this->DB(); 636 if (!$db) { 637 return false; 638 } 639 $table = $this->TableInfo(); 640 $where = $this->GenWhere($db, $table); 641 return($this->Load($where)); 642 } 643 644 645 // set a numeric array (using natural table field ordering) as object properties 646 function Set(&$row) 647 { 648 global $ACTIVE_RECORD_SAFETY; 649 650 $db = $this->DB(); 651 652 if (!$row) { 653 $this->_saved = false; 654 return false; 655 } 656 657 $this->_saved = true; 658 659 $table = $this->TableInfo(); 660 if ($ACTIVE_RECORD_SAFETY && sizeof($table->flds) != sizeof($row)) { 661 # <AP> 662 $bad_size = TRUE; 663 if (sizeof($row) == 2 * sizeof($table->flds)) { 664 // Only keep string keys 665 $keys = array_filter(array_keys($row), 'is_string'); 666 if (sizeof($keys) == sizeof($table->flds)) { 667 $bad_size = FALSE; 668 } 669 } 670 if ($bad_size) { 671 $this->Error("Table structure of $this->_table has changed","Load"); 672 return false; 673 } 674 # </AP> 675 } 676 else 677 $keys = array_keys($row); 678 679 # <AP> 680 reset($keys); 681 $this->_original = array(); 682 foreach($table->flds as $name=>$fld) { 683 $value = $row[current($keys)]; 684 $this->$name = $value; 685 $this->_original[] = $value; 686 next($keys); 687 } 688 689 # </AP> 690 return true; 691 } 692 693 // get last inserted id for INSERT 694 function LastInsertID(&$db,$fieldname) 695 { 696 if ($db->hasInsertID) { 697 $val = $db->Insert_ID($this->_table,$fieldname); 698 } 699 else { 700 $val = false; 701 } 702 703 if (is_null($val) || $val === false) { 704 // this might not work reliably in multi-user environment 705 return $db->GetOne("select max(".$fieldname.") from ".$this->_table); 706 } 707 return $val; 708 } 709 710 // quote data in where clause 711 function doquote(&$db, $val,$t) 712 { 713 switch($t) { 714 case 'L': 715 if (strpos($db->databaseType,'postgres') !== false) { 716 return $db->qstr($val); 717 } 718 case 'D': 719 case 'T': 720 if (empty($val)) { 721 return 'null'; 722 } 723 case 'B': 724 case 'N': 725 case 'C': 726 case 'X': 727 if (is_null($val)) { 728 return 'null'; 729 } 730 731 if (strlen($val)>0 && 732 (strncmp($val,"'",1) != 0 || substr($val,strlen($val)-1,1) != "'") 733 ) { 734 return $db->qstr($val); 735 break; 736 } 737 default: 738 return $val; 739 break; 740 } 741 } 742 743 // generate where clause for an UPDATE/SELECT 744 function GenWhere(&$db, &$table) 745 { 746 $keys = $table->keys; 747 $parr = array(); 748 749 foreach($keys as $k) { 750 $f = $table->flds[$k]; 751 if ($f) { 752 $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type)); 753 } 754 } 755 return implode(' and ', $parr); 756 } 757 758 759 function _QName($n,$db=false) 760 { 761 if (!ADODB_Active_Record::$_quoteNames) { 762 return $n; 763 } 764 if (!$db) { 765 $db = $this->DB(); 766 if (!$db) { 767 return false; 768 } 769 } 770 return $db->nameQuote.$n.$db->nameQuote; 771 } 772 773 //------------------------------------------------------------ Public functions below 774 775 function Load($where=null,$bindarr=false, $lock = false) 776 { 777 global $ADODB_FETCH_MODE; 778 779 $db = $this->DB(); 780 if (!$db) { 781 return false; 782 } 783 $this->_where = $where; 784 785 $save = $ADODB_FETCH_MODE; 786 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 787 if ($db->fetchMode !== false) { 788 $savem = $db->SetFetchMode(false); 789 } 790 791 $qry = "select * from ".$this->_table; 792 793 if($where) { 794 $qry .= ' WHERE '.$where; 795 } 796 if ($lock) { 797 $qry .= $this->lockMode; 798 } 799 800 $row = $db->GetRow($qry,$bindarr); 801 802 if (isset($savem)) { 803 $db->SetFetchMode($savem); 804 } 805 $ADODB_FETCH_MODE = $save; 806 807 return $this->Set($row); 808 } 809 810 function LoadLocked($where=null, $bindarr=false) 811 { 812 $this->Load($where,$bindarr,true); 813 } 814 815 # useful for multiple record inserts 816 # see http://phplens.com/lens/lensforum/msgs.php?id=17795 817 function Reset() 818 { 819 $this->_where=null; 820 $this->_saved = false; 821 $this->_lasterr = false; 822 $this->_original = false; 823 $vars=get_object_vars($this); 824 foreach($vars as $k=>$v){ 825 if(substr($k,0,1)!=='_'){ 826 $this->{$k}=null; 827 } 828 } 829 $this->foreignName=strtolower(get_class($this)); 830 return true; 831 } 832 833 // false on error 834 function Save() 835 { 836 if ($this->_saved) { 837 $ok = $this->Update(); 838 } 839 else { 840 $ok = $this->Insert(); 841 } 842 843 return $ok; 844 } 845 846 847 // false on error 848 function Insert() 849 { 850 $db = $this->DB(); 851 if (!$db) { 852 return false; 853 } 854 $cnt = 0; 855 $table = $this->TableInfo(); 856 857 $valarr = array(); 858 $names = array(); 859 $valstr = array(); 860 861 foreach($table->flds as $name=>$fld) { 862 $val = $this->$name; 863 if(!is_array($val) || !is_null($val) || !array_key_exists($name, $table->keys)) { 864 $valarr[] = $val; 865 $names[] = $this->_QName($name,$db); 866 $valstr[] = $db->Param($cnt); 867 $cnt += 1; 868 } 869 } 870 871 if (empty($names)){ 872 foreach($table->flds as $name=>$fld) { 873 $valarr[] = null; 874 $names[] = $name; 875 $valstr[] = $db->Param($cnt); 876 $cnt += 1; 877 } 878 } 879 $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')'; 880 $ok = $db->Execute($sql,$valarr); 881 882 if ($ok) { 883 $this->_saved = true; 884 $autoinc = false; 885 foreach($table->keys as $k) { 886 if (is_null($this->$k)) { 887 $autoinc = true; 888 break; 889 } 890 } 891 if ($autoinc && sizeof($table->keys) == 1) { 892 $k = reset($table->keys); 893 $this->$k = $this->LastInsertID($db,$k); 894 } 895 } 896 897 $this->_original = $valarr; 898 return !empty($ok); 899 } 900 901 function Delete() 902 { 903 $db = $this->DB(); 904 if (!$db) { 905 return false; 906 } 907 $table = $this->TableInfo(); 908 909 $where = $this->GenWhere($db,$table); 910 $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where; 911 $ok = $db->Execute($sql); 912 913 return $ok ? true : false; 914 } 915 916 // returns an array of active record objects 917 function Find($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array()) 918 { 919 $db = $this->DB(); 920 if (!$db || empty($this->_table)) { 921 return false; 922 } 923 $arr = $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr,$extra); 924 return $arr; 925 } 926 927 // returns 0 on error, 1 on update, 2 on insert 928 function Replace() 929 { 930 $db = $this->DB(); 931 if (!$db) { 932 return false; 933 } 934 $table = $this->TableInfo(); 935 936 $pkey = $table->keys; 937 938 foreach($table->flds as $name=>$fld) { 939 $val = $this->$name; 940 /* 941 if (is_null($val)) { 942 if (isset($fld->not_null) && $fld->not_null) { 943 if (isset($fld->default_value) && strlen($fld->default_value)) { 944 continue; 945 } 946 else { 947 $this->Error("Cannot update null into $name","Replace"); 948 return false; 949 } 950 } 951 }*/ 952 if (is_null($val) && !empty($fld->auto_increment)) { 953 continue; 954 } 955 956 if (is_array($val)) { 957 continue; 958 } 959 960 $t = $db->MetaType($fld->type); 961 $arr[$name] = $this->doquote($db,$val,$t); 962 $valarr[] = $val; 963 } 964 965 if (!is_array($pkey)) { 966 $pkey = array($pkey); 967 } 968 969 switch (ADODB_ASSOC_CASE) { 970 case ADODB_ASSOC_CASE_LOWER: 971 foreach ($pkey as $k => $v) { 972 $pkey[$k] = strtolower($v); 973 } 974 break; 975 case ADODB_ASSOC_CASE_UPPER: 976 foreach ($pkey as $k => $v) { 977 $pkey[$k] = strtoupper($v); 978 } 979 break; 980 } 981 982 $ok = $db->Replace($this->_table,$arr,$pkey); 983 if ($ok) { 984 $this->_saved = true; // 1= update 2=insert 985 if ($ok == 2) { 986 $autoinc = false; 987 foreach($table->keys as $k) { 988 if (is_null($this->$k)) { 989 $autoinc = true; 990 break; 991 } 992 } 993 if ($autoinc && sizeof($table->keys) == 1) { 994 $k = reset($table->keys); 995 $this->$k = $this->LastInsertID($db,$k); 996 } 997 } 998 999 $this->_original = $valarr; 1000 } 1001 return $ok; 1002 } 1003 1004 // returns 0 on error, 1 on update, -1 if no change in data (no update) 1005 function Update() 1006 { 1007 $db = $this->DB(); 1008 if (!$db) { 1009 return false; 1010 } 1011 $table = $this->TableInfo(); 1012 1013 $where = $this->GenWhere($db, $table); 1014 1015 if (!$where) { 1016 $this->error("Where missing for table $table", "Update"); 1017 return false; 1018 } 1019 $valarr = array(); 1020 $neworig = array(); 1021 $pairs = array(); 1022 $i = -1; 1023 $cnt = 0; 1024 foreach($table->flds as $name=>$fld) { 1025 $i += 1; 1026 $val = $this->$name; 1027 $neworig[] = $val; 1028 1029 if (isset($table->keys[$name]) || is_array($val)) { 1030 continue; 1031 } 1032 1033 if (is_null($val)) { 1034 if (isset($fld->not_null) && $fld->not_null) { 1035 if (isset($fld->default_value) && strlen($fld->default_value)) { 1036 continue; 1037 } 1038 else { 1039 $this->Error("Cannot set field $name to NULL","Update"); 1040 return false; 1041 } 1042 } 1043 } 1044 1045 if (isset($this->_original[$i]) && strcmp($val,$this->_original[$i]) == 0) { 1046 continue; 1047 } 1048 1049 if (is_null($this->_original[$i]) && is_null($val)) { 1050 continue; 1051 } 1052 1053 $valarr[] = $val; 1054 $pairs[] = $this->_QName($name,$db).'='.$db->Param($cnt); 1055 $cnt += 1; 1056 } 1057 1058 1059 if (!$cnt) { 1060 return -1; 1061 } 1062 1063 $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where; 1064 $ok = $db->Execute($sql,$valarr); 1065 if ($ok) { 1066 $this->_original = $neworig; 1067 return 1; 1068 } 1069 return 0; 1070 } 1071 1072 function GetAttributeNames() 1073 { 1074 $table = $this->TableInfo(); 1075 if (!$table) { 1076 return false; 1077 } 1078 return array_keys($table->flds); 1079 } 1080 1081 }; 1082 1083 function adodb_GetActiveRecordsClass(&$db, $class, $table,$whereOrderBy,$bindarr, $primkeyArr, 1084 $extra) 1085 { 1086 global $_ADODB_ACTIVE_DBS; 1087 1088 1089 $save = $db->SetFetchMode(ADODB_FETCH_NUM); 1090 $qry = "select * from ".$table; 1091 1092 if (!empty($whereOrderBy)) { 1093 $qry .= ' WHERE '.$whereOrderBy; 1094 } 1095 if(isset($extra['limit'])) { 1096 $rows = false; 1097 if(isset($extra['offset'])) { 1098 $rs = $db->SelectLimit($qry, $extra['limit'], $extra['offset'],$bindarr); 1099 } else { 1100 $rs = $db->SelectLimit($qry, $extra['limit'],-1,$bindarr); 1101 } 1102 if ($rs) { 1103 while (!$rs->EOF) { 1104 $rows[] = $rs->fields; 1105 $rs->MoveNext(); 1106 } 1107 } 1108 } else 1109 $rows = $db->GetAll($qry,$bindarr); 1110 1111 $db->SetFetchMode($save); 1112 1113 $false = false; 1114 1115 if ($rows === false) { 1116 return $false; 1117 } 1118 1119 1120 if (!class_exists($class)) { 1121 $db->outp_throw("Unknown class $class in GetActiveRecordsClass()",'GetActiveRecordsClass'); 1122 return $false; 1123 } 1124 $arr = array(); 1125 // arrRef will be the structure that knows about our objects. 1126 // It is an associative array. 1127 // We will, however, return arr, preserving regular 0.. order so that 1128 // obj[0] can be used by app developpers. 1129 $arrRef = array(); 1130 $bTos = array(); // Will store belongTo's indices if any 1131 foreach($rows as $row) { 1132 1133 $obj = new $class($table,$primkeyArr,$db); 1134 if ($obj->ErrorNo()){ 1135 $db->_errorMsg = $obj->ErrorMsg(); 1136 return $false; 1137 } 1138 $obj->Set($row); 1139 $arr[] = $obj; 1140 } // foreach($rows as $row) 1141 1142 return $arr; 1143 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body