Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/adodb/adodb-active-record.inc.php
Go to the documentation of this file.
00001 <?php
00002 /*
00003 
00004 @version V5.14 8 Sept 2011   (c) 2000-2011 John Lim (jlim#natsoft.com). All rights reserved.
00005   Latest version is available at http://adodb.sourceforge.net
00006  
00007   Released under both BSD license and Lesser GPL library license. 
00008   Whenever there is any discrepancy between the two licenses, 
00009   the BSD license will take precedence.
00010   
00011   Active Record implementation. Superset of Zend Framework's.
00012   
00013   Version 0.92
00014   
00015   See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord 
00016         for info on Ruby on Rails Active Record implementation
00017 */
00018 
00019 
00020 global $_ADODB_ACTIVE_DBS;
00021 global $ADODB_ACTIVE_CACHESECS; // set to true to enable caching of metadata such as field info
00022 global $ACTIVE_RECORD_SAFETY; // set to false to disable safety checks
00023 global $ADODB_ACTIVE_DEFVALS; // use default values of table definition when creating new active record.
00024 
00025 // array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat
00026 $_ADODB_ACTIVE_DBS = array();
00027 $ACTIVE_RECORD_SAFETY = true;
00028 $ADODB_ACTIVE_DEFVALS = false;
00029 $ADODB_ACTIVE_CACHESECS = 0;
00030 
00031 class ADODB_Active_DB {
00032         var $db; // ADOConnection
00033         var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename
00034 }
00035 
00036 class ADODB_Active_Table {
00037         var $name; // table name
00038         var $flds; // assoc array of adofieldobjs, indexed by fieldname
00039         var $keys; // assoc array of primary keys, indexed by fieldname
00040         var $_created; // only used when stored as a cached file
00041         var $_belongsTo = array();
00042         var $_hasMany = array();
00043 }
00044 
00045 // $db = database connection
00046 // $index = name of index - can be associative, for an example see
00047 //    http://phplens.com/lens/lensforum/msgs.php?id=17790 
00048 // returns index into $_ADODB_ACTIVE_DBS
00049 function ADODB_SetDatabaseAdapter(&$db, $index=false)
00050 {
00051         global $_ADODB_ACTIVE_DBS;
00052         
00053                 foreach($_ADODB_ACTIVE_DBS as $k => $d) {
00054                         if (PHP_VERSION >= 5) {
00055                                 if ($d->db === $db) return $k;
00056                         } else {
00057                                 if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database) 
00058                                         return $k;
00059                         }
00060                 }
00061                 
00062                 $obj = new ADODB_Active_DB();
00063                 $obj->db = $db;
00064                 $obj->tables = array();
00065                 
00066                 if ($index == false) $index = sizeof($_ADODB_ACTIVE_DBS);
00067 
00068                 
00069                 $_ADODB_ACTIVE_DBS[$index] = $obj;
00070                 
00071                 return sizeof($_ADODB_ACTIVE_DBS)-1;
00072 }
00073 
00074 
00075 class ADODB_Active_Record {
00076         static $_changeNames = true; // dynamically pluralize table names
00077         static $_quoteNames = false;
00078         
00079         static $_foreignSuffix = '_id'; // 
00080         var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
00081         var $_table; // tablename, if set in class definition then use it as table name
00082         var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
00083         var $_where; // where clause set in Load()
00084         var $_saved = false; // indicates whether data is already inserted.
00085         var $_lasterr = false; // last error message
00086         var $_original = false; // the original values loaded or inserted, refreshed on update
00087 
00088         var $foreignName; // CFR: class name when in a relationship
00089 
00090         static function UseDefaultValues($bool=null)
00091         {
00092         global $ADODB_ACTIVE_DEFVALS;
00093                 if (isset($bool)) $ADODB_ACTIVE_DEFVALS = $bool;
00094                 return $ADODB_ACTIVE_DEFVALS;
00095         }
00096 
00097         // should be static
00098         static function SetDatabaseAdapter(&$db, $index=false) 
00099         {
00100                 return ADODB_SetDatabaseAdapter($db, $index);
00101         }
00102         
00103         
00104         public function __set($name, $value)
00105         {
00106                 $name = str_replace(' ', '_', $name);
00107                 $this->$name = $value;
00108         }
00109         
00110         // php5 constructor
00111         function __construct($table = false, $pkeyarr=false, $db=false)
00112         {
00113         global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
00114         
00115                 if ($db == false && is_object($pkeyarr)) {
00116                         $db = $pkeyarr;
00117                         $pkeyarr = false;
00118                 }
00119                 
00120                 if (!$table) { 
00121                         if (!empty($this->_table)) $table = $this->_table;
00122                         else $table = $this->_pluralize(get_class($this));
00123                 }
00124                 $this->foreignName = strtolower(get_class($this)); // CFR: default foreign name
00125                 if ($db) {
00126                         $this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
00127                 } else if (!isset($this->_dbat)) {
00128                         if (sizeof($_ADODB_ACTIVE_DBS) == 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
00129                         end($_ADODB_ACTIVE_DBS);
00130                         $this->_dbat = key($_ADODB_ACTIVE_DBS);
00131                 }
00132 
00133                 $this->_table = $table;
00134                 $this->_tableat = $table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
00135 
00136                 $this->UpdateActiveTable($pkeyarr);
00137         }
00138         
00139         function __wakeup()
00140         {
00141                 $class = get_class($this);
00142                 new $class;
00143         }
00144         
00145         function _pluralize($table)
00146         {
00147                 if (!ADODB_Active_Record::$_changeNames) return $table;
00148 
00149                 $ut = strtoupper($table);
00150                 $len = strlen($table);
00151                 $lastc = $ut[$len-1];
00152                 $lastc2 = substr($ut,$len-2);
00153                 switch ($lastc) {
00154                 case 'S':
00155                         return $table.'es';     
00156                 case 'Y':
00157                         return substr($table,0,$len-1).'ies';
00158                 case 'X':       
00159                         return $table.'es';
00160                 case 'H': 
00161                         if ($lastc2 == 'CH' || $lastc2 == 'SH')
00162                                 return $table.'es';
00163                 default:
00164                         return $table.'s';
00165                 }
00166         }
00167         
00168         // CFR Lamest singular inflector ever - @todo Make it real!
00169         // Note: There is an assumption here...and it is that the argument's length >= 4
00170         function _singularize($tables)
00171         {
00172         
00173                 if (!ADODB_Active_Record::$_changeNames) return $table;
00174         
00175                 $ut = strtoupper($tables);
00176                 $len = strlen($tables);
00177                 if($ut[$len-1] != 'S')
00178                         return $tables; // I know...forget oxen
00179                 if($ut[$len-2] != 'E')
00180                         return substr($tables, 0, $len-1);
00181                 switch($ut[$len-3])
00182                 {
00183                         case 'S':
00184                         case 'X':
00185                                 return substr($tables, 0, $len-2);
00186                         case 'I':
00187                                 return substr($tables, 0, $len-3) . 'y';
00188                         case 'H';
00189                                 if($ut[$len-4] == 'C' || $ut[$len-4] == 'S')
00190                                         return substr($tables, 0, $len-2);
00191                         default:
00192                                 return substr($tables, 0, $len-1); // ?
00193                 }
00194         }
00195 
00196         function hasMany($foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
00197         {
00198                 $ar = new $foreignClass($foreignRef);
00199                 $ar->foreignName = $foreignRef;
00200                 $ar->UpdateActiveTable();
00201                 $ar->foreignKey = ($foreignKey) ? $foreignKey : $foreignRef.ADODB_Active_Record::$_foreignSuffix;
00202                 $table =& $this->TableInfo();
00203                 $table->_hasMany[$foreignRef] = $ar;
00204         #       $this->$foreignRef = $this->_hasMany[$foreignRef]; // WATCHME Removed assignment by ref. to please __get()
00205         }
00206         
00207         // use when you don't want ADOdb to auto-pluralize tablename
00208         static function TableHasMany($table, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
00209         {
00210                 $ar = new ADODB_Active_Record($table);
00211                 $ar->hasMany($foreignRef, $foreignKey, $foreignClass);
00212         }
00213         
00214         // use when you don't want ADOdb to auto-pluralize tablename
00215         static function TableKeyHasMany($table, $tablePKey, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
00216         {
00217                 if (!is_array($tablePKey)) $tablePKey = array($tablePKey);
00218                 $ar = new ADODB_Active_Record($table,$tablePKey);
00219                 $ar->hasMany($foreignRef, $foreignKey, $foreignClass);
00220         }
00221         
00222         
00223         // use when you want ADOdb to auto-pluralize tablename for you. Note that the class must already be defined.
00224         // e.g. class Person will generate relationship for table Persons
00225         static function ClassHasMany($parentclass, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
00226         {
00227                 $ar = new $parentclass();
00228                 $ar->hasMany($foreignRef, $foreignKey, $foreignClass);
00229         }
00230         
00231 
00232         function belongsTo($foreignRef,$foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
00233         {
00234                 global $inflector;
00235 
00236                 $ar = new $parentClass($this->_pluralize($foreignRef));
00237                 $ar->foreignName = $foreignRef;
00238                 $ar->parentKey = $parentKey;
00239                 $ar->UpdateActiveTable();
00240                 $ar->foreignKey = ($foreignKey) ? $foreignKey : $foreignRef.ADODB_Active_Record::$_foreignSuffix;
00241                 
00242                 $table =& $this->TableInfo();
00243                 $table->_belongsTo[$foreignRef] = $ar;
00244         #       $this->$foreignRef = $this->_belongsTo[$foreignRef];
00245         }
00246         
00247         static function ClassBelongsTo($class, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
00248         {
00249                 $ar = new $class();
00250                 $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
00251         }
00252         
00253         static function TableBelongsTo($table, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
00254         {
00255                 $ar = new ADOdb_Active_Record($table);
00256                 $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
00257         }
00258         
00259         static function TableKeyBelongsTo($table, $tablePKey, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
00260         {
00261                 if (!is_array($tablePKey)) $tablePKey = array($tablePKey);
00262                 $ar = new ADOdb_Active_Record($table, $tablePKey);
00263                 $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
00264         }
00265 
00266 
00274          function __get($name)
00275         {
00276                 return $this->LoadRelations($name, '', -1, -1);
00277         }
00278         
00286         function LoadRelations($name, $whereOrderBy='', $offset=-1,$limit=-1)
00287         {
00288                 $extras = array();
00289                 $table = $this->TableInfo();
00290                 if ($limit >= 0) $extras['limit'] = $limit;
00291                 if ($offset >= 0) $extras['offset'] = $offset;
00292                 
00293                 if (strlen($whereOrderBy)) 
00294                         if (!preg_match('/^[ \n\r]*AND/i',$whereOrderBy))
00295                                 if (!preg_match('/^[ \n\r]*ORDER[ \n\r]/i',$whereOrderBy))
00296                                         $whereOrderBy = 'AND '.$whereOrderBy;
00297                                 
00298                 if(!empty($table->_belongsTo[$name]))
00299                 {
00300                         $obj = $table->_belongsTo[$name];
00301                         $columnName = $obj->foreignKey;
00302                         if(empty($this->$columnName))
00303                                 $this->$name = null;
00304                         else
00305                         {
00306                                 if ($obj->parentKey) $key = $obj->parentKey;
00307                                 else $key = reset($table->keys);
00308                                 
00309                                 $arrayOfOne = $obj->Find($key.'='.$this->$columnName.' '.$whereOrderBy,false,false,$extras);
00310                                 if ($arrayOfOne) {
00311                                         $this->$name = $arrayOfOne[0];
00312                                         return $arrayOfOne[0];
00313                                 }
00314                         }
00315                 }
00316                 if(!empty($table->_hasMany[$name]))
00317                 {       
00318                         $obj = $table->_hasMany[$name];
00319                         $key = reset($table->keys);
00320                         $id = @$this->$key;
00321                         if (!is_numeric($id)) {
00322                                 $db = $this->DB();
00323                                 $id = $db->qstr($id);
00324                         }
00325                         $objs = $obj->Find($obj->foreignKey.'='.$id. ' '.$whereOrderBy,false,false,$extras);
00326                         if (!$objs) $objs = array();
00327                         $this->$name = $objs;
00328                         return $objs;
00329                 }
00330                 
00331                 return array();
00332         }
00334         
00335         // update metadata
00336         function UpdateActiveTable($pkeys=false,$forceUpdate=false)
00337         {
00338         global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
00339         global $ADODB_ACTIVE_DEFVALS,$ADODB_FETCH_MODE;
00340 
00341                 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00342 
00343                 $table = $this->_table;
00344                 $tables = $activedb->tables;
00345                 $tableat = $this->_tableat;
00346                 if (!$forceUpdate && !empty($tables[$tableat])) {
00347 
00348                         $acttab = $tables[$tableat];
00349                         foreach($acttab->flds as $name => $fld) {
00350                         if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) 
00351                                 $this->$name = $fld->default_value;
00352                         else
00353                                 $this->$name = null;
00354                         }
00355                         return;
00356                 }
00357                 $db = $activedb->db;
00358                 $fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
00359                 if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
00360                         $fp = fopen($fname,'r');
00361                         @flock($fp, LOCK_SH);
00362                         $acttab = unserialize(fread($fp,100000));
00363                         fclose($fp);
00364                         if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) { 
00365                                 // abs(rand()) randomizes deletion, reducing contention to delete/refresh file
00366                                 // ideally, you should cache at least 32 secs
00367                                 
00368                                 foreach($acttab->flds as $name => $fld) {
00369                                         if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) 
00370                                                 $this->$name = $fld->default_value;
00371                                         else
00372                                                 $this->$name = null;
00373                                 }
00374         
00375                                 $activedb->tables[$table] = $acttab;
00376                                 
00377                                 //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname");
00378                                 return;
00379                         } else if ($db->debug) {
00380                                 ADOConnection::outp("Refreshing cached active record file: $fname");
00381                         }
00382                 }
00383                 $activetab = new ADODB_Active_Table();
00384                 $activetab->name = $table;
00385                 
00386                 $save = $ADODB_FETCH_MODE;
00387                 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
00388                 if ($db->fetchMode !== false) $savem = $db->SetFetchMode(false);
00389                 
00390                 $cols = $db->MetaColumns($table);
00391                 
00392                 if (isset($savem)) $db->SetFetchMode($savem);
00393                 $ADODB_FETCH_MODE = $save;
00394                 
00395                 if (!$cols) {
00396                         $this->Error("Invalid table name: $table",'UpdateActiveTable'); 
00397                         return false;
00398                 }
00399                 $fld = reset($cols);
00400                 if (!$pkeys) {
00401                         if (isset($fld->primary_key)) {
00402                                 $pkeys = array();
00403                                 foreach($cols as $name => $fld) {
00404                                         if (!empty($fld->primary_key)) $pkeys[] = $name;
00405                                 }
00406                         } else  
00407                                 $pkeys = $this->GetPrimaryKeys($db, $table);
00408                 }
00409                 if (empty($pkeys)) {
00410                         $this->Error("No primary key found for table $table",'UpdateActiveTable');
00411                         return false;
00412                 }
00413                 
00414                 $attr = array();
00415                 $keys = array();
00416                 
00417                 switch($ADODB_ASSOC_CASE) {
00418                 case 0:
00419                         foreach($cols as $name => $fldobj) {
00420                                 $name = strtolower($name);
00421                 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
00422                     $this->$name = $fldobj->default_value;
00423                 else
00424                                         $this->$name = null;
00425                                 $attr[$name] = $fldobj;
00426                         }
00427                         foreach($pkeys as $k => $name) {
00428                                 $keys[strtolower($name)] = strtolower($name);
00429                         }
00430                         break;
00431                         
00432                 case 1: 
00433                         foreach($cols as $name => $fldobj) {
00434                                 $name = strtoupper($name);
00435                
00436                 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
00437                     $this->$name = $fldobj->default_value;
00438                 else
00439                                         $this->$name = null;
00440                                 $attr[$name] = $fldobj;
00441                         }
00442                         
00443                         foreach($pkeys as $k => $name) {
00444                                 $keys[strtoupper($name)] = strtoupper($name);
00445                         }
00446                         break;
00447                 default:
00448                         foreach($cols as $name => $fldobj) {
00449                                 $name = ($fldobj->name);
00450                 
00451                 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
00452                     $this->$name = $fldobj->default_value;
00453                 else
00454                                         $this->$name = null;
00455                                 $attr[$name] = $fldobj;
00456                         }
00457                         foreach($pkeys as $k => $name) {
00458                                 $keys[$name] = $cols[$name]->name;
00459                         }
00460                         break;
00461                 }
00462                 
00463                 $activetab->keys = $keys;
00464                 $activetab->flds = $attr;
00465 
00466                 if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) {
00467                         $activetab->_created = time();
00468                         $s = serialize($activetab);
00469                         if (!function_exists('adodb_write_file')) include(ADODB_DIR.'/adodb-csvlib.inc.php');
00470                         adodb_write_file($fname,$s);
00471                 }
00472                 if (isset($activedb->tables[$table])) {
00473                         $oldtab = $activedb->tables[$table];
00474                 
00475                         if ($oldtab) $activetab->_belongsTo = $oldtab->_belongsTo;
00476                         if ($oldtab) $activetab->_hasMany = $oldtab->_hasMany;
00477                 }
00478                 $activedb->tables[$table] = $activetab;
00479         }
00480         
00481         function GetPrimaryKeys(&$db, $table)
00482         {
00483                 return $db->MetaPrimaryKeys($table);
00484         }
00485         
00486         // error handler for both PHP4+5. 
00487         function Error($err,$fn)
00488         {
00489         global $_ADODB_ACTIVE_DBS;
00490         
00491                 $fn = get_class($this).'::'.$fn;
00492                 $this->_lasterr = $fn.': '.$err;
00493                 
00494                 if ($this->_dbat < 0) $db = false;
00495                 else {
00496                         $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00497                         $db = $activedb->db;
00498                 }
00499                 
00500                 if (function_exists('adodb_throw')) {   
00501                         if (!$db) adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
00502                         else adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
00503                 } else
00504                         if (!$db || $db->debug) ADOConnection::outp($this->_lasterr);
00505                 
00506         }
00507         
00508         // return last error message
00509         function ErrorMsg()
00510         {
00511                 if (!function_exists('adodb_throw')) {
00512                         if ($this->_dbat < 0) $db = false;
00513                         else $db = $this->DB();
00514                 
00515                         // last error could be database error too
00516                         if ($db && $db->ErrorMsg()) return $db->ErrorMsg();
00517                 }
00518                 return $this->_lasterr;
00519         }
00520         
00521         function ErrorNo() 
00522         {
00523                 if ($this->_dbat < 0) return -9999; // no database connection...
00524                 $db = $this->DB();
00525                 
00526                 return (int) $db->ErrorNo();
00527         }
00528 
00529 
00530         // retrieve ADOConnection from _ADODB_Active_DBs
00531         function DB()
00532         {
00533         global $_ADODB_ACTIVE_DBS;
00534         
00535                 if ($this->_dbat < 0) {
00536                         $false = false;
00537                         $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
00538                         return $false;
00539                 }
00540                 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00541                 $db = $activedb->db;
00542                 return $db;
00543         }
00544         
00545         // retrieve ADODB_Active_Table
00546         function &TableInfo()
00547         {
00548         global $_ADODB_ACTIVE_DBS;
00549                 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00550                 $table = $activedb->tables[$this->_tableat];
00551                 return $table;
00552         }
00553         
00554         
00555         // I have an ON INSERT trigger on a table that sets other columns in the table.
00556         // So, I find that for myTable, I want to reload an active record after saving it. -- Malcolm Cook
00557         function Reload()
00558         {
00559                 $db =& $this->DB(); if (!$db) return false;
00560                 $table =& $this->TableInfo();
00561                 $where = $this->GenWhere($db, $table);
00562                 return($this->Load($where));
00563         }
00564 
00565         
00566         // set a numeric array (using natural table field ordering) as object properties
00567         function Set(&$row)
00568         {
00569         global $ACTIVE_RECORD_SAFETY;
00570         
00571                 $db = $this->DB();
00572                 
00573                 if (!$row) {
00574                         $this->_saved = false;          
00575                         return false;
00576                 }
00577                 
00578                 $this->_saved = true;
00579                 
00580                 $table = $this->TableInfo();
00581                 if ($ACTIVE_RECORD_SAFETY && sizeof($table->flds) != sizeof($row)) {
00582             # <AP>
00583             $bad_size = TRUE;
00584             if (sizeof($row) == 2 * sizeof($table->flds)) {
00585                 // Only keep string keys
00586                 $keys = array_filter(array_keys($row), 'is_string');
00587                 if (sizeof($keys) == sizeof($table->flds))
00588                     $bad_size = FALSE;
00589             }
00590             if ($bad_size) {
00591                         $this->Error("Table structure of $this->_table has changed","Load");
00592                         return false;
00593                 }
00594             # </AP>
00595                 }
00596         else
00597                         $keys = array_keys($row);
00598                         
00599         # <AP>
00600         reset($keys);
00601         $this->_original = array();
00602                 foreach($table->flds as $name=>$fld) {
00603             $value = $row[current($keys)];
00604                         $this->$name = $value;
00605             $this->_original[] = $value;
00606             next($keys);
00607                 }
00608 
00609         # </AP>
00610                 return true;
00611         }
00612         
00613         // get last inserted id for INSERT
00614         function LastInsertID(&$db,$fieldname)
00615         {
00616                 if ($db->hasInsertID)
00617                         $val = $db->Insert_ID($this->_table,$fieldname);
00618                 else
00619                         $val = false;
00620                         
00621                 if (is_null($val) || $val === false) {
00622                         // this might not work reliably in multi-user environment
00623                         return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
00624                 }
00625                 return $val;
00626         }
00627         
00628         // quote data in where clause
00629         function doquote(&$db, $val,$t)
00630         {
00631                 switch($t) {
00632                 case 'L':
00633                         if (strpos($db->databaseType,'postgres') !== false) return $db->qstr($val);
00634                 case 'D':       
00635                 case 'T':
00636                         if (empty($val)) return 'null';
00637                 
00638                 case 'B':       
00639                 case 'N':
00640                 case 'C':
00641                 case 'X':
00642                         if (is_null($val)) return 'null';
00643                         
00644                         if (strlen($val)>1 && 
00645                                 (strncmp($val,"'",1) != 0 || substr($val,strlen($val)-1,1) != "'")) { 
00646                                 return $db->qstr($val);
00647                                 break;
00648                         }
00649                 default:
00650                         return $val;
00651                         break;
00652                 }
00653         }
00654         
00655         // generate where clause for an UPDATE/SELECT
00656         function GenWhere(&$db, &$table)
00657         {
00658                 $keys = $table->keys;
00659                 $parr = array();
00660                 
00661                 foreach($keys as $k) {
00662                         $f = $table->flds[$k];
00663                         if ($f) {
00664                                 $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
00665                         }
00666                 }
00667                 return implode(' and ', $parr);
00668         }
00669         
00670         
00671         function _QName($n,$db=false)
00672         {
00673                 if (!ADODB_Active_Record::$_quoteNames) return $n;
00674                 if (!$db) $db = $this->DB(); if (!$db) return false;
00675                 return $db->nameQuote.$n.$db->nameQuote;
00676         }
00677         
00678         //------------------------------------------------------------ Public functions below
00679         
00680         function Load($where=null,$bindarr=false)
00681         {
00682         global $ADODB_FETCH_MODE;
00683         
00684                 $db = $this->DB(); if (!$db) return false;
00685                 $this->_where = $where;
00686                 
00687                 $save = $ADODB_FETCH_MODE;
00688                 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
00689                 if ($db->fetchMode !== false) $savem = $db->SetFetchMode(false);
00690                 
00691                 $qry = "select * from ".$this->_table;
00692 
00693                 if($where) {
00694                         $qry .= ' WHERE '.$where;
00695                 }
00696                 $row = $db->GetRow($qry,$bindarr);
00697                 
00698                 if (isset($savem)) $db->SetFetchMode($savem);
00699                 $ADODB_FETCH_MODE = $save;
00700                 
00701                 return $this->Set($row);
00702         }
00703         
00704         # useful for multiple record inserts
00705         # see http://phplens.com/lens/lensforum/msgs.php?id=17795
00706         function Reset()
00707         {
00708         $this->_where=null;
00709         $this->_saved = false; 
00710         $this->_lasterr = false; 
00711         $this->_original = false;
00712         $vars=get_object_vars($this);
00713         foreach($vars as $k=>$v){
00714                 if(substr($k,0,1)!=='_'){
00715                         $this->{$k}=null;
00716                 }
00717         }
00718         $this->foreignName=strtolower(get_class($this));
00719         return true;
00720     }
00721         
00722         // false on error
00723         function Save()
00724         {
00725                 if ($this->_saved) $ok = $this->Update();
00726                 else $ok = $this->Insert();
00727                 
00728                 return $ok;
00729         }
00730         
00731         
00732         // false on error
00733         function Insert()
00734         {
00735                 $db = $this->DB(); if (!$db) return false;
00736                 $cnt = 0;
00737                 $table = $this->TableInfo();
00738                 
00739                 $valarr = array();
00740                 $names = array();
00741                 $valstr = array();
00742 
00743                 foreach($table->flds as $name=>$fld) {
00744                         $val = $this->$name;
00745                         if(!is_array($val) || !is_null($val) || !array_key_exists($name, $table->keys)) {
00746                                 $valarr[] = $val;
00747                                 $names[] = $this->_QName($name,$db);
00748                                 $valstr[] = $db->Param($cnt);
00749                                 $cnt += 1;
00750                         }
00751                 }
00752                 
00753                 if (empty($names)){
00754                         foreach($table->flds as $name=>$fld) {
00755                                 $valarr[] = null;
00756                                 $names[] = $name;
00757                                 $valstr[] = $db->Param($cnt);
00758                                 $cnt += 1;
00759                         }
00760                 }
00761                 $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
00762                 $ok = $db->Execute($sql,$valarr);
00763                 
00764                 if ($ok) {
00765                         $this->_saved = true;
00766                         $autoinc = false;
00767                         foreach($table->keys as $k) {
00768                                 if (is_null($this->$k)) {
00769                                         $autoinc = true;
00770                                         break;
00771                                 }
00772                         }
00773                         if ($autoinc && sizeof($table->keys) == 1) {
00774                                 $k = reset($table->keys);
00775                                 $this->$k = $this->LastInsertID($db,$k);
00776                         }
00777                 }
00778                 
00779                 $this->_original = $valarr;
00780                 return !empty($ok);
00781         }
00782         
00783         function Delete()
00784         {
00785                 $db = $this->DB(); if (!$db) return false;
00786                 $table = $this->TableInfo();
00787                 
00788                 $where = $this->GenWhere($db,$table);
00789                 $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
00790                 $ok = $db->Execute($sql);
00791                 
00792                 return $ok ? true : false;
00793         }
00794         
00795         // returns an array of active record objects
00796         function Find($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
00797         {
00798                 $db = $this->DB(); if (!$db || empty($this->_table)) return false;
00799                 $arr = $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr,$extra);
00800                 return $arr;
00801         }
00802         
00803         // returns 0 on error, 1 on update, 2 on insert
00804         function Replace()
00805         {
00806         global $ADODB_ASSOC_CASE;
00807                 
00808                 $db = $this->DB(); if (!$db) return false;
00809                 $table = $this->TableInfo();
00810                 
00811                 $pkey = $table->keys;
00812                 
00813                 foreach($table->flds as $name=>$fld) {
00814                         $val = $this->$name;
00815                         /*
00816                         if (is_null($val)) {
00817                                 if (isset($fld->not_null) && $fld->not_null) {
00818                                         if (isset($fld->default_value) && strlen($fld->default_value)) continue;
00819                                         else {
00820                                                 $this->Error("Cannot update null into $name","Replace");
00821                                                 return false;
00822                                         }
00823                                 }
00824                         }*/
00825                         if (is_null($val) && !empty($fld->auto_increment)) {
00826                 continue;
00827             }
00828                         
00829                         if (is_array($val)) continue;
00830                         
00831                         $t = $db->MetaType($fld->type);
00832                         $arr[$name] = $this->doquote($db,$val,$t);
00833                         $valarr[] = $val;
00834                 }
00835                 
00836                 if (!is_array($pkey)) $pkey = array($pkey);
00837                 
00838                 
00839                 if ($ADODB_ASSOC_CASE == 0) 
00840                         foreach($pkey as $k => $v)
00841                                 $pkey[$k] = strtolower($v);
00842                 elseif ($ADODB_ASSOC_CASE == 1) 
00843                         foreach($pkey as $k => $v)
00844                                 $pkey[$k] = strtoupper($v);
00845                                 
00846                 $ok = $db->Replace($this->_table,$arr,$pkey);
00847                 if ($ok) {
00848                         $this->_saved = true; // 1= update 2=insert
00849                         if ($ok == 2) {
00850                                 $autoinc = false;
00851                                 foreach($table->keys as $k) {
00852                                         if (is_null($this->$k)) {
00853                                                 $autoinc = true;
00854                                                 break;
00855                                         }
00856                                 }
00857                                 if ($autoinc && sizeof($table->keys) == 1) {
00858                                         $k = reset($table->keys);
00859                                         $this->$k = $this->LastInsertID($db,$k);
00860                                 }
00861                         }
00862                         
00863                         $this->_original = $valarr;
00864                 } 
00865                 return $ok;
00866         }
00867 
00868         // returns 0 on error, 1 on update, -1 if no change in data (no update)
00869         function Update()
00870         {
00871                 $db = $this->DB(); if (!$db) return false;
00872                 $table = $this->TableInfo();
00873                 
00874                 $where = $this->GenWhere($db, $table);
00875                 
00876                 if (!$where) {
00877                         $this->error("Where missing for table $table", "Update");
00878                         return false;
00879                 }
00880                 $valarr = array(); 
00881                 $neworig = array();
00882                 $pairs = array();
00883                 $i = -1;
00884                 $cnt = 0;
00885                 foreach($table->flds as $name=>$fld) {
00886                         $i += 1;
00887                         $val = $this->$name;
00888                         $neworig[] = $val;
00889                         
00890                         if (isset($table->keys[$name]) || is_array($val)) 
00891                                 continue;
00892                         
00893                         if (is_null($val)) {
00894                                 if (isset($fld->not_null) && $fld->not_null) {
00895                                         if (isset($fld->default_value) && strlen($fld->default_value)) continue;
00896                                         else {
00897                                                 $this->Error("Cannot set field $name to NULL","Update");
00898                                                 return false;
00899                                         }
00900                                 }
00901                         }
00902 
00903                         if (isset($this->_original[$i]) && strcmp($val,$this->_original[$i]) == 0) {
00904                                 continue;
00905                         }
00906                         $valarr[] = $val;
00907                         $pairs[] = $this->_QName($name,$db).'='.$db->Param($cnt);
00908                         $cnt += 1;
00909                 }
00910                 
00911                 
00912                 if (!$cnt) return -1;
00913                 $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
00914                 $ok = $db->Execute($sql,$valarr);
00915                 if ($ok) {
00916                         $this->_original = $neworig;
00917                         return 1;
00918                 }
00919                 return 0;
00920         }
00921         
00922         function GetAttributeNames()
00923         {
00924                 $table = $this->TableInfo();
00925                 if (!$table) return false;
00926                 return array_keys($table->flds);
00927         }
00928         
00929 };
00930 
00931 function adodb_GetActiveRecordsClass(&$db, $class, $table,$whereOrderBy,$bindarr, $primkeyArr,
00932                         $extra)
00933 {
00934 global $_ADODB_ACTIVE_DBS;
00935 
00936         
00937         $save = $db->SetFetchMode(ADODB_FETCH_NUM);
00938         $qry = "select * from ".$table;
00939         
00940         if (!empty($whereOrderBy))
00941                 $qry .= ' WHERE '.$whereOrderBy;
00942         if(isset($extra['limit']))
00943         {
00944                 $rows = false;
00945                 if(isset($extra['offset'])) {
00946                         $rs = $db->SelectLimit($qry, $extra['limit'], $extra['offset'],$bindarr);
00947                 } else {
00948                         $rs = $db->SelectLimit($qry, $extra['limit'],-1,$bindarr);
00949                 }
00950                 if ($rs) {
00951                         while (!$rs->EOF) {
00952                                 $rows[] = $rs->fields;
00953                                 $rs->MoveNext();
00954                         }
00955                 }
00956         } else
00957                 $rows = $db->GetAll($qry,$bindarr);
00958 
00959         $db->SetFetchMode($save);
00960         
00961         $false = false;
00962         
00963         if ($rows === false) {  
00964                 return $false;
00965         }
00966         
00967 
00968         if (!class_exists($class)) {
00969                 $db->outp_throw("Unknown class $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
00970                 return $false;
00971         }
00972         $arr = array();
00973         // arrRef will be the structure that knows about our objects.
00974         // It is an associative array.
00975         // We will, however, return arr, preserving regular 0.. order so that
00976         // obj[0] can be used by app developpers.
00977         $arrRef = array();
00978         $bTos = array(); // Will store belongTo's indices if any
00979         foreach($rows as $row) {
00980         
00981                 $obj = new $class($table,$primkeyArr,$db);
00982                 if ($obj->ErrorNo()){
00983                         $db->_errorMsg = $obj->ErrorMsg();
00984                         return $false;
00985                 }
00986                 $obj->Set($row);
00987                 $arr[] = $obj;
00988         } // foreach($rows as $row) 
00989 
00990         return $arr;
00991 }
00992 ?>
 All Data Structures Namespaces Files Functions Variables Enumerations