source: sandbox/2.5.1-evolucao/phpgwapi/inc/adodb/adodb-active-recordx.inc.php @ 8222

Revision 8222, 37.8 KB checked in by angelo, 11 years ago (diff)

Ticket #3491 - Compatibilizar Expresso com novas versoes do PHP

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