Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/adodb/adodb-active-recordx.inc.php
Go to the documentation of this file.
00001 <?php
00002 /*
00003 
00004 @version V5.06 29 Sept 2008   (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   This is "Active Record eXtended" to support JOIN, WORK and LAZY mode by Chris Ravenscroft  chris#voilaweb.com 
00014   
00015   Version 0.9
00016   
00017   See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord 
00018         for info on Ruby on Rails Active Record implementation
00019 */
00020 
00021 
00022         // CFR: Active Records Definitions
00023 define('ADODB_JOIN_AR', 0x01);
00024 define('ADODB_WORK_AR', 0x02);
00025 define('ADODB_LAZY_AR', 0x03);
00026 
00027 
00028 global $_ADODB_ACTIVE_DBS;
00029 global $ADODB_ACTIVE_CACHESECS; // set to true to enable caching of metadata such as field info
00030 global $ACTIVE_RECORD_SAFETY; // set to false to disable safety checks
00031 global $ADODB_ACTIVE_DEFVALS; // use default values of table definition when creating new active record.
00032 
00033 // array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat
00034 $_ADODB_ACTIVE_DBS = array();
00035 $ACTIVE_RECORD_SAFETY = true; // CFR: disabled while playing with relations
00036 $ADODB_ACTIVE_DEFVALS = false;
00037 
00038 class ADODB_Active_DB {
00039         var $db; // ADOConnection
00040         var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename
00041 }
00042 
00043 class ADODB_Active_Table {
00044         var $name; // table name
00045         var $flds; // assoc array of adofieldobjs, indexed by fieldname
00046         var $keys; // assoc array of primary keys, indexed by fieldname
00047         var $_created; // only used when stored as a cached file
00048         var $_belongsTo = array();
00049         var $_hasMany = array();
00050         var $_colsCount; // total columns count, including relations
00051 
00052         function updateColsCount()
00053         {
00054                 $this->_colsCount = sizeof($this->flds);
00055                 foreach($this->_belongsTo as $foreignTable)
00056                         $this->_colsCount += sizeof($foreignTable->TableInfo()->flds);
00057                 foreach($this->_hasMany as $foreignTable)
00058                         $this->_colsCount += sizeof($foreignTable->TableInfo()->flds);
00059         }
00060 }
00061 
00062 // returns index into $_ADODB_ACTIVE_DBS
00063 function ADODB_SetDatabaseAdapter(&$db)
00064 {
00065         global $_ADODB_ACTIVE_DBS;
00066         
00067                 foreach($_ADODB_ACTIVE_DBS as $k => $d) {
00068                         if (PHP_VERSION >= 5) {
00069                                 if ($d->db === $db) return $k;
00070                         } else {
00071                                 if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database) 
00072                                         return $k;
00073                         }
00074                 }
00075                 
00076                 $obj = new ADODB_Active_DB();
00077                 $obj->db = $db;
00078                 $obj->tables = array();
00079                 
00080                 $_ADODB_ACTIVE_DBS[] = $obj;
00081                 
00082                 return sizeof($_ADODB_ACTIVE_DBS)-1;
00083 }
00084 
00085 
00086 class ADODB_Active_Record {
00087         static $_changeNames = true; // dynamically pluralize table names
00088         static $_foreignSuffix = '_id'; // 
00089         var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
00090         var $_table; // tablename, if set in class definition then use it as table name
00091         var $_sTable; // singularized table name
00092         var $_pTable; // pluralized table name
00093         var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
00094         var $_where; // where clause set in Load()
00095         var $_saved = false; // indicates whether data is already inserted.
00096         var $_lasterr = false; // last error message
00097         var $_original = false; // the original values loaded or inserted, refreshed on update
00098 
00099         var $foreignName; // CFR: class name when in a relationship
00100 
00101         static function UseDefaultValues($bool=null)
00102         {
00103         global $ADODB_ACTIVE_DEFVALS;
00104                 if (isset($bool)) $ADODB_ACTIVE_DEFVALS = $bool;
00105                 return $ADODB_ACTIVE_DEFVALS;
00106         }
00107 
00108         // should be static
00109         static function SetDatabaseAdapter(&$db) 
00110         {
00111                 return ADODB_SetDatabaseAdapter($db);
00112         }
00113         
00114         
00115         public function __set($name, $value)
00116         {
00117                 $name = str_replace(' ', '_', $name);
00118                 $this->$name = $value;
00119         }
00120         
00121         // php5 constructor
00122         // Note: if $table is defined, then we will use it as our table name
00123         // Otherwise we will use our classname...
00124         // In our database, table names are pluralized (because there can be
00125         // more than one row!)
00126         // Similarly, if $table is defined here, it has to be plural form.
00127         //
00128         // $options is an array that allows us to tweak the constructor's behaviour
00129         // if $options['refresh'] is true, we re-scan our metadata information
00130         // if $options['new'] is true, we forget all relations
00131         function __construct($table = false, $pkeyarr=false, $db=false, $options=array())
00132         {
00133         global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
00134         
00135                 if ($db == false && is_object($pkeyarr)) {
00136                         $db = $pkeyarr;
00137                         $pkeyarr = false;
00138                 }
00139                 
00140                 if($table)
00141                 {
00142                         // table argument exists. It is expected to be
00143                         // already plural form.
00144                         $this->_pTable = $table;
00145                         $this->_sTable = $this->_singularize($this->_pTable);
00146                 }
00147                 else
00148                 {
00149                         // We will use current classname as table name.
00150                         // We need to pluralize it for the real table name.
00151                         $this->_sTable = strtolower(get_class($this));
00152                         $this->_pTable = $this->_pluralize($this->_sTable);
00153                 }
00154                 $this->_table = &$this->_pTable;
00155 
00156                 $this->foreignName = $this->_sTable; // CFR: default foreign name (singular)
00157 
00158                 if ($db) {
00159                         $this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
00160                 } else
00161                         $this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1;
00162                 
00163                 
00164                 if ($this->_dbat < 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
00165                 
00166                 $this->_tableat = $this->_table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
00167 
00168                 // CFR: Just added this option because UpdateActiveTable() can refresh its information
00169                 // but there was no way to ask it to do that.
00170                 $forceUpdate = (isset($options['refresh']) && true === $options['refresh']);
00171                 $this->UpdateActiveTable($pkeyarr, $forceUpdate);
00172                 if(isset($options['new']) && true === $options['new'])
00173                 {
00174                         $table =& $this->TableInfo();
00175                         unset($table->_hasMany);
00176                         unset($table->_belongsTo);
00177                         $table->_hasMany = array();
00178                         $table->_belongsTo = array();
00179                 }
00180         }
00181         
00182         function __wakeup()
00183         {
00184                 $class = get_class($this);
00185                 new $class;
00186         }
00187         
00188         // CFR: Constants found in Rails
00189         static $IrregularP = array(
00190                 'PERSON'    => 'people',
00191                 'MAN'       => 'men',
00192                 'WOMAN'     => 'women',
00193                 'CHILD'     => 'children',
00194                 'COW'       => 'kine',
00195         );
00196 
00197         static $IrregularS = array(
00198                 'PEOPLE'    => 'PERSON',
00199                 'MEN'       => 'man',
00200                 'WOMEN'     => 'woman',
00201                 'CHILDREN'  => 'child',
00202                 'KINE'      => 'cow',
00203         );
00204 
00205         static $WeIsI = array(
00206                 'EQUIPMENT' => true,
00207                 'INFORMATION'   => true,
00208                 'RICE'      => true,
00209                 'MONEY'     => true,
00210                 'SPECIES'   => true,
00211                 'SERIES'    => true,
00212                 'FISH'      => true,
00213                 'SHEEP'     => true,
00214         );
00215 
00216         function _pluralize($table)
00217         {
00218                 if (!ADODB_Active_Record::$_changeNames) return $table;
00219 
00220                 $ut = strtoupper($table);
00221                 if(isset(self::$WeIsI[$ut]))
00222                 {
00223                         return $table;
00224                 }
00225                 if(isset(self::$IrregularP[$ut]))
00226                 {
00227                         return self::$IrregularP[$ut];
00228                 }
00229                 $len = strlen($table);
00230                 $lastc = $ut[$len-1];
00231                 $lastc2 = substr($ut,$len-2);
00232                 switch ($lastc) {
00233                 case 'S':
00234                         return $table.'es';     
00235                 case 'Y':
00236                         return substr($table,0,$len-1).'ies';
00237                 case 'X':       
00238                         return $table.'es';
00239                 case 'H': 
00240                         if ($lastc2 == 'CH' || $lastc2 == 'SH')
00241                                 return $table.'es';
00242                 default:
00243                         return $table.'s';
00244                 }
00245         }
00246         
00247         // CFR Lamest singular inflector ever - @todo Make it real!
00248         // Note: There is an assumption here...and it is that the argument's length >= 4
00249         function _singularize($table)
00250         {
00251         
00252                 if (!ADODB_Active_Record::$_changeNames) return $table;
00253         
00254                 $ut = strtoupper($table);
00255                 if(isset(self::$WeIsI[$ut]))
00256                 {
00257                         return $table;
00258                 }
00259                 if(isset(self::$IrregularS[$ut]))
00260                 {
00261                         return self::$IrregularS[$ut];
00262                 }
00263                 $len = strlen($table);
00264                 if($ut[$len-1] != 'S')
00265                         return $table; // I know...forget oxen
00266                 if($ut[$len-2] != 'E')
00267                         return substr($table, 0, $len-1);
00268                 switch($ut[$len-3])
00269                 {
00270                         case 'S':
00271                         case 'X':
00272                                 return substr($table, 0, $len-2);
00273                         case 'I':
00274                                 return substr($table, 0, $len-3) . 'y';
00275                         case 'H';
00276                                 if($ut[$len-4] == 'C' || $ut[$len-4] == 'S')
00277                                         return substr($table, 0, $len-2);
00278                         default:
00279                                 return substr($table, 0, $len-1); // ?
00280                 }
00281         }
00282 
00283         /*
00284          * ar->foreignName will contain the name of the tables associated with this table because
00285          * these other tables' rows may also be referenced by this table using theirname_id or the provided
00286          * foreign keys (this index name is stored in ar->foreignKey)
00287          *
00288          * this-table.id = other-table-#1.this-table_id
00289          *               = other-table-#2.this-table_id
00290          */
00291         function hasMany($foreignRef,$foreignKey=false)
00292         {
00293                 $ar = new ADODB_Active_Record($foreignRef);
00294                 $ar->foreignName = $foreignRef;
00295                 $ar->UpdateActiveTable();
00296                 $ar->foreignKey = ($foreignKey) ? $foreignKey : strtolower(get_class($this)) . self::$_foreignSuffix;
00297 
00298                 $table =& $this->TableInfo();
00299                 if(!isset($table->_hasMany[$foreignRef]))
00300                 {
00301                         $table->_hasMany[$foreignRef] = $ar;
00302                         $table->updateColsCount();
00303                 }
00304 # @todo Can I make this guy be lazy?
00305                 $this->$foreignRef = $table->_hasMany[$foreignRef]; // WATCHME Removed assignment by ref. to please __get()
00306         }
00307 
00315         function belongsTo($foreignRef,$foreignKey=false)
00316         {
00317                 global $inflector;
00318 
00319                 $ar = new ADODB_Active_Record($this->_pluralize($foreignRef));
00320                 $ar->foreignName = $foreignRef;
00321                 $ar->UpdateActiveTable();
00322                 $ar->foreignKey = ($foreignKey) ? $foreignKey : $ar->foreignName . self::$_foreignSuffix;
00323                 
00324                 $table =& $this->TableInfo();
00325                 if(!isset($table->_belongsTo[$foreignRef]))
00326                 {
00327                         $table->_belongsTo[$foreignRef] = $ar;
00328                         $table->updateColsCount();
00329                 }
00330                 $this->$foreignRef = $table->_belongsTo[$foreignRef];
00331         }
00332 
00340         function __get($name)
00341         {
00342                 return $this->LoadRelations($name, '', -1. -1);
00343         }
00344 
00345         function LoadRelations($name, $whereOrderBy, $offset=-1, $limit=-1)
00346         {
00347                 $extras = array();
00348                 if($offset >= 0) $extras['offset'] = $offset;
00349                 if($limit >= 0) $extras['limit'] = $limit;
00350                 $table =& $this->TableInfo();
00351                 
00352                 if (strlen($whereOrderBy)) 
00353                         if (!preg_match('/^[ \n\r]*AND/i',$whereOrderBy))
00354                                 if (!preg_match('/^[ \n\r]*ORDER[ \n\r]/i',$whereOrderBy))
00355                                         $whereOrderBy = 'AND '.$whereOrderBy;
00356                                         
00357                 if(!empty($table->_belongsTo[$name]))
00358                 {
00359                         $obj = $table->_belongsTo[$name];
00360                         $columnName = $obj->foreignKey;
00361                         if(empty($this->$columnName))
00362                                 $this->$name = null;
00363                         else
00364                         {
00365                                 if(($k = reset($obj->TableInfo()->keys)))
00366                                         $belongsToId = $k;
00367                                 else
00368                                         $belongsToId = 'id';
00369                                 
00370                                 $arrayOfOne =
00371                                         $obj->Find(
00372                                                 $belongsToId.'='.$this->$columnName.' '.$whereOrderBy, false, false, $extras);
00373                                 $this->$name = $arrayOfOne[0];
00374                         }
00375                         return $this->$name;
00376                 }
00377                 if(!empty($table->_hasMany[$name]))
00378                 {
00379                         $obj = $table->_hasMany[$name];
00380                         if(($k = reset($table->keys)))
00381                                 $hasManyId   = $k;
00382                         else
00383                                 $hasManyId   = 'id';                    
00384 
00385                         $this->$name =
00386                                 $obj->Find(
00387                                         $obj->foreignKey.'='.$this->$hasManyId.' '.$whereOrderBy, false, false, $extras);
00388                         return $this->$name;
00389                 }
00390         }
00392         
00393         // update metadata
00394         function UpdateActiveTable($pkeys=false,$forceUpdate=false)
00395         {
00396         global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
00397         global $ADODB_ACTIVE_DEFVALS, $ADODB_FETCH_MODE;
00398 
00399                 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00400 
00401                 $table = $this->_table;
00402                 $tables = $activedb->tables;
00403                 $tableat = $this->_tableat;
00404                 if (!$forceUpdate && !empty($tables[$tableat])) {
00405 
00406                         $tobj = $tables[$tableat];
00407                         foreach($tobj->flds as $name => $fld) {
00408                         if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) 
00409                                 $this->$name = $fld->default_value;
00410                         else
00411                                 $this->$name = null;
00412                         }
00413                         return;
00414                 }
00415                 
00416                 $db = $activedb->db;
00417                 $fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
00418                 if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
00419                         $fp = fopen($fname,'r');
00420                         @flock($fp, LOCK_SH);
00421                         $acttab = unserialize(fread($fp,100000));
00422                         fclose($fp);
00423                         if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) { 
00424                                 // abs(rand()) randomizes deletion, reducing contention to delete/refresh file
00425                                 // ideally, you should cache at least 32 secs
00426                                 $activedb->tables[$table] = $acttab;
00427                                 
00428                                 //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname");
00429                                 return;
00430                         } else if ($db->debug) {
00431                                 ADOConnection::outp("Refreshing cached active record file: $fname");
00432                         }
00433                 }
00434                 $activetab = new ADODB_Active_Table();
00435                 $activetab->name = $table;
00436                 
00437                 $save = $ADODB_FETCH_MODE;
00438                 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
00439                 if ($db->fetchMode !== false) $savem = $db->SetFetchMode(false);
00440                 
00441                 $cols = $db->MetaColumns($table);
00442                 
00443                 if (isset($savem)) $db->SetFetchMode($savem);
00444                 $ADODB_FETCH_MODE = $save;
00445                 
00446                 if (!$cols) {
00447                         $this->Error("Invalid table name: $table",'UpdateActiveTable'); 
00448                         return false;
00449                 }
00450                 $fld = reset($cols);
00451                 if (!$pkeys) {
00452                         if (isset($fld->primary_key)) {
00453                                 $pkeys = array();
00454                                 foreach($cols as $name => $fld) {
00455                                         if (!empty($fld->primary_key)) $pkeys[] = $name;
00456                                 }
00457                         } else  
00458                                 $pkeys = $this->GetPrimaryKeys($db, $table);
00459                 }
00460                 if (empty($pkeys)) {
00461                         $this->Error("No primary key found for table $table",'UpdateActiveTable');
00462                         return false;
00463                 }
00464                 
00465                 $attr = array();
00466                 $keys = array();
00467                 
00468                 switch($ADODB_ASSOC_CASE) {
00469                 case 0:
00470                         foreach($cols as $name => $fldobj) {
00471                                 $name = strtolower($name);
00472                 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
00473                     $this->$name = $fldobj->default_value;
00474                 else
00475                                         $this->$name = null;
00476                                 $attr[$name] = $fldobj;
00477                         }
00478                         foreach($pkeys as $k => $name) {
00479                                 $keys[strtolower($name)] = strtolower($name);
00480                         }
00481                         break;
00482                         
00483                 case 1: 
00484                         foreach($cols as $name => $fldobj) {
00485                                 $name = strtoupper($name);
00486                
00487                 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
00488                     $this->$name = $fldobj->default_value;
00489                 else
00490                                         $this->$name = null;
00491                                 $attr[$name] = $fldobj;
00492                         }
00493                         
00494                         foreach($pkeys as $k => $name) {
00495                                 $keys[strtoupper($name)] = strtoupper($name);
00496                         }
00497                         break;
00498                 default:
00499                         foreach($cols as $name => $fldobj) {
00500                                 $name = ($fldobj->name);
00501                 
00502                 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
00503                     $this->$name = $fldobj->default_value;
00504                 else
00505                                         $this->$name = null;
00506                                 $attr[$name] = $fldobj;
00507                         }
00508                         foreach($pkeys as $k => $name) {
00509                                 $keys[$name] = $cols[$name]->name;
00510                         }
00511                         break;
00512                 }
00513                 
00514                 $activetab->keys = $keys;
00515                 $activetab->flds = $attr;
00516                 $activetab->updateColsCount();
00517 
00518                 if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) {
00519                         $activetab->_created = time();
00520                         $s = serialize($activetab);
00521                         if (!function_exists('adodb_write_file')) include(ADODB_DIR.'/adodb-csvlib.inc.php');
00522                         adodb_write_file($fname,$s);
00523                 }
00524                 if (isset($activedb->tables[$table])) {
00525                         $oldtab = $activedb->tables[$table];
00526                 
00527                         if ($oldtab) $activetab->_belongsTo = $oldtab->_belongsTo;
00528                         if ($oldtab) $activetab->_hasMany = $oldtab->_hasMany;
00529                 }
00530                 $activedb->tables[$table] = $activetab;
00531         }
00532         
00533         function GetPrimaryKeys(&$db, $table)
00534         {
00535                 return $db->MetaPrimaryKeys($table);
00536         }
00537         
00538         // error handler for both PHP4+5. 
00539         function Error($err,$fn)
00540         {
00541         global $_ADODB_ACTIVE_DBS;
00542         
00543                 $fn = get_class($this).'::'.$fn;
00544                 $this->_lasterr = $fn.': '.$err;
00545                 
00546                 if ($this->_dbat < 0) $db = false;
00547                 else {
00548                         $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00549                         $db = $activedb->db;
00550                 }
00551                 
00552                 if (function_exists('adodb_throw')) {   
00553                         if (!$db) adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
00554                         else adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
00555                 } else
00556                         if (!$db || $db->debug) ADOConnection::outp($this->_lasterr);
00557                 
00558         }
00559         
00560         // return last error message
00561         function ErrorMsg()
00562         {
00563                 if (!function_exists('adodb_throw')) {
00564                         if ($this->_dbat < 0) $db = false;
00565                         else $db = $this->DB();
00566                 
00567                         // last error could be database error too
00568                         if ($db && $db->ErrorMsg()) return $db->ErrorMsg();
00569                 }
00570                 return $this->_lasterr;
00571         }
00572         
00573         function ErrorNo() 
00574         {
00575                 if ($this->_dbat < 0) return -9999; // no database connection...
00576                 $db = $this->DB();
00577                 
00578                 return (int) $db->ErrorNo();
00579         }
00580 
00581 
00582         // retrieve ADOConnection from _ADODB_Active_DBs
00583         function DB()
00584         {
00585         global $_ADODB_ACTIVE_DBS;
00586         
00587                 if ($this->_dbat < 0) {
00588                         $false = false;
00589                         $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
00590                         return $false;
00591                 }
00592                 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00593                 $db = $activedb->db;
00594                 return $db;
00595         }
00596         
00597         // retrieve ADODB_Active_Table
00598         function &TableInfo()
00599         {
00600         global $_ADODB_ACTIVE_DBS;
00601         
00602                 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00603                 $table = $activedb->tables[$this->_tableat];
00604                 return $table;
00605         }
00606         
00607         
00608         // I have an ON INSERT trigger on a table that sets other columns in the table.
00609         // So, I find that for myTable, I want to reload an active record after saving it. -- Malcolm Cook
00610         function Reload()
00611         {
00612                 $db =& $this->DB(); if (!$db) return false;
00613                 $table =& $this->TableInfo();
00614                 $where = $this->GenWhere($db, $table);
00615                 return($this->Load($where));
00616         }
00617 
00618         
00619         // set a numeric array (using natural table field ordering) as object properties
00620         function Set(&$row)
00621         {
00622         global $ACTIVE_RECORD_SAFETY;
00623         
00624                 $db = $this->DB();
00625                 
00626                 if (!$row) {
00627                         $this->_saved = false;          
00628                         return false;
00629                 }
00630                 
00631                 $this->_saved = true;
00632                 
00633                 $table = $this->TableInfo();
00634                 $sizeofFlds = sizeof($table->flds);
00635                 $sizeofRow  = sizeof($row);
00636                 if ($ACTIVE_RECORD_SAFETY && $table->_colsCount != $sizeofRow && $sizeofFlds != $sizeofRow) {
00637             # <AP>
00638             $bad_size = TRUE;
00639         if($sizeofRow == 2 * $table->_colsCount || $sizeofRow == 2 * $sizeofFlds) {
00640                 // Only keep string keys
00641                 $keys = array_filter(array_keys($row), 'is_string');
00642                 if (sizeof($keys) == sizeof($table->flds))
00643                     $bad_size = FALSE;
00644             }
00645             if ($bad_size) {
00646                         $this->Error("Table structure of $this->_table has changed","Load");
00647                         return false;
00648                 }
00649             # </AP>
00650                 }
00651         else
00652                 $keys = array_keys($row);
00653         # <AP>
00654         reset($keys);
00655         $this->_original = array();
00656                 foreach($table->flds as $name=>$fld)
00657                 {
00658             $value = $row[current($keys)];
00659                         $this->$name = $value;
00660             $this->_original[] = $value;
00661             if(!next($keys)) break;
00662                 }
00663                 $table =& $this->TableInfo();
00664                 foreach($table->_belongsTo as $foreignTable)
00665                 {
00666                         $ft = $foreignTable->TableInfo();
00667                         $propertyName = $ft->name;
00668                         foreach($ft->flds as $name=>$fld)
00669                         {
00670                                 $value = $row[current($keys)];
00671                                 $foreignTable->$name = $value;
00672                                 $foreignTable->_original[] = $value;
00673                                 if(!next($keys)) break;
00674                         }
00675                 }
00676                 foreach($table->_hasMany as $foreignTable)
00677                 {
00678                         $ft = $foreignTable->TableInfo();
00679                         foreach($ft->flds as $name=>$fld)
00680                         {
00681                                 $value = $row[current($keys)];
00682                                 $foreignTable->$name = $value;
00683                                 $foreignTable->_original[] = $value;
00684                                 if(!next($keys)) break;
00685                         }
00686                 }
00687         # </AP>
00688                 return true;
00689         }
00690         
00691         // get last inserted id for INSERT
00692         function LastInsertID(&$db,$fieldname)
00693         {
00694                 if ($db->hasInsertID)
00695                         $val = $db->Insert_ID($this->_table,$fieldname);
00696                 else
00697                         $val = false;
00698                         
00699                 if (is_null($val) || $val === false) {
00700                         // this might not work reliably in multi-user environment
00701                         return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
00702                 }
00703                 return $val;
00704         }
00705         
00706         // quote data in where clause
00707         function doquote(&$db, $val,$t)
00708         {
00709                 switch($t) {
00710                 case 'D':
00711                 case 'T':
00712                         if (empty($val)) return 'null';
00713                         
00714                 case 'C':
00715                 case 'X':
00716                         if (is_null($val)) return 'null';
00717                         
00718                         if (strlen($val)>1 && 
00719                                 (strncmp($val,"'",1) != 0 || substr($val,strlen($val)-1,1) != "'")) { 
00720                                 return $db->qstr($val);
00721                                 break;
00722                         }
00723                 default:
00724                         return $val;
00725                         break;
00726                 }
00727         }
00728         
00729         // generate where clause for an UPDATE/SELECT
00730         function GenWhere(&$db, &$table)
00731         {
00732                 $keys = $table->keys;
00733                 $parr = array();
00734                 
00735                 foreach($keys as $k) {
00736                         $f = $table->flds[$k];
00737                         if ($f) {
00738                                 $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
00739                         }
00740                 }
00741                 return implode(' and ', $parr);
00742         }
00743         
00744         
00745         //------------------------------------------------------------ Public functions below
00746         
00747         function Load($where=null,$bindarr=false)
00748         {
00749                 $db = $this->DB(); if (!$db) return false;
00750                 $this->_where = $where;
00751                 
00752                 $save = $db->SetFetchMode(ADODB_FETCH_NUM);
00753                 $qry = "select * from ".$this->_table;
00754                 $table =& $this->TableInfo();
00755 
00756                 if(($k = reset($table->keys)))
00757                         $hasManyId   = $k;
00758                 else
00759                         $hasManyId   = 'id';
00760                 
00761                 foreach($table->_belongsTo as $foreignTable)
00762                 {
00763                         if(($k = reset($foreignTable->TableInfo()->keys)))
00764                         {
00765                                 $belongsToId = $k;
00766                         }
00767                         else
00768                         {
00769                                 $belongsToId = 'id';
00770                         }
00771                         $qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
00772                                 $this->_table.'.'.$foreignTable->foreignKey.'='.
00773                                 $foreignTable->_table.'.'.$belongsToId;
00774                 }
00775                 foreach($table->_hasMany as $foreignTable)
00776                 {
00777                         $qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
00778                                 $this->_table.'.'.$hasManyId.'='.
00779                                 $foreignTable->_table.'.'.$foreignTable->foreignKey;
00780                 }
00781                 if($where)
00782                         $qry .= ' WHERE '.$where;
00783                 
00784                 // Simple case: no relations. Load row and return.
00785                 if((count($table->_hasMany) + count($table->_belongsTo)) < 1)
00786                 {
00787                         $row = $db->GetRow($qry,$bindarr);
00788                         if(!$row)
00789                                 return false;
00790                         $db->SetFetchMode($save);
00791                         return $this->Set($row);
00792                 }
00793                 
00794                 // More complex case when relations have to be collated
00795                 $rows = $db->GetAll($qry,$bindarr);
00796                 if(!$rows)
00797                         return false;
00798                 $db->SetFetchMode($save);
00799                 if(count($rows) < 1)
00800                         return false;
00801                 $class = get_class($this);
00802                 $isFirstRow = true;
00803                 
00804                 if(($k = reset($this->TableInfo()->keys)))
00805                         $myId   = $k;
00806                 else
00807                         $myId   = 'id';
00808                 $index = 0; $found = false;
00811                 foreach($this->TableInfo()->flds as $fld)
00812                 {
00813                         if($fld->name == $myId)
00814                         {
00815                                 $found = true;
00816                                 break;
00817                         }
00818                         $index++;
00819                 }
00820                 if(!$found)
00821                         $this->outp_throw("Unable to locate key $myId for $class in Load()",'Load');
00822                 
00823                 foreach($rows as $row)
00824                 {
00825                         $rowId = intval($row[$index]);
00826                         if($rowId > 0)
00827                         {
00828                                 if($isFirstRow)
00829                                 {
00830                                         $isFirstRow = false;
00831                                         if(!$this->Set($row))
00832                                                 return false;
00833                                 }
00834                                 $obj = new $class($table,false,$db);
00835                                 $obj->Set($row);
00836                                 // TODO Copy/paste code below: bad!
00837                                 if(count($table->_hasMany) > 0)
00838                                 {
00839                                         foreach($table->_hasMany as $foreignTable)
00840                                         {
00841                                                 $foreignName = $foreignTable->foreignName;
00842                                                 if(!empty($obj->$foreignName))
00843                                                 {
00844                                                         if(!is_array($this->$foreignName))
00845                                                         {
00846                                                                 $foreignObj = $this->$foreignName;
00847                                                                 $this->$foreignName = array(clone($foreignObj));
00848                                                         }
00849                                                         else
00850                                                         {
00851                                                                 $foreignObj = $obj->$foreignName;
00852                                                                 array_push($this->$foreignName, clone($foreignObj));
00853                                                         }
00854                                                 }
00855                                         }
00856                                 }
00857                                 if(count($table->_belongsTo) > 0)
00858                                 {
00859                                         foreach($table->_belongsTo as $foreignTable)
00860                                         {
00861                                                 $foreignName = $foreignTable->foreignName;
00862                                                 if(!empty($obj->$foreignName))
00863                                                 {
00864                                                         if(!is_array($this->$foreignName))
00865                                                         {
00866                                                                 $foreignObj = $this->$foreignName;
00867                                                                 $this->$foreignName = array(clone($foreignObj));
00868                                                         }
00869                                                         else
00870                                                         {
00871                                                                 $foreignObj = $obj->$foreignName;
00872                                                                 array_push($this->$foreignName, clone($foreignObj));
00873                                                         }
00874                                                 }
00875                                         }
00876                                 }                               
00877                         }
00878                 }
00879                 return true;
00880         }
00881         
00882         // false on error
00883         function Save()
00884         {
00885                 if ($this->_saved) $ok = $this->Update();
00886                 else $ok = $this->Insert();
00887                 
00888                 return $ok;
00889         }
00890         
00891         // CFR: Sometimes we may wish to consider that an object is not to be replaced but inserted.
00892         // Sample use case: an 'undo' command object (after a delete())
00893         function Dirty()
00894         {
00895                 $this->_saved = false;
00896         }
00897 
00898         // false on error
00899         function Insert()
00900         {
00901                 $db = $this->DB(); if (!$db) return false;
00902                 $cnt = 0;
00903                 $table = $this->TableInfo();
00904                 
00905                 $valarr = array();
00906                 $names = array();
00907                 $valstr = array();
00908 
00909                 foreach($table->flds as $name=>$fld) {
00910                         $val = $this->$name;
00911                         if(!is_null($val) || !array_key_exists($name, $table->keys)) {
00912                                 $valarr[] = $val;
00913                                 $names[] = $name;
00914                                 $valstr[] = $db->Param($cnt);
00915                                 $cnt += 1;
00916                         }
00917                 }
00918                 
00919                 if (empty($names)){
00920                         foreach($table->flds as $name=>$fld) {
00921                                 $valarr[] = null;
00922                                 $names[] = $name;
00923                                 $valstr[] = $db->Param($cnt);
00924                                 $cnt += 1;
00925                         }
00926                 }
00927                 $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
00928                 $ok = $db->Execute($sql,$valarr);
00929                 
00930                 if ($ok) {
00931                         $this->_saved = true;
00932                         $autoinc = false;
00933                         foreach($table->keys as $k) {
00934                                 if (is_null($this->$k)) {
00935                                         $autoinc = true;
00936                                         break;
00937                                 }
00938                         }
00939                         if ($autoinc && sizeof($table->keys) == 1) {
00940                                 $k = reset($table->keys);
00941                                 $this->$k = $this->LastInsertID($db,$k);
00942                         }
00943                 }
00944                 
00945                 $this->_original = $valarr;
00946                 return !empty($ok);
00947         }
00948         
00949         function Delete()
00950         {
00951                 $db = $this->DB(); if (!$db) return false;
00952                 $table = $this->TableInfo();
00953                 
00954                 $where = $this->GenWhere($db,$table);
00955                 $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
00956                 $ok = $db->Execute($sql);
00957                 
00958                 return $ok ? true : false;
00959         }
00960         
00961         // returns an array of active record objects
00962         function Find($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
00963         {
00964                 $db = $this->DB(); if (!$db || empty($this->_table)) return false;
00965                 $table =& $this->TableInfo();
00966                 $arr = $db->GetActiveRecordsClass(get_class($this),$this, $whereOrderBy,$bindarr,$pkeysArr,$extra,
00967                         array('foreignName'=>$this->foreignName, 'belongsTo'=>$table->_belongsTo, 'hasMany'=>$table->_hasMany));
00968                 return $arr;
00969         }
00970         
00971         // CFR: In introduced this method to ensure that inner workings are not disturbed by
00972         // subclasses...for instance when GetActiveRecordsClass invokes Find()
00973         // Why am I not invoking parent::Find?
00974         // Shockingly because I want to preserve PHP4 compatibility.
00975         function packageFind($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
00976         {
00977                 $db = $this->DB(); if (!$db || empty($this->_table)) return false;
00978                 $table =& $this->TableInfo();
00979                 $arr = $db->GetActiveRecordsClass(get_class($this),$this, $whereOrderBy,$bindarr,$pkeysArr,$extra,
00980                         array('foreignName'=>$this->foreignName, 'belongsTo'=>$table->_belongsTo, 'hasMany'=>$table->_hasMany));
00981                 return $arr;
00982         }
00983 
00984         // returns 0 on error, 1 on update, 2 on insert
00985         function Replace()
00986         {
00987         global $ADODB_ASSOC_CASE;
00988                 
00989                 $db = $this->DB(); if (!$db) return false;
00990                 $table = $this->TableInfo();
00991                 
00992                 $pkey = $table->keys;
00993                 
00994                 foreach($table->flds as $name=>$fld) {
00995                         $val = $this->$name;
00996                         /*
00997                         if (is_null($val)) {
00998                                 if (isset($fld->not_null) && $fld->not_null) {
00999                                         if (isset($fld->default_value) && strlen($fld->default_value)) continue;
01000                                         else {
01001                                                 $this->Error("Cannot update null into $name","Replace");
01002                                                 return false;
01003                                         }
01004                                 }
01005                         }*/
01006                         if (is_null($val) && !empty($fld->auto_increment)) {
01007                 continue;
01008             }
01009                         $t = $db->MetaType($fld->type);
01010                         $arr[$name] = $this->doquote($db,$val,$t);
01011                         $valarr[] = $val;
01012                 }
01013                 
01014                 if (!is_array($pkey)) $pkey = array($pkey);
01015                 
01016                 
01017                 if ($ADODB_ASSOC_CASE == 0) 
01018                         foreach($pkey as $k => $v)
01019                                 $pkey[$k] = strtolower($v);
01020                 elseif ($ADODB_ASSOC_CASE == 1) 
01021                         foreach($pkey as $k => $v)
01022                                 $pkey[$k] = strtoupper($v);
01023                                 
01024                 $ok = $db->Replace($this->_table,$arr,$pkey);
01025                 if ($ok) {
01026                         $this->_saved = true; // 1= update 2=insert
01027                         if ($ok == 2) {
01028                                 $autoinc = false;
01029                                 foreach($table->keys as $k) {
01030                                         if (is_null($this->$k)) {
01031                                                 $autoinc = true;
01032                                                 break;
01033                                         }
01034                                 }
01035                                 if ($autoinc && sizeof($table->keys) == 1) {
01036                                         $k = reset($table->keys);
01037                                         $this->$k = $this->LastInsertID($db,$k);
01038                                 }
01039                         }
01040                         
01041                         $this->_original = $valarr;
01042                 } 
01043                 return $ok;
01044         }
01045 
01046         // returns 0 on error, 1 on update, -1 if no change in data (no update)
01047         function Update()
01048         {
01049                 $db = $this->DB(); if (!$db) return false;
01050                 $table = $this->TableInfo();
01051                 
01052                 $where = $this->GenWhere($db, $table);
01053                 
01054                 if (!$where) {
01055                         $this->error("Where missing for table $table", "Update");
01056                         return false;
01057                 }
01058                 $valarr = array(); 
01059                 $neworig = array();
01060                 $pairs = array();
01061                 $i = -1;
01062                 $cnt = 0;
01063                 foreach($table->flds as $name=>$fld) {
01064                         $i += 1;
01065                         $val = $this->$name;
01066                         $neworig[] = $val;
01067                         
01068                         if (isset($table->keys[$name])) {
01069                                 continue;
01070                         }
01071                         
01072                         if (is_null($val)) {
01073                                 if (isset($fld->not_null) && $fld->not_null) {
01074                                         if (isset($fld->default_value) && strlen($fld->default_value)) continue;
01075                                         else {
01076                                                 $this->Error("Cannot set field $name to NULL","Update");
01077                                                 return false;
01078                                         }
01079                                 }
01080                         }
01081                         
01082                         if (isset($this->_original[$i]) && $val == $this->_original[$i]) {
01083                                 continue;
01084                         }                       
01085                         $valarr[] = $val;
01086                         $pairs[] = $name.'='.$db->Param($cnt);
01087                         $cnt += 1;
01088                 }
01089                 
01090                 
01091                 if (!$cnt) return -1;
01092                 $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
01093                 $ok = $db->Execute($sql,$valarr);
01094                 if ($ok) {
01095                         $this->_original = $neworig;
01096                         return 1;
01097                 }
01098                 return 0;
01099         }
01100         
01101         function GetAttributeNames()
01102         {
01103                 $table = $this->TableInfo();
01104                 if (!$table) return false;
01105                 return array_keys($table->flds);
01106         }
01107         
01108 };
01109 
01110 function adodb_GetActiveRecordsClass(&$db, $class, $tableObj,$whereOrderBy,$bindarr, $primkeyArr,
01111                         $extra, $relations)
01112 {
01113         global $_ADODB_ACTIVE_DBS;
01114         
01115                 if (empty($extra['loading'])) $extra['loading'] = ADODB_LAZY_AR;
01116                 
01117                 $save = $db->SetFetchMode(ADODB_FETCH_NUM);
01118                 $table = &$tableObj->_table;
01119                 $tableInfo =& $tableObj->TableInfo();
01120                 if(($k = reset($tableInfo->keys)))
01121                         $myId   = $k;
01122                 else
01123                         $myId   = 'id';
01124                 $index = 0; $found = false;
01127                 foreach($tableInfo->flds as $fld)
01128                 {
01129                         if($fld->name == $myId)
01130                         {
01131                                 $found = true;
01132                                 break;
01133                         }
01134                         $index++;
01135                 }
01136                 if(!$found)
01137                         $db->outp_throw("Unable to locate key $myId for $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
01138                 
01139                 $qry = "select * from ".$table;
01140                 if(ADODB_JOIN_AR == $extra['loading'])
01141                 {
01142                         if(!empty($relations['belongsTo']))
01143                         {
01144                                 foreach($relations['belongsTo'] as $foreignTable)
01145                                 {
01146                                         if(($k = reset($foreignTable->TableInfo()->keys)))
01147                                         {
01148                                                 $belongsToId = $k;
01149                                         }
01150                                         else
01151                                         {
01152                                                 $belongsToId = 'id';
01153                                         }
01154 
01155                                         $qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
01156                                                 $table.'.'.$foreignTable->foreignKey.'='.
01157                                                 $foreignTable->_table.'.'.$belongsToId;
01158                                 }
01159                         }
01160                         if(!empty($relations['hasMany']))
01161                         {
01162                                 if(empty($relations['foreignName']))
01163                                         $db->outp_throw("Missing foreignName is relation specification in GetActiveRecordsClass()",'GetActiveRecordsClass');
01164                                 if(($k = reset($tableInfo->keys)))
01165                                         $hasManyId   = $k;
01166                                 else
01167                                         $hasManyId   = 'id';
01168 
01169                                 foreach($relations['hasMany'] as $foreignTable)
01170                                 {
01171                                         $qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
01172                                                 $table.'.'.$hasManyId.'='.
01173                                                 $foreignTable->_table.'.'.$foreignTable->foreignKey;
01174                                 }
01175                         }
01176                 }
01177                 if (!empty($whereOrderBy))
01178                         $qry .= ' WHERE '.$whereOrderBy;
01179                 if(isset($extra['limit']))
01180                 {
01181                         $rows = false;
01182                         if(isset($extra['offset'])) {
01183                                 $rs = $db->SelectLimit($qry, $extra['limit'], $extra['offset']);
01184                         } else {
01185                                 $rs = $db->SelectLimit($qry, $extra['limit']);
01186                         }
01187                         if ($rs) {
01188                                 while (!$rs->EOF) {
01189                                         $rows[] = $rs->fields;
01190                                         $rs->MoveNext();
01191                                 }
01192                         }
01193                 } else
01194                         $rows = $db->GetAll($qry,$bindarr);
01195                         
01196                 $db->SetFetchMode($save);
01197                 
01198                 $false = false;
01199                 
01200                 if ($rows === false) {  
01201                         return $false;
01202                 }
01203                 
01204                 
01205                 if (!isset($_ADODB_ACTIVE_DBS)) {
01206                         include(ADODB_DIR.'/adodb-active-record.inc.php');
01207                 }       
01208                 if (!class_exists($class)) {
01209                         $db->outp_throw("Unknown class $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
01210                         return $false;
01211                 }
01212                 $uniqArr = array(); // CFR Keep track of records for relations
01213                 $arr = array();
01214                 // arrRef will be the structure that knows about our objects.
01215                 // It is an associative array.
01216                 // We will, however, return arr, preserving regular 0.. order so that
01217                 // obj[0] can be used by app developpers.
01218                 $arrRef = array();
01219                 $bTos = array(); // Will store belongTo's indices if any
01220                 foreach($rows as $row) {
01221                 
01222                         $obj = new $class($table,$primkeyArr,$db);
01223                         if ($obj->ErrorNo()){
01224                                 $db->_errorMsg = $obj->ErrorMsg();
01225                                 return $false;
01226                         }
01227                         $obj->Set($row);
01228                         // CFR: FIXME: Insane assumption here:
01229                         // If the first column returned is an integer, then it's a 'id' field
01230                         // And to make things a bit worse, I use intval() rather than is_int() because, in fact,
01231                         // $row[0] is not an integer.
01232                         //
01233                         // So, what does this whole block do?
01234                         // When relationships are found, we perform JOINs. This is fast. But not accurate:
01235                         // instead of returning n objects with their n' associated cousins,
01236                         // we get n*n' objects. This code fixes this.
01237                         // Note: to-many relationships mess around with the 'limit' parameter
01238                         $rowId = intval($row[$index]);
01239 
01240                         if(ADODB_WORK_AR == $extra['loading'])
01241                         {
01242                                 $arrRef[$rowId] = $obj;
01243                                 $arr[] = &$arrRef[$rowId];
01244                                 if(!isset($indices))
01245                                         $indices = $rowId;
01246                                 else
01247                                         $indices .= ','.$rowId;
01248                                 if(!empty($relations['belongsTo']))
01249                                 {
01250                                         foreach($relations['belongsTo'] as $foreignTable)
01251                                         {
01252                                                 $foreignTableRef = $foreignTable->foreignKey;
01253                                                 // First array: list of foreign ids we are looking for
01254                                                 if(empty($bTos[$foreignTableRef]))
01255                                                         $bTos[$foreignTableRef] = array();
01256                                                 // Second array: list of ids found
01257                                                 if(empty($obj->$foreignTableRef))
01258                                                         continue;
01259                                                 if(empty($bTos[$foreignTableRef][$obj->$foreignTableRef]))
01260                                                         $bTos[$foreignTableRef][$obj->$foreignTableRef] = array();
01261                                                 $bTos[$foreignTableRef][$obj->$foreignTableRef][] = $obj;
01262                                         }
01263                                 }
01264                                 continue;
01265                         }
01266 
01267                         if($rowId>0)
01268                         {
01269                                 if(ADODB_JOIN_AR == $extra['loading'])
01270                                 {
01271                                         $isNewObj = !isset($uniqArr['_'.$row[0]]); 
01272                                         if($isNewObj)
01273                                                 $uniqArr['_'.$row[0]] = $obj;
01274 
01275                                         // TODO Copy/paste code below: bad!
01276                                         if(!empty($relations['hasMany']))
01277                                         {
01278                                                 foreach($relations['hasMany'] as $foreignTable)
01279                                                 {
01280                                                         $foreignName = $foreignTable->foreignName;
01281                                                         if(!empty($obj->$foreignName))
01282                                                         {
01283                                                                 $masterObj = &$uniqArr['_'.$row[0]];
01284                                                                 // Assumption: this property exists in every object since they are instances of the same class
01285                                                                 if(!is_array($masterObj->$foreignName))
01286                                                                 {
01287                                                                         // Pluck!
01288                                                                         $foreignObj = $masterObj->$foreignName;
01289                                                                         $masterObj->$foreignName = array(clone($foreignObj));
01290                                                                 }
01291                                                                 else
01292                                                                 {
01293                                                                         // Pluck pluck!
01294                                                                         $foreignObj = $obj->$foreignName;
01295                                                                         array_push($masterObj->$foreignName, clone($foreignObj));
01296                                                                 }
01297                                                         }
01298                                                 }
01299                                         }
01300                                         if(!empty($relations['belongsTo']))
01301                                         {
01302                                                 foreach($relations['belongsTo'] as $foreignTable)
01303                                                 {
01304                                                         $foreignName = $foreignTable->foreignName;
01305                                                         if(!empty($obj->$foreignName))
01306                                                         {
01307                                                                 $masterObj = &$uniqArr['_'.$row[0]];
01308                                                                 // Assumption: this property exists in every object since they are instances of the same class
01309                                                                 if(!is_array($masterObj->$foreignName))
01310                                                                 {
01311                                                                         // Pluck!
01312                                                                         $foreignObj = $masterObj->$foreignName;
01313                                                                         $masterObj->$foreignName = array(clone($foreignObj));
01314                                                                 }
01315                                                                 else
01316                                                                 {
01317                                                                         // Pluck pluck!
01318                                                                         $foreignObj = $obj->$foreignName;
01319                                                                         array_push($masterObj->$foreignName, clone($foreignObj));
01320                                                                 }
01321                                                         }
01322                                                 }
01323                                         }
01324                                         if(!$isNewObj)
01325                                                 unset($obj); // We do not need this object itself anymore and do not want it re-added to the main array                                 
01326                                 }
01327                                 else if(ADODB_LAZY_AR == $extra['loading'])
01328                                 {
01329                                         // Lazy loading: we need to give AdoDb a hint that we have not really loaded
01330                                         // anything, all the while keeping enough information on what we wish to load.
01331                                         // Let's do this by keeping the relevant info in our relationship arrays
01332                                         // but get rid of the actual properties.
01333                                         // We will then use PHP's __get to load these properties on-demand.
01334                                         if(!empty($relations['hasMany']))
01335                                         {
01336                                                 foreach($relations['hasMany'] as $foreignTable)
01337                                                 {
01338                                                         $foreignName = $foreignTable->foreignName;
01339                                                         if(!empty($obj->$foreignName))
01340                                                         {
01341                                                                 unset($obj->$foreignName);
01342                                                         }
01343                                                 }
01344                                         }
01345                                         if(!empty($relations['belongsTo']))
01346                                         {
01347                                                 foreach($relations['belongsTo'] as $foreignTable)
01348                                                 {
01349                                                         $foreignName = $foreignTable->foreignName;
01350                                                         if(!empty($obj->$foreignName))
01351                                                         {
01352                                                                 unset($obj->$foreignName);
01353                                                         }
01354                                                 }
01355                                         }
01356                                 }
01357                         }
01358 
01359                         if(isset($obj))
01360                                 $arr[] = $obj;
01361                 }
01362 
01363                 if(ADODB_WORK_AR == $extra['loading'])
01364                 {
01365                         // The best of both worlds?
01366                         // Here, the number of queries is constant: 1 + n*relationship.
01367                         // The second query will allow us to perform a good join
01368                         // while preserving LIMIT etc.
01369                         if(!empty($relations['hasMany']))
01370                         {
01371                                 foreach($relations['hasMany'] as $foreignTable)
01372                                 {
01373                                         $foreignName = $foreignTable->foreignName;
01374                                         $className = ucfirst($foreignTable->_singularize($foreignName));
01375                                         $obj = new $className();
01376                                         $dbClassRef = $foreignTable->foreignKey;
01377                                         $objs = $obj->packageFind($dbClassRef.' IN ('.$indices.')');
01378                                         foreach($objs as $obj)
01379                                         {
01380                                                 if(!is_array($arrRef[$obj->$dbClassRef]->$foreignName))
01381                                                         $arrRef[$obj->$dbClassRef]->$foreignName = array();
01382                                                 array_push($arrRef[$obj->$dbClassRef]->$foreignName, $obj);
01383                                         }
01384                                 }
01385                                 
01386                         }
01387                         if(!empty($relations['belongsTo']))
01388                         {
01389                                 foreach($relations['belongsTo'] as $foreignTable)
01390                                 {
01391                                         $foreignTableRef = $foreignTable->foreignKey;
01392                                         if(empty($bTos[$foreignTableRef]))
01393                                                 continue;
01394                                         if(($k = reset($foreignTable->TableInfo()->keys)))
01395                                         {
01396                                                 $belongsToId = $k;
01397                                         }
01398                                         else
01399                                         {
01400                                                 $belongsToId = 'id';
01401                                         }                                               
01402                                         $origObjsArr = $bTos[$foreignTableRef];
01403                                         $bTosString = implode(',', array_keys($bTos[$foreignTableRef]));
01404                                         $foreignName = $foreignTable->foreignName;
01405                                         $className = ucfirst($foreignTable->_singularize($foreignName));
01406                                         $obj = new $className();
01407                                         $objs = $obj->packageFind($belongsToId.' IN ('.$bTosString.')');
01408                                         foreach($objs as $obj)
01409                                         {
01410                                                 foreach($origObjsArr[$obj->$belongsToId] as $idx=>$origObj)
01411                                                 {
01412                                                         $origObj->$foreignName = $obj;
01413                                                 }
01414                                         }
01415                                 }
01416                         }
01417                 }
01418 
01419                 return $arr;
01420 }
01421 ?>
 All Data Structures Namespaces Files Functions Variables Enumerations