| 1 | efrain | 1 | <?php
 | 
        
           |  |  | 2 | /**
 | 
        
           |  |  | 3 |  * Active Record implementation. Superset of Zend Framework's.
 | 
        
           |  |  | 4 |  *
 | 
        
           |  |  | 5 |  * This is "Active Record eXtended" to support JOIN, WORK and LAZY mode
 | 
        
           |  |  | 6 |  *
 | 
        
           |  |  | 7 |  * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
 | 
        
           |  |  | 8 |  *
 | 
        
           |  |  | 9 |  * @package ADOdb
 | 
        
           |  |  | 10 |  * @link https://adodb.org Project's web site and documentation
 | 
        
           |  |  | 11 |  * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
 | 
        
           |  |  | 12 |  *
 | 
        
           |  |  | 13 |  * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause
 | 
        
           |  |  | 14 |  * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,
 | 
        
           |  |  | 15 |  * any later version. This means you can use it in proprietary products.
 | 
        
           |  |  | 16 |  * See the LICENSE.md file distributed with this source code for details.
 | 
        
           |  |  | 17 |  * @license BSD-3-Clause
 | 
        
           |  |  | 18 |  * @license LGPL-2.1-or-later
 | 
        
           |  |  | 19 |  *
 | 
        
           |  |  | 20 |  * @copyright 2000-2013 John Lim
 | 
        
           |  |  | 21 |  * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
 | 
        
           |  |  | 22 |  */
 | 
        
           |  |  | 23 |   | 
        
           |  |  | 24 | // CFR: Active Records Definitions
 | 
        
           |  |  | 25 | define('ADODB_JOIN_AR', 0x01);
 | 
        
           |  |  | 26 | define('ADODB_WORK_AR', 0x02);
 | 
        
           |  |  | 27 | define('ADODB_LAZY_AR', 0x03);
 | 
        
           |  |  | 28 |   | 
        
           |  |  | 29 |   | 
        
           |  |  | 30 | global $_ADODB_ACTIVE_DBS;
 | 
        
           |  |  | 31 | global $ADODB_ACTIVE_CACHESECS; // set to true to enable caching of metadata such as field info
 | 
        
           |  |  | 32 | global $ACTIVE_RECORD_SAFETY; // set to false to disable safety checks
 | 
        
           |  |  | 33 | global $ADODB_ACTIVE_DEFVALS; // use default values of table definition when creating new active record.
 | 
        
           |  |  | 34 |   | 
        
           |  |  | 35 | // array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat
 | 
        
           |  |  | 36 | $_ADODB_ACTIVE_DBS = array();
 | 
        
           |  |  | 37 | $ACTIVE_RECORD_SAFETY = true; // CFR: disabled while playing with relations
 | 
        
           |  |  | 38 | $ADODB_ACTIVE_DEFVALS = false;
 | 
        
           |  |  | 39 |   | 
        
           |  |  | 40 | class ADODB_Active_DB {
 | 
        
           |  |  | 41 | 	var $db; // ADOConnection
 | 
        
           |  |  | 42 | 	var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename
 | 
        
           |  |  | 43 | }
 | 
        
           |  |  | 44 |   | 
        
           |  |  | 45 | class ADODB_Active_Table {
 | 
        
           |  |  | 46 | 	var $name; // table name
 | 
        
           |  |  | 47 | 	var $flds; // assoc array of adofieldobjs, indexed by fieldname
 | 
        
           |  |  | 48 | 	var $keys; // assoc array of primary keys, indexed by fieldname
 | 
        
           |  |  | 49 | 	var $_created; // only used when stored as a cached file
 | 
        
           |  |  | 50 | 	var $_belongsTo = array();
 | 
        
           |  |  | 51 | 	var $_hasMany = array();
 | 
        
           |  |  | 52 | 	var $_colsCount; // total columns count, including relations
 | 
        
           |  |  | 53 |   | 
        
           |  |  | 54 | 	function updateColsCount()
 | 
        
           |  |  | 55 | 	{
 | 
        
           |  |  | 56 | 		$this->_colsCount = sizeof($this->flds);
 | 
        
           |  |  | 57 | 		foreach($this->_belongsTo as $foreignTable)
 | 
        
           |  |  | 58 | 			$this->_colsCount += sizeof($foreignTable->TableInfo()->flds);
 | 
        
           |  |  | 59 | 		foreach($this->_hasMany as $foreignTable)
 | 
        
           |  |  | 60 | 			$this->_colsCount += sizeof($foreignTable->TableInfo()->flds);
 | 
        
           |  |  | 61 | 	}
 | 
        
           |  |  | 62 | }
 | 
        
           |  |  | 63 |   | 
        
           |  |  | 64 | // returns index into $_ADODB_ACTIVE_DBS
 | 
        
           |  |  | 65 | function ADODB_SetDatabaseAdapter(&$db)
 | 
        
           |  |  | 66 | {
 | 
        
           |  |  | 67 | 	global $_ADODB_ACTIVE_DBS;
 | 
        
           |  |  | 68 |   | 
        
           |  |  | 69 | 	foreach($_ADODB_ACTIVE_DBS as $k => $d) {
 | 
        
           |  |  | 70 | 		if ($d->db === $db) {
 | 
        
           |  |  | 71 | 			return $k;
 | 
        
           |  |  | 72 | 		}
 | 
        
           |  |  | 73 | 	}
 | 
        
           |  |  | 74 |   | 
        
           |  |  | 75 | 	$obj = new ADODB_Active_DB();
 | 
        
           |  |  | 76 | 	$obj->db = $db;
 | 
        
           |  |  | 77 | 	$obj->tables = array();
 | 
        
           |  |  | 78 |   | 
        
           |  |  | 79 | 	$_ADODB_ACTIVE_DBS[] = $obj;
 | 
        
           |  |  | 80 |   | 
        
           |  |  | 81 | 	return sizeof($_ADODB_ACTIVE_DBS)-1;
 | 
        
           |  |  | 82 | }
 | 
        
           |  |  | 83 |   | 
        
           |  |  | 84 |   | 
        
           |  |  | 85 | class ADODB_Active_Record {
 | 
        
           |  |  | 86 | 	static $_changeNames = true; // dynamically pluralize table names
 | 
        
           |  |  | 87 | 	static $_foreignSuffix = '_id'; //
 | 
        
           |  |  | 88 | 	var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
 | 
        
           |  |  | 89 | 	var $_table; // tablename, if set in class definition then use it as table name
 | 
        
           |  |  | 90 | 	var $_sTable; // singularized table name
 | 
        
           |  |  | 91 | 	var $_pTable; // pluralized table name
 | 
        
           |  |  | 92 | 	var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
 | 
        
           |  |  | 93 | 	var $_where; // where clause set in Load()
 | 
        
           |  |  | 94 | 	var $_saved = false; // indicates whether data is already inserted.
 | 
        
           |  |  | 95 | 	var $_lasterr = false; // last error message
 | 
        
           |  |  | 96 | 	var $_original = false; // the original values loaded or inserted, refreshed on update
 | 
        
           |  |  | 97 |   | 
        
           |  |  | 98 | 	var $foreignName; // CFR: class name when in a relationship
 | 
        
           |  |  | 99 |   | 
        
           |  |  | 100 | 	static function UseDefaultValues($bool=null)
 | 
        
           |  |  | 101 | 	{
 | 
        
           |  |  | 102 | 	global $ADODB_ACTIVE_DEFVALS;
 | 
        
           |  |  | 103 | 		if (isset($bool)) {
 | 
        
           |  |  | 104 | 			$ADODB_ACTIVE_DEFVALS = $bool;
 | 
        
           |  |  | 105 | 		}
 | 
        
           |  |  | 106 | 		return $ADODB_ACTIVE_DEFVALS;
 | 
        
           |  |  | 107 | 	}
 | 
        
           |  |  | 108 |   | 
        
           |  |  | 109 | 	// should be static
 | 
        
           |  |  | 110 | 	static function SetDatabaseAdapter(&$db)
 | 
        
           |  |  | 111 | 	{
 | 
        
           |  |  | 112 | 		return ADODB_SetDatabaseAdapter($db);
 | 
        
           |  |  | 113 | 	}
 | 
        
           |  |  | 114 |   | 
        
           |  |  | 115 |   | 
        
           |  |  | 116 | 	public function __set($name, $value)
 | 
        
           |  |  | 117 | 	{
 | 
        
           |  |  | 118 | 		$name = str_replace(' ', '_', $name);
 | 
        
           |  |  | 119 | 		$this->$name = $value;
 | 
        
           |  |  | 120 | 	}
 | 
        
           |  |  | 121 |   | 
        
           |  |  | 122 | 	// php5 constructor
 | 
        
           |  |  | 123 | 	// Note: if $table is defined, then we will use it as our table name
 | 
        
           |  |  | 124 | 	// Otherwise we will use our classname...
 | 
        
           |  |  | 125 | 	// In our database, table names are pluralized (because there can be
 | 
        
           |  |  | 126 | 	// more than one row!)
 | 
        
           |  |  | 127 | 	// Similarly, if $table is defined here, it has to be plural form.
 | 
        
           |  |  | 128 | 	//
 | 
        
           |  |  | 129 | 	// $options is an array that allows us to tweak the constructor's behaviour
 | 
        
           |  |  | 130 | 	// if $options['refresh'] is true, we re-scan our metadata information
 | 
        
           |  |  | 131 | 	// if $options['new'] is true, we forget all relations
 | 
        
           |  |  | 132 | 	function __construct($table = false, $pkeyarr=false, $db=false, $options=array())
 | 
        
           |  |  | 133 | 	{
 | 
        
           |  |  | 134 | 	global $_ADODB_ACTIVE_DBS;
 | 
        
           |  |  | 135 |   | 
        
           |  |  | 136 | 		if ($db == false && is_object($pkeyarr)) {
 | 
        
           |  |  | 137 | 			$db = $pkeyarr;
 | 
        
           |  |  | 138 | 			$pkeyarr = false;
 | 
        
           |  |  | 139 | 		}
 | 
        
           |  |  | 140 |   | 
        
           |  |  | 141 | 		if($table) {
 | 
        
           |  |  | 142 | 			// table argument exists. It is expected to be
 | 
        
           |  |  | 143 | 			// already plural form.
 | 
        
           |  |  | 144 | 			$this->_pTable = $table;
 | 
        
           |  |  | 145 | 			$this->_sTable = $this->_singularize($this->_pTable);
 | 
        
           |  |  | 146 | 		}
 | 
        
           |  |  | 147 | 		else {
 | 
        
           |  |  | 148 | 			// We will use current classname as table name.
 | 
        
           |  |  | 149 | 			// We need to pluralize it for the real table name.
 | 
        
           |  |  | 150 | 			$this->_sTable = strtolower(get_class($this));
 | 
        
           |  |  | 151 | 			$this->_pTable = $this->_pluralize($this->_sTable);
 | 
        
           |  |  | 152 | 		}
 | 
        
           |  |  | 153 | 		$this->_table = &$this->_pTable;
 | 
        
           |  |  | 154 |   | 
        
           |  |  | 155 | 		$this->foreignName = $this->_sTable; // CFR: default foreign name (singular)
 | 
        
           |  |  | 156 |   | 
        
           |  |  | 157 | 		if ($db) {
 | 
        
           |  |  | 158 | 			$this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
 | 
        
           |  |  | 159 | 		} else
 | 
        
           |  |  | 160 | 			$this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1;
 | 
        
           |  |  | 161 |   | 
        
           |  |  | 162 |   | 
        
           |  |  | 163 | 		if ($this->_dbat < 0) {
 | 
        
           |  |  | 164 | 			$this->Error(
 | 
        
           |  |  | 165 | 				"No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",
 | 
        
           |  |  | 166 | 				'ADODB_Active_Record::__constructor'
 | 
        
           |  |  | 167 | 			);
 | 
        
           |  |  | 168 | 		}
 | 
        
           |  |  | 169 |   | 
        
           |  |  | 170 | 		$this->_tableat = $this->_table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
 | 
        
           |  |  | 171 |   | 
        
           |  |  | 172 | 		// CFR: Just added this option because UpdateActiveTable() can refresh its information
 | 
        
           |  |  | 173 | 		// but there was no way to ask it to do that.
 | 
        
           |  |  | 174 | 		$forceUpdate = (isset($options['refresh']) && true === $options['refresh']);
 | 
        
           |  |  | 175 | 		$this->UpdateActiveTable($pkeyarr, $forceUpdate);
 | 
        
           |  |  | 176 | 		if(isset($options['new']) && true === $options['new']) {
 | 
        
           |  |  | 177 | 			$table =& $this->TableInfo();
 | 
        
           |  |  | 178 | 			unset($table->_hasMany);
 | 
        
           |  |  | 179 | 			unset($table->_belongsTo);
 | 
        
           |  |  | 180 | 			$table->_hasMany = array();
 | 
        
           |  |  | 181 | 			$table->_belongsTo = array();
 | 
        
           |  |  | 182 | 		}
 | 
        
           |  |  | 183 | 	}
 | 
        
           |  |  | 184 |   | 
        
           |  |  | 185 | 	function __wakeup()
 | 
        
           |  |  | 186 | 	{
 | 
        
           |  |  | 187 | 		$class = get_class($this);
 | 
        
           |  |  | 188 | 		new $class;
 | 
        
           |  |  | 189 | 	}
 | 
        
           |  |  | 190 |   | 
        
           |  |  | 191 | 	// CFR: Constants found in Rails
 | 
        
           |  |  | 192 | 	static $IrregularP = array(
 | 
        
           |  |  | 193 | 		'PERSON'    => 'people',
 | 
        
           |  |  | 194 | 		'MAN'       => 'men',
 | 
        
           |  |  | 195 | 		'WOMAN'     => 'women',
 | 
        
           |  |  | 196 | 		'CHILD'     => 'children',
 | 
        
           |  |  | 197 | 		'COW'       => 'kine',
 | 
        
           |  |  | 198 | 	);
 | 
        
           |  |  | 199 |   | 
        
           |  |  | 200 | 	static $IrregularS = array(
 | 
        
           |  |  | 201 | 		'PEOPLE'    => 'PERSON',
 | 
        
           |  |  | 202 | 		'MEN'       => 'man',
 | 
        
           |  |  | 203 | 		'WOMEN'     => 'woman',
 | 
        
           |  |  | 204 | 		'CHILDREN'  => 'child',
 | 
        
           |  |  | 205 | 		'KINE'      => 'cow',
 | 
        
           |  |  | 206 | 	);
 | 
        
           |  |  | 207 |   | 
        
           |  |  | 208 | 	static $WeIsI = array(
 | 
        
           |  |  | 209 | 		'EQUIPMENT' => true,
 | 
        
           |  |  | 210 | 		'INFORMATION'   => true,
 | 
        
           |  |  | 211 | 		'RICE'      => true,
 | 
        
           |  |  | 212 | 		'MONEY'     => true,
 | 
        
           |  |  | 213 | 		'SPECIES'   => true,
 | 
        
           |  |  | 214 | 		'SERIES'    => true,
 | 
        
           |  |  | 215 | 		'FISH'      => true,
 | 
        
           |  |  | 216 | 		'SHEEP'     => true,
 | 
        
           |  |  | 217 | 	);
 | 
        
           |  |  | 218 |   | 
        
           |  |  | 219 | 	function _pluralize($table)
 | 
        
           |  |  | 220 | 	{
 | 
        
           |  |  | 221 | 		if (!ADODB_Active_Record::$_changeNames) {
 | 
        
           |  |  | 222 | 			return $table;
 | 
        
           |  |  | 223 | 		}
 | 
        
           |  |  | 224 | 		$ut = strtoupper($table);
 | 
        
           |  |  | 225 | 		if(isset(self::$WeIsI[$ut])) {
 | 
        
           |  |  | 226 | 			return $table;
 | 
        
           |  |  | 227 | 		}
 | 
        
           |  |  | 228 | 		if(isset(self::$IrregularP[$ut])) {
 | 
        
           |  |  | 229 | 			return self::$IrregularP[$ut];
 | 
        
           |  |  | 230 | 		}
 | 
        
           |  |  | 231 | 		$len = strlen($table);
 | 
        
           |  |  | 232 | 		$lastc = $ut[$len-1];
 | 
        
           |  |  | 233 | 		$lastc2 = substr($ut,$len-2);
 | 
        
           |  |  | 234 | 		switch ($lastc) {
 | 
        
           |  |  | 235 | 			case 'S':
 | 
        
           |  |  | 236 | 				return $table.'es';
 | 
        
           |  |  | 237 | 			case 'Y':
 | 
        
           |  |  | 238 | 				return substr($table,0,$len-1).'ies';
 | 
        
           |  |  | 239 | 			case 'X':
 | 
        
           |  |  | 240 | 				return $table.'es';
 | 
        
           |  |  | 241 | 			case 'H':
 | 
        
           |  |  | 242 | 				if ($lastc2 == 'CH' || $lastc2 == 'SH') {
 | 
        
           |  |  | 243 | 					return $table.'es';
 | 
        
           |  |  | 244 | 				}
 | 
        
           |  |  | 245 | 			default:
 | 
        
           |  |  | 246 | 				return $table.'s';
 | 
        
           |  |  | 247 | 		}
 | 
        
           |  |  | 248 | 	}
 | 
        
           |  |  | 249 |   | 
        
           |  |  | 250 | 	// CFR Lamest singular inflector ever - @todo Make it real!
 | 
        
           |  |  | 251 | 	// Note: There is an assumption here...and it is that the argument's length >= 4
 | 
        
           |  |  | 252 | 	function _singularize($table)
 | 
        
           |  |  | 253 | 	{
 | 
        
           |  |  | 254 |   | 
        
           |  |  | 255 | 		if (!ADODB_Active_Record::$_changeNames) {
 | 
        
           |  |  | 256 | 		return $table;
 | 
        
           |  |  | 257 | 	}
 | 
        
           |  |  | 258 | 		$ut = strtoupper($table);
 | 
        
           |  |  | 259 | 		if(isset(self::$WeIsI[$ut])) {
 | 
        
           |  |  | 260 | 			return $table;
 | 
        
           |  |  | 261 | 		}
 | 
        
           |  |  | 262 | 		if(isset(self::$IrregularS[$ut])) {
 | 
        
           |  |  | 263 | 			return self::$IrregularS[$ut];
 | 
        
           |  |  | 264 | 		}
 | 
        
           |  |  | 265 | 		$len = strlen($table);
 | 
        
           |  |  | 266 | 		if($ut[$len-1] != 'S') {
 | 
        
           |  |  | 267 | 			return $table; // I know...forget oxen
 | 
        
           |  |  | 268 | 		}
 | 
        
           |  |  | 269 | 		if($ut[$len-2] != 'E') {
 | 
        
           |  |  | 270 | 			return substr($table, 0, $len-1);
 | 
        
           |  |  | 271 | 		}
 | 
        
           |  |  | 272 | 		switch($ut[$len-3]) {
 | 
        
           |  |  | 273 | 			case 'S':
 | 
        
           |  |  | 274 | 			case 'X':
 | 
        
           |  |  | 275 | 				return substr($table, 0, $len-2);
 | 
        
           |  |  | 276 | 			case 'I':
 | 
        
           |  |  | 277 | 				return substr($table, 0, $len-3) . 'y';
 | 
        
           |  |  | 278 | 			case 'H';
 | 
        
           |  |  | 279 | 				if($ut[$len-4] == 'C' || $ut[$len-4] == 'S') {
 | 
        
           |  |  | 280 | 					return substr($table, 0, $len-2);
 | 
        
           |  |  | 281 | 				}
 | 
        
           |  |  | 282 | 			default:
 | 
        
           |  |  | 283 | 				return substr($table, 0, $len-1); // ?
 | 
        
           |  |  | 284 | 		}
 | 
        
           |  |  | 285 | 	}
 | 
        
           |  |  | 286 |   | 
        
           |  |  | 287 | 	/*
 | 
        
           |  |  | 288 | 	 * ar->foreignName will contain the name of the tables associated with this table because
 | 
        
           |  |  | 289 | 	 * these other tables' rows may also be referenced by this table using theirname_id or the provided
 | 
        
           |  |  | 290 | 	 * foreign keys (this index name is stored in ar->foreignKey)
 | 
        
           |  |  | 291 | 	 *
 | 
        
           |  |  | 292 | 	 * this-table.id = other-table-#1.this-table_id
 | 
        
           |  |  | 293 | 	 *               = other-table-#2.this-table_id
 | 
        
           |  |  | 294 | 	 */
 | 
        
           |  |  | 295 | 	function hasMany($foreignRef,$foreignKey=false)
 | 
        
           |  |  | 296 | 	{
 | 
        
           |  |  | 297 | 		$ar = new ADODB_Active_Record($foreignRef);
 | 
        
           |  |  | 298 | 		$ar->foreignName = $foreignRef;
 | 
        
           |  |  | 299 | 		$ar->UpdateActiveTable();
 | 
        
           |  |  | 300 | 		$ar->foreignKey = ($foreignKey) ? $foreignKey : strtolower(get_class($this)) . self::$_foreignSuffix;
 | 
        
           |  |  | 301 |   | 
        
           |  |  | 302 | 		$table =& $this->TableInfo();
 | 
        
           |  |  | 303 | 		if(!isset($table->_hasMany[$foreignRef])) {
 | 
        
           |  |  | 304 | 			$table->_hasMany[$foreignRef] = $ar;
 | 
        
           |  |  | 305 | 			$table->updateColsCount();
 | 
        
           |  |  | 306 | 		}
 | 
        
           |  |  | 307 | # @todo Can I make this guy be lazy?
 | 
        
           |  |  | 308 | 		$this->$foreignRef = $table->_hasMany[$foreignRef]; // WATCHME Removed assignment by ref. to please __get()
 | 
        
           |  |  | 309 | 	}
 | 
        
           |  |  | 310 |   | 
        
           |  |  | 311 | 	/**
 | 
        
           |  |  | 312 | 	 * ar->foreignName will contain the name of the tables associated with this table because
 | 
        
           |  |  | 313 | 	 * this table's rows may also be referenced by those tables using thistable_id or the provided
 | 
        
           |  |  | 314 | 	 * foreign keys (this index name is stored in ar->foreignKey)
 | 
        
           |  |  | 315 | 	 *
 | 
        
           |  |  | 316 | 	 * this-table.other-table_id = other-table.id
 | 
        
           |  |  | 317 | 	 */
 | 
        
           |  |  | 318 | 	function belongsTo($foreignRef,$foreignKey=false)
 | 
        
           |  |  | 319 | 	{
 | 
        
           |  |  | 320 | 		global $inflector;
 | 
        
           |  |  | 321 |   | 
        
           |  |  | 322 | 		$ar = new ADODB_Active_Record($this->_pluralize($foreignRef));
 | 
        
           |  |  | 323 | 		$ar->foreignName = $foreignRef;
 | 
        
           |  |  | 324 | 		$ar->UpdateActiveTable();
 | 
        
           |  |  | 325 | 		$ar->foreignKey = ($foreignKey) ? $foreignKey : $ar->foreignName . self::$_foreignSuffix;
 | 
        
           |  |  | 326 |   | 
        
           |  |  | 327 | 		$table =& $this->TableInfo();
 | 
        
           |  |  | 328 | 		if(!isset($table->_belongsTo[$foreignRef])) {
 | 
        
           |  |  | 329 | 			$table->_belongsTo[$foreignRef] = $ar;
 | 
        
           |  |  | 330 | 			$table->updateColsCount();
 | 
        
           |  |  | 331 | 		}
 | 
        
           |  |  | 332 | 		$this->$foreignRef = $table->_belongsTo[$foreignRef];
 | 
        
           |  |  | 333 | 	}
 | 
        
           |  |  | 334 |   | 
        
           |  |  | 335 | 	/**
 | 
        
           |  |  | 336 | 	 * __get Access properties - used for lazy loading
 | 
        
           |  |  | 337 | 	 *
 | 
        
           |  |  | 338 | 	 * @param mixed $name
 | 
        
           |  |  | 339 | 	 * @access protected
 | 
        
           |  |  | 340 | 	 * @return void
 | 
        
           |  |  | 341 | 	 */
 | 
        
           |  |  | 342 | 	function __get($name)
 | 
        
           |  |  | 343 | 	{
 | 
        
           |  |  | 344 | 		return $this->LoadRelations($name, '', -1. -1);
 | 
        
           |  |  | 345 | 	}
 | 
        
           |  |  | 346 |   | 
        
           |  |  | 347 | 	function LoadRelations($name, $whereOrderBy, $offset=-1, $limit=-1)
 | 
        
           |  |  | 348 | 	{
 | 
        
           |  |  | 349 | 		$extras = array();
 | 
        
           |  |  | 350 | 		if($offset >= 0) {
 | 
        
           |  |  | 351 | 			$extras['offset'] = $offset;
 | 
        
           |  |  | 352 | 		}
 | 
        
           |  |  | 353 | 		if($limit >= 0) {
 | 
        
           |  |  | 354 | 			$extras['limit'] = $limit;
 | 
        
           |  |  | 355 | 		}
 | 
        
           |  |  | 356 | 		$table =& $this->TableInfo();
 | 
        
           |  |  | 357 |   | 
        
           |  |  | 358 | 		if (strlen($whereOrderBy)) {
 | 
        
           |  |  | 359 | 			if (!preg_match('/^[ \n\r]*AND/i',$whereOrderBy)) {
 | 
        
           |  |  | 360 | 				if (!preg_match('/^[ \n\r]*ORDER[ \n\r]/i',$whereOrderBy)) {
 | 
        
           |  |  | 361 | 					$whereOrderBy = 'AND '.$whereOrderBy;
 | 
        
           |  |  | 362 | 				}
 | 
        
           |  |  | 363 | 			}
 | 
        
           |  |  | 364 | 		}
 | 
        
           |  |  | 365 |   | 
        
           |  |  | 366 | 		if(!empty($table->_belongsTo[$name])) {
 | 
        
           |  |  | 367 | 			$obj = $table->_belongsTo[$name];
 | 
        
           |  |  | 368 | 			$columnName = $obj->foreignKey;
 | 
        
           |  |  | 369 | 			if(empty($this->$columnName)) {
 | 
        
           |  |  | 370 | 				$this->$name = null;
 | 
        
           |  |  | 371 | 			}
 | 
        
           |  |  | 372 | 			else {
 | 
        
           |  |  | 373 | 				if(($k = reset($obj->TableInfo()->keys))) {
 | 
        
           |  |  | 374 | 					$belongsToId = $k;
 | 
        
           |  |  | 375 | 				}
 | 
        
           |  |  | 376 | 				else {
 | 
        
           |  |  | 377 | 					$belongsToId = 'id';
 | 
        
           |  |  | 378 | 				}
 | 
        
           |  |  | 379 |   | 
        
           |  |  | 380 | 				$arrayOfOne =
 | 
        
           |  |  | 381 | 					$obj->Find(
 | 
        
           |  |  | 382 | 						$belongsToId.'='.$this->$columnName.' '.$whereOrderBy, false, false, $extras);
 | 
        
           |  |  | 383 | 				$this->$name = $arrayOfOne[0];
 | 
        
           |  |  | 384 | 			}
 | 
        
           |  |  | 385 | 			return $this->$name;
 | 
        
           |  |  | 386 | 		}
 | 
        
           |  |  | 387 | 		if(!empty($table->_hasMany[$name])) {
 | 
        
           |  |  | 388 | 			$obj = $table->_hasMany[$name];
 | 
        
           |  |  | 389 | 			if(($k = reset($table->keys))) {
 | 
        
           |  |  | 390 | 				$hasManyId   = $k;
 | 
        
           |  |  | 391 | 			}
 | 
        
           |  |  | 392 | 			else {
 | 
        
           |  |  | 393 | 				$hasManyId   = 'id';
 | 
        
           |  |  | 394 | 			}
 | 
        
           |  |  | 395 |   | 
        
           |  |  | 396 | 			$this->$name =
 | 
        
           |  |  | 397 | 				$obj->Find(
 | 
        
           |  |  | 398 | 					$obj->foreignKey.'='.$this->$hasManyId.' '.$whereOrderBy, false, false, $extras);
 | 
        
           |  |  | 399 | 			return $this->$name;
 | 
        
           |  |  | 400 | 		}
 | 
        
           |  |  | 401 | 	}
 | 
        
           |  |  | 402 | 	//////////////////////////////////
 | 
        
           |  |  | 403 |   | 
        
           |  |  | 404 | 	// update metadata
 | 
        
           |  |  | 405 | 	function UpdateActiveTable($pkeys=false,$forceUpdate=false)
 | 
        
           |  |  | 406 | 	{
 | 
        
           |  |  | 407 | 	global $_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
 | 
        
           |  |  | 408 | 	global $ADODB_ACTIVE_DEFVALS, $ADODB_FETCH_MODE;
 | 
        
           |  |  | 409 |   | 
        
           |  |  | 410 | 		$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
 | 
        
           |  |  | 411 |   | 
        
           |  |  | 412 | 		$table = $this->_table;
 | 
        
           |  |  | 413 | 		$tables = $activedb->tables;
 | 
        
           |  |  | 414 | 		$tableat = $this->_tableat;
 | 
        
           |  |  | 415 | 		if (!$forceUpdate && !empty($tables[$tableat])) {
 | 
        
           |  |  | 416 |   | 
        
           |  |  | 417 | 			$tobj = $tables[$tableat];
 | 
        
           |  |  | 418 | 			foreach($tobj->flds as $name => $fld) {
 | 
        
           |  |  | 419 | 				if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) {
 | 
        
           |  |  | 420 | 					$this->$name = $fld->default_value;
 | 
        
           |  |  | 421 | 				}
 | 
        
           |  |  | 422 | 				else {
 | 
        
           |  |  | 423 | 					$this->$name = null;
 | 
        
           |  |  | 424 | 				}
 | 
        
           |  |  | 425 | 			}
 | 
        
           |  |  | 426 | 			return;
 | 
        
           |  |  | 427 | 		}
 | 
        
           |  |  | 428 |   | 
        
           |  |  | 429 | 		$db = $activedb->db;
 | 
        
           |  |  | 430 | 		$fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
 | 
        
           |  |  | 431 | 		if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
 | 
        
           |  |  | 432 | 			$fp = fopen($fname,'r');
 | 
        
           |  |  | 433 | 			@flock($fp, LOCK_SH);
 | 
        
           |  |  | 434 | 			$acttab = unserialize(fread($fp,100000));
 | 
        
           |  |  | 435 | 			fclose($fp);
 | 
        
           |  |  | 436 | 			if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) {
 | 
        
           |  |  | 437 | 				// abs(rand()) randomizes deletion, reducing contention to delete/refresh file
 | 
        
           |  |  | 438 | 				// ideally, you should cache at least 32 secs
 | 
        
           |  |  | 439 | 				$activedb->tables[$table] = $acttab;
 | 
        
           |  |  | 440 |   | 
        
           |  |  | 441 | 				//if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname");
 | 
        
           |  |  | 442 | 					return;
 | 
        
           |  |  | 443 | 			} else if ($db->debug) {
 | 
        
           |  |  | 444 | 				ADOConnection::outp("Refreshing cached active record file: $fname");
 | 
        
           |  |  | 445 | 			}
 | 
        
           |  |  | 446 | 		}
 | 
        
           |  |  | 447 | 		$activetab = new ADODB_Active_Table();
 | 
        
           |  |  | 448 | 		$activetab->name = $table;
 | 
        
           |  |  | 449 |   | 
        
           |  |  | 450 | 		$save = $ADODB_FETCH_MODE;
 | 
        
           |  |  | 451 | 		$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
 | 
        
           |  |  | 452 | 		if ($db->fetchMode !== false) {
 | 
        
           |  |  | 453 | 			$savem = $db->SetFetchMode(false);
 | 
        
           |  |  | 454 | 		}
 | 
        
           |  |  | 455 |   | 
        
           |  |  | 456 | 		$cols = $db->MetaColumns($table);
 | 
        
           |  |  | 457 |   | 
        
           |  |  | 458 | 		if (isset($savem)) {
 | 
        
           |  |  | 459 | 			$db->SetFetchMode($savem);
 | 
        
           |  |  | 460 | 		}
 | 
        
           |  |  | 461 | 		$ADODB_FETCH_MODE = $save;
 | 
        
           |  |  | 462 |   | 
        
           |  |  | 463 | 		if (!$cols) {
 | 
        
           |  |  | 464 | 			$this->Error("Invalid table name: $table",'UpdateActiveTable');
 | 
        
           |  |  | 465 | 			return false;
 | 
        
           |  |  | 466 | 		}
 | 
        
           |  |  | 467 | 		$fld = reset($cols);
 | 
        
           |  |  | 468 | 		if (!$pkeys) {
 | 
        
           |  |  | 469 | 			if (isset($fld->primary_key)) {
 | 
        
           |  |  | 470 | 				$pkeys = array();
 | 
        
           |  |  | 471 | 				foreach($cols as $name => $fld) {
 | 
        
           |  |  | 472 | 					if (!empty($fld->primary_key)) {
 | 
        
           |  |  | 473 | 						$pkeys[] = $name;
 | 
        
           |  |  | 474 | 					}
 | 
        
           |  |  | 475 | 				}
 | 
        
           |  |  | 476 | 			} else {
 | 
        
           |  |  | 477 | 				$pkeys = $this->GetPrimaryKeys($db, $table);
 | 
        
           |  |  | 478 | 			}
 | 
        
           |  |  | 479 | 		}
 | 
        
           |  |  | 480 | 		if (empty($pkeys)) {
 | 
        
           |  |  | 481 | 			$this->Error("No primary key found for table $table",'UpdateActiveTable');
 | 
        
           |  |  | 482 | 			return false;
 | 
        
           |  |  | 483 | 		}
 | 
        
           |  |  | 484 |   | 
        
           |  |  | 485 | 		$attr = array();
 | 
        
           |  |  | 486 | 		$keys = array();
 | 
        
           |  |  | 487 |   | 
        
           |  |  | 488 | 		switch (ADODB_ASSOC_CASE) {
 | 
        
           |  |  | 489 | 		case ADODB_ASSOC_CASE_LOWER:
 | 
        
           |  |  | 490 | 			foreach($cols as $name => $fldobj) {
 | 
        
           |  |  | 491 | 				$name = strtolower($name);
 | 
        
           |  |  | 492 | 				if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) {
 | 
        
           |  |  | 493 | 					$this->$name = $fldobj->default_value;
 | 
        
           |  |  | 494 | 				}
 | 
        
           |  |  | 495 | 				else {
 | 
        
           |  |  | 496 | 					$this->$name = null;
 | 
        
           |  |  | 497 | 				}
 | 
        
           |  |  | 498 | 				$attr[$name] = $fldobj;
 | 
        
           |  |  | 499 | 			}
 | 
        
           |  |  | 500 | 			foreach($pkeys as $k => $name) {
 | 
        
           |  |  | 501 | 				$keys[strtolower($name)] = strtolower($name);
 | 
        
           |  |  | 502 | 			}
 | 
        
           |  |  | 503 | 			break;
 | 
        
           |  |  | 504 |   | 
        
           |  |  | 505 | 		case ADODB_ASSOC_CASE_UPPER:
 | 
        
           |  |  | 506 | 			foreach($cols as $name => $fldobj) {
 | 
        
           |  |  | 507 | 				$name = strtoupper($name);
 | 
        
           |  |  | 508 |   | 
        
           |  |  | 509 | 				if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) {
 | 
        
           |  |  | 510 | 					$this->$name = $fldobj->default_value;
 | 
        
           |  |  | 511 | 				}
 | 
        
           |  |  | 512 | 				else {
 | 
        
           |  |  | 513 | 					$this->$name = null;
 | 
        
           |  |  | 514 | 				}
 | 
        
           |  |  | 515 | 				$attr[$name] = $fldobj;
 | 
        
           |  |  | 516 | 			}
 | 
        
           |  |  | 517 |   | 
        
           |  |  | 518 | 			foreach($pkeys as $k => $name) {
 | 
        
           |  |  | 519 | 				$keys[strtoupper($name)] = strtoupper($name);
 | 
        
           |  |  | 520 | 			}
 | 
        
           |  |  | 521 | 			break;
 | 
        
           |  |  | 522 | 		default:
 | 
        
           |  |  | 523 | 			foreach($cols as $name => $fldobj) {
 | 
        
           |  |  | 524 | 				$name = ($fldobj->name);
 | 
        
           |  |  | 525 |   | 
        
           |  |  | 526 | 				if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) {
 | 
        
           |  |  | 527 | 					$this->$name = $fldobj->default_value;
 | 
        
           |  |  | 528 | 				}
 | 
        
           |  |  | 529 | 				else {
 | 
        
           |  |  | 530 | 					$this->$name = null;
 | 
        
           |  |  | 531 | 				}
 | 
        
           |  |  | 532 | 				$attr[$name] = $fldobj;
 | 
        
           |  |  | 533 | 			}
 | 
        
           |  |  | 534 | 			foreach($pkeys as $k => $name) {
 | 
        
           |  |  | 535 | 				$keys[$name] = $cols[$name]->name;
 | 
        
           |  |  | 536 | 			}
 | 
        
           |  |  | 537 | 			break;
 | 
        
           |  |  | 538 | 		}
 | 
        
           |  |  | 539 |   | 
        
           |  |  | 540 | 		$activetab->keys = $keys;
 | 
        
           |  |  | 541 | 		$activetab->flds = $attr;
 | 
        
           |  |  | 542 | 		$activetab->updateColsCount();
 | 
        
           |  |  | 543 |   | 
        
           |  |  | 544 | 		if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) {
 | 
        
           |  |  | 545 | 			$activetab->_created = time();
 | 
        
           |  |  | 546 | 			$s = serialize($activetab);
 | 
        
           |  |  | 547 | 			if (!function_exists('adodb_write_file')) {
 | 
        
           |  |  | 548 | 				include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
 | 
        
           |  |  | 549 | 			}
 | 
        
           |  |  | 550 | 			adodb_write_file($fname,$s);
 | 
        
           |  |  | 551 | 		}
 | 
        
           |  |  | 552 | 		if (isset($activedb->tables[$table])) {
 | 
        
           |  |  | 553 | 			$oldtab = $activedb->tables[$table];
 | 
        
           |  |  | 554 |   | 
        
           |  |  | 555 | 			if ($oldtab) {
 | 
        
           |  |  | 556 | 				$activetab->_belongsTo = $oldtab->_belongsTo;
 | 
        
           |  |  | 557 | 				$activetab->_hasMany = $oldtab->_hasMany;
 | 
        
           |  |  | 558 | 			}
 | 
        
           |  |  | 559 | 		}
 | 
        
           |  |  | 560 | 		$activedb->tables[$table] = $activetab;
 | 
        
           |  |  | 561 | 	}
 | 
        
           |  |  | 562 |   | 
        
           |  |  | 563 | 	function GetPrimaryKeys(&$db, $table)
 | 
        
           |  |  | 564 | 	{
 | 
        
           |  |  | 565 | 		return $db->MetaPrimaryKeys($table);
 | 
        
           |  |  | 566 | 	}
 | 
        
           |  |  | 567 |   | 
        
           |  |  | 568 | 	// error handler for both PHP4+5.
 | 
        
           |  |  | 569 | 	function Error($err,$fn)
 | 
        
           |  |  | 570 | 	{
 | 
        
           |  |  | 571 | 	global $_ADODB_ACTIVE_DBS;
 | 
        
           |  |  | 572 |   | 
        
           |  |  | 573 | 		$fn = get_class($this).'::'.$fn;
 | 
        
           |  |  | 574 | 		$this->_lasterr = $fn.': '.$err;
 | 
        
           |  |  | 575 |   | 
        
           |  |  | 576 | 		if ($this->_dbat < 0) {
 | 
        
           |  |  | 577 | 			$db = false;
 | 
        
           |  |  | 578 | 		}
 | 
        
           |  |  | 579 | 		else {
 | 
        
           |  |  | 580 | 			$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
 | 
        
           |  |  | 581 | 			$db = $activedb->db;
 | 
        
           |  |  | 582 | 		}
 | 
        
           |  |  | 583 |   | 
        
           |  |  | 584 | 		if (function_exists('adodb_throw')) {
 | 
        
           |  |  | 585 | 			if (!$db) {
 | 
        
           |  |  | 586 | 				adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
 | 
        
           |  |  | 587 | 			}
 | 
        
           |  |  | 588 | 			else {
 | 
        
           |  |  | 589 | 				adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
 | 
        
           |  |  | 590 | 			}
 | 
        
           |  |  | 591 | 		} else {
 | 
        
           |  |  | 592 | 			if (!$db || $db->debug) {
 | 
        
           |  |  | 593 | 				ADOConnection::outp($this->_lasterr);
 | 
        
           |  |  | 594 | 			}
 | 
        
           |  |  | 595 | 		}
 | 
        
           |  |  | 596 |   | 
        
           |  |  | 597 | 	}
 | 
        
           |  |  | 598 |   | 
        
           |  |  | 599 | 	// return last error message
 | 
        
           |  |  | 600 | 	function ErrorMsg()
 | 
        
           |  |  | 601 | 	{
 | 
        
           |  |  | 602 | 		if (!function_exists('adodb_throw')) {
 | 
        
           |  |  | 603 | 			if ($this->_dbat < 0) {
 | 
        
           |  |  | 604 | 				$db = false;
 | 
        
           |  |  | 605 | 			}
 | 
        
           |  |  | 606 | 			else {
 | 
        
           |  |  | 607 | 				$db = $this->DB();
 | 
        
           |  |  | 608 | 			}
 | 
        
           |  |  | 609 |   | 
        
           |  |  | 610 | 			// last error could be database error too
 | 
        
           |  |  | 611 | 			if ($db && $db->ErrorMsg()) {
 | 
        
           |  |  | 612 | 				return $db->ErrorMsg();
 | 
        
           |  |  | 613 | 			}
 | 
        
           |  |  | 614 | 		}
 | 
        
           |  |  | 615 | 		return $this->_lasterr;
 | 
        
           |  |  | 616 | 	}
 | 
        
           |  |  | 617 |   | 
        
           |  |  | 618 | 	function ErrorNo()
 | 
        
           |  |  | 619 | 	{
 | 
        
           |  |  | 620 | 		if ($this->_dbat < 0) {
 | 
        
           |  |  | 621 | 			return -9999; // no database connection...
 | 
        
           |  |  | 622 | 		}
 | 
        
           |  |  | 623 | 		$db = $this->DB();
 | 
        
           |  |  | 624 |   | 
        
           |  |  | 625 | 		return (int) $db->ErrorNo();
 | 
        
           |  |  | 626 | 	}
 | 
        
           |  |  | 627 |   | 
        
           |  |  | 628 |   | 
        
           |  |  | 629 | 	// retrieve ADOConnection from _ADODB_Active_DBs
 | 
        
           |  |  | 630 | 	function DB()
 | 
        
           |  |  | 631 | 	{
 | 
        
           |  |  | 632 | 	global $_ADODB_ACTIVE_DBS;
 | 
        
           |  |  | 633 |   | 
        
           |  |  | 634 | 		if ($this->_dbat < 0) {
 | 
        
           |  |  | 635 | 			$false = false;
 | 
        
           |  |  | 636 | 			$this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
 | 
        
           |  |  | 637 | 			return $false;
 | 
        
           |  |  | 638 | 		}
 | 
        
           |  |  | 639 | 		$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
 | 
        
           |  |  | 640 | 		$db = $activedb->db;
 | 
        
           |  |  | 641 | 		return $db;
 | 
        
           |  |  | 642 | 	}
 | 
        
           |  |  | 643 |   | 
        
           |  |  | 644 | 	// retrieve ADODB_Active_Table
 | 
        
           |  |  | 645 | 	function &TableInfo()
 | 
        
           |  |  | 646 | 	{
 | 
        
           |  |  | 647 | 	global $_ADODB_ACTIVE_DBS;
 | 
        
           |  |  | 648 |   | 
        
           |  |  | 649 | 		$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
 | 
        
           |  |  | 650 | 		$table = $activedb->tables[$this->_tableat];
 | 
        
           |  |  | 651 | 		return $table;
 | 
        
           |  |  | 652 | 	}
 | 
        
           |  |  | 653 |   | 
        
           |  |  | 654 |   | 
        
           |  |  | 655 | 	// I have an ON INSERT trigger on a table that sets other columns in the table.
 | 
        
           |  |  | 656 | 	// So, I find that for myTable, I want to reload an active record after saving it. -- Malcolm Cook
 | 
        
           |  |  | 657 | 	function Reload()
 | 
        
           |  |  | 658 | 	{
 | 
        
           |  |  | 659 | 		$db =& $this->DB();
 | 
        
           |  |  | 660 | 		if (!$db) {
 | 
        
           |  |  | 661 | 			return false;
 | 
        
           |  |  | 662 | 		}
 | 
        
           |  |  | 663 | 		$table =& $this->TableInfo();
 | 
        
           |  |  | 664 | 		$where = $this->GenWhere($db, $table);
 | 
        
           |  |  | 665 | 		return($this->Load($where));
 | 
        
           |  |  | 666 | 	}
 | 
        
           |  |  | 667 |   | 
        
           |  |  | 668 |   | 
        
           |  |  | 669 | 	// set a numeric array (using natural table field ordering) as object properties
 | 
        
           |  |  | 670 | 	function Set(&$row)
 | 
        
           |  |  | 671 | 	{
 | 
        
           |  |  | 672 | 	global $ACTIVE_RECORD_SAFETY;
 | 
        
           |  |  | 673 |   | 
        
           |  |  | 674 | 		$db = $this->DB();
 | 
        
           |  |  | 675 |   | 
        
           |  |  | 676 | 		if (!$row) {
 | 
        
           |  |  | 677 | 			$this->_saved = false;
 | 
        
           |  |  | 678 | 			return false;
 | 
        
           |  |  | 679 | 		}
 | 
        
           |  |  | 680 |   | 
        
           |  |  | 681 | 		$this->_saved = true;
 | 
        
           |  |  | 682 |   | 
        
           |  |  | 683 | 		$table = $this->TableInfo();
 | 
        
           |  |  | 684 | 		$sizeofFlds = sizeof($table->flds);
 | 
        
           |  |  | 685 | 		$sizeofRow  = sizeof($row);
 | 
        
           |  |  | 686 | 		if ($ACTIVE_RECORD_SAFETY && $table->_colsCount != $sizeofRow && $sizeofFlds != $sizeofRow) {
 | 
        
           |  |  | 687 | 			# <AP>
 | 
        
           |  |  | 688 | 			$bad_size = TRUE;
 | 
        
           |  |  | 689 | 			if($sizeofRow == 2 * $table->_colsCount || $sizeofRow == 2 * $sizeofFlds) {
 | 
        
           |  |  | 690 | 				// Only keep string keys
 | 
        
           |  |  | 691 | 				$keys = array_filter(array_keys($row), 'is_string');
 | 
        
           |  |  | 692 | 				if (sizeof($keys) == sizeof($table->flds)) {
 | 
        
           |  |  | 693 | 					$bad_size = FALSE;
 | 
        
           |  |  | 694 | 				}
 | 
        
           |  |  | 695 | 			}
 | 
        
           |  |  | 696 | 			if ($bad_size) {
 | 
        
           |  |  | 697 | 				$this->Error("Table structure of $this->_table has changed","Load");
 | 
        
           |  |  | 698 | 				return false;
 | 
        
           |  |  | 699 | 			}
 | 
        
           |  |  | 700 | 			# </AP>
 | 
        
           |  |  | 701 | 		}
 | 
        
           |  |  | 702 | 		else {
 | 
        
           |  |  | 703 | 			$keys = array_keys($row);
 | 
        
           |  |  | 704 | 		}
 | 
        
           |  |  | 705 |   | 
        
           |  |  | 706 | 		# <AP>
 | 
        
           |  |  | 707 | 		reset($keys);
 | 
        
           |  |  | 708 | 		$this->_original = array();
 | 
        
           |  |  | 709 | 		foreach($table->flds as $name=>$fld) {
 | 
        
           |  |  | 710 | 			$value = $row[current($keys)];
 | 
        
           |  |  | 711 | 			$this->$name = $value;
 | 
        
           |  |  | 712 | 			$this->_original[] = $value;
 | 
        
           |  |  | 713 | 			if(!next($keys)) {
 | 
        
           |  |  | 714 | 				break;
 | 
        
           |  |  | 715 | 			}
 | 
        
           |  |  | 716 | 		}
 | 
        
           |  |  | 717 | 		$table =& $this->TableInfo();
 | 
        
           |  |  | 718 | 		foreach($table->_belongsTo as $foreignTable) {
 | 
        
           |  |  | 719 | 			$ft = $foreignTable->TableInfo();
 | 
        
           |  |  | 720 | 			$propertyName = $ft->name;
 | 
        
           |  |  | 721 | 			foreach($ft->flds as $name=>$fld) {
 | 
        
           |  |  | 722 | 				$value = $row[current($keys)];
 | 
        
           |  |  | 723 | 				$foreignTable->$name = $value;
 | 
        
           |  |  | 724 | 				$foreignTable->_original[] = $value;
 | 
        
           |  |  | 725 | 				if(!next($keys)) {
 | 
        
           |  |  | 726 | 					break;
 | 
        
           |  |  | 727 | 				}
 | 
        
           |  |  | 728 | 			}
 | 
        
           |  |  | 729 | 		}
 | 
        
           |  |  | 730 | 		foreach($table->_hasMany as $foreignTable) {
 | 
        
           |  |  | 731 | 			$ft = $foreignTable->TableInfo();
 | 
        
           |  |  | 732 | 			foreach($ft->flds as $name=>$fld) {
 | 
        
           |  |  | 733 | 				$value = $row[current($keys)];
 | 
        
           |  |  | 734 | 				$foreignTable->$name = $value;
 | 
        
           |  |  | 735 | 				$foreignTable->_original[] = $value;
 | 
        
           |  |  | 736 | 				if(!next($keys)) {
 | 
        
           |  |  | 737 | 					break;
 | 
        
           |  |  | 738 | 				}
 | 
        
           |  |  | 739 | 			}
 | 
        
           |  |  | 740 | 		}
 | 
        
           |  |  | 741 | 		# </AP>
 | 
        
           |  |  | 742 |   | 
        
           |  |  | 743 | 		return true;
 | 
        
           |  |  | 744 | 	}
 | 
        
           |  |  | 745 |   | 
        
           |  |  | 746 | 	// get last inserted id for INSERT
 | 
        
           |  |  | 747 | 	function LastInsertID(&$db,$fieldname)
 | 
        
           |  |  | 748 | 	{
 | 
        
           |  |  | 749 | 		if ($db->hasInsertID) {
 | 
        
           |  |  | 750 | 			$val = $db->Insert_ID($this->_table,$fieldname);
 | 
        
           |  |  | 751 | 		}
 | 
        
           |  |  | 752 | 		else {
 | 
        
           |  |  | 753 | 			$val = false;
 | 
        
           |  |  | 754 | 		}
 | 
        
           |  |  | 755 |   | 
        
           |  |  | 756 | 		if (is_null($val) || $val === false) {
 | 
        
           |  |  | 757 | 			// this might not work reliably in multi-user environment
 | 
        
           |  |  | 758 | 			return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
 | 
        
           |  |  | 759 | 		}
 | 
        
           |  |  | 760 | 		return $val;
 | 
        
           |  |  | 761 | 	}
 | 
        
           |  |  | 762 |   | 
        
           |  |  | 763 | 	// quote data in where clause
 | 
        
           |  |  | 764 | 	function doquote(&$db, $val,$t)
 | 
        
           |  |  | 765 | 	{
 | 
        
           |  |  | 766 | 		switch($t) {
 | 
        
           |  |  | 767 | 		case 'D':
 | 
        
           |  |  | 768 | 		case 'T':
 | 
        
           |  |  | 769 | 			if (empty($val)) {
 | 
        
           |  |  | 770 | 				return 'null';
 | 
        
           |  |  | 771 | 			}
 | 
        
           |  |  | 772 | 		case 'C':
 | 
        
           |  |  | 773 | 		case 'X':
 | 
        
           |  |  | 774 | 			if (is_null($val)) {
 | 
        
           |  |  | 775 | 				return 'null';
 | 
        
           |  |  | 776 | 			}
 | 
        
           |  |  | 777 | 			if (strlen($val)>0 &&
 | 
        
           |  |  | 778 | 				(strncmp($val,"'",1) != 0 || substr($val,strlen($val)-1,1) != "'")
 | 
        
           |  |  | 779 | 			) {
 | 
        
           |  |  | 780 | 				return $db->qstr($val);
 | 
        
           |  |  | 781 | 				break;
 | 
        
           |  |  | 782 | 			}
 | 
        
           |  |  | 783 | 		default:
 | 
        
           |  |  | 784 | 			return $val;
 | 
        
           |  |  | 785 | 			break;
 | 
        
           |  |  | 786 | 		}
 | 
        
           |  |  | 787 | 	}
 | 
        
           |  |  | 788 |   | 
        
           |  |  | 789 | 	// generate where clause for an UPDATE/SELECT
 | 
        
           |  |  | 790 | 	function GenWhere(&$db, &$table)
 | 
        
           |  |  | 791 | 	{
 | 
        
           |  |  | 792 | 		$keys = $table->keys;
 | 
        
           |  |  | 793 | 		$parr = array();
 | 
        
           |  |  | 794 |   | 
        
           |  |  | 795 | 		foreach($keys as $k) {
 | 
        
           |  |  | 796 | 			$f = $table->flds[$k];
 | 
        
           |  |  | 797 | 			if ($f) {
 | 
        
           |  |  | 798 | 				$parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
 | 
        
           |  |  | 799 | 			}
 | 
        
           |  |  | 800 | 		}
 | 
        
           |  |  | 801 | 		return implode(' and ', $parr);
 | 
        
           |  |  | 802 | 	}
 | 
        
           |  |  | 803 |   | 
        
           |  |  | 804 |   | 
        
           |  |  | 805 | 	//------------------------------------------------------------ Public functions below
 | 
        
           |  |  | 806 |   | 
        
           |  |  | 807 | 	function Load($where=null,$bindarr=false)
 | 
        
           |  |  | 808 | 	{
 | 
        
           |  |  | 809 | 		$db = $this->DB();
 | 
        
           |  |  | 810 | 		if (!$db) {
 | 
        
           |  |  | 811 | 			return false;
 | 
        
           |  |  | 812 | 		}
 | 
        
           |  |  | 813 | 		$this->_where = $where;
 | 
        
           |  |  | 814 |   | 
        
           |  |  | 815 | 		$save = $db->SetFetchMode(ADODB_FETCH_NUM);
 | 
        
           |  |  | 816 | 		$qry = "select * from ".$this->_table;
 | 
        
           |  |  | 817 | 		$table =& $this->TableInfo();
 | 
        
           |  |  | 818 |   | 
        
           |  |  | 819 | 		if(($k = reset($table->keys))) {
 | 
        
           |  |  | 820 | 			$hasManyId   = $k;
 | 
        
           |  |  | 821 | 		}
 | 
        
           |  |  | 822 | 		else {
 | 
        
           |  |  | 823 | 			$hasManyId   = 'id';
 | 
        
           |  |  | 824 | 		}
 | 
        
           |  |  | 825 |   | 
        
           |  |  | 826 | 		foreach($table->_belongsTo as $foreignTable) {
 | 
        
           |  |  | 827 | 			if(($k = reset($foreignTable->TableInfo()->keys))) {
 | 
        
           |  |  | 828 | 				$belongsToId = $k;
 | 
        
           |  |  | 829 | 			}
 | 
        
           |  |  | 830 | 			else {
 | 
        
           |  |  | 831 | 				$belongsToId = 'id';
 | 
        
           |  |  | 832 | 			}
 | 
        
           |  |  | 833 | 			$qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
 | 
        
           |  |  | 834 | 				$this->_table.'.'.$foreignTable->foreignKey.'='.
 | 
        
           |  |  | 835 | 				$foreignTable->_table.'.'.$belongsToId;
 | 
        
           |  |  | 836 | 		}
 | 
        
           |  |  | 837 | 		foreach($table->_hasMany as $foreignTable)
 | 
        
           |  |  | 838 | 		{
 | 
        
           |  |  | 839 | 			$qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
 | 
        
           |  |  | 840 | 				$this->_table.'.'.$hasManyId.'='.
 | 
        
           |  |  | 841 | 				$foreignTable->_table.'.'.$foreignTable->foreignKey;
 | 
        
           |  |  | 842 | 		}
 | 
        
           |  |  | 843 | 		if($where) {
 | 
        
           |  |  | 844 | 			$qry .= ' WHERE '.$where;
 | 
        
           |  |  | 845 | 		}
 | 
        
           |  |  | 846 |   | 
        
           |  |  | 847 | 		// Simple case: no relations. Load row and return.
 | 
        
           |  |  | 848 | 		if((count($table->_hasMany) + count($table->_belongsTo)) < 1) {
 | 
        
           |  |  | 849 | 			$row = $db->GetRow($qry,$bindarr);
 | 
        
           |  |  | 850 | 			if(!$row) {
 | 
        
           |  |  | 851 | 				return false;
 | 
        
           |  |  | 852 | 			}
 | 
        
           |  |  | 853 | 			$db->SetFetchMode($save);
 | 
        
           |  |  | 854 | 			return $this->Set($row);
 | 
        
           |  |  | 855 | 		}
 | 
        
           |  |  | 856 |   | 
        
           |  |  | 857 | 		// More complex case when relations have to be collated
 | 
        
           |  |  | 858 | 		$rows = $db->GetAll($qry,$bindarr);
 | 
        
           |  |  | 859 | 		if(!$rows) {
 | 
        
           |  |  | 860 | 			return false;
 | 
        
           |  |  | 861 | 		}
 | 
        
           |  |  | 862 | 		$db->SetFetchMode($save);
 | 
        
           |  |  | 863 | 		if(count($rows) < 1) {
 | 
        
           |  |  | 864 | 			return false;
 | 
        
           |  |  | 865 | 		}
 | 
        
           |  |  | 866 | 		$class = get_class($this);
 | 
        
           |  |  | 867 | 		$isFirstRow = true;
 | 
        
           |  |  | 868 |   | 
        
           |  |  | 869 | 		if(($k = reset($this->TableInfo()->keys))) {
 | 
        
           |  |  | 870 | 			$myId   = $k;
 | 
        
           |  |  | 871 | 		}
 | 
        
           |  |  | 872 | 		else {
 | 
        
           |  |  | 873 | 			$myId   = 'id';
 | 
        
           |  |  | 874 | 		}
 | 
        
           |  |  | 875 | 		$index = 0; $found = false;
 | 
        
           |  |  | 876 | 		/** @todo Improve by storing once and for all in table metadata */
 | 
        
           |  |  | 877 | 		/** @todo Also re-use info for hasManyId */
 | 
        
           |  |  | 878 | 		foreach($this->TableInfo()->flds as $fld) {
 | 
        
           |  |  | 879 | 			if($fld->name == $myId) {
 | 
        
           |  |  | 880 | 				$found = true;
 | 
        
           |  |  | 881 | 				break;
 | 
        
           |  |  | 882 | 			}
 | 
        
           |  |  | 883 | 			$index++;
 | 
        
           |  |  | 884 | 		}
 | 
        
           |  |  | 885 | 		if(!$found) {
 | 
        
           |  |  | 886 | 			$this->outp_throw("Unable to locate key $myId for $class in Load()",'Load');
 | 
        
           |  |  | 887 | 		}
 | 
        
           |  |  | 888 |   | 
        
           |  |  | 889 | 		foreach($rows as $row) {
 | 
        
           |  |  | 890 | 			$rowId = intval($row[$index]);
 | 
        
           |  |  | 891 | 			if($rowId > 0) {
 | 
        
           |  |  | 892 | 				if($isFirstRow) {
 | 
        
           |  |  | 893 | 					$isFirstRow = false;
 | 
        
           |  |  | 894 | 					if(!$this->Set($row)) {
 | 
        
           |  |  | 895 | 						return false;
 | 
        
           |  |  | 896 | 					}
 | 
        
           |  |  | 897 | 				}
 | 
        
           |  |  | 898 | 				$obj = new $class($table,false,$db);
 | 
        
           |  |  | 899 | 				$obj->Set($row);
 | 
        
           |  |  | 900 | 				// TODO Copy/paste code below: bad!
 | 
        
           |  |  | 901 | 				if(count($table->_hasMany) > 0) {
 | 
        
           |  |  | 902 | 					foreach($table->_hasMany as $foreignTable) {
 | 
        
           |  |  | 903 | 						$foreignName = $foreignTable->foreignName;
 | 
        
           |  |  | 904 | 						if(!empty($obj->$foreignName)) {
 | 
        
           |  |  | 905 | 							if(!is_array($this->$foreignName)) {
 | 
        
           |  |  | 906 | 								$foreignObj = $this->$foreignName;
 | 
        
           |  |  | 907 | 								$this->$foreignName = array(clone($foreignObj));
 | 
        
           |  |  | 908 | 							}
 | 
        
           |  |  | 909 | 							else {
 | 
        
           |  |  | 910 | 								$foreignObj = $obj->$foreignName;
 | 
        
           |  |  | 911 | 								array_push($this->$foreignName, clone($foreignObj));
 | 
        
           |  |  | 912 | 							}
 | 
        
           |  |  | 913 | 						}
 | 
        
           |  |  | 914 | 					}
 | 
        
           |  |  | 915 | 				}
 | 
        
           |  |  | 916 | 				if(count($table->_belongsTo) > 0) {
 | 
        
           |  |  | 917 | 					foreach($table->_belongsTo as $foreignTable) {
 | 
        
           |  |  | 918 | 						$foreignName = $foreignTable->foreignName;
 | 
        
           |  |  | 919 | 						if(!empty($obj->$foreignName)) {
 | 
        
           |  |  | 920 | 							if(!is_array($this->$foreignName)) {
 | 
        
           |  |  | 921 | 								$foreignObj = $this->$foreignName;
 | 
        
           |  |  | 922 | 								$this->$foreignName = array(clone($foreignObj));
 | 
        
           |  |  | 923 | 							}
 | 
        
           |  |  | 924 | 							else {
 | 
        
           |  |  | 925 | 								$foreignObj = $obj->$foreignName;
 | 
        
           |  |  | 926 | 								array_push($this->$foreignName, clone($foreignObj));
 | 
        
           |  |  | 927 | 							}
 | 
        
           |  |  | 928 | 						}
 | 
        
           |  |  | 929 | 					}
 | 
        
           |  |  | 930 | 				}
 | 
        
           |  |  | 931 | 			}
 | 
        
           |  |  | 932 | 		}
 | 
        
           |  |  | 933 | 		return true;
 | 
        
           |  |  | 934 | 	}
 | 
        
           |  |  | 935 |   | 
        
           |  |  | 936 | 	// false on error
 | 
        
           |  |  | 937 | 	function Save()
 | 
        
           |  |  | 938 | 	{
 | 
        
           |  |  | 939 | 		if ($this->_saved) {
 | 
        
           |  |  | 940 | 			$ok = $this->Update();
 | 
        
           |  |  | 941 | 		}
 | 
        
           |  |  | 942 | 		else {
 | 
        
           |  |  | 943 | 			$ok = $this->Insert();
 | 
        
           |  |  | 944 | 		}
 | 
        
           |  |  | 945 |   | 
        
           |  |  | 946 | 		return $ok;
 | 
        
           |  |  | 947 | 	}
 | 
        
           |  |  | 948 |   | 
        
           |  |  | 949 | 	// CFR: Sometimes we may wish to consider that an object is not to be replaced but inserted.
 | 
        
           |  |  | 950 | 	// Sample use case: an 'undo' command object (after a delete())
 | 
        
           |  |  | 951 | 	function Dirty()
 | 
        
           |  |  | 952 | 	{
 | 
        
           |  |  | 953 | 		$this->_saved = false;
 | 
        
           |  |  | 954 | 	}
 | 
        
           |  |  | 955 |   | 
        
           |  |  | 956 | 	// false on error
 | 
        
           |  |  | 957 | 	function Insert()
 | 
        
           |  |  | 958 | 	{
 | 
        
           |  |  | 959 | 		$db = $this->DB();
 | 
        
           |  |  | 960 | 		if (!$db) {
 | 
        
           |  |  | 961 | 			return false;
 | 
        
           |  |  | 962 | 		}
 | 
        
           |  |  | 963 | 		$cnt = 0;
 | 
        
           |  |  | 964 | 		$table = $this->TableInfo();
 | 
        
           |  |  | 965 |   | 
        
           |  |  | 966 | 		$valarr = array();
 | 
        
           |  |  | 967 | 		$names = array();
 | 
        
           |  |  | 968 | 		$valstr = array();
 | 
        
           |  |  | 969 |   | 
        
           |  |  | 970 | 		foreach($table->flds as $name=>$fld) {
 | 
        
           |  |  | 971 | 			$val = $this->$name;
 | 
        
           |  |  | 972 | 			if(!is_null($val) || !array_key_exists($name, $table->keys)) {
 | 
        
           |  |  | 973 | 				$valarr[] = $val;
 | 
        
           |  |  | 974 | 				$names[] = $name;
 | 
        
           |  |  | 975 | 				$valstr[] = $db->Param($cnt);
 | 
        
           |  |  | 976 | 				$cnt += 1;
 | 
        
           |  |  | 977 | 			}
 | 
        
           |  |  | 978 | 		}
 | 
        
           |  |  | 979 |   | 
        
           |  |  | 980 | 		if (empty($names)){
 | 
        
           |  |  | 981 | 			foreach($table->flds as $name=>$fld) {
 | 
        
           |  |  | 982 | 				$valarr[] = null;
 | 
        
           |  |  | 983 | 				$names[] = $name;
 | 
        
           |  |  | 984 | 				$valstr[] = $db->Param($cnt);
 | 
        
           |  |  | 985 | 				$cnt += 1;
 | 
        
           |  |  | 986 | 			}
 | 
        
           |  |  | 987 | 		}
 | 
        
           |  |  | 988 | 		$sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
 | 
        
           |  |  | 989 | 		$ok = $db->Execute($sql,$valarr);
 | 
        
           |  |  | 990 |   | 
        
           |  |  | 991 | 		if ($ok) {
 | 
        
           |  |  | 992 | 			$this->_saved = true;
 | 
        
           |  |  | 993 | 			$autoinc = false;
 | 
        
           |  |  | 994 | 			foreach($table->keys as $k) {
 | 
        
           |  |  | 995 | 				if (is_null($this->$k)) {
 | 
        
           |  |  | 996 | 					$autoinc = true;
 | 
        
           |  |  | 997 | 					break;
 | 
        
           |  |  | 998 | 				}
 | 
        
           |  |  | 999 | 			}
 | 
        
           |  |  | 1000 | 			if ($autoinc && sizeof($table->keys) == 1) {
 | 
        
           |  |  | 1001 | 				$k = reset($table->keys);
 | 
        
           |  |  | 1002 | 				$this->$k = $this->LastInsertID($db,$k);
 | 
        
           |  |  | 1003 | 			}
 | 
        
           |  |  | 1004 | 		}
 | 
        
           |  |  | 1005 |   | 
        
           |  |  | 1006 | 		$this->_original = $valarr;
 | 
        
           |  |  | 1007 | 		return !empty($ok);
 | 
        
           |  |  | 1008 | 	}
 | 
        
           |  |  | 1009 |   | 
        
           |  |  | 1010 | 	function Delete()
 | 
        
           |  |  | 1011 | 	{
 | 
        
           |  |  | 1012 | 		$db = $this->DB();
 | 
        
           |  |  | 1013 | 		if (!$db) {
 | 
        
           |  |  | 1014 | 			return false;
 | 
        
           |  |  | 1015 | 		}
 | 
        
           |  |  | 1016 | 		$table = $this->TableInfo();
 | 
        
           |  |  | 1017 |   | 
        
           |  |  | 1018 | 		$where = $this->GenWhere($db,$table);
 | 
        
           |  |  | 1019 | 		$sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
 | 
        
           |  |  | 1020 | 		$ok = $db->Execute($sql);
 | 
        
           |  |  | 1021 |   | 
        
           |  |  | 1022 | 		return $ok ? true : false;
 | 
        
           |  |  | 1023 | 	}
 | 
        
           |  |  | 1024 |   | 
        
           |  |  | 1025 | 	// returns an array of active record objects
 | 
        
           |  |  | 1026 | 	function Find($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
 | 
        
           |  |  | 1027 | 	{
 | 
        
           |  |  | 1028 | 		$db = $this->DB();
 | 
        
           |  |  | 1029 | 		if (!$db || empty($this->_table)) {
 | 
        
           |  |  | 1030 | 			return false;
 | 
        
           |  |  | 1031 | 		}
 | 
        
           |  |  | 1032 | 		$table =& $this->TableInfo();
 | 
        
           |  |  | 1033 | 		$arr = $db->GetActiveRecordsClass(get_class($this),$this, $whereOrderBy,$bindarr,$pkeysArr,$extra,
 | 
        
           |  |  | 1034 | 			array('foreignName'=>$this->foreignName, 'belongsTo'=>$table->_belongsTo, 'hasMany'=>$table->_hasMany));
 | 
        
           |  |  | 1035 | 		return $arr;
 | 
        
           |  |  | 1036 | 	}
 | 
        
           |  |  | 1037 |   | 
        
           |  |  | 1038 | 	// CFR: In introduced this method to ensure that inner workings are not disturbed by
 | 
        
           |  |  | 1039 | 	// subclasses...for instance when GetActiveRecordsClass invokes Find()
 | 
        
           |  |  | 1040 | 	// Why am I not invoking parent::Find?
 | 
        
           |  |  | 1041 | 	// Shockingly because I want to preserve PHP4 compatibility.
 | 
        
           |  |  | 1042 | 	function packageFind($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
 | 
        
           |  |  | 1043 | 	{
 | 
        
           |  |  | 1044 | 		$db = $this->DB();
 | 
        
           |  |  | 1045 | 		if (!$db || empty($this->_table)) {
 | 
        
           |  |  | 1046 | 			return false;
 | 
        
           |  |  | 1047 | 		}
 | 
        
           |  |  | 1048 | 		$table =& $this->TableInfo();
 | 
        
           |  |  | 1049 | 		$arr = $db->GetActiveRecordsClass(get_class($this),$this, $whereOrderBy,$bindarr,$pkeysArr,$extra,
 | 
        
           |  |  | 1050 | 			array('foreignName'=>$this->foreignName, 'belongsTo'=>$table->_belongsTo, 'hasMany'=>$table->_hasMany));
 | 
        
           |  |  | 1051 | 		return $arr;
 | 
        
           |  |  | 1052 | 	}
 | 
        
           |  |  | 1053 |   | 
        
           |  |  | 1054 | 	// returns 0 on error, 1 on update, 2 on insert
 | 
        
           |  |  | 1055 | 	function Replace()
 | 
        
           |  |  | 1056 | 	{
 | 
        
           |  |  | 1057 | 		$db = $this->DB();
 | 
        
           |  |  | 1058 | 		if (!$db) {
 | 
        
           |  |  | 1059 | 			return false;
 | 
        
           |  |  | 1060 | 		}
 | 
        
           |  |  | 1061 | 		$table = $this->TableInfo();
 | 
        
           |  |  | 1062 |   | 
        
           |  |  | 1063 | 		$pkey = $table->keys;
 | 
        
           |  |  | 1064 |   | 
        
           |  |  | 1065 | 		foreach($table->flds as $name=>$fld) {
 | 
        
           |  |  | 1066 | 			$val = $this->$name;
 | 
        
           |  |  | 1067 | 			/*
 | 
        
           |  |  | 1068 | 			if (is_null($val)) {
 | 
        
           |  |  | 1069 | 				if (isset($fld->not_null) && $fld->not_null) {
 | 
        
           |  |  | 1070 | 					if (isset($fld->default_value) && strlen($fld->default_value)) {
 | 
        
           |  |  | 1071 | 						continue;
 | 
        
           |  |  | 1072 | 					}
 | 
        
           |  |  | 1073 | 					else {
 | 
        
           |  |  | 1074 | 						$this->Error("Cannot update null into $name","Replace");
 | 
        
           |  |  | 1075 | 						return false;
 | 
        
           |  |  | 1076 | 					}
 | 
        
           |  |  | 1077 | 				}
 | 
        
           |  |  | 1078 | 			}*/
 | 
        
           |  |  | 1079 | 			if (is_null($val) && !empty($fld->auto_increment)) {
 | 
        
           |  |  | 1080 | 				continue;
 | 
        
           |  |  | 1081 | 			}
 | 
        
           |  |  | 1082 | 			$t = $db->MetaType($fld->type);
 | 
        
           |  |  | 1083 | 			$arr[$name] = $this->doquote($db,$val,$t);
 | 
        
           |  |  | 1084 | 			$valarr[] = $val;
 | 
        
           |  |  | 1085 | 		}
 | 
        
           |  |  | 1086 |   | 
        
           |  |  | 1087 | 		if (!is_array($pkey)) {
 | 
        
           |  |  | 1088 | 			$pkey = array($pkey);
 | 
        
           |  |  | 1089 | 		}
 | 
        
           |  |  | 1090 |   | 
        
           |  |  | 1091 |   | 
        
           |  |  | 1092 | 		switch (ADODB_ASSOC_CASE) {
 | 
        
           |  |  | 1093 | 			case ADODB_ASSOC_CASE_LOWER:
 | 
        
           |  |  | 1094 | 				foreach($pkey as $k => $v) {
 | 
        
           |  |  | 1095 | 					$pkey[$k] = strtolower($v);
 | 
        
           |  |  | 1096 | 				}
 | 
        
           |  |  | 1097 | 				break;
 | 
        
           |  |  | 1098 | 			case ADODB_ASSOC_CASE_UPPER:
 | 
        
           |  |  | 1099 | 				foreach($pkey as $k => $v) {
 | 
        
           |  |  | 1100 | 					$pkey[$k] = strtoupper($v);
 | 
        
           |  |  | 1101 | 				}
 | 
        
           |  |  | 1102 | 				break;
 | 
        
           |  |  | 1103 | 		}
 | 
        
           |  |  | 1104 |   | 
        
           |  |  | 1105 | 		$ok = $db->Replace($this->_table,$arr,$pkey);
 | 
        
           |  |  | 1106 | 		if ($ok) {
 | 
        
           |  |  | 1107 | 			$this->_saved = true; // 1= update 2=insert
 | 
        
           |  |  | 1108 | 			if ($ok == 2) {
 | 
        
           |  |  | 1109 | 				$autoinc = false;
 | 
        
           |  |  | 1110 | 				foreach($table->keys as $k) {
 | 
        
           |  |  | 1111 | 					if (is_null($this->$k)) {
 | 
        
           |  |  | 1112 | 						$autoinc = true;
 | 
        
           |  |  | 1113 | 						break;
 | 
        
           |  |  | 1114 | 					}
 | 
        
           |  |  | 1115 | 				}
 | 
        
           |  |  | 1116 | 				if ($autoinc && sizeof($table->keys) == 1) {
 | 
        
           |  |  | 1117 | 					$k = reset($table->keys);
 | 
        
           |  |  | 1118 | 					$this->$k = $this->LastInsertID($db,$k);
 | 
        
           |  |  | 1119 | 				}
 | 
        
           |  |  | 1120 | 			}
 | 
        
           |  |  | 1121 |   | 
        
           |  |  | 1122 | 			$this->_original = $valarr;
 | 
        
           |  |  | 1123 | 		}
 | 
        
           |  |  | 1124 | 		return $ok;
 | 
        
           |  |  | 1125 | 	}
 | 
        
           |  |  | 1126 |   | 
        
           |  |  | 1127 | 	// returns 0 on error, 1 on update, -1 if no change in data (no update)
 | 
        
           |  |  | 1128 | 	function Update()
 | 
        
           |  |  | 1129 | 	{
 | 
        
           |  |  | 1130 | 		$db = $this->DB();
 | 
        
           |  |  | 1131 | 		if (!$db) {
 | 
        
           |  |  | 1132 | 			return false;
 | 
        
           |  |  | 1133 | 		}
 | 
        
           |  |  | 1134 | 		$table = $this->TableInfo();
 | 
        
           |  |  | 1135 |   | 
        
           |  |  | 1136 | 		$where = $this->GenWhere($db, $table);
 | 
        
           |  |  | 1137 |   | 
        
           |  |  | 1138 | 		if (!$where) {
 | 
        
           |  |  | 1139 | 			$this->error("Where missing for table $table", "Update");
 | 
        
           |  |  | 1140 | 			return false;
 | 
        
           |  |  | 1141 | 		}
 | 
        
           |  |  | 1142 | 		$valarr = array();
 | 
        
           |  |  | 1143 | 		$neworig = array();
 | 
        
           |  |  | 1144 | 		$pairs = array();
 | 
        
           | 1441 | ariadna | 1145 | 		$i = 0;
 | 
        
           | 1 | efrain | 1146 | 		$cnt = 0;
 | 
        
           |  |  | 1147 | 		foreach($table->flds as $name=>$fld) {
 | 
        
           | 1441 | ariadna | 1148 | 			$orig = $this->_original[$i++] ?? null;
 | 
        
           | 1 | efrain | 1149 | 			$val = $this->$name;
 | 
        
           |  |  | 1150 | 			$neworig[] = $val;
 | 
        
           |  |  | 1151 |   | 
        
           |  |  | 1152 | 			if (isset($table->keys[$name])) {
 | 
        
           |  |  | 1153 | 				continue;
 | 
        
           |  |  | 1154 | 			}
 | 
        
           |  |  | 1155 |   | 
        
           |  |  | 1156 | 			if (is_null($val)) {
 | 
        
           |  |  | 1157 | 				if (isset($fld->not_null) && $fld->not_null) {
 | 
        
           |  |  | 1158 | 					if (isset($fld->default_value) && strlen($fld->default_value)) {
 | 
        
           |  |  | 1159 | 						continue;
 | 
        
           |  |  | 1160 | 					}
 | 
        
           |  |  | 1161 | 					else {
 | 
        
           |  |  | 1162 | 						$this->Error("Cannot set field $name to NULL","Update");
 | 
        
           |  |  | 1163 | 						return false;
 | 
        
           |  |  | 1164 | 					}
 | 
        
           |  |  | 1165 | 				}
 | 
        
           |  |  | 1166 | 			}
 | 
        
           |  |  | 1167 |   | 
        
           | 1441 | ariadna | 1168 | 			if ($val === $orig) {
 | 
        
           | 1 | efrain | 1169 | 				continue;
 | 
        
           |  |  | 1170 | 			}
 | 
        
           |  |  | 1171 | 			$valarr[] = $val;
 | 
        
           |  |  | 1172 | 			$pairs[] = $name.'='.$db->Param($cnt);
 | 
        
           |  |  | 1173 | 			$cnt += 1;
 | 
        
           |  |  | 1174 | 		}
 | 
        
           |  |  | 1175 |   | 
        
           |  |  | 1176 |   | 
        
           |  |  | 1177 | 		if (!$cnt) {
 | 
        
           |  |  | 1178 | 			return -1;
 | 
        
           |  |  | 1179 | 		}
 | 
        
           |  |  | 1180 | 		$sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
 | 
        
           |  |  | 1181 | 		$ok = $db->Execute($sql,$valarr);
 | 
        
           |  |  | 1182 | 		if ($ok) {
 | 
        
           |  |  | 1183 | 			$this->_original = $neworig;
 | 
        
           |  |  | 1184 | 			return 1;
 | 
        
           |  |  | 1185 | 		}
 | 
        
           |  |  | 1186 | 		return 0;
 | 
        
           |  |  | 1187 | 	}
 | 
        
           |  |  | 1188 |   | 
        
           |  |  | 1189 | 	function GetAttributeNames()
 | 
        
           |  |  | 1190 | 	{
 | 
        
           |  |  | 1191 | 		$table = $this->TableInfo();
 | 
        
           |  |  | 1192 | 		if (!$table) {
 | 
        
           |  |  | 1193 | 			return false;
 | 
        
           |  |  | 1194 | 		}
 | 
        
           |  |  | 1195 | 		return array_keys($table->flds);
 | 
        
           |  |  | 1196 | 	}
 | 
        
           |  |  | 1197 |   | 
        
           |  |  | 1198 | };
 | 
        
           |  |  | 1199 |   | 
        
           |  |  | 1200 | function adodb_GetActiveRecordsClass(&$db, $class, $tableObj,$whereOrderBy,$bindarr, $primkeyArr,
 | 
        
           |  |  | 1201 | 			$extra, $relations)
 | 
        
           |  |  | 1202 | {
 | 
        
           |  |  | 1203 | 	global $_ADODB_ACTIVE_DBS;
 | 
        
           |  |  | 1204 |   | 
        
           |  |  | 1205 | 		if (empty($extra['loading'])) {
 | 
        
           |  |  | 1206 | 			$extra['loading'] = ADODB_LAZY_AR;
 | 
        
           |  |  | 1207 | 		}
 | 
        
           |  |  | 1208 | 		$save = $db->SetFetchMode(ADODB_FETCH_NUM);
 | 
        
           |  |  | 1209 | 		$table = &$tableObj->_table;
 | 
        
           |  |  | 1210 | 		$tableInfo =& $tableObj->TableInfo();
 | 
        
           |  |  | 1211 | 		if(($k = reset($tableInfo->keys))) {
 | 
        
           |  |  | 1212 | 			$myId = $k;
 | 
        
           |  |  | 1213 | 		}
 | 
        
           |  |  | 1214 | 		else {
 | 
        
           |  |  | 1215 | 			$myId = 'id';
 | 
        
           |  |  | 1216 | 		}
 | 
        
           |  |  | 1217 | 		$index = 0; $found = false;
 | 
        
           |  |  | 1218 | 		/** @todo Improve by storing once and for all in table metadata */
 | 
        
           |  |  | 1219 | 		/** @todo Also re-use info for hasManyId */
 | 
        
           |  |  | 1220 | 		foreach($tableInfo->flds as $fld)
 | 
        
           |  |  | 1221 | 		{
 | 
        
           |  |  | 1222 | 			if($fld->name == $myId) {
 | 
        
           |  |  | 1223 | 				$found = true;
 | 
        
           |  |  | 1224 | 				break;
 | 
        
           |  |  | 1225 | 			}
 | 
        
           |  |  | 1226 | 			$index++;
 | 
        
           |  |  | 1227 | 		}
 | 
        
           |  |  | 1228 | 		if(!$found) {
 | 
        
           |  |  | 1229 | 			$db->outp_throw("Unable to locate key $myId for $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
 | 
        
           |  |  | 1230 | 		}
 | 
        
           |  |  | 1231 |   | 
        
           |  |  | 1232 | 		$qry = "select * from ".$table;
 | 
        
           |  |  | 1233 | 		if(ADODB_JOIN_AR == $extra['loading']) {
 | 
        
           |  |  | 1234 | 			if(!empty($relations['belongsTo'])) {
 | 
        
           |  |  | 1235 | 				foreach($relations['belongsTo'] as $foreignTable) {
 | 
        
           |  |  | 1236 | 					if(($k = reset($foreignTable->TableInfo()->keys))) {
 | 
        
           |  |  | 1237 | 						$belongsToId = $k;
 | 
        
           |  |  | 1238 | 					}
 | 
        
           |  |  | 1239 | 					else {
 | 
        
           |  |  | 1240 | 						$belongsToId = 'id';
 | 
        
           |  |  | 1241 | 					}
 | 
        
           |  |  | 1242 |   | 
        
           |  |  | 1243 | 					$qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
 | 
        
           |  |  | 1244 | 						$table.'.'.$foreignTable->foreignKey.'='.
 | 
        
           |  |  | 1245 | 						$foreignTable->_table.'.'.$belongsToId;
 | 
        
           |  |  | 1246 | 				}
 | 
        
           |  |  | 1247 | 			}
 | 
        
           |  |  | 1248 | 			if(!empty($relations['hasMany'])) {
 | 
        
           |  |  | 1249 | 				if(empty($relations['foreignName'])) {
 | 
        
           |  |  | 1250 | 					$db->outp_throw("Missing foreignName is relation specification in GetActiveRecordsClass()",'GetActiveRecordsClass');
 | 
        
           |  |  | 1251 | 				}
 | 
        
           |  |  | 1252 | 				if(($k = reset($tableInfo->keys))) {
 | 
        
           |  |  | 1253 | 					$hasManyId   = $k;
 | 
        
           |  |  | 1254 | 				}
 | 
        
           |  |  | 1255 | 				else {
 | 
        
           |  |  | 1256 | 					$hasManyId   = 'id';
 | 
        
           |  |  | 1257 | 				}
 | 
        
           |  |  | 1258 |   | 
        
           |  |  | 1259 | 				foreach($relations['hasMany'] as $foreignTable) {
 | 
        
           |  |  | 1260 | 					$qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
 | 
        
           |  |  | 1261 | 						$table.'.'.$hasManyId.'='.
 | 
        
           |  |  | 1262 | 						$foreignTable->_table.'.'.$foreignTable->foreignKey;
 | 
        
           |  |  | 1263 | 				}
 | 
        
           |  |  | 1264 | 			}
 | 
        
           |  |  | 1265 | 		}
 | 
        
           |  |  | 1266 | 		if (!empty($whereOrderBy)) {
 | 
        
           |  |  | 1267 | 			$qry .= ' WHERE '.$whereOrderBy;
 | 
        
           |  |  | 1268 | 		}
 | 
        
           |  |  | 1269 | 		if(isset($extra['limit'])) {
 | 
        
           |  |  | 1270 | 			$rows = false;
 | 
        
           |  |  | 1271 | 			if(isset($extra['offset'])) {
 | 
        
           |  |  | 1272 | 				$rs = $db->SelectLimit($qry, $extra['limit'], $extra['offset']);
 | 
        
           |  |  | 1273 | 			} else {
 | 
        
           |  |  | 1274 | 				$rs = $db->SelectLimit($qry, $extra['limit']);
 | 
        
           |  |  | 1275 | 			}
 | 
        
           |  |  | 1276 | 			if ($rs) {
 | 
        
           |  |  | 1277 | 				while (!$rs->EOF) {
 | 
        
           |  |  | 1278 | 					$rows[] = $rs->fields;
 | 
        
           |  |  | 1279 | 					$rs->MoveNext();
 | 
        
           |  |  | 1280 | 				}
 | 
        
           |  |  | 1281 | 			}
 | 
        
           |  |  | 1282 | 		} else
 | 
        
           |  |  | 1283 | 			$rows = $db->GetAll($qry,$bindarr);
 | 
        
           |  |  | 1284 |   | 
        
           |  |  | 1285 | 		$db->SetFetchMode($save);
 | 
        
           |  |  | 1286 |   | 
        
           |  |  | 1287 | 		$false = false;
 | 
        
           |  |  | 1288 |   | 
        
           |  |  | 1289 | 		if ($rows === false) {
 | 
        
           |  |  | 1290 | 			return $false;
 | 
        
           |  |  | 1291 | 		}
 | 
        
           |  |  | 1292 |   | 
        
           |  |  | 1293 |   | 
        
           |  |  | 1294 | 		if (!isset($_ADODB_ACTIVE_DBS)) {
 | 
        
           |  |  | 1295 | 			include_once(ADODB_DIR.'/adodb-active-record.inc.php');
 | 
        
           |  |  | 1296 | 		}
 | 
        
           |  |  | 1297 | 		if (!class_exists($class)) {
 | 
        
           |  |  | 1298 | 			$db->outp_throw("Unknown class $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
 | 
        
           |  |  | 1299 | 			return $false;
 | 
        
           |  |  | 1300 | 		}
 | 
        
           |  |  | 1301 | 		$uniqArr = array(); // CFR Keep track of records for relations
 | 
        
           |  |  | 1302 | 		$arr = array();
 | 
        
           |  |  | 1303 | 		// arrRef will be the structure that knows about our objects.
 | 
        
           |  |  | 1304 | 		// It is an associative array.
 | 
        
           |  |  | 1305 | 		// We will, however, return arr, preserving regular 0.. order so that
 | 
        
           |  |  | 1306 | 		// obj[0] can be used by app developers.
 | 
        
           |  |  | 1307 | 		$arrRef = array();
 | 
        
           |  |  | 1308 | 		$bTos = array(); // Will store belongTo's indices if any
 | 
        
           |  |  | 1309 | 		foreach($rows as $row) {
 | 
        
           |  |  | 1310 |   | 
        
           |  |  | 1311 | 			$obj = new $class($table,$primkeyArr,$db);
 | 
        
           |  |  | 1312 | 			if ($obj->ErrorNo()){
 | 
        
           |  |  | 1313 | 				$db->_errorMsg = $obj->ErrorMsg();
 | 
        
           |  |  | 1314 | 				return $false;
 | 
        
           |  |  | 1315 | 			}
 | 
        
           |  |  | 1316 | 			$obj->Set($row);
 | 
        
           |  |  | 1317 | 			// CFR: FIXME: Insane assumption here:
 | 
        
           |  |  | 1318 | 			// If the first column returned is an integer, then it's a 'id' field
 | 
        
           |  |  | 1319 | 			// And to make things a bit worse, I use intval() rather than is_int() because, in fact,
 | 
        
           |  |  | 1320 | 			// $row[0] is not an integer.
 | 
        
           |  |  | 1321 | 			//
 | 
        
           |  |  | 1322 | 			// So, what does this whole block do?
 | 
        
           |  |  | 1323 | 			// When relationships are found, we perform JOINs. This is fast. But not accurate:
 | 
        
           |  |  | 1324 | 			// instead of returning n objects with their n' associated cousins,
 | 
        
           |  |  | 1325 | 			// we get n*n' objects. This code fixes this.
 | 
        
           |  |  | 1326 | 			// Note: to-many relationships mess around with the 'limit' parameter
 | 
        
           |  |  | 1327 | 			$rowId = intval($row[$index]);
 | 
        
           |  |  | 1328 |   | 
        
           |  |  | 1329 | 			if(ADODB_WORK_AR == $extra['loading']) {
 | 
        
           |  |  | 1330 | 				$arrRef[$rowId] = $obj;
 | 
        
           |  |  | 1331 | 				$arr[] = &$arrRef[$rowId];
 | 
        
           |  |  | 1332 | 				if(!isset($indices)) {
 | 
        
           |  |  | 1333 | 					$indices = $rowId;
 | 
        
           |  |  | 1334 | 				}
 | 
        
           |  |  | 1335 | 				else {
 | 
        
           |  |  | 1336 | 					$indices .= ','.$rowId;
 | 
        
           |  |  | 1337 | 				}
 | 
        
           |  |  | 1338 | 				if(!empty($relations['belongsTo'])) {
 | 
        
           |  |  | 1339 | 					foreach($relations['belongsTo'] as $foreignTable) {
 | 
        
           |  |  | 1340 | 						$foreignTableRef = $foreignTable->foreignKey;
 | 
        
           |  |  | 1341 | 						// First array: list of foreign ids we are looking for
 | 
        
           |  |  | 1342 | 						if(empty($bTos[$foreignTableRef])) {
 | 
        
           |  |  | 1343 | 							$bTos[$foreignTableRef] = array();
 | 
        
           |  |  | 1344 | 						}
 | 
        
           |  |  | 1345 | 						// Second array: list of ids found
 | 
        
           |  |  | 1346 | 						if(empty($obj->$foreignTableRef)) {
 | 
        
           |  |  | 1347 | 							continue;
 | 
        
           |  |  | 1348 | 						}
 | 
        
           |  |  | 1349 | 						if(empty($bTos[$foreignTableRef][$obj->$foreignTableRef])) {
 | 
        
           |  |  | 1350 | 							$bTos[$foreignTableRef][$obj->$foreignTableRef] = array();
 | 
        
           |  |  | 1351 | 						}
 | 
        
           |  |  | 1352 | 						$bTos[$foreignTableRef][$obj->$foreignTableRef][] = $obj;
 | 
        
           |  |  | 1353 | 					}
 | 
        
           |  |  | 1354 | 				}
 | 
        
           |  |  | 1355 | 				continue;
 | 
        
           |  |  | 1356 | 			}
 | 
        
           |  |  | 1357 |   | 
        
           |  |  | 1358 | 			if($rowId>0) {
 | 
        
           |  |  | 1359 | 				if(ADODB_JOIN_AR == $extra['loading']) {
 | 
        
           |  |  | 1360 | 					$isNewObj = !isset($uniqArr['_'.$row[0]]);
 | 
        
           |  |  | 1361 | 					if($isNewObj) {
 | 
        
           |  |  | 1362 | 						$uniqArr['_'.$row[0]] = $obj;
 | 
        
           |  |  | 1363 | 					}
 | 
        
           |  |  | 1364 |   | 
        
           |  |  | 1365 | 					// TODO Copy/paste code below: bad!
 | 
        
           |  |  | 1366 | 					if(!empty($relations['hasMany'])) {
 | 
        
           |  |  | 1367 | 						foreach($relations['hasMany'] as $foreignTable) {
 | 
        
           |  |  | 1368 | 							$foreignName = $foreignTable->foreignName;
 | 
        
           |  |  | 1369 | 							if(!empty($obj->$foreignName)) {
 | 
        
           |  |  | 1370 | 								$masterObj = &$uniqArr['_'.$row[0]];
 | 
        
           |  |  | 1371 | 								// Assumption: this property exists in every object since they are instances of the same class
 | 
        
           |  |  | 1372 | 								if(!is_array($masterObj->$foreignName)) {
 | 
        
           |  |  | 1373 | 									// Pluck!
 | 
        
           |  |  | 1374 | 									$foreignObj = $masterObj->$foreignName;
 | 
        
           |  |  | 1375 | 									$masterObj->$foreignName = array(clone($foreignObj));
 | 
        
           |  |  | 1376 | 								}
 | 
        
           |  |  | 1377 | 								else {
 | 
        
           |  |  | 1378 | 									// Pluck pluck!
 | 
        
           |  |  | 1379 | 									$foreignObj = $obj->$foreignName;
 | 
        
           |  |  | 1380 | 									array_push($masterObj->$foreignName, clone($foreignObj));
 | 
        
           |  |  | 1381 | 								}
 | 
        
           |  |  | 1382 | 							}
 | 
        
           |  |  | 1383 | 						}
 | 
        
           |  |  | 1384 | 					}
 | 
        
           |  |  | 1385 | 					if(!empty($relations['belongsTo'])) {
 | 
        
           |  |  | 1386 | 						foreach($relations['belongsTo'] as $foreignTable) {
 | 
        
           |  |  | 1387 | 							$foreignName = $foreignTable->foreignName;
 | 
        
           |  |  | 1388 | 							if(!empty($obj->$foreignName)) {
 | 
        
           |  |  | 1389 | 								$masterObj = &$uniqArr['_'.$row[0]];
 | 
        
           |  |  | 1390 | 								// Assumption: this property exists in every object since they are instances of the same class
 | 
        
           |  |  | 1391 | 								if(!is_array($masterObj->$foreignName)) {
 | 
        
           |  |  | 1392 | 									// Pluck!
 | 
        
           |  |  | 1393 | 									$foreignObj = $masterObj->$foreignName;
 | 
        
           |  |  | 1394 | 									$masterObj->$foreignName = array(clone($foreignObj));
 | 
        
           |  |  | 1395 | 								}
 | 
        
           |  |  | 1396 | 								else {
 | 
        
           |  |  | 1397 | 									// Pluck pluck!
 | 
        
           |  |  | 1398 | 									$foreignObj = $obj->$foreignName;
 | 
        
           |  |  | 1399 | 									array_push($masterObj->$foreignName, clone($foreignObj));
 | 
        
           |  |  | 1400 | 								}
 | 
        
           |  |  | 1401 | 							}
 | 
        
           |  |  | 1402 | 						}
 | 
        
           |  |  | 1403 | 					}
 | 
        
           |  |  | 1404 | 					if(!$isNewObj) {
 | 
        
           |  |  | 1405 | 						unset($obj); // We do not need this object itself anymore and do not want it re-added to the main array
 | 
        
           |  |  | 1406 | 					}
 | 
        
           |  |  | 1407 | 				}
 | 
        
           |  |  | 1408 | 				else if(ADODB_LAZY_AR == $extra['loading']) {
 | 
        
           |  |  | 1409 | 					// Lazy loading: we need to give AdoDb a hint that we have not really loaded
 | 
        
           |  |  | 1410 | 					// anything, all the while keeping enough information on what we wish to load.
 | 
        
           |  |  | 1411 | 					// Let's do this by keeping the relevant info in our relationship arrays
 | 
        
           |  |  | 1412 | 					// but get rid of the actual properties.
 | 
        
           |  |  | 1413 | 					// We will then use PHP's __get to load these properties on-demand.
 | 
        
           |  |  | 1414 | 					if(!empty($relations['hasMany'])) {
 | 
        
           |  |  | 1415 | 						foreach($relations['hasMany'] as $foreignTable) {
 | 
        
           |  |  | 1416 | 							$foreignName = $foreignTable->foreignName;
 | 
        
           |  |  | 1417 | 							if(!empty($obj->$foreignName)) {
 | 
        
           |  |  | 1418 | 								unset($obj->$foreignName);
 | 
        
           |  |  | 1419 | 							}
 | 
        
           |  |  | 1420 | 						}
 | 
        
           |  |  | 1421 | 					}
 | 
        
           |  |  | 1422 | 					if(!empty($relations['belongsTo'])) {
 | 
        
           |  |  | 1423 | 						foreach($relations['belongsTo'] as $foreignTable) {
 | 
        
           |  |  | 1424 | 							$foreignName = $foreignTable->foreignName;
 | 
        
           |  |  | 1425 | 							if(!empty($obj->$foreignName)) {
 | 
        
           |  |  | 1426 | 								unset($obj->$foreignName);
 | 
        
           |  |  | 1427 | 							}
 | 
        
           |  |  | 1428 | 						}
 | 
        
           |  |  | 1429 | 					}
 | 
        
           |  |  | 1430 | 				}
 | 
        
           |  |  | 1431 | 			}
 | 
        
           |  |  | 1432 |   | 
        
           |  |  | 1433 | 			if(isset($obj)) {
 | 
        
           |  |  | 1434 | 				$arr[] = $obj;
 | 
        
           |  |  | 1435 | 			}
 | 
        
           |  |  | 1436 | 		}
 | 
        
           |  |  | 1437 |   | 
        
           |  |  | 1438 | 		if(ADODB_WORK_AR == $extra['loading']) {
 | 
        
           |  |  | 1439 | 			// The best of both worlds?
 | 
        
           |  |  | 1440 | 			// Here, the number of queries is constant: 1 + n*relationship.
 | 
        
           |  |  | 1441 | 			// The second query will allow us to perform a good join
 | 
        
           |  |  | 1442 | 			// while preserving LIMIT etc.
 | 
        
           |  |  | 1443 | 			if(!empty($relations['hasMany'])) {
 | 
        
           |  |  | 1444 | 				foreach($relations['hasMany'] as $foreignTable) {
 | 
        
           |  |  | 1445 | 					$foreignName = $foreignTable->foreignName;
 | 
        
           |  |  | 1446 | 					$className = ucfirst($foreignTable->_singularize($foreignName));
 | 
        
           |  |  | 1447 | 					$obj = new $className();
 | 
        
           |  |  | 1448 | 					$dbClassRef = $foreignTable->foreignKey;
 | 
        
           |  |  | 1449 | 					$objs = $obj->packageFind($dbClassRef.' IN ('.$indices.')');
 | 
        
           |  |  | 1450 | 					foreach($objs as $obj) {
 | 
        
           |  |  | 1451 | 						if(!is_array($arrRef[$obj->$dbClassRef]->$foreignName)) {
 | 
        
           |  |  | 1452 | 							$arrRef[$obj->$dbClassRef]->$foreignName = array();
 | 
        
           |  |  | 1453 | 						}
 | 
        
           |  |  | 1454 | 						array_push($arrRef[$obj->$dbClassRef]->$foreignName, $obj);
 | 
        
           |  |  | 1455 | 					}
 | 
        
           |  |  | 1456 | 				}
 | 
        
           |  |  | 1457 |   | 
        
           |  |  | 1458 | 			}
 | 
        
           |  |  | 1459 | 			if(!empty($relations['belongsTo'])) {
 | 
        
           |  |  | 1460 | 				foreach($relations['belongsTo'] as $foreignTable) {
 | 
        
           |  |  | 1461 | 					$foreignTableRef = $foreignTable->foreignKey;
 | 
        
           |  |  | 1462 | 					if(empty($bTos[$foreignTableRef])) {
 | 
        
           |  |  | 1463 | 						continue;
 | 
        
           |  |  | 1464 | 					}
 | 
        
           |  |  | 1465 | 					if(($k = reset($foreignTable->TableInfo()->keys))) {
 | 
        
           |  |  | 1466 | 						$belongsToId = $k;
 | 
        
           |  |  | 1467 | 					}
 | 
        
           |  |  | 1468 | 					else {
 | 
        
           |  |  | 1469 | 						$belongsToId = 'id';
 | 
        
           |  |  | 1470 | 					}
 | 
        
           |  |  | 1471 | 					$origObjsArr = $bTos[$foreignTableRef];
 | 
        
           |  |  | 1472 | 					$bTosString = implode(',', array_keys($bTos[$foreignTableRef]));
 | 
        
           |  |  | 1473 | 					$foreignName = $foreignTable->foreignName;
 | 
        
           |  |  | 1474 | 					$className = ucfirst($foreignTable->_singularize($foreignName));
 | 
        
           |  |  | 1475 | 					$obj = new $className();
 | 
        
           |  |  | 1476 | 					$objs = $obj->packageFind($belongsToId.' IN ('.$bTosString.')');
 | 
        
           |  |  | 1477 | 					foreach($objs as $obj)
 | 
        
           |  |  | 1478 | 					{
 | 
        
           |  |  | 1479 | 						foreach($origObjsArr[$obj->$belongsToId] as $idx=>$origObj)
 | 
        
           |  |  | 1480 | 						{
 | 
        
           |  |  | 1481 | 							$origObj->$foreignName = $obj;
 | 
        
           |  |  | 1482 | 						}
 | 
        
           |  |  | 1483 | 					}
 | 
        
           |  |  | 1484 | 				}
 | 
        
           |  |  | 1485 | 			}
 | 
        
           |  |  | 1486 | 		}
 | 
        
           |  |  | 1487 |   | 
        
           |  |  | 1488 | 		return $arr;
 | 
        
           |  |  | 1489 | }
 |