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