[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/adodb/ -> adodb-active-record.inc.php (source)

   1  <?php
   2  /*
   3  
   4  @version   v5.20.3  01-Jan-2016
   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.sourceforge.net
   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_ASSOC_CASE,$_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_ASSOC_CASE,$_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 0:
 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 1:
 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      global $ADODB_ASSOC_CASE;
 931  
 932          $db = $this->DB();
 933          if (!$db) {
 934              return false;
 935          }
 936          $table = $this->TableInfo();
 937  
 938          $pkey = $table->keys;
 939  
 940          foreach($table->flds as $name=>$fld) {
 941              $val = $this->$name;
 942              /*
 943              if (is_null($val)) {
 944                  if (isset($fld->not_null) && $fld->not_null) {
 945                      if (isset($fld->default_value) && strlen($fld->default_value)) {
 946                          continue;
 947                      }
 948                      else {
 949                          $this->Error("Cannot update null into $name","Replace");
 950                          return false;
 951                      }
 952                  }
 953              }*/
 954              if (is_null($val) && !empty($fld->auto_increment)) {
 955                  continue;
 956              }
 957  
 958              if (is_array($val)) {
 959                  continue;
 960              }
 961  
 962              $t = $db->MetaType($fld->type);
 963              $arr[$name] = $this->doquote($db,$val,$t);
 964              $valarr[] = $val;
 965          }
 966  
 967          if (!is_array($pkey)) {
 968              $pkey = array($pkey);
 969          }
 970  
 971          if ($ADODB_ASSOC_CASE == 0) {
 972              foreach($pkey as $k => $v)
 973                  $pkey[$k] = strtolower($v);
 974          }
 975          elseif ($ADODB_ASSOC_CASE == 1) {
 976              foreach($pkey as $k => $v) {
 977                  $pkey[$k] = strtoupper($v);
 978              }
 979          }
 980  
 981          $ok = $db->Replace($this->_table,$arr,$pkey);
 982          if ($ok) {
 983              $this->_saved = true; // 1= update 2=insert
 984              if ($ok == 2) {
 985                  $autoinc = false;
 986                  foreach($table->keys as $k) {
 987                      if (is_null($this->$k)) {
 988                          $autoinc = true;
 989                          break;
 990                      }
 991                  }
 992                  if ($autoinc && sizeof($table->keys) == 1) {
 993                      $k = reset($table->keys);
 994                      $this->$k = $this->LastInsertID($db,$k);
 995                  }
 996              }
 997  
 998              $this->_original = $valarr;
 999          }
1000          return $ok;
1001      }
1002  
1003      // returns 0 on error, 1 on update, -1 if no change in data (no update)
1004  	function Update()
1005      {
1006          $db = $this->DB();
1007          if (!$db) {
1008              return false;
1009          }
1010          $table = $this->TableInfo();
1011  
1012          $where = $this->GenWhere($db, $table);
1013  
1014          if (!$where) {
1015              $this->error("Where missing for table $table", "Update");
1016              return false;
1017          }
1018          $valarr = array();
1019          $neworig = array();
1020          $pairs = array();
1021          $i = -1;
1022          $cnt = 0;
1023          foreach($table->flds as $name=>$fld) {
1024              $i += 1;
1025              $val = $this->$name;
1026              $neworig[] = $val;
1027  
1028              if (isset($table->keys[$name]) || is_array($val)) {
1029                  continue;
1030              }
1031  
1032              if (is_null($val)) {
1033                  if (isset($fld->not_null) && $fld->not_null) {
1034                      if (isset($fld->default_value) && strlen($fld->default_value)) {
1035                          continue;
1036                      }
1037                      else {
1038                          $this->Error("Cannot set field $name to NULL","Update");
1039                          return false;
1040                      }
1041                  }
1042              }
1043  
1044              if (isset($this->_original[$i]) && strcmp($val,$this->_original[$i]) == 0) {
1045                  continue;
1046              }
1047  
1048              if (is_null($this->_original[$i]) && is_null($val)) {
1049                  continue;
1050              }
1051  
1052              $valarr[] = $val;
1053              $pairs[] = $this->_QName($name,$db).'='.$db->Param($cnt);
1054              $cnt += 1;
1055          }
1056  
1057  
1058          if (!$cnt) {
1059              return -1;
1060          }
1061  
1062          $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
1063          $ok = $db->Execute($sql,$valarr);
1064          if ($ok) {
1065              $this->_original = $neworig;
1066              return 1;
1067          }
1068          return 0;
1069      }
1070  
1071  	function GetAttributeNames()
1072      {
1073          $table = $this->TableInfo();
1074          if (!$table) {
1075              return false;
1076          }
1077          return array_keys($table->flds);
1078      }
1079  
1080  };
1081  
1082  function adodb_GetActiveRecordsClass(&$db, $class, $table,$whereOrderBy,$bindarr, $primkeyArr,
1083              $extra)
1084  {
1085  global $_ADODB_ACTIVE_DBS;
1086  
1087  
1088      $save = $db->SetFetchMode(ADODB_FETCH_NUM);
1089      $qry = "select * from ".$table;
1090  
1091      if (!empty($whereOrderBy)) {
1092          $qry .= ' WHERE '.$whereOrderBy;
1093      }
1094      if(isset($extra['limit'])) {
1095          $rows = false;
1096          if(isset($extra['offset'])) {
1097              $rs = $db->SelectLimit($qry, $extra['limit'], $extra['offset'],$bindarr);
1098          } else {
1099              $rs = $db->SelectLimit($qry, $extra['limit'],-1,$bindarr);
1100          }
1101          if ($rs) {
1102              while (!$rs->EOF) {
1103                  $rows[] = $rs->fields;
1104                  $rs->MoveNext();
1105              }
1106          }
1107      } else
1108          $rows = $db->GetAll($qry,$bindarr);
1109  
1110      $db->SetFetchMode($save);
1111  
1112      $false = false;
1113  
1114      if ($rows === false) {
1115          return $false;
1116      }
1117  
1118  
1119      if (!class_exists($class)) {
1120          $db->outp_throw("Unknown class $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
1121          return $false;
1122      }
1123      $arr = array();
1124      // arrRef will be the structure that knows about our objects.
1125      // It is an associative array.
1126      // We will, however, return arr, preserving regular 0.. order so that
1127      // obj[0] can be used by app developpers.
1128      $arrRef = array();
1129      $bTos = array(); // Will store belongTo's indices if any
1130      foreach($rows as $row) {
1131  
1132          $obj = new $class($table,$primkeyArr,$db);
1133          if ($obj->ErrorNo()){
1134              $db->_errorMsg = $obj->ErrorMsg();
1135              return $false;
1136          }
1137          $obj->Set($row);
1138          $arr[] = $obj;
1139      } // foreach($rows as $row)
1140  
1141      return $arr;
1142  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1