]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Update to DB_DataObject 1.11.2
authorMikael Nordfeldth <mmn@hethane.se>
Mon, 12 Aug 2013 10:32:39 +0000 (12:32 +0200)
committerMikael Nordfeldth <mmn@hethane.se>
Mon, 12 Aug 2013 10:34:37 +0000 (12:34 +0200)
Now there's definitely no PHP4 support whatsoever, if there even
was little of it before this commit.

extlib/DB/DataObject.php [changed mode: 0644->0755]
extlib/DB/DataObject/Cast.php [changed mode: 0644->0755]
extlib/DB/DataObject/Error.php [changed mode: 0644->0755]
extlib/DB/DataObject/Generator.php [changed mode: 0644->0755]
extlib/DB/DataObject/Links.php [new file with mode: 0644]
extlib/DB/DataObject/createTables.php [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
index 811d775..828477d
@@ -15,7 +15,7 @@
  * @author     Alan Knowles <alan@akbkhome.com>
  * @copyright  1997-2006 The PHP Group
  * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
- * @version    CVS: $Id: DataObject.php 301030 2010-07-07 02:26:31Z alan_k $
+ * @version    CVS: $Id: DataObject.php 329992 2013-04-03 11:38:43Z alan_k $
  * @link       http://pear.php.net/package/DB_DataObject
  */
   
@@ -176,10 +176,11 @@ $GLOBALS['_DB_DATAOBJECT']['QUERYENDTIME'] = 0;
 
  
 // this will be horrifically slow!!!!
-// NOTE: Overload SEGFAULTS ON PHP4 + Zend Optimizer (see define before..)
 // these two are BC/FC handlers for call in PHP4/5
 
-if ( substr(phpversion(),0,1) == 5) {
+if (!defined('DB_DATAOBJECT_NO_OVERLOAD')) {
+    
     class DB_DataObject_Overload 
     {
         function __call($method,$args) 
@@ -194,27 +195,10 @@ if ( substr(phpversion(),0,1) == 5) {
         }
     }
 } else {
-    if (version_compare(phpversion(),'4.3.10','eq') && !defined('DB_DATAOBJECT_NO_OVERLOAD')) {
-        trigger_error(
-            "overload does not work with PHP4.3.10, either upgrade 
-            (snaps.php.net) or more recent version 
-            or define DB_DATAOBJECT_NO_OVERLOAD as per the manual.
-            ",E_USER_ERROR);
-    }
-
-    if (!function_exists('clone')) {
-        // emulate clone  - as per php_compact, slow but really the correct behaviour..
-        eval('function clone($t) { $r = $t; if (method_exists($r,"__clone")) { $r->__clone(); } return $r; }');
-    }
-    eval('
-        class DB_DataObject_Overload {
-            function __call($method,$args,&$return) {
-                return $this->_call($method,$args,$return); 
-            }
-        }
-    ');
+    class DB_DataObject_Overload {}
 }
 
+
     
 
 
@@ -235,7 +219,7 @@ class DB_DataObject extends DB_DataObject_Overload
     * @access   private
     * @var      string
     */
-    var $_DB_DataObject_version = "1.9.5";
+    var $_DB_DataObject_version = "1.11.0";
 
     /**
      * The Database table (used by table extends)
@@ -290,7 +274,7 @@ class DB_DataObject extends DB_DataObject_Overload
             $v = $k;
             $keys = $this->keys();
             if (!$keys) {
-                $this->raiseError("No Keys available for {$this->__table}", DB_DATAOBJECT_ERROR_INVALIDCONFIG);
+                $this->raiseError("No Keys available for {$this->tableName()}", DB_DATAOBJECT_ERROR_INVALIDCONFIG);
                 return false;
             }
             $k = $keys[0];
@@ -306,68 +290,37 @@ class DB_DataObject extends DB_DataObject_Overload
         $this->$k = $v;
         return $this->find(1);
     }
-
+    
     /**
-     * An autoloading, caching static get method  using key, value (based on get)
-     * (depreciated - use ::get / and your own caching method)
-     * 
-     * Usage:
-     * $object = DB_DataObject::staticGet("DbTable_mytable",12);
-     * or
-     * $object =  DB_DataObject::staticGet("DbTable_mytable","name","fred");
+     * Get the value of the primary id
      *
-     * or write it into your extended class:
-     * function &staticGet($k,$v=NULL) { return DB_DataObject::staticGet("This_Class",$k,$v);  }
+     * While I normally use 'id' as the PRIMARY KEY value, some database use
+     * {table}_id as the column name.
      *
-     * @param   string  $class class name
-     * @param   string  $k     column (or value if using keys)
-     * @param   string  $v     value (optional)
-     * @access  public
-     * @return  object
+     * To save a bit of typing,
+     *
+     * $id = $do->pid();
+     *
+     * @return the id 
      */
-    function &staticGet($class, $k, $v = null)
+    function pid()
     {
-        $lclass = strtolower($class);
-        global $_DB_DATAOBJECT;
-        if (empty($_DB_DATAOBJECT['CONFIG'])) {
-            DB_DataObject::_loadConfig();
-        }
-
-        
-
-        $key = "$k:$v";
-        if ($v === null) {
-            $key = $k;
-        }
-        if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
-            DB_DataObject::debug("$class $key","STATIC GET - TRY CACHE");
-        }
-        if (!empty($_DB_DATAOBJECT['CACHE'][$lclass][$key])) {
-            return $_DB_DATAOBJECT['CACHE'][$lclass][$key];
-        }
-        if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
-            DB_DataObject::debug("$class $key","STATIC GET - NOT IN CACHE");
-        }
-
-        $obj = DB_DataObject::factory(substr($class,strlen($_DB_DATAOBJECT['CONFIG']['class_prefix'])));
-        if (PEAR::isError($obj)) {
-            DB_DataObject::raiseError("could not autoload $class", DB_DATAOBJECT_ERROR_NOCLASS);
-            $r = false;
-            return $r;
-        }
-        
-        if (!isset($_DB_DATAOBJECT['CACHE'][$lclass])) {
-            $_DB_DATAOBJECT['CACHE'][$lclass] = array();
+        $keys = $this->keys();
+        if (!$keys) {
+            $this->raiseError("No Keys available for {$this->tableName()}",
+                            DB_DATAOBJECT_ERROR_INVALIDCONFIG);
+            return false;
         }
-        if (!$obj->get($k,$v)) {
-            DB_DataObject::raiseError("No Data return from get $k $v", DB_DATAOBJECT_ERROR_NODATA);
-            
-            $r = false;
-            return $r;
+        $k = $keys[0];
+        if (empty($this->$k)) { // we do not 
+            $this->raiseError("pid() called on Object where primary key value not available",
+                            DB_DATAOBJECT_ERROR_NODATA);
+            return false;
         }
-        $_DB_DATAOBJECT['CACHE'][$lclass][$key] = $obj;
-        return $_DB_DATAOBJECT['CACHE'][$lclass][$key];
+        return $this->$k;
     }
+    
+
 
     /**
      * build the basic select query.
@@ -381,11 +334,35 @@ class DB_DataObject extends DB_DataObject_Overload
         $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
         if ($quoteIdentifiers) {
             $this->_connect();
-            $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+            $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+        }
+        $tn = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName()) : $this->tableName()) ;
+        if (!empty($this->_query['derive_table']) && !empty($this->_query['derive_select']) ) {
+            
+            // this is a derived select..
+            // not much support in the api yet..
+            
+             $sql = 'SELECT ' .
+               $this->_query['derive_select']
+               .' FROM ( SELECT'.
+                    $this->_query['data_select'] . " \n" .
+                    " FROM   $tn \n" .
+                    $this->_join . " \n" .
+                    $this->_query['condition'] . " \n" .
+                    $this->_query['group_by'] . " \n" .
+                    $this->_query['having'] . " \n" .
+                ') ' . $this->_query['derive_table'];
+                     
+            return $sql;
+            
+            
         }
+        
+       
+        
         $sql = 'SELECT ' .
             $this->_query['data_select'] . " \n" .
-            ' FROM ' . ($quoteIdentifiers ? $DB->quoteIdentifier($this->__table) : $this->__table) . " \n" .
+            " FROM   $tn \n" .
             $this->_join . " \n" .
             $this->_query['condition'] . " \n" .
             $this->_query['group_by'] . " \n" .
@@ -408,6 +385,10 @@ class DB_DataObject extends DB_DataObject_Overload
      * will set $object->N to number of rows, and expects next command to fetch rows
      * will return $object->N
      *
+     * if an error occurs $object->N will be set to false and return value will also be false;
+     * if numRows is not supported it will 
+     * 
+     *
      * @param   boolean $n Fetch first result
      * @access  public
      * @return  mixed (number of rows returned, or true if numRows fetching is not supported)
@@ -439,7 +420,7 @@ class DB_DataObject extends DB_DataObject_Overload
         
        
         $this->_connect();
-        $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+        $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
        
         
         $sql = $this->_build_select();
@@ -467,7 +448,10 @@ class DB_DataObject extends DB_DataObject_Overload
         }
         
         
-        $this->_query($sql);
+        $err = $this->_query($sql);
+        if (is_a($err,'PEAR_Error')) {
+            return false;
+        }
         
         if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
             $this->debug("CHECK autofetchd $n", "find", 1);
@@ -539,7 +523,7 @@ class DB_DataObject extends DB_DataObject_Overload
         }
         
         if (empty($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]) || 
-            !is_object($result = &$_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid])) 
+            !is_object($result = $_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid])) 
         {
             if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
                 $this->debug('fetched on object after fetch completed (no results found)');
@@ -584,10 +568,12 @@ class DB_DataObject extends DB_DataObject_Overload
             // note: we dont declare this to keep the print_r size down.
             $_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]= array_flip(array_keys($array));
         }
-        
+        $replace = array('.', ' ');
         foreach($array as $k=>$v) {
-            $kk = str_replace(".", "_", $k);
-            $kk = str_replace(" ", "_", $kk);
+            // use strpos as str_replace is slow.
+            $kk =  (strpos($k, '.') === false && strpos($k, ' ') === false) ?
+                $k : str_replace($replace, '_', $k);
+                
             if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
                 $this->debug("$kk = ". $array[$k], "fetchrow LINE", 3);
             }
@@ -597,7 +583,7 @@ class DB_DataObject extends DB_DataObject_Overload
         // set link flag
         $this->_link_loaded=false;
         if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
-            $this->debug("{$this->__table} DONE", "fetchrow",2);
+            $this->debug("{$this->tableName()} DONE", "fetchrow",2);
         }
         if (($this->_query !== false) &&  empty($_DB_DATAOBJECT['CONFIG']['keep_query_after_fetch'])) {
             $this->_query = false;
@@ -759,8 +745,9 @@ class DB_DataObject extends DB_DataObject_Overload
         $ar = array();
         foreach($list as $k) {
             settype($k, $type);
-            $ar[] = $type =='string' ? $this->_quote($k) : $k;
+            $ar[] = $type == 'string' ? $this->_quote($k) : $k;
         }
+      
         if (!$ar) {
             return $not ? $this->_query['condition'] : $this->whereAdd("1=0");
         }
@@ -912,7 +899,7 @@ class DB_DataObject extends DB_DataObject_Overload
         }
         global $_DB_DATAOBJECT;
         $this->_connect();
-        $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+        $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
         
         $this->_query['limit_start'] = ($b == null) ? 0 : (int)$a;
         $this->_query['limit_count'] = ($b == null) ? (int)$a : (int)$b;
@@ -992,9 +979,9 @@ class DB_DataObject extends DB_DataObject_Overload
         }
         
         
-        $table = $this->__table;
+        $table = $this->tableName();
         if (is_object($from)) {
-            $table = $from->__table;
+            $table = $from->tableName();
             $from = array_keys($from->table());
         }
         
@@ -1004,7 +991,7 @@ class DB_DataObject extends DB_DataObject_Overload
         $s = '%s';
         if (!empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers'])) {
             $this->_connect();
-            $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+            $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
             $s      = $DB->quoteIdentifier($s);
             $format = $DB->quoteIdentifier($format); 
         }
@@ -1042,25 +1029,24 @@ class DB_DataObject extends DB_DataObject_Overload
         
         $quoteIdentifiers  = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
         
-        $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+        $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
          
-        $items =  isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table]) ?   
-            $_DB_DATAOBJECT['INI'][$this->_database][$this->__table] : $this->table();
+        $items = $this->table();
             
         if (!$items) {
-            $this->raiseError("insert:No table definition for {$this->__table}",
+            $this->raiseError("insert:No table definition for {$this->tableName()}",
                 DB_DATAOBJECT_ERROR_INVALIDCONFIG);
             return false;
         }
-        $options = &$_DB_DATAOBJECT['CONFIG'];
+        $options = $_DB_DATAOBJECT['CONFIG'];
 
 
         $datasaved = 1;
         $leftq     = '';
         $rightq    = '';
      
-        $seqKeys   = isset($_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table]) ?
-                        $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] : 
+        $seqKeys   = isset($_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()]) ?
+                        $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] : 
                         $this->sequenceKey();
         
         $key       = isset($seqKeys[0]) ? $seqKeys[0] : false;
@@ -1077,7 +1063,7 @@ class DB_DataObject extends DB_DataObject_Overload
         if (($key !== false) && !$useNative) { 
         
             if (!$seq) {
-                $keyvalue =  $DB->nextId($this->__table);
+                $keyvalue =  $DB->nextId($this->tableName());
             } else {
                 $f = $DB->getOption('seqname_format');
                 $DB->setOption('seqname_format','%s');
@@ -1124,7 +1110,7 @@ class DB_DataObject extends DB_DataObject_Overload
             
             $leftq .= ($quoteIdentifiers ? ($DB->quoteIdentifier($k) . ' ')  : "$k ");
             
-            if (is_a($this->$k,'DB_DataObject_Cast')) {
+            if (is_object($this->$k) && is_a($this->$k,'DB_DataObject_Cast')) {
                 $value = $this->$k->toString($v,$DB);
                 if (PEAR::isError($value)) {
                     $this->raiseError($value->toString() ,DB_DATAOBJECT_ERROR_INVALIDARGS);
@@ -1179,7 +1165,7 @@ class DB_DataObject extends DB_DataObject_Overload
         
         
         if ($leftq || $useNative) {
-            $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->__table)    : $this->__table);
+            $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName())    : $this->tableName());
             
             
             if (($dbtype == 'pgsql') && empty($leftq)) {
@@ -1231,7 +1217,7 @@ class DB_DataObject extends DB_DataObject_Overload
                         
                     case 'pgsql':
                         if (!$seq) {
-                            $seq = $DB->getSequenceName(strtolower($this->__table));
+                            $seq = $DB->getSequenceName(strtolower($this->tableName()));
                         }
                         $db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
                         $method = ($db_driver  == 'DB') ? 'getOne' : 'queryOne';
@@ -1314,8 +1300,7 @@ class DB_DataObject extends DB_DataObject_Overload
         
         $original_query =  $this->_query;
         
-        $items =  isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table]) ?   
-            $_DB_DATAOBJECT['INI'][$this->_database][$this->__table] : $this->table();
+        $items = $this->table();
         
         // only apply update against sequence key if it is set?????
         
@@ -1335,14 +1320,14 @@ class DB_DataObject extends DB_DataObject_Overload
         
          
         if (!$items) {
-            $this->raiseError("update:No table definition for {$this->__table}", DB_DATAOBJECT_ERROR_INVALIDCONFIG);
+            $this->raiseError("update:No table definition for {$this->tableName()}", DB_DATAOBJECT_ERROR_INVALIDCONFIG);
             return false;
         }
         $datasaved = 1;
         $settings  = '';
         $this->_connect();
         
-        $DB            = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+        $DB            = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
         $dbtype        = $DB->dsn["phptype"];
         $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
         $options = $_DB_DATAOBJECT['CONFIG'];
@@ -1383,7 +1368,7 @@ class DB_DataObject extends DB_DataObject_Overload
             
             $kSql = ($quoteIdentifiers ? $DB->quoteIdentifier($k) : $k);
             
-            if (is_a($this->$k,'DB_DataObject_Cast')) {
+            if (is_object($this->$k) && is_a($this->$k,'DB_DataObject_Cast')) {
                 $value = $this->$k->toString($v,$DB);
                 if (PEAR::isError($value)) {
                     $this->raiseError($value->getMessage() ,DB_DATAOBJECT_ERROR_INVALIDARG);
@@ -1449,7 +1434,7 @@ class DB_DataObject extends DB_DataObject_Overload
         //  echo " $settings, $this->condition ";
         if ($settings && isset($this->_query) && $this->_query['condition']) {
             
-            $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->__table) : $this->__table);
+            $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName()) : $this->tableName());
         
             $r = $this->_query("UPDATE  {$table}  SET {$settings} {$this->_query['condition']} ");
             
@@ -1512,7 +1497,7 @@ class DB_DataObject extends DB_DataObject_Overload
         global $_DB_DATAOBJECT;
         // connect will load the config!
         $this->_connect();
-        $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+        $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
         $quoteIdentifiers  = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
         
         $extra_cond = ' ' . (isset($this->_query['order_by']) ? $this->_query['order_by'] : ''); 
@@ -1534,7 +1519,7 @@ class DB_DataObject extends DB_DataObject_Overload
         // don't delete without a condition
         if (($this->_query !== false) && $this->_query['condition']) {
         
-            $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->__table) : $this->__table);
+            $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName()) : $this->tableName());
             $sql = "DELETE ";
             // using a joined delete. - with useWhere..
             $sql .= (!empty($this->_join) && $useWhere) ? 
@@ -1596,9 +1581,9 @@ class DB_DataObject extends DB_DataObject_Overload
             $this->_loadConfig();
         }
         if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
-            $this->debug("{$this->__table} $row of {$this->N}", "fetchrow",3);
+            $this->debug("{$this->tableName()} $row of {$this->N}", "fetchrow",3);
         }
-        if (!$this->__table) {
+        if (!$this->tableName()) {
             $this->raiseError("fetchrow: No table", DB_DATAOBJECT_ERROR_INVALIDCONFIG);
             return false;
         }
@@ -1611,19 +1596,22 @@ class DB_DataObject extends DB_DataObject_Overload
             return false;
         }
         if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
-            $this->debug("{$this->__table} $row of {$this->N}", "fetchrow",3);
+            $this->debug("{$this->tableName()} $row of {$this->N}", "fetchrow",3);
         }
 
 
-        $result = &$_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid];
+        $result = $_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid];
         $array  = $result->fetchrow(DB_DATAOBJECT_FETCHMODE_ASSOC,$row);
         if (!is_array($array)) {
             $this->raiseError("fetchrow: No results available", DB_DATAOBJECT_ERROR_NODATA);
             return false;
         }
-
+        $replace = array('.', ' ');
         foreach($array as $k => $v) {
-            $kk = str_replace(".", "_", $k);
+            // use strpos as str_replace is slow.
+            $kk =  (strpos($k, '.') === false && strpos($k, ' ') === false) ?
+                $k : str_replace($replace, '_', $k);
+            
             if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
                 $this->debug("$kk = ". $array[$k], "fetchrow LINE", 3);
             }
@@ -1631,7 +1619,7 @@ class DB_DataObject extends DB_DataObject_Overload
         }
 
         if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
-            $this->debug("{$this->__table} DONE", "fetchrow", 3);
+            $this->debug("{$this->tableName()} DONE", "fetchrow", 3);
         }
         return true;
     }
@@ -1685,7 +1673,7 @@ class DB_DataObject extends DB_DataObject_Overload
             return false;
         }
         $this->_connect();
-        $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+        $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
        
 
         if (!$whereAddOnly && $items)  {
@@ -1700,7 +1688,7 @@ class DB_DataObject extends DB_DataObject_Overload
             return false;
             
         }
-        $table   = ($quoteIdentifiers ? $DB->quoteIdentifier($this->__table) : $this->__table);
+        $table   = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName()) : $this->tableName());
         $key_col = empty($keys[0]) ? '' : (($quoteIdentifiers ? $DB->quoteIdentifier($keys[0]) : $keys[0]));
         $as      = ($quoteIdentifiers ? $DB->quoteIdentifier('DATAOBJECT_NUM') : 'DATAOBJECT_NUM');
         
@@ -1717,11 +1705,13 @@ class DB_DataObject extends DB_DataObject_Overload
             return false;
         }
          
-        $result  = &$_DB_DATAOBJECT['RESULTS'][$t->_DB_resultid];
+        $result  = $_DB_DATAOBJECT['RESULTS'][$t->_DB_resultid];
         $l = $result->fetchRow(DB_DATAOBJECT_FETCHMODE_ORDERED);
         // free the results - essential on oracle.
         $t->free();
-        
+        if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+            $this->debug('Count returned '. $l[0] ,1);
+        }
         return (int) $l[0];
     }
 
@@ -1755,7 +1745,7 @@ class DB_DataObject extends DB_DataObject_Overload
     {
         global $_DB_DATAOBJECT;
         $this->_connect();
-        $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+        $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
         // mdb2 uses escape...
         $dd = empty($_DB_DATAOBJECT['CONFIG']['db_driver']) ? 'DB' : $_DB_DATAOBJECT['CONFIG']['db_driver'];
         $ret = ($dd == 'DB') ? $DB->escapeSimple($string) : $DB->escape($string);
@@ -1817,7 +1807,9 @@ class DB_DataObject extends DB_DataObject_Overload
         'limit_start' => '', // the LIMIT condition
         'limit_count' => '', // the LIMIT condition
         'data_select' => '*', // the columns to be SELECTed
-        'unions'      => array(), // the added unions
+        'unions'      => array(), // the added unions,
+        'derive_table' => '', // derived table name (BETA)
+        'derive_select' => '', // derived table select (BETA)
     );
         
     
@@ -1886,7 +1878,7 @@ class DB_DataObject extends DB_DataObject_Overload
                 $x = new DB_DataObject;
                 $x->_database = $args[0];
                 $this->_connect();
-                $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+                $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
        
                 $tables = $DB->getListOf('tables');
                 class_exists('DB_DataObject_Generator') ? '' : 
@@ -1917,32 +1909,41 @@ class DB_DataObject extends DB_DataObject_Overload
             $this->_connect();
         }
         
-        // loaded already?
-        if (!empty($_DB_DATAOBJECT['INI'][$this->_database])) {
-            
-            // database loaded - but this is table is not available..
-            if (
-                    empty($_DB_DATAOBJECT['INI'][$this->_database][$this->__table]) 
-                    && !empty($_DB_DATAOBJECT['CONFIG']['proxy'])
-                ) {
-                if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
-                    $this->debug("Loading Generator to fetch Schema",1);
-                }
-                class_exists('DB_DataObject_Generator') ? '' : 
-                    require_once 'DB/DataObject/Generator.php';
-                    
-                
-                $x = new DB_DataObject_Generator;
-                $x->fillTableSchema($this->_database,$this->__table);
-            }
+        
+        // if this table is already loaded this table..
+        if (!empty($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()])) {
             return true;
         }
         
-        
+        // initialize the ini data.. if empt..
+        if (empty($_DB_DATAOBJECT['INI'][$this->_database])) {
+            $_DB_DATAOBJECT['INI'][$this->_database] = array();
+        }
+         
         if (empty($_DB_DATAOBJECT['CONFIG'])) {
             DB_DataObject::_loadConfig();
         }
         
+        // we do not have the data for this table yet...
+        
+        // if we are configured to use the proxy..
+        
+        if ( !empty($_DB_DATAOBJECT['CONFIG']['proxy']) ) {
+            if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+                $this->debug("Loading Generator to fetch Schema",1);
+            }
+            class_exists('DB_DataObject_Generator') ? '' : 
+                require_once 'DB/DataObject/Generator.php';
+                
+            
+            $x = new DB_DataObject_Generator;
+            $x->fillTableSchema($this->_database,$this->tableName());
+            return true;
+        }
+            
+             
+       
+        
         // if you supply this with arguments, then it will take those
         // as the database and links array...
          
@@ -1980,9 +1981,18 @@ class DB_DataObject extends DB_DataObject_Overload
             }
              
         }
+        // are table name lowecased..
+        if (!empty($_DB_DATAOBJECT['CONFIG']['portability']) && $_DB_DATAOBJECT['CONFIG']['portability'] & 1) {
+            foreach($_DB_DATAOBJECT['INI'][$this->_database] as $k=>$v) {
+                // results in duplicate cols.. but not a big issue..
+                $_DB_DATAOBJECT['INI'][$this->_database][strtolower($k)] = $v;
+            }
+        }
+        
+        
         // now have we loaded the structure.. 
         
-        if (!empty($_DB_DATAOBJECT['INI'][$this->_database][$this->__table])) {
+        if (!empty($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()])) {
             return true;
         }
         // - if not try building it..
@@ -1991,11 +2001,11 @@ class DB_DataObject extends DB_DataObject_Overload
                 require_once 'DB/DataObject/Generator.php';
                 
             $x = new DB_DataObject_Generator;
-            $x->fillTableSchema($this->_database,$this->__table);
+            $x->fillTableSchema($this->_database,$this->tableName());
             // should this fail!!!???
             return true;
         }
-        $this->debug("Cant find database schema: {$this->_database}/{$this->__table} \n".
+        $this->debug("Cant find database schema: {$this->_database}/{$this->tableName()} \n".
                     "in links file data: " . print_r($_DB_DATAOBJECT['INI'],true),"databaseStructure",5);
         // we have to die here!! - it causes chaos if we dont (including looping forever!)
         $this->raiseError( "Unable to load schema for database and table (turn debugging up to 5 for full error message)", DB_DATAOBJECT_ERROR_INVALIDARGS, PEAR_ERROR_DIE);
@@ -2017,10 +2027,14 @@ class DB_DataObject extends DB_DataObject_Overload
      */
     function tableName()
     {
+        global $_DB_DATAOBJECT;
         $args = func_get_args();
         if (count($args)) {
             $this->__table = $args[0];
         }
+        if (!empty($_DB_DATAOBJECT['CONFIG']['portability']) && $_DB_DATAOBJECT['CONFIG']['portability'] & 1) {
+            return strtolower($this->__table);
+        }
         return $this->__table;
     }
     
@@ -2036,7 +2050,10 @@ class DB_DataObject extends DB_DataObject_Overload
         $args = func_get_args();
         if (count($args)) {
             $this->_database = $args[0];
+        } else {
+            $this->_connect();
         }
+        
         return $this->_database;
     }
   
@@ -2065,17 +2082,17 @@ class DB_DataObject extends DB_DataObject_Overload
         if (!isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
             $this->_connect();
         }
-        
-        if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table])) {
-            return $_DB_DATAOBJECT['INI'][$this->_database][$this->__table];
+          
+        if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()])) {
+            return $_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()];
         }
         
         $this->databaseStructure();
  
         
         $ret = array();
-        if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table])) {
-            $ret =  $_DB_DATAOBJECT['INI'][$this->_database][$this->__table];
+        if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()])) {
+            $ret =  $_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()];
         }
         
         return $ret;
@@ -2090,7 +2107,7 @@ class DB_DataObject extends DB_DataObject_Overload
      * or you do not want to use ini tables, you can override this.
      * @param  string optional set the key
      * @param  *   optional  set more keys
-     * @access private
+     * @access public
      * @return array
      */
     function keys()
@@ -2109,13 +2126,13 @@ class DB_DataObject extends DB_DataObject_Overload
         if (!isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
             $this->_connect();
         }
-        if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"])) {
-            return array_keys($_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"]);
+        if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()."__keys"])) {
+            return array_keys($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()."__keys"]);
         }
         $this->databaseStructure();
         
-        if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"])) {
-            return array_keys($_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"]);
+        if (isset($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()."__keys"])) {
+            return array_keys($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()."__keys"]);
         }
         return array();
     }
@@ -2130,7 +2147,7 @@ class DB_DataObject extends DB_DataObject_Overload
      * @param  string  optional the key sequence/autoinc. key
      * @param  boolean optional use native increment. default false 
      * @param  false|string optional native sequence name
-     * @access private
+     * @access public
      * @return array (column,use_native,sequence_name)
      */
     function sequenceKey()
@@ -2151,10 +2168,10 @@ class DB_DataObject extends DB_DataObject_Overload
         if (count($args)) {
             $args[1] = isset($args[1]) ? $args[1] : false;
             $args[2] = isset($args[2]) ? $args[2] : false;
-            $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] = $args;
+            $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = $args;
         }
-        if (isset($_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table])) {
-            return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table];
+        if (isset($_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()])) {
+            return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()];
         }
         // end call setting (eg. $do->sequenceKeys(a,b,c); )
         
@@ -2163,13 +2180,12 @@ class DB_DataObject extends DB_DataObject_Overload
         
         $keys = $this->keys();
         if (!$keys) {
-            return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table
+            return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()
                 = array(false,false,false);
         }
  
 
-        $table =  isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table]) ?   
-            $_DB_DATAOBJECT['INI'][$this->_database][$this->__table] : $this->table();
+        $table =  $this->table();
        
         $dbtype    = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'];
         
@@ -2179,8 +2195,8 @@ class DB_DataObject extends DB_DataObject_Overload
         
         $seqname = false;
         
-        if (!empty($_DB_DATAOBJECT['CONFIG']['sequence_'.$this->__table])) {
-            $seqname = $_DB_DATAOBJECT['CONFIG']['sequence_'.$this->__table];
+        if (!empty($_DB_DATAOBJECT['CONFIG']['sequence_'.$this->tableName()])) {
+            $seqname = $_DB_DATAOBJECT['CONFIG']['sequence_'.$this->tableName()];
             if (strpos($seqname,':') !== false) {
                 list($usekey,$seqname) = explode(':',$seqname);
             }
@@ -2189,25 +2205,25 @@ class DB_DataObject extends DB_DataObject_Overload
         
         // if the key is not an integer - then it's not a sequence or native
         if (empty($table[$usekey]) || !($table[$usekey] & DB_DATAOBJECT_INT)) {
-                return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] = array(false,false,false);
+                return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array(false,false,false);
         }
         
         
         if (!empty($_DB_DATAOBJECT['CONFIG']['ignore_sequence_keys'])) {
             $ignore =  $_DB_DATAOBJECT['CONFIG']['ignore_sequence_keys'];
             if (is_string($ignore) && (strtoupper($ignore) == 'ALL')) {
-                return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] = array(false,false,$seqname);
+                return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array(false,false,$seqname);
             }
             if (is_string($ignore)) {
                 $ignore = $_DB_DATAOBJECT['CONFIG']['ignore_sequence_keys'] = explode(',',$ignore);
             }
-            if (in_array($this->__table,$ignore)) {
-                return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] = array(false,false,$seqname);
+            if (in_array($this->tableName(),$ignore)) {
+                return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array(false,false,$seqname);
             }
         }
         
         
-        $realkeys = $_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"];
+        $realkeys = $_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()."__keys"];
         
         // if you are using an old ini file - go back to old behaviour...
         if (is_numeric($realkeys[$usekey])) {
@@ -2216,25 +2232,38 @@ class DB_DataObject extends DB_DataObject_Overload
         
         // multiple unique primary keys without a native sequence...
         if (($realkeys[$usekey] == 'K') && (count($keys) > 1)) {
-            return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] = array(false,false,$seqname);
+            return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array(false,false,$seqname);
         }
         // use native sequence keys...
         // technically postgres native here...
         // we need to get the new improved tabledata sorted out first.
         
+        // support named sequence keys.. - currently postgres only..
+        
+        if (    in_array($dbtype , array('pgsql')) &&
+                ($table[$usekey] & DB_DATAOBJECT_INT) && 
+                isset($realkeys[$usekey]) && strlen($realkeys[$usekey]) > 1) {
+            return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array($usekey,true, $realkeys[$usekey]);
+        }
+        
         if (    in_array($dbtype , array('pgsql', 'mysql', 'mysqli', 'mssql', 'ifx')) && 
                 ($table[$usekey] & DB_DATAOBJECT_INT) && 
                 isset($realkeys[$usekey]) && ($realkeys[$usekey] == 'N')
                 ) {
-            return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] = array($usekey,true,$seqname);
+            return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array($usekey,true,$seqname);
         }
+        
+        
         // if not a native autoinc, and we have not assumed all primary keys are sequence
         if (($realkeys[$usekey] != 'N') && 
             !empty($_DB_DATAOBJECT['CONFIG']['dont_use_pear_sequences'])) {
             return array(false,false,false);
         }
+        
+        
+        
         // I assume it's going to try and be a nextval DB sequence.. (not native)
-        return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] = array($usekey,false,$seqname);
+        return $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] = array($usekey,false,$seqname);
     }
     
     
@@ -2346,13 +2375,13 @@ class DB_DataObject extends DB_DataObject_Overload
         // it's not currently connected!
         // try and work out what to use for the dsn !
 
-        $options= &$_DB_DATAOBJECT['CONFIG'];
+        $options= $_DB_DATAOBJECT['CONFIG'];
         // if the databse dsn dis defined in the object..
         $dsn = isset($this->_database_dsn) ? $this->_database_dsn : null;
         
         if (!$dsn) {
-            if (!$this->_database) {
-                $this->_database = isset($options["table_{$this->__table}"]) ? $options["table_{$this->__table}"] : null;
+            if (!$this->_database && !empty($this->__table)) {
+                $this->_database = isset($options["table_{$this->tableName()}"]) ? $options["table_{$this->tableName()}"] : null;
             }
             if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
                 $this->debug("Checking for database specific ini ('{$this->_database}') : database_{$this->_database} in options","CONNECT");
@@ -2421,9 +2450,9 @@ class DB_DataObject extends DB_DataObject_Overload
             $db_options = PEAR::getStaticProperty('DB','options');
             require_once 'DB.php';
             if ($db_options) {
-                $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5] = &DB::connect($dsn,$db_options);
+                $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5] = DB::connect($dsn,$db_options);
             } else {
-                $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5] = &DB::connect($dsn);
+                $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5] = DB::connect($dsn);
             }
             
         } else {
@@ -2434,13 +2463,13 @@ class DB_DataObject extends DB_DataObject_Overload
             $db_options = is_array($db_options) ? $db_options : array();
             $db_options['portability'] = isset($db_options['portability'] )
                 ? $db_options['portability']  : MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_FIX_CASE;
-            $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5] = &MDB2::connect($dsn,$db_options);
+            $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5] = MDB2::connect($dsn,$db_options);
             
         }
         
         
         if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
-            $this->debug(serialize($_DB_DATAOBJECT['CONNECTIONS']), "CONNECT",5);
+            $this->debug(print_r($_DB_DATAOBJECT['CONNECTIONS'],true), "CONNECT",5);
         }
         if (PEAR::isError($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
             $this->debug($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->toString(), "CONNECT FAILED",5);
@@ -2467,7 +2496,6 @@ class DB_DataObject extends DB_DataObject_Overload
         }
         
         // Oracle need to optimize for portibility - not sure exactly what this does though :)
-        $c = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
          
         return true;
     }
@@ -2486,9 +2514,9 @@ class DB_DataObject extends DB_DataObject_Overload
         $this->_connect();
         
 
-        $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+        $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
 
-        $options = &$_DB_DATAOBJECT['CONFIG'];
+        $options = $_DB_DATAOBJECT['CONFIG'];
         
         $_DB_driver = empty($_DB_DATAOBJECT['CONFIG']['db_driver']) ? 
                     'DB':  $_DB_DATAOBJECT['CONFIG']['db_driver'];
@@ -2501,10 +2529,10 @@ class DB_DataObject extends DB_DataObject_Overload
         if (strtoupper($string) == 'BEGIN') {
             if ($_DB_driver == 'DB') {
                 $DB->autoCommit(false);
+                $DB->simpleQuery('BEGIN');
             } else {
                 $DB->beginTransaction();
             }
-            // db backend adds begin anyway from now on..
             return true;
         }
         if (strtoupper($string) == 'COMMIT') {
@@ -2564,7 +2592,7 @@ class DB_DataObject extends DB_DataObject_Overload
             }
             
             // see if we got a failure.. - try again a few times..
-            if (!is_a($result,'PEAR_Error')) {
+            if (!is_object($result) || !is_a($result,'PEAR_Error')) {
                 break;
             }
             if ($result->getCode() != -14) {  // *DB_ERROR_NODBSELECTED
@@ -2575,10 +2603,11 @@ class DB_DataObject extends DB_DataObject_Overload
         }
        
 
-        if (is_a($result,'PEAR_Error')) {
+        if (is_object($result) && is_a($result,'PEAR_Error')) {
             if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { 
                 $this->debug($result->toString(), "Query Error",1 );
             }
+            $this->N = false;
             return $this->raiseError($result);
         }
         if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
@@ -2607,14 +2636,17 @@ class DB_DataObject extends DB_DataObject_Overload
         if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
             $this->debug(serialize($result), 'RESULT',5);
         }
-        if (method_exists($result, 'numrows')) {
+        if (method_exists($result, 'numRows')) {
             if ($_DB_driver == 'DB') {
                 $DB->expectError(DB_ERROR_UNSUPPORTED);
             } else {
                 $DB->expectError(MDB2_ERROR_UNSUPPORTED);
             }
-            $this->N = $result->numrows();
-            if (is_a($this->N,'PEAR_Error')) {
+            
+            $this->N = $result->numRows();
+            //var_dump($this->N);
+            
+            if (is_object($this->N) && is_a($this->N,'PEAR_Error')) {
                 $this->N = true;
             }
             $DB->popExpect();
@@ -2634,7 +2666,7 @@ class DB_DataObject extends DB_DataObject_Overload
     {
         global $_DB_DATAOBJECT;
         $this->_connect();
-        $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+        $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
        
         $quoteIdentifiers  = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
         $options = $_DB_DATAOBJECT['CONFIG'];
@@ -2666,12 +2698,12 @@ class DB_DataObject extends DB_DataObject_Overload
             }
             
             $kSql = $quoteIdentifiers 
-                ? ( $DB->quoteIdentifier($this->__table) . '.' . $DB->quoteIdentifier($k) )  
-                : "{$this->__table}.{$k}";
+                ? ( $DB->quoteIdentifier($this->tableName()) . '.' . $DB->quoteIdentifier($k) )  
+                : "{$this->tableName()}.{$k}";
              
              
             
-            if (is_a($this->$k,'DB_DataObject_Cast')) {
+            if (is_object($this->$k) && is_a($this->$k,'DB_DataObject_Cast')) {
                 $dbtype = $DB->dsn["phptype"];
                 $value = $this->$k->toString($v,$DB);
                 if (PEAR::isError($value)) {
@@ -2711,28 +2743,6 @@ class DB_DataObject extends DB_DataObject_Overload
         }
     }
 
-    /**
-     * autoload Class relating to a table
-     * (depreciated - use ::factory)
-     *
-     * @param  string  $table  table
-     * @access private
-     * @return string classname on Success
-     */
-    function staticAutoloadTable($table)
-    {
-        global $_DB_DATAOBJECT;
-        if (empty($_DB_DATAOBJECT['CONFIG'])) {
-            DB_DataObject::_loadConfig();
-        }
-        $p = isset($_DB_DATAOBJECT['CONFIG']['class_prefix']) ?
-            $_DB_DATAOBJECT['CONFIG']['class_prefix'] : '';
-        $class = $p . preg_replace('/[^A-Z0-9]/i','_',ucfirst($table));
-        
-        $ce = substr(phpversion(),0,1) > 4 ? class_exists($class,false) : class_exists($class);
-        $class = $ce ? $class  : DB_DataObject::_autoloadClass($class);
-        return $class;
-    }
     
     
      /**
@@ -2756,7 +2766,8 @@ class DB_DataObject extends DB_DataObject_Overload
     
     
 
-    function factory($table = '') {
+    function factory($table = '')
+    {
         global $_DB_DATAOBJECT;
         
         
@@ -2781,8 +2792,8 @@ class DB_DataObject extends DB_DataObject_Overload
        
         
         if ($table === '') {
-            if (is_a($this,'DB_DataObject') && strlen($this->__table)) {
-                $table = $this->__table;
+            if (is_a($this,'DB_DataObject') && strlen($this->tableName())) {
+                $table = $this->tableName();
             } else {
                 return DB_DataObject::raiseError(
                     "factory did not recieve a table name",
@@ -2794,6 +2805,8 @@ class DB_DataObject extends DB_DataObject_Overload
         $cp = isset($_DB_DATAOBJECT['CONFIG']['class_prefix']) ?
             explode(PATH_SEPARATOR, $_DB_DATAOBJECT['CONFIG']['class_prefix']) : '';
         
+        //print_r($cp);
+        
         // multiprefix support.
         $tbl = preg_replace('/[^A-Z0-9]/i','_',ucfirst($table));
         if (is_array($cp)) {
@@ -2813,7 +2826,6 @@ class DB_DataObject extends DB_DataObject_Overload
         
         
         $rclass = $ce ? $class  : DB_DataObject::_autoloadClass($class, $table);
-        
         // proxy = full|light
         if (!$rclass && isset($_DB_DATAOBJECT['CONFIG']['proxy'])) { 
         
@@ -2828,7 +2840,9 @@ class DB_DataObject extends DB_DataObject_Overload
             $d = new DB_DataObject;
            
             $d->__table = $table;
-            if (is_a($ret = $d->_connect(), 'PEAR_Error')) {
+            
+            $ret = $d->_connect();
+            if (is_object($ret) && is_a($ret, 'PEAR_Error')) {
                 return $ret;
             }
             
@@ -2836,14 +2850,16 @@ class DB_DataObject extends DB_DataObject_Overload
             return $x->$proxyMethod( $d->_database, $table);
         }
         
-        if (!$rclass) {
+        if (!$rclass || !class_exists($rclass)) {
             return DB_DataObject::raiseError(
                 "factory could not find class " . 
                 (is_array($class) ? implode(PATH_SEPARATOR, $class)  : $class  ). 
                 "from $table",
                 DB_DATAOBJECT_ERROR_INVALIDCONFIG);
         }
-        $ret = new $rclass;
+        $ret = new $rclass();
         if (!empty($database)) {
             DB_DataObject::debug("Setting database to $database","FACTORY",1);
             $ret->database($database);
@@ -2968,11 +2984,14 @@ class DB_DataObject extends DB_DataObject_Overload
     * Should look a bit like
     *       [local_col_name] => "related_tablename:related_col_name"
     * 
+    * @param    array $new_links optional - force update of the links for this table
+    *               You probably want to restore it to it's original state after,
+    *               as modifying here does it for the whole PHP request.
     * 
     * @return   array|null    
     *           array       = if there are links defined for this table.
     *           empty array - if there is a links.ini file, but no links on this table
-    *           null        - if no links.ini exists for this database (hence try auto_links).
+    *           false       - if no links.ini exists for this database (hence try auto_links).
     * @access   public
     * @see      DB_DataObject::getLinks(), DB_DataObject::getLink()
     */
@@ -2986,232 +3005,183 @@ class DB_DataObject extends DB_DataObject_Overload
         // have to connect.. -> otherwise things break later.
         $this->_connect();
         
-        if (isset($_DB_DATAOBJECT['LINKS'][$this->_database][$this->__table])) {
-            return $_DB_DATAOBJECT['LINKS'][$this->_database][$this->__table];
+        // alias for shorter code..
+        $lcfg  = &$_DB_DATAOBJECT['LINKS'];
+        $cfg   =  $_DB_DATAOBJECT['CONFIG'];
+
+        if ($args = func_get_args()) {
+            // an associative array was specified, that updates the current
+            // schema... - be careful doing this
+            if (empty( $lcfg[$this->_database])) {
+                $lcfg[$this->_database] = array();
+            }
+            $lcfg[$this->_database][$this->tableName()] = $args[0];
+            
+        }
+        // loaded and available.
+        if (isset($lcfg[$this->_database][$this->tableName()])) {
+            return $lcfg[$this->_database][$this->tableName()];
+        }
+
+        // loaded 
+        if (isset($lcfg[$this->_database])) {
+            // either no file, or empty..
+            return $lcfg[$this->_database] === false ? null : array();
         }
         
-        
-        
-        
-        
-        // attempt to load links file here..
-        
-        if (!isset($_DB_DATAOBJECT['LINKS'][$this->_database])) {
-            $schemas = isset($_DB_DATAOBJECT['CONFIG']['schema_location']) ?
-                array("{$_DB_DATAOBJECT['CONFIG']['schema_location']}/{$this->_database}.ini") :
-                array() ;
-                     
-            if (isset($_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"])) {
-                $schemas = is_array($_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"]) ?
-                    $_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"] :
-                    explode(PATH_SEPARATOR,$_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"]);
+        // links are same place as schema by default.
+        $schemas = isset($cfg['schema_location']) ?
+            array("{$cfg['schema_location']}/{$this->_database}.ini") :
+            array() ;
+
+        // if ini_* is set look there instead.
+        // and support multiple locations.                 
+        if (isset($cfg["ini_{$this->_database}"])) {
+            $schemas = is_array($cfg["ini_{$this->_database}"]) ?
+                $cfg["ini_{$this->_database}"] :
+                explode(PATH_SEPARATOR,$cfg["ini_{$this->_database}"]);
+        }
+                        
+        // default to not available.
+        $lcfg[$this->_database] = false;
+
+        foreach ($schemas as $ini) {
+                
+            $links = isset($cfg["links_{$this->_database}"]) ?
+                    $cfg["links_{$this->_database}"] :
+                    str_replace('.ini','.links.ini',$ini);
+            
+            // file really exists..
+            if (!file_exists($links) || !is_file($links)) {
+                if (!empty($cfg['debug'])) {
+                    $this->debug("Missing links.ini file: $links","links",1);
+                }
+                continue;
             }
+
+            // set to empty array - as we have at least one file now..
+            $lcfg[$this->_database] = empty($lcfg[$this->_database]) ? array() : $lcfg[$this->_database];
+
+            // merge schema file into lcfg..
+            $lcfg[$this->_database] = array_merge(
+                $lcfg[$this->_database],
+                parse_ini_file($links, true)
+            );
+
                         
+            if (!empty($cfg['debug'])) {
+                $this->debug("Loaded links.ini file: $links","links",1);
+            }
              
-            $_DB_DATAOBJECT['LINKS'][$this->_database] = array();
-            foreach ($schemas as $ini) {
+        }
+        
+        if (!empty($_DB_DATAOBJECT['CONFIG']['portability']) && $_DB_DATAOBJECT['CONFIG']['portability'] & 1) {
+            foreach($lcfg[$this->_database] as $k=>$v) {
                 
-                $links =
-                    isset($_DB_DATAOBJECT['CONFIG']["links_{$this->_database}"]) ?
-                        $_DB_DATAOBJECT['CONFIG']["links_{$this->_database}"] :
-                        str_replace('.ini','.links.ini',$ini);
-        
-                if (file_exists($links) && is_file($links)) {
-                    /* not sure why $links = ... here  - TODO check if that works */
-                    $_DB_DATAOBJECT['LINKS'][$this->_database] = array_merge(
-                        $_DB_DATAOBJECT['LINKS'][$this->_database],
-                        parse_ini_file($links, true)
-                    );
-                        
-                    if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
-                        $this->debug("Loaded links.ini file: $links","links",1);
-                    }
-                } else {
-                    if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
-                        $this->debug("Missing links.ini file: $links","links",1);
-                    }
+                $nk = strtolower($k);
+                // results in duplicate cols.. but not a big issue..
+                $lcfg[$this->_database][$nk] = isset($lcfg[$this->_database][$nk])
+                    ? $lcfg[$this->_database][$nk]  : array();
+                
+                foreach($v as $kk =>$vv) {
+                    //var_Dump($vv);exit;
+                    $vv =explode(':', $vv);
+                    $vv[0] = strtolower($vv[0]);
+                    $lcfg[$this->_database][$nk][$kk] = implode(':', $vv);
                 }
+                
+                
             }
         }
-        
+        //echo '<PRE>';print_r($lcfg);exit;
         
         // if there is no link data at all on the file!
         // we return null.
-        if (!isset($_DB_DATAOBJECT['LINKS'][$this->_database])) {
+        if ($lcfg[$this->_database] === false) {
             return null;
         }
         
-        if (isset($_DB_DATAOBJECT['LINKS'][$this->_database][$this->__table])) {
-            return $_DB_DATAOBJECT['LINKS'][$this->_database][$this->__table];
+        if (isset($lcfg[$this->_database][$this->tableName()])) {
+            return $lcfg[$this->_database][$this->tableName()];
         }
         
         return array();
     }
+    
+    
     /**
-     * load related objects
+     * generic getter/setter for links
      *
-     * There are two ways to use this, one is to set up a <dbname>.links.ini file
-     * into a static property named <dbname>.links and specifies the table joins,
-     * the other highly dependent on naming columns 'correctly' :)
-     * using colname = xxxxx_yyyyyy
-     * xxxxxx = related table; (yyyyy = user defined..)
-     * looks up table xxxxx, for value id=$this->xxxxx
-     * stores it in $this->_xxxxx_yyyyy
-     * you can change what object vars the links are stored in by 
-     * changeing the format parameter
+     * This is the new 'recommended' way to get get/set linked objects.
+     * must be used with links.ini
      *
+     * usage:
+     *  get:
+     *  $obj = $do->link('company_id');
+     *  $obj = $do->link(array('local_col', 'linktable:linked_col'));
+     *  
+     *  set:
+     *  $do->link('company_id',0);
+     *  $do->link('company_id',$obj);
+     *  $do->link('company_id', array($obj));
      *
-     * @param  string format (default _%s) where %s is the table name.
-     * @author Tim White <tim@cyface.com>
+     *  example function
+     *
+     *  function company() {
+     *     $this->link(array('company_id','company:id'), func_get_args());
+     *   }
+     *
+     * 
+     *
+     * @param  mixed $link_spec              link specification (normally a string)
+     *                                       uses similar rules to  joinAdd() array argument.
+     * @param  mixed $set_value (optional)   int, DataObject, or array('set')
+     * @author Alan Knowles
      * @access public
-     * @return boolean , true on success
+     * @return mixed true or false on setting, object on getting
      */
-    function getLinks($format = '_%s')
+    function link($field, $set_args = array())
     {
-         
-        // get table will load the options.
-        if ($this->_link_loaded) {
-            return true;
-        }
-        $this->_link_loaded = false;
-        $cols  = $this->table();
-        $links = $this->links();
-         
-        $loaded = array();
-        
-        if ($links) {   
-            foreach($links as $key => $match) {
-                list($table,$link) = explode(':', $match);
-                $k = sprintf($format, str_replace('.', '_', $key));
-                // makes sure that '.' is the end of the key;
-                if ($p = strpos($key,'.')) {
-                      $key = substr($key, 0, $p);
-                }
-                
-                $this->$k = $this->getLink($key, $table, $link);
-                
-                if (is_object($this->$k)) {
-                    $loaded[] = $k; 
-                }
-            }
-            $this->_link_loaded = $loaded;
-            return true;
-        }
-        // this is the autonaming stuff..
-        // it sends the column name down to getLink and lets that sort it out..
-        // if there is a links file then it is not used!
-        // IT IS DEPRECIATED!!!! - USE 
-        if (!is_null($links)) {    
-            return false;
-        }
-        
+        require_once 'DB/DataObject/Links.php';
+        $l = new DB_DataObject_Links($this);
+        return  $l->link($field,$set_args) ;
         
-        foreach (array_keys($cols) as $key) {
-            if (!($p = strpos($key, '_'))) {
-                continue;
-            }
-            // does the table exist.
-            $k =sprintf($format, $key);
-            $this->$k = $this->getLink($key);
-            if (is_object($this->$k)) {
-                $loaded[] = $k; 
-            }
-        }
-        $this->_link_loaded = $loaded;
-        return true;
     }
-
-    /**
-     * return name from related object
-     *
-     * There are two ways to use this, one is to set up a <dbname>.links.ini file
-     * into a static property named <dbname>.links and specifies the table joins,
-     * the other is highly dependant on naming columns 'correctly' :)
+    
+      /**
+     * load related objects
      *
-     * NOTE: the naming convention is depreciated!!! - use links.ini
+     * Generally not recommended to use this.
+     * The generator should support creating getter_setter methods which are better suited.
      *
-     * using colname = xxxxx_yyyyyy
-     * xxxxxx = related table; (yyyyy = user defined..)
-     * looks up table xxxxx, for value id=$this->xxxxx
-     * stores it in $this->_xxxxx_yyyyy
+     * Relies on  <dbname>.links.ini
      *
-     * you can also use $this->getLink('thisColumnName','otherTable','otherTableColumnName')
+     * Sets properties on the calling dataobject  you can change what
+     * object vars the links are stored in by  changeing the format parameter
      *
      *
-     * @param string $row    either row or row.xxxxx
-     * @param string $table  name of table to look up value in
-     * @param string $link   name of column in other table to match
+     * @param  string format (default _%s) where %s is the table name.
      * @author Tim White <tim@cyface.com>
      * @access public
-     * @return mixed object on success
+     * @return boolean , true on success
      */
-    function getLink($row, $table = null, $link = false)
+    function getLinks($format = '_%s')
     {
-        
-        
-        // GUESS THE LINKED TABLE.. (if found - recursevly call self)
-        
-        if ($table === null) {
-            $links = $this->links();
-            
-            if (is_array($links)) {
-            
-                if ($links[$row]) {
-                    list($table,$link) = explode(':', $links[$row]);
-                    if ($p = strpos($row,".")) {
-                        $row = substr($row,0,$p);
-                    }
-                    return $this->getLink($row,$table,$link);
-                    
-                } 
-                
-                $this->raiseError(
-                    "getLink: $row is not defined as a link (normally this is ok)", 
-                    DB_DATAOBJECT_ERROR_NODATA);
-                    
-                $r = false;
-                return $r;// technically a possible error condition?
-
-            }  
-            // use the old _ method - this shouldnt happen if called via getLinks()
-            if (!($p = strpos($row, '_'))) {
-                $r = null;
-                return $r; 
-            }
-            $table = substr($row, 0, $p);
-            return $this->getLink($row, $table);
-            
+        require_once 'DB/DataObject/Links.php';
+         $l = new DB_DataObject_Links($this);
+        return $l->applyLinks($format);
+           
+    }
 
-        }
-        
-        
-        
-        if (!isset($this->$row)) {
-            $this->raiseError("getLink: row not set $row", DB_DATAOBJECT_ERROR_NODATA);
-            return false;
-        }
-        
-        // check to see if we know anything about this table..
-        
-        $obj = $this->factory($table);
-        
-        if (!is_a($obj,'DB_DataObject')) {
-            $this->raiseError(
-                "getLink:Could not find class for row $row, table $table", 
-                DB_DATAOBJECT_ERROR_INVALIDCONFIG);
-            return false;
-        }
-        if ($link) {
-            if ($obj->get($link, $this->$row)) {
-                return $obj;
-            } 
-            return  false;
-        }
-        
-        if ($obj->get($this->$row)) {
-            return $obj;
-        }
-        return false;
+    /**
+     * deprecited : @use link() 
+     */
+    function getLink($row, $table = null, $link = false)
+    {
+        require_once 'DB/DataObject/Links.php';
+        $l = new DB_DataObject_Links($this);
+        return $l->getLink($row, $table === null ? false: $table, $link);
+         
         
     }
 
@@ -3242,47 +3212,12 @@ class DB_DataObject extends DB_DataObject_Overload
      * }
      * 
      */
-    function &getLinkArray($row, $table = null)
+    function getLinkArray($row, $table = null)
     {
-        
-        $ret = array();
-        if (!$table) {
-            $links = $this->links();
-            
-            if (is_array($links)) {
-                if (!isset($links[$row])) {
-                    // failed..
-                    return $ret;
-                }
-                list($table,$link) = explode(':',$links[$row]);
-            } else {
-                if (!($p = strpos($row,'_'))) {
-                    return $ret;
-                }
-                $table = substr($row,0,$p);
-            }
-        }
-        
-        $c  = $this->factory($table);
-        
-        if (!is_a($c,'DB_DataObject')) {
-            $this->raiseError(
-                "getLinkArray:Could not find class for row $row, table $table", 
-                DB_DATAOBJECT_ERROR_INVALIDCONFIG
-            );
-            return $ret;
-        }
-
-        // if the user defined method list exists - use it...
-        if (method_exists($c, 'listFind')) {
-            $c->listFind($this->id);
-        } else {
-            $c->find();
-        }
-        while ($c->fetch()) {
-            $ret[] = $c;
-        }
-        return $ret;
+        require_once 'DB/DataObject/Links.php';
+        $l = new DB_DataObject_Links($this);
+        return $l->getLinkArray($row, $table === null ? false: $table);
+     
     }
 
      /**
@@ -3362,9 +3297,10 @@ class DB_DataObject extends DB_DataObject_Overload
      * @param    optional $obj       object |array    the joining object (no value resets the join)
      *                                          If you use an array here it should be in the format:
      *                                          array('local_column','remotetable:remote_column');
-     *                                          if remotetable does not have a definition, you should
-     *                                          use @ to hide the include error message..
-     *                                      
+     *                                             if remotetable does not have a definition, you should
+     *                                             use @ to hide the include error message..
+     *                                          array('local_column',  $dataobject , 'remote_column');
+     *                                             if array has 3 args, then second is assumed to be the linked dataobject.
      *
      * @param    optional $joinType  string | array
      *                                          'LEFT'|'INNER'|'RIGHT'|'' Inner is default, '' indicates 
@@ -3424,14 +3360,21 @@ class DB_DataObject extends DB_DataObject_Overload
         $toTable = false;
         if (is_array($obj)) {
             $tfield = $obj[0];
-            list($toTable,$ofield) = explode(':',$obj[1]);
-            $obj = DB_DataObject::factory($toTable);
             
-            if (!$obj || is_a($obj,'PEAR_Error')) {
-                $obj = new DB_DataObject;
-                $obj->__table = $toTable;
+            if (count($obj) == 3) {
+                $ofield = $obj[2];
+                $obj = $obj[1];
+            } else {
+                list($toTable,$ofield) = explode(':',$obj[1]);
+            
+                $obj = is_string($toTable) ? DB_DataObject::factory($toTable) : $toTable;
+            
+                if (!$obj || !is_object($obj) || is_a($obj,'PEAR_Error')) {
+                    $obj = new DB_DataObject;
+                    $obj->__table = $toTable;
+                }
+                $obj->_connect();
             }
-            $obj->_connect();
             // set the table items to nothing.. - eg. do not try and match
             // things in the child table...???
             $items = array();
@@ -3442,7 +3385,7 @@ class DB_DataObject extends DB_DataObject_Overload
         }
         /*  make sure $this->_database is set.  */
         $this->_connect();
-        $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
+        $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
        
 
         /// CHANGED 26 JUN 2009 - we prefer links from our local table over the remote one.
@@ -3473,7 +3416,7 @@ class DB_DataObject extends DB_DataObject_Overload
                         $ar[1] = explode(',', $ar[1]);
                     }
 
-                    if ($ar[0] != $obj->__table) {
+                    if ($ar[0] != $obj->tableName()) {
                         continue;
                     }
                     if ($joinCol !== false) {
@@ -3518,7 +3461,7 @@ class DB_DataObject extends DB_DataObject_Overload
                         $ar[1] = explode(',', $ar[1]);
                     }
                  
-                    if ($ar[0] != $this->__table) {
+                    if ($ar[0] != $this->tableName()) {
                         continue;
                     }
                     
@@ -3555,7 +3498,7 @@ class DB_DataObject extends DB_DataObject_Overload
 
         if ($ofield === false) {
             $this->raiseError(
-                "joinAdd: {$obj->__table} has no link with {$this->__table}",
+                "joinAdd: {$obj->tableName()} has no link with {$this->tableName()}",
                 DB_DATAOBJECT_ERROR_NODATA);
             return false;
         }
@@ -3564,7 +3507,7 @@ class DB_DataObject extends DB_DataObject_Overload
         // we default to joining as the same name (this is remvoed later..)
         
         if ($joinAs === false) {
-            $joinAs = $obj->__table;
+            $joinAs = $obj->tableName();
         }
         
         $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
@@ -3572,8 +3515,8 @@ class DB_DataObject extends DB_DataObject_Overload
         
         // not sure  how portable adding database prefixes is..
         $objTable = $quoteIdentifiers ? 
-                $DB->quoteIdentifier($obj->__table) : 
-                 $obj->__table ;
+                $DB->quoteIdentifier($obj->tableName()) : 
+                 $obj->tableName() ;
                 
         $dbPrefix  = '';
         if (strlen($obj->_database) && in_array($DB->dsn['phptype'],array('mysql','mysqli'))) {
@@ -3649,7 +3592,7 @@ class DB_DataObject extends DB_DataObject_Overload
                     continue;
                 }
                             
-                if (is_a($obj->$k,'DB_DataObject_Cast')) {
+                if (is_object($obj->$k) && is_a($obj->$k,'DB_DataObject_Cast')) {
                     $value = $obj->$k->toString($v,$DB);
                     if (PEAR::isError($value)) {
                         $this->raiseError($value->getMessage() ,DB_DATAOBJECT_ERROR_INVALIDARG);
@@ -3706,7 +3649,7 @@ class DB_DataObject extends DB_DataObject_Overload
                
         
         
-        $table = $this->__table;
+        $table = $this->tableName();
         
         if ($quoteIdentifiers) {
             $joinAs   = $DB->quoteIdentifier($joinAs);
@@ -3718,7 +3661,7 @@ class DB_DataObject extends DB_DataObject_Overload
        
         
         $fullJoinAs = '';
-        $addJoinAs  = ($quoteIdentifiers ? $DB->quoteIdentifier($obj->__table) : $obj->__table) != $joinAs;
+        $addJoinAs  = ($quoteIdentifiers ? $DB->quoteIdentifier($obj->tableName()) : $obj->tableName()) != $joinAs;
         if ($addJoinAs) {
             // join table a AS b - is only supported by a few databases and is probably not needed
             // , however since it makes the whole Statement alot clearer we are leaving it in
@@ -3767,6 +3710,247 @@ class DB_DataObject extends DB_DataObject_Overload
 
     }
 
+    /**
+     * autoJoin - using the links.ini file, it builds a query with all the joins 
+     * usage: 
+     * $x = DB_DataObject::factory('mytable');
+     * $x->autoJoin();
+     * $x->get(123); 
+     *   will result in all of the joined data being added to the fetched object..
+     * 
+     * $x = DB_DataObject::factory('mytable');
+     * $x->autoJoin();
+     * $ar = $x->fetchAll();
+     *   will result in an array containing all the data from the table, and any joined tables..
+     * 
+     * $x = DB_DataObject::factory('mytable');
+     * $jdata = $x->autoJoin();
+     * $x->selectAdd(); //reset..
+     * foreach($_REQUEST['requested_cols'] as $c) {
+     *    if (!isset($jdata[$c])) continue; // ignore columns not available..
+     *    $x->selectAdd( $jdata[$c] . ' as ' . $c);
+     * }
+     * $ar = $x->fetchAll(); 
+     *   will result in only the columns requested being fetched...
+     *
+     *
+     *
+     * @param     array     Configuration
+     *          exclude  Array of columns to exclude from results (eg. modified_by_id)
+     *          links    The equivilant links.ini data for this table eg.
+     *                    array( 'person_id' => 'person:id', .... )
+     *          include  Array of columns to include
+     *          distinct Array of distinct columns.
+     *          
+     * @return   array      info about joins
+     *                      cols => map of resulting {joined_tablename}.{joined_table_column_name}
+     *                      join_names => map of resulting {join_name_as}.{joined_table_column_name}
+     *                      count => the column to count on.
+     * @access   public
+     */
+    function autoJoin($cfg = array())
+    {
+        //var_Dump($cfg);exit;
+        $pre_links = $this->links();
+        if (!empty($cfg['links'])) {
+            $this->links(array_merge( $pre_links , $cfg['links']));
+        }
+        $map = $this->links( );
+        
+        
+        //print_r($map);
+        $tabdef = $this->table();
+         
+        // we need this as normally it's only cleared by an empty selectAs call.
+       
+        
+        $keys = array_keys($tabdef);
+        if (!empty($cfg['exclude'])) {
+            $keys = array_intersect($keys, array_diff($keys, $cfg['exclude'])); 
+        }
+        if (!empty($cfg['include'])) {
+            
+            $keys =  array_intersect($keys,  $cfg['include']); 
+        }
+        
+        $selectAs = array();
+        
+        if (!empty($keys)) {
+            $selectAs = array(array( $keys , '%s', false));
+        }
+        
+        $ret = array(
+            'cols' => array(),
+            'join_names' => array(),
+            'count' => false,
+        );
+        
+        
+        
+        $has_distinct = false;
+        if (!empty($cfg['distinct']) && $keys) {
+            
+            // reset the columsn?
+            $cols = array();
+            
+             //echo '<PRE>' ;print_r($xx);exit;
+            foreach($keys as $c) {
+                //var_dump($c);
+                
+                if (  $cfg['distinct'] == $c) {
+                    $has_distinct = 'DISTINCT( ' . $this->tableName() .'.'. $c .') as ' . $c;
+                    $ret['count'] =  'DISTINCT  ' . $this->tableName() .'.'. $c .'';
+                    continue;
+                }
+                // cols is in our filtered keys...
+                $cols = $c;
+                
+            }
+            // apply our filtered version, which excludes the distinct column.
+            
+            $selectAs = empty($cols) ?  array() : array(array(  $cols , '%s', false)) ;
+            
+            
+            
+        } 
+                
+        foreach($keys as $k) {
+            $ret['cols'][$k] = $this->tableName(). '.' . $k;
+        }
+        
+         
+        
+        foreach($map as $ocl=>$info) {
+            
+            list($tab,$col) = explode(':', $info);
+            // what about multiple joins on the same table!!!
+            $xx = DB_DataObject::factory($tab);
+            if (!is_object($xx) || !is_a($xx, 'DB_DataObject')) {
+                continue;
+            }
+            // skip columns that are excluded.
+            
+            // we ignore include here... - as
+             
+            // this is borked ... for multiple jions..
+            $this->joinAdd($xx, 'LEFT', 'join_'.$ocl.'_'. $col, $ocl);
+            
+            if (!empty($cfg['exclude']) && in_array($ocl, $cfg['exclude'])) {
+                continue;
+            }
+            
+            $tabdef = $xx->table();
+            $table = $xx->tableName();
+            
+            $keys = array_keys($tabdef);
+            
+            
+            if (!empty($cfg['exclude'])) {
+                $keys = array_intersect($keys, array_diff($keys, $cfg['exclude']));
+                
+                foreach($keys as $k) {
+                    if (in_array($ocl.'_'.$k, $cfg['exclude'])) {
+                        $keys = array_diff($keys, $k); // removes the k..
+                    }
+                }
+                
+            }
+            
+            if (!empty($cfg['include'])) {
+                // include will basically be BASECOLNAME_joinedcolname
+                $nkeys = array();
+                foreach($keys as $k) {
+                    if (in_array( sprintf($ocl.'_%s', $k), $cfg['include'])) {
+                        $nkeys[] = $k;
+                    }
+                }
+                $keys = $nkeys;
+            }
+            
+            if (empty($keys)) {
+                continue;
+            }
+            // got distinct, and not yet found it..
+            if (!$has_distinct && !empty($cfg['distinct']))  {
+                $cols = array();
+                foreach($keys as $c) {
+                    $tn = sprintf($ocl.'_%s', $c);
+                      
+                    if ( $tn == $cfg['distinct']) {
+                        
+                        $has_distinct = 'DISTINCT( ' . 'join_'.$ocl.'_'.$col.'.'.$c .')  as ' . $tn ;
+                        $ret['count'] =  'DISTINCT  join_'.$ocl.'_'.$col.'.'.$c;
+                       // var_dump($this->countWhat );
+                        continue;
+                    }
+                    $cols[] = $c;
+                     
+                }
+                
+                if (!empty($cols)) {
+                    $selectAs[] = array($cols, $ocl.'_%s', 'join_'.$ocl.'_'. $col);
+                }
+                
+            } else {
+                $selectAs[] = array($keys, $ocl.'_%s', 'join_'.$ocl.'_'. $col);
+            }
+              
+            foreach($keys as $k) {
+                $ret['cols'][sprintf('%s_%s', $ocl, $k)] = $tab.'.'.$k;
+                $ret['join_names'][sprintf('%s_%s', $ocl, $k)] = sprintf('join_%s_%s.%s',$ocl, $col, $k);
+            }
+             
+        }
+        
+        // fill in the select details..
+        $this->selectAdd(); 
+        
+        if ($has_distinct) {
+            $this->selectAdd($has_distinct);
+        }
+         
+        foreach($selectAs as $ar) {
+            
+            $this->selectAs($ar[0], $ar[1], $ar[2]);
+        }
+        // restore links..
+        $this->links( $pre_links );
+        
+        return $ret;
+        
+    }
+    
+    /**
+     * Factory method for calling DB_DataObject_Cast
+     *
+     * if used with 1 argument DB_DataObject_Cast::sql($value) is called
+     * 
+     * if used with 2 arguments DB_DataObject_Cast::$value($callvalue) is called
+     * valid first arguments are: blob, string, date, sql
+     * 
+     * eg. $member->updated = $member->sqlValue('NOW()');
+     * 
+     * 
+     * might handle more arguments for escaping later...
+     * 
+     *
+     * @param string $value (or type if used with 2 arguments)
+     * @param string $callvalue (optional) used with date/null etc..
+     */
+    
+    function sqlValue($value)
+    {
+        $method = 'sql';
+        if (func_num_args() == 2) {
+            $method = $value;
+            $value = func_get_arg(1);
+        }
+        require_once 'DB/DataObject/Cast.php';
+        return call_user_func(array('DB_DataObject_Cast', $method), $value);
+        
+    }
+    
+    
     /**
      * Copies items that are in the table definitions from an
      * array or object into the current object
@@ -3786,7 +3970,7 @@ class DB_DataObject extends DB_DataObject_Overload
         $items = $this->table();
         if (!$items) {
             $this->raiseError(
-                "setFrom:Could not find table definition for {$this->__table}", 
+                "setFrom:Could not find table definition for {$this->tableName()}", 
                 DB_DATAOBJECT_ERROR_INVALIDCONFIG);
             return;
         }
@@ -3838,13 +4022,15 @@ class DB_DataObject extends DB_DataObject_Overload
                 }
                 continue;
             }
-            if (is_object($from[sprintf($format,$k)])) {
+            $val = $from[sprintf($format,$k)];
+            if (is_a($val, 'DB_DataObject_Cast')) {
+                $this->$k = $val;
                 continue;
             }
-            if (is_array($from[sprintf($format,$k)])) {
+            if (is_object($val) || is_array($val)) {
                 continue;
             }
-            $ret = $this->fromValue($k,$from[sprintf($format,$k)]);
+            $ret = $this->fromValue($k,$val);
             if ($ret !== true)  {
                 $overload_return[$k] = 'Not A Valid Value';
             }
@@ -3867,7 +4053,9 @@ class DB_DataObject extends DB_DataObject_Overload
      * will also return links converted to arrays.
      *
      * @param   string  sprintf format for array
-     * @param   bool    empty only return elemnts that have a value set.
+     * @param   bool||number    [true = elemnts that have a value set],
+     *                          [false = table + returned colums] ,
+     *                          [0 = returned columsn only]
      *
      * @access   public
      * @return   array of key => value for row
@@ -3876,34 +4064,40 @@ class DB_DataObject extends DB_DataObject_Overload
     function toArray($format = '%s', $hideEmpty = false) 
     {
         global $_DB_DATAOBJECT;
+        
+        // we use false to ignore sprintf.. (speed up..)
+        $format = $format == '%s' ? false : $format;
+        
         $ret = array();
         $rf = ($this->_resultFields !== false) ? $this->_resultFields : 
-                (isset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]) ? $_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid] : false);
+                (isset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]) ?
+                 $_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid] : false);
+        
         $ar = ($rf !== false) ?
-            array_merge($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid],$this->table()) :
+            (($hideEmpty === 0) ? $rf : array_merge($rf, $this->table())) :
             $this->table();
 
         foreach($ar as $k=>$v) {
              
             if (!isset($this->$k)) {
                 if (!$hideEmpty) {
-                    $ret[sprintf($format,$k)] = '';
+                    $ret[$format === false ? $k : sprintf($format,$k)] = '';
                 }
                 continue;
             }
             // call the overloaded getXXXX() method. - except getLink and getLinks
             if (method_exists($this,'get'.$k) && !in_array(strtolower($k),array('links','link'))) {
-                $ret[sprintf($format,$k)] = $this->{'get'.$k}();
+                $ret[$format === false ? $k : sprintf($format,$k)] = $this->{'get'.$k}();
                 continue;
             }
             // should this call toValue() ???
-            $ret[sprintf($format,$k)] = $this->$k;
+            $ret[$format === false ? $k : sprintf($format,$k)] = $this->$k;
         }
         if (!$this->_link_loaded) {
             return $ret;
         }
         foreach($this->_link_loaded as $k) {
-            $ret[sprintf($format,$k)] = $this->$k->toArray();
+            $ret[$format === false ? $k : sprintf($format,$k)] = $this->$k->toArray();
         
         }
         
@@ -4018,7 +4212,7 @@ class DB_DataObject extends DB_DataObject_Overload
      * @access public
      * @return object The DB connection
      */
-    function &getDatabaseConnection()
+    function getDatabaseConnection()
     {
         global $_DB_DATAOBJECT;
 
@@ -4041,7 +4235,7 @@ class DB_DataObject extends DB_DataObject_Overload
      * @return object The DB result object
      */
      
-    function &getDatabaseResult()
+    function getDatabaseResult()
     {
         global $_DB_DATAOBJECT;
         $this->_connect();
@@ -4173,7 +4367,7 @@ class DB_DataObject extends DB_DataObject_Overload
         $options = $_DB_DATAOBJECT['CONFIG'];
         $cols = $this->table();
         // dont know anything about this col..
-        if (!isset($cols[$col])) {
+        if (!isset($cols[$col]) || is_a($value, 'DB_DataObject_Cast')) {
             $this->$col = $value;
             return true;
         }
@@ -4433,17 +4627,9 @@ class DB_DataObject extends DB_DataObject_Overload
         if ($behaviour == PEAR_ERROR_DIE && !empty($_DB_DATAOBJECT['CONFIG']['dont_die'])) {
             $behaviour = null;
         }
-        $error = &PEAR::getStaticProperty('DB_DataObject','lastError');
+        $error = PEAR::getStaticProperty('DB_DataObject','lastError');
         
-        // this will never work totally with PHP's object model.
-        // as this is passed on static calls (like staticGet in our case)
-
-        if (isset($this) && is_object($this) && is_subclass_of($this,'db_dataobject')) {
-            $this->_lastError = $error;
-        }
-
-        $_DB_DATAOBJECT['LASTERROR'] = $error;
-
+      
         // no checks for production here?....... - we log  errors before we throw them.
         DB_DataObject::debug($message,'ERROR',1);
         
@@ -4456,6 +4642,14 @@ class DB_DataObject extends DB_DataObject_Overload
                             $opts=null, $userinfo=null, 'DB_DataObject_Error'
                         );
         }
+        // this will never work totally with PHP's object model.
+        // as this is passed on static calls (like staticGet in our case)
+        $_DB_DATAOBJECT['LASTERROR'] = $error;
+        
+        if (isset($this) && is_object($this) && is_subclass_of($this,'db_dataobject')) {
+            $this->_lastError = $error;
+        }
    
         return $error;
     }
@@ -4562,6 +4756,76 @@ class DB_DataObject extends DB_DataObject_Overload
        
     }
     
+    /**
+     * (deprecated - use ::get / and your own caching method)
+     */
+    function staticGet($class, $k, $v = null)
+    {
+        $lclass = strtolower($class);
+        global $_DB_DATAOBJECT;
+        if (empty($_DB_DATAOBJECT['CONFIG'])) {
+            DB_DataObject::_loadConfig();
+        }
+
+        
+
+        $key = "$k:$v";
+        if ($v === null) {
+            $key = $k;
+        }
+        if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+            DB_DataObject::debug("$class $key","STATIC GET - TRY CACHE");
+        }
+        if (!empty($_DB_DATAOBJECT['CACHE'][$lclass][$key])) {
+            return $_DB_DATAOBJECT['CACHE'][$lclass][$key];
+        }
+        if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
+            DB_DataObject::debug("$class $key","STATIC GET - NOT IN CACHE");
+        }
+
+        $obj = DB_DataObject::factory(substr($class,strlen($_DB_DATAOBJECT['CONFIG']['class_prefix'])));
+        if (PEAR::isError($obj)) {
+            DB_DataObject::raiseError("could not autoload $class", DB_DATAOBJECT_ERROR_NOCLASS);
+            $r = false;
+            return $r;
+        }
+        
+        if (!isset($_DB_DATAOBJECT['CACHE'][$lclass])) {
+            $_DB_DATAOBJECT['CACHE'][$lclass] = array();
+        }
+        if (!$obj->get($k,$v)) {
+            DB_DataObject::raiseError("No Data return from get $k $v", DB_DATAOBJECT_ERROR_NODATA);
+            
+            $r = false;
+            return $r;
+        }
+        $_DB_DATAOBJECT['CACHE'][$lclass][$key] = $obj;
+        return $_DB_DATAOBJECT['CACHE'][$lclass][$key];
+    }
+    
+    /**
+     * autoload Class relating to a table
+     * (deprecited - use ::factory)
+     *
+     * @param  string  $table  table
+     * @access private
+     * @return string classname on Success
+     */
+    function staticAutoloadTable($table)
+    {
+        global $_DB_DATAOBJECT;
+        if (empty($_DB_DATAOBJECT['CONFIG'])) {
+            DB_DataObject::_loadConfig();
+        }
+        $p = isset($_DB_DATAOBJECT['CONFIG']['class_prefix']) ?
+            $_DB_DATAOBJECT['CONFIG']['class_prefix'] : '';
+        $class = $p . preg_replace('/[^A-Z0-9]/i','_',ucfirst($table));
+        
+        $ce = substr(phpversion(),0,1) > 4 ? class_exists($class,false) : class_exists($class);
+        $class = $ce ? $class  : DB_DataObject::_autoloadClass($class);
+        return $class;
+    }
+    
     /* ---- LEGACY BC METHODS - NOT DOCUMENTED - See Documentation on New Methods. ---*/
     
     function _get_table() { return $this->table(); }
old mode 100644 (file)
new mode 100755 (executable)
index 2049beb..59cc0af
@@ -17,7 +17,7 @@
  * @author     Alan Knowles <alan@akbkhome.com>
  * @copyright  1997-2008 The PHP Group
  * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
- * @version    CVS: $Id: Cast.php 287158 2009-08-12 13:58:31Z alan_k $
+ * @version    CVS: $Id: Cast.php 326604 2012-07-12 03:02:00Z alan_k $
  * @link       http://pear.php.net/package/DB_DataObject
  */
   
@@ -395,7 +395,16 @@ class DB_DataObject_Cast {
                 // this is funny - the parameter order is reversed ;)
                 return "'".sqlite_escape_string($this->value)."'";
            
+            case 'mssql':
+                
+                if(is_numeric($this->value)) {
+                    return $this->value;
+                }
+                $unpacked = unpack('H*hex', $this->value);
+                return '0x' . $unpacked['hex'];
+                        
                  
+   
             default:
                 return PEAR::raiseError("DB_DataObject_Cast cant handle blobs for Database:{$db->dsn['phptype']} Yet");
         }
@@ -422,10 +431,10 @@ class DB_DataObject_Cast {
         // perhaps we should support TEXT fields???
         // 
         
-        if (!($to & DB_DATAOBJECT_BLOB)) {
-            return PEAR::raiseError('Invalid Cast from a DB_DataObject_Cast::string to something other than a blob!'.
-                ' (why not just use native features)');
-        }
+        // $to == a string field which is the default type (0)
+        // so we do not test it here. - we assume that number fields
+        // will accept a string?? - which is stretching it a bit ...
+        // should probaly add that test as some point. 
         
         switch ($db->dsn['phptype']) {
             case 'pgsql':
@@ -438,7 +447,15 @@ class DB_DataObject_Cast {
             case 'mysqli':
                 return "'".mysqli_real_escape_string($db->connection, $this->value)."'";
 
-            
+            case 'mssql':
+                // copied from the old DB mssql code...?? not sure how safe this is.
+                return "'" . str_replace(
+                        array("'", "\\\r\n", "\\\n"),
+                        array("''", "\\\\\r\n\r\n", "\\\\\n\n"),
+                        $this->value 
+                    ) . "'";
+                
+
             default:
                 return PEAR::raiseError("DB_DataObject_Cast cant handle blobs for Database:{$db->dsn['phptype']} Yet");
         }
@@ -544,6 +561,5 @@ class DB_DataObject_Cast {
     
     
     
-    
 }
 
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index 7ea716d..c06d6ed
@@ -15,7 +15,7 @@
  * @author     Alan Knowles <alan@akbkhome.com>
  * @copyright  1997-2006 The PHP Group
  * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
- * @version    CVS: $Id: Generator.php 298560 2010-04-25 23:01:51Z alan_k $
+ * @version    CVS: $Id: Generator.php 327926 2012-10-08 02:42:09Z alan_k $
  * @link       http://pear.php.net/package/DB_DataObject
  */
  
@@ -86,6 +86,13 @@ class DB_DataObject_Generator extends DB_DataObject
      */
     var $table; // active tablename
 
+    /**
+     * links (generated)
+     *
+     * @var array
+     * @access private
+     */
+    var $_fkeys; // active tablename
 
     /**
      * The 'starter' = call this to start the process
@@ -142,6 +149,7 @@ class DB_DataObject_Generator extends DB_DataObject
                 $t->_database = basename($t->_database);
             }
             $t->_createTableList();
+            $t->_createForiegnKeys();
 
             foreach(get_class_methods($class) as $method) {
                 if (substr($method,0,8 ) != 'generate') {
@@ -173,14 +181,17 @@ class DB_DataObject_Generator extends DB_DataObject
     function _createTableList()
     {
         $this->_connect();
+        
         $options = &PEAR::getStaticProperty('DB_DataObject','options');
 
+       
+
         $__DB= &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
 
         $db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
         $is_MDB2 = ($db_driver != 'DB') ? true : false;
 
-        if (is_a($__DB , 'PEAR_Error')) {
+        if (is_object($__DB) && is_a($__DB , 'PEAR_Error')) {
             return PEAR::raiseError($__DB->toString(), null, PEAR_ERROR_DIE);
         }
         
@@ -202,7 +213,7 @@ class DB_DataObject_Generator extends DB_DataObject
             $__DB->loadModule('Reverse');
         }
 
-        if ((empty($this->tables) || is_a($this->tables , 'PEAR_Error'))) {
+        if ((empty($this->tables) || (is_object($this->tables) && is_a($this->tables , 'PEAR_Error')))) {
             //if that fails fall back to clasic tables list.
             if (!$is_MDB2) {
                 // try getting a list of schema tables first. (postgres)
@@ -218,18 +229,19 @@ class DB_DataObject_Generator extends DB_DataObject
             }
         }
 
-        if (is_a($this->tables , 'PEAR_Error')) {
+        if (is_object($this->tables) && is_a($this->tables , 'PEAR_Error')) {
             return PEAR::raiseError($this->tables->toString(), null, PEAR_ERROR_DIE);
         }
 
         // build views as well if asked to.
         if (!empty($options['build_views'])) {
             if (!$is_MDB2) {
-                $views = $__DB->getListOf('views');
+                $views = $__DB->getListOf(is_string($options['build_views']) ?
+                                    $options['build_views'] : 'views');
             } else {
                 $views = $__DB->manager->listViews();
             }
-            if (is_a($views,'PEAR_Error')) {
+            if (is_object($views) && is_a($views,'PEAR_Error')) {
                 return PEAR::raiseError(
                 'Error getting Views (check the PEAR bug database for the fix to DB), ' .
                 $views->toString(),
@@ -246,23 +258,36 @@ class DB_DataObject_Generator extends DB_DataObject
 
         foreach($this->tables as $table) {
             if (isset($options['generator_include_regex']) &&
-            !preg_match($options['generator_include_regex'],$table)) {
+                    !preg_match($options['generator_include_regex'],$table)) {
+                $this->debug("SKIPPING (generator_include_regex) : $table");
                 continue;
-            } else if (isset($options['generator_exclude_regex']) &&
-            preg_match($options['generator_exclude_regex'],$table)) {
+            } 
+            
+            if (isset($options['generator_exclude_regex']) &&
+                    preg_match($options['generator_exclude_regex'],$table)) {
                 continue;
             }
+            
+            $strip = empty($options['generator_strip_schema']) ? false : $options['generator_strip_schema'];
+            $strip = is_numeric($strip) ? (bool) $strip : $strip;
+            $strip = (is_string($strip) && strtolower($strip) == 'true') ? true : $strip;
+        
             // postgres strip the schema bit from the
-            if (!empty($options['generator_strip_schema'])) {
-                $bits = explode('.', $table,2);
-                $table = $bits[0];
-                if (count($bits) > 1) {
-                    $table = $bits[1];
+            if (!empty($strip) ) {
+                
+                if (!is_string($strip) || preg_match($strip, $table)) { 
+                    $bits = explode('.', $table,2);
+                    $table = $bits[0];
+                    if (count($bits) > 1) {
+                        $table = $bits[1];
+                    }
                 }
             }
+            $this->debug("EXTRACTING : $table");
+            
             $quotedTable = !empty($options['quote_identifiers_tableinfo']) ? 
                 $__DB->quoteIdentifier($table) : $table;
-                
+          
             if (!$is_MDB2) {
                 
                 $defs =  $__DB->tableInfo($quotedTable);
@@ -272,8 +297,9 @@ class DB_DataObject_Generator extends DB_DataObject
                 
             }
 
-            if (is_a($defs,'PEAR_Error')) {
+            if (is_object($defs) && is_a($defs,'PEAR_Error')) {
                 // running in debug mode should pick this up as a big warning..
+                $this->debug("Error reading tableInfo: $table");
                 $this->raiseError('Error reading tableInfo, '. $defs->toString());
                 continue;
             }
@@ -300,6 +326,7 @@ class DB_DataObject_Generator extends DB_DataObject
         // the temporary table array is now the right one (tables names matching
         // with regex expressions have been removed)
         $this->tables = $tmp_table;
+         
         //print_r($this->_definitions);
     }
     
@@ -352,6 +379,12 @@ class DB_DataObject_Generator extends DB_DataObject
         $tmpname = tempnam(session_save_path(),'DataObject_');
         //print_r($this->_newConfig);
         $fh = fopen($tmpname,'w');
+        if (!$fh) {
+            return PEAR::raiseError(
+                "Failed to create temporary file: $tmpname\n".
+                "make sure session.save_path is set and is writable\n"
+                ,null, PEAR_ERROR_DIE);
+        }
         fwrite($fh,$this->_newConfig);
         fclose($fh);
         $perms = file_exists($file) ? fileperms($file) : 0755;
@@ -368,15 +401,15 @@ class DB_DataObject_Generator extends DB_DataObject
         //    return PEAR::raiseError($ret->message,null,PEAR_ERROR_DIE);
         // }
     }
-
-    /**
-     * generate Foreign Keys (for links.ini) 
-     * Currenly only works with mysql / mysqli
+     /**
+     * create the data for Foreign Keys (for links.ini) 
+     * Currenly only works with mysql / mysqli / posgtreas
      * to use, you must set option: generate_links=true
      * 
      * @author Pascal Schöni 
      */
-    function generateForeignKeys() 
+    
+    function _createForiegnKeys()
     {
         $options = PEAR::getStaticProperty('DB_DataObject','options');
         if (empty($options['generate_links'])) {
@@ -387,7 +420,7 @@ class DB_DataObject_Generator extends DB_DataObject
             echo "WARNING: cant handle non-mysql and pgsql introspection for defaults.";
             return; // cant handle non-mysql introspection for defaults.
         }
-
+        $this->debug("generateForeignKeys: Start");
         $DB = $this->getDatabaseConnection();
 
         $fk = array();
@@ -458,6 +491,38 @@ class DB_DataObject_Generator extends DB_DataObject
                 }
 
         }
+     
+        $this->_fkeys = $fk;
+        
+        
+        
+        
+        
+    }
+    
+
+    /**
+     * generate Foreign Keys (for links.ini) 
+     * Currenly only works with mysql / mysqli
+     * to use, you must set option: generate_links=true
+     * 
+     * @author Pascal Schöni 
+     */
+    function generateForeignKeys() 
+    {
+        $options = PEAR::getStaticProperty('DB_DataObject','options');
+        if (empty($options['generate_links'])) {
+            return false;
+        }
+        $__DB = &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
+        if (!in_array($__DB->phptype, array('mysql', 'mysqli', 'pgsql'))) {
+            echo "WARNING: cant handle non-mysql and pgsql introspection for defaults.";
+            return; // cant handle non-mysql introspection for defaults.
+        }
+        $this->debug("generateForeignKeys: Start");
+        
+        $fk = $this->_fkeys;
         $links_ini = "";
 
         foreach($fk as $table => $details) {
@@ -467,21 +532,23 @@ class DB_DataObject_Generator extends DB_DataObject
             }
             $links_ini .= "\n";
         }
-
+      
         // dont generate a schema if location is not set
         // it's created on the fly!
         $options = PEAR::getStaticProperty('DB_DataObject','options');
 
-        if (empty($options['schema_location'])) {
+        if (!empty($options['schema_location'])) {
+             $file = "{$options['schema_location']}/{$this->_database}.links.ini";
+        } elseif (isset($options["ini_{$this->_database}"])) {
+            $file = preg_replace('/\.ini/','.links.ini',$options["ini_{$this->_database}"]);
+        } else {
+            $this->debug("generateForeignKeys: SKIP - schema_location or ini_{database} was not set");
             return;
         }
-
-        
-        $file = "{$options['schema_location']}/{$this->_database}.links.ini";
+         
 
         if (!file_exists(dirname($file))) {
-            require_once 'System.php';
-            System::mkdir(array('-p','-m',0755,dirname($file)));
+            mkdir(dirname($file),0755, true);
         }
 
         $this->debug("Writing ini as {$file}\n");
@@ -490,6 +557,12 @@ class DB_DataObject_Generator extends DB_DataObject
         $tmpname = tempnam(session_save_path(),'DataObject_');
        
         $fh = fopen($tmpname,'w');
+        if (!$fh) {
+            return PEAR::raiseError(
+                "Failed to create temporary file: $tmpname\n".
+                "make sure session.save_path is set and is writable\n"
+                ,null, PEAR_ERROR_DIE);
+        }
         fwrite($fh,$links_ini);
         fclose($fh);
         $perms = file_exists($file) ? fileperms($file) : 0755;
@@ -615,6 +688,7 @@ class DB_DataObject_Generator extends DB_DataObject
                 case 'TEXT':
                 case 'MEDIUMTEXT':
                 case 'LONGTEXT':
+                case '_TEXT':   //postgres (?? view ??)
                     
                     $type = DB_DATAOBJECT_STR + DB_DATAOBJECT_TXT;
                     break;
@@ -706,14 +780,20 @@ class DB_DataObject_Generator extends DB_DataObject
             //echo "\n{$t->name} => {$t->flags}\n";
             $secondary_key_match = isset($options['generator_secondary_key_match']) ? $options['generator_secondary_key_match'] : 'primary|unique';
             
-            if (preg_match('/(auto_increment|nextval\()/i',rawurldecode($t->flags)) 
+            $m = array();
+            if (preg_match('/(auto_increment|nextval\(([^)]*))/i',rawurldecode($t->flags),$m) 
                 || (isset($t->autoincrement) && ($t->autoincrement === true))) {
-                    
+                
+                $sn = 'N';
+                if ($DB->phptype == 'pgsql' && !empty($m[2])) { 
+                    $sn = preg_replace('/[("]+/','', $m[2]);
+                    //echo urldecode($t->flags) . "\n" ;
+                }
                 // native sequences = 2
                 if ($write_ini) {
-                    $keys_out_primary .= "{$t->name} = N\n";
+                    $keys_out_primary .= "{$t->name} = $sn\n";
                 }
-                $ret_keys_primary[$t->name] = 'N';
+                $ret_keys_primary[$t->name] = $sn;
             
             } else if ($secondary_key_match && preg_match('/('.$secondary_key_match.')/i',$t->flags)) {
                 // keys.. = 1
@@ -814,9 +894,9 @@ class DB_DataObject_Generator extends DB_DataObject
         //echo "Generating Class files:        \n";
         $options = &PEAR::getStaticProperty('DB_DataObject','options');
        
-       $this->_extends = empty($options['extends']) ? $this->_extends : $options['extends'];
-       $this->_extendsFile = empty($options['extends_location']) ? $this->_extendsFile : $options['extends_location'];
+        $this->_extends = empty($options['extends']) ? $this->_extends : $options['extends'];
+        $this->_extendsFile = empty($options['extends_location']) ? $this->_extendsFile : $options['extends_location'];
+     
 
         foreach($this->tables as $this->table) {
             $this->table        = trim($this->table);
@@ -835,6 +915,12 @@ class DB_DataObject_Generator extends DB_DataObject
             $tmpname = tempnam(session_save_path(),'DataObject_');
        
             $fh = fopen($tmpname, "w");
+            if (!$fh) {
+                return PEAR::raiseError(
+                    "Failed to create temporary file: $tmpname\n".
+                    "make sure session.save_path is set and is writable\n"
+                    ,null, PEAR_ERROR_DIE);
+            }
             fputs($fh,$out);
             fclose($fh);
             $perms = file_exists($outfilename) ? fileperms($outfilename) : 0755;
@@ -912,7 +998,6 @@ class DB_DataObject_Generator extends DB_DataObject
         
         $body .= "    {$var} \$__table = '{$this->table}';  {$p}// table name\n";
     
-        
         // if we are using the option database_{databasename} = dsn
         // then we should add var $_database = here
         // as database names may not always match.. 
@@ -924,7 +1009,7 @@ class DB_DataObject_Generator extends DB_DataObject
          // Only include the $_database property if the omit_database_var is unset or false
         
         if (isset($options["database_{$this->_database}"]) && empty($GLOBALS['_DB_DATAOBJECT']['CONFIG']['generator_omit_database_var'])) {
-            $p = str_repeat(' ',   max(2, (16 - strlen($this->table))));
+            $p = str_repeat(' ',   max(2, (16 - strlen($this->_database))));
             $body .= "    {$var} \$_database = '{$this->_database}';  {$p}// database name (used with database_{*} config)\n";
         }
         
@@ -972,22 +1057,27 @@ class DB_DataObject_Generator extends DB_DataObject
         // grep -r __clone * to find all it's uses
         // and replace them with $x = clone($y);
         // due to the change in the PHP5 clone design.
-        
+        $static = 'static';
         if ( substr(phpversion(),0,1) < 5) {
             $body .= "\n";
             $body .= "    /* ZE2 compatibility trick*/\n";
             $body .= "    function __clone() { return \$this;}\n";
         }
-
-        // simple creation tools ! (static stuff!)
-        $body .= "\n";
-        $body .= "    /* Static get */\n";
-        $body .= "    function staticGet(\$k,\$v=NULL) { return DB_DataObject::staticGet('{$this->classname}',\$k,\$v); }\n";
         
+        
+        // depricated - in here for BC...
+        if (!empty($options['static_get'])) {
+            
+            // simple creation tools ! (static stuff!)
+            $body .= "\n";
+            $body .= "    /* Static get */\n";
+            $body .= "    $static  function staticGet(\$k,\$v=NULL) { " .
+                    "return DB_DataObject::staticGet('{$this->classname}',\$k,\$v = null); }\n";
+        }
         // generate getter and setter methods
         $body .= $this->_generateGetters($input);
         $body .= $this->_generateSetters($input);
-        
+        $body .= $this->_generateLinkMethods($input);
         /*
         theoretically there is scope here to introduce 'list' methods
         based up 'xxxx_up' column!!! for heiracitcal trees..
@@ -1193,7 +1283,7 @@ class DB_DataObject_Generator extends DB_DataObject
         $class_prefix  = empty($options['class_prefix']) ? '' : $options['class_prefix'];
         
         $this->_extends = empty($options['extends']) ? $this->_extends : $options['extends'];
-       $this->_extendsFile = empty($options['extends_location']) ? $this->_extendsFile : $options['extends_location'];
+        $this->_extendsFile = empty($options['extends_location']) ? $this->_extendsFile : $options['extends_location'];
  
         $classname = $this->classname = $this->getClassNameFromTableName($this->table);
         
@@ -1346,7 +1436,74 @@ class DB_DataObject_Generator extends DB_DataObject
 
         return $getters;
     }
+    /**
+    * Generate link setter/getter methods for class definition
+    *
+    * @param    string  Existing class contents
+    * @return   string
+    * @access   public
+    */
+    function _generateLinkMethods($input) 
+    {
+
+        $options = &PEAR::getStaticProperty('DB_DataObject','options');
+        $setters = '';
+
+        // only generate if option is set to true
+        
+        // generate_link_methods true::
+        
+        
+        if  (empty($options['generate_link_methods'])) {
+            //echo "skip lm? - not set";
+            return '';
+        }
+        
+        if (empty($this->_fkeys)) {
+            // echo "skip lm? - fkyes empty";
+            return '';
+        }
+        if (empty($this->_fkeys[$this->table])) {
+            //echo "skip lm? - no fkeys for {$this->table}";
+            return '';
+        }
+            
+        // remove auto-generated code from input to be able to check if the method exists outside of the auto-code
+        $input = preg_replace('/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n).*(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s', '', $input);
+
+        $setters .= "\n";
+        $defs     = $this->_fkeys[$this->table];
+         
+        
+        // $fk[$this->table][$tref[1]] = $tref[2] . ":" . $tref[3];
+
+        // loop through properties and create setter methods
+        foreach ($defs as $k => $info) {
 
+            // build mehtod name
+            $methodName =  is_callable($options['generate_link_methods']) ?
+                    $options['generate_link_methods']($k) : $k;
+
+            if (!strlen(trim($k)) || preg_match("/function[\s]+[&]?$methodName\(/i", $input)) {
+                continue;
+            }
+
+            $setters .= "   /**\n";
+            $setters .= "    * Getter / Setter for \${$k}\n";
+            $setters .= "    *\n";
+            $setters .= "    * @param    mixed   (optional) value to assign\n";
+            $setters .= "    * @access   public\n";
+            
+            $setters .= "    */\n";
+            $setters .= (substr(phpversion(),0,1) > 4) ? '    public '
+                                                       : '    ';
+            $setters .= "function $methodName() {\n";
+            $setters .= "        return \$this->link('$k', func_get_args());\n";
+            $setters .= "    }\n\n";
+        }
+         
+        return $setters;
+    }
 
    /**
     * Generate setter methods for class definition
diff --git a/extlib/DB/DataObject/Links.php b/extlib/DB/DataObject/Links.php
new file mode 100644 (file)
index 0000000..9b51b56
--- /dev/null
@@ -0,0 +1,485 @@
+<?php
+/**
+ * Link tool for DB_DataObject
+ *
+ * PHP versions 5
+ *
+ * LICENSE: This source file is subject to version 3.01 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * http://www.php.net/license/3_01.txt.  If you did not receive a copy of
+ * the PHP License and are unable to obtain it through the web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category   Database
+ * @package    DB_DataObject
+ * @author     Alan Knowles <alan@akbkhome.com>
+ * @copyright  1997-2006 The PHP Group
+ * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
+ * @version    : FIXME
+ * @link       http://pear.php.net/package/DB_DataObject
+ */
+
+
+/**
+ *
+ * Example of how this could be used..
+ * 
+ * The lind method are now in here.
+ *
+ * Currenly only supports existing methods, and new 'link()' method
+ *
+ */
+  
+  
+/**
+ * Links class
+ *
+ * @package DB_DataObject
+ */
+class DB_DataObject_Links 
+{
+     /**
+     * @property {DB_DataObject}      do   DataObject to apply this to.
+     */
+    var $do = false;
+    
+    
+    /**
+     * @property {Array|String} load    What to load, 'all' or an array of properties. (default all)
+     */
+    var $load = 'all';
+    /**
+     * @property {String|Boolean}       scanf   use part of column name as resulting
+     *                                          property name. (default false)
+     */
+    var $scanf = false;
+    /**
+     * @property {String|Boolean}       printf  use column name as sprintf for resulting property name..
+     *                                     (default %s_link if apply is true, otherwise it is %s)
+     */
+    var $printf = false;
+    /**
+     * @property {Boolean}      cached  cache the result, so future queries will use cache rather
+     *                                  than running the expensive sql query.
+     */
+    var $cached = false;
+    /**
+     * @property {Boolean}      apply   apply the result to this object, (default true)
+     */
+    var $apply = true;
+   
+    
+    //------------------------- RETURN ------------------------------------
+    /**
+     * @property {Array}      links    key value associative array of links.
+     */
+    var $links;
+    
+    
+    /**
+     * Constructor
+     *   -- good ole style..
+     *  @param {DB_DataObject}           do  DataObject to apply to.
+     *  @param {Array}           cfg  Configuration (basically properties of this object)
+     */
+    
+    function DB_DataObject_Links($do,$cfg= array())
+    {
+        // check if do is set!!!?
+        $this->do = $do;
+        
+        foreach($cfg as $k=>$v) {
+            $this->$k = $v;
+        }
+       
+        
+    }
+     
+    /**
+     * return name from related object
+     *
+     * The relies on  a <dbname>.links.ini file, unless you specify the arguments.
+     * 
+     * you can also use $this->getLink('thisColumnName','otherTable','otherTableColumnName')
+     *
+     *
+     * @param string $field|array    either row or row.xxxxx or links spec.
+     * @param string|DB_DataObject $table  (optional) name of table to look up value in
+     * @param string $link   (optional)  name of column in other table to match
+     * @author Tim White <tim@cyface.com>
+     * @access public
+     * @return mixed object on success false on failure or '0' when not linked
+     */
+    function getLink($field, $table= false, $link='')
+    {
+        
+        static $cache = array();
+        
+        // GUESS THE LINKED TABLE.. (if found - recursevly call self)
+        
+        if ($table == false) {
+            
+            
+            $info = $this->linkInfo($field);
+            
+            if ($info) {
+                return $this->getLink($field, $info[0],  $link === false ? $info[1] : $link );
+            }
+            
+            // no links defined.. - use borked BC method...
+                  // use the old _ method - this shouldnt happen if called via getLinks()
+            if (!($p = strpos($field, '_'))) {
+                return false;
+            }
+            $table = substr($field, 0, $p);
+            return $this->getLink($field, $table);
+            
+            
+
+        }
+         
+        $tn = is_string($table) ? $table : $table->tableName();
+         
+            
+        if (!isset($this->do->$field)) {
+            $this->do->raiseError("getLink: row not set $field", DB_DATAOBJECT_ERROR_NODATA);
+            return false;
+        }
+        
+        // check to see if we know anything about this table..
+        
+      
+        if (empty($this->do->$field) || $this->do->$field < 0) {
+            return 0; // no record. 
+        }
+        
+        if ($this->cached && isset($cache[$tn.':'. $link .':'. $this->do->$field])) {
+            return $cache[$tn.':'. $link .':'. $this->do->$field];    
+        }
+        
+        $obj = is_string($table) ? $this->do->factory($tn) : $table;;
+        
+        if (!is_a($obj,'DB_DataObject')) {
+            $this->do->raiseError(
+                "getLink:Could not find class for row $field, table $tn", 
+                DB_DATAOBJECT_ERROR_INVALIDCONFIG);
+            return false;
+        }
+        // -1 or 0 -- no referenced record..
+       
+        $ret = false;
+        if ($link) {
+            
+            if ($obj->get($link, $this->do->$field)) {
+                $ret = $obj;
+            }
+            
+            
+        // this really only happens when no link config is set (old BC stuff)    
+        } else if ($obj->get($this->do->$field)) {
+            $ret= $obj;
+             
+        }
+        if ($this->cached) {
+            $cache[$tn.':'. $link .':'. $this->do->$field] = $ret;
+        }
+        return $ret;
+        
+    }
+    /**
+     * get link information for a field or field specification
+     *
+     * alll link (and join methods accept the 'link' info ) in various ways
+     * string : 'field' = which field to get (uses ???.links.ini to work out what)
+     * array(2) : 'field', 'table:remote_col' << just like the links.ini def.
+     * array(3) : 'field', $dataobject, 'remote_col'  (handy for joinAdd to do nested joins.)
+     *
+     * @param string|array $field or link spec to use. 
+     * @return (false|array) array of dataobject and linked field or false.
+     *
+     *
+     */
+    
+    function linkInfo($field)
+    {
+         
+        if (is_array($field)) {
+            if (count($field) == 3) {
+                // array with 3 args:
+                // local_col , dataobject, remote_col
+                return array(
+                    $field[1],
+                    $field[2],
+                    $field[0]
+                );
+                
+            } 
+            list($table,$link) = explode(':', $field[1]);
+            
+            return array(
+                $this->do->factory($table),
+                $link,
+                $field[0]
+            );
+            
+        }
+        // work out the link.. (classic way)
+        
+        $links = $this->do->links();
+        
+        if (empty($links) || !is_array($links)) {
+             
+            return false;
+        }
+            
+            
+        if (!isset($links[$field])) {
+            
+            return false;
+        }
+        list($table,$link) = explode(':', $links[$field]);
+    
+        
+        //??? needed???
+        if ($p = strpos($field,".")) {
+            $field = substr($field,0,$p);
+        }
+        
+        return array(
+            $this->do->factory($table),
+            $link,
+            $field
+        );
+        
+        
+         
+        
+    }
+    
+    
+        
+    /**
+     *  a generic geter/setter provider..
+     *
+     *  provides a generic getter setter for the referenced object
+     *  eg.
+     *  $link->link('company_id') returns getLink for the object
+     *  if nothing is linked (it will return an empty dataObject)
+     *  $link->link('company_id', array(1)) - just sets the 
+     *
+     *  also array as the field speck supports
+     *      $link->link(array('company_id', 'company:id'))
+     *  
+     *
+     *  @param  string|array   $field   the field to fetch or link spec.
+     *  @params array          $args    the arguments sent to the getter setter
+     *  @return mixed true of false on set, the object on getter.
+     *
+     */
+    function link($field, $args = array())
+    {
+        $info = $this->linkInfo($field);
+         
+        if (!$info) {
+            $this->do->raiseError(
+                "getLink:Could not find link for row $field", 
+                DB_DATAOBJECT_ERROR_INVALIDCONFIG);
+            return false;
+        }
+        $field = $info[2];
+        
+        
+        if (empty($args)) { // either an empty array or really empty....
+            
+            if (!isset($this->do->$field)) {
+                return $info[0]; // empty dataobject.
+            }
+            
+            $ret = $this->getLink($field);
+            // nothing linked -- return new object..
+            return ($ret === 0) ? $info[0] : $ret;
+            
+        }
+        $assign = is_array($args) ? $args[0] : $args;
+         
+        // otherwise it's a set call..
+        if (!is_a($assign , 'DB_DataObject')) {
+            
+            if (is_numeric($assign) && is_integer($assign * 1)) {
+                if ($assign  > 0) {
+                    
+                    if (!$info) {
+                        return false;
+                    }
+                    // check that record exists..
+                    if (!$info[0]->get($info[1], $assign )) {
+                        return false;
+                    }
+                    
+                }
+                
+                $this->do->$field = $assign ;
+                return true;
+            }
+            
+            return false;
+        }
+        
+        // otherwise we are assigning it ...
+        
+        $this->do->$field = $assign->{$info[1]};
+        return true;
+        
+        
+    }
+    /**
+     * load related objects
+     *
+     * Generally not recommended to use this.
+     * The generator should support creating getter_setter methods which are better suited.
+     *
+     * Relies on  <dbname>.links.ini
+     *
+     * Sets properties on the calling dataobject  you can change what
+     * object vars the links are stored in by  changeing the format parameter
+     *
+     *
+     * @param  string format (default _%s) where %s is the table name.
+     * @author Tim White <tim@cyface.com>
+     * @access public
+     * @return boolean , true on success
+     */
+    
+    function applyLinks($format = '_%s')
+    {
+         
+        // get table will load the options.
+        if ($this->do->_link_loaded) {
+            return true;
+        }
+        
+        $this->do->_link_loaded = false;
+        $cols  = $this->do->table();
+        $links = $this->do->links();
+         
+        $loaded = array();
+        
+        if ($links) {   
+            foreach($links as $key => $match) {
+                list($table,$link) = explode(':', $match);
+                $k = sprintf($format, str_replace('.', '_', $key));
+                // makes sure that '.' is the end of the key;
+                if ($p = strpos($key,'.')) {
+                      $key = substr($key, 0, $p);
+                }
+                
+                $this->do->$k = $this->getLink($key, $table, $link);
+                
+                if (is_object($this->do->$k)) {
+                    $loaded[] = $k; 
+                }
+            }
+            $this->do->_link_loaded = $loaded;
+            return true;
+        }
+        // this is the autonaming stuff..
+        // it sends the column name down to getLink and lets that sort it out..
+        // if there is a links file then it is not used!
+        // IT IS DEPRECATED!!!! - DO NOT USE 
+        if (!is_null($links)) {    
+            return false;
+        }
+        
+        
+        foreach (array_keys($cols) as $key) {
+            if (!($p = strpos($key, '_'))) {
+                continue;
+            }
+            // does the table exist.
+            $k =sprintf($format, $key);
+            $this->do->$k = $this->getLink($key);
+            if (is_object($this->do->$k)) {
+                $loaded[] = $k; 
+            }
+        }
+        $this->do->_link_loaded = $loaded;
+        return true;
+    }
+    
+    /**
+     * getLinkArray
+     * Fetch an array of related objects. This should be used in conjunction with a
+     * <dbname>.links.ini file configuration (see the introduction on linking for details on this).
+     *
+     * You may also use this with all parameters to specify, the column and related table.
+     * 
+     * @access public
+     * @param string $field- either column or column.xxxxx
+     * @param string $table (optional) name of table to look up value in
+     * @param string $fkey (optional) fetchall key see DB_DataObject::fetchAll()
+     * @param string $fval (optional)fetchall val DB_DataObject::fetchAll()
+     * @param string $fval (optional) fetchall method DB_DataObject::fetchAll()
+     * @return array - array of results (empty array on failure)
+     * 
+     * Example - Getting the related objects
+     * 
+     * $person = new DataObjects_Person;
+     * $person->get(12);
+     * $children = $person->getLinkArray('children');
+     * 
+     * echo 'There are ', count($children), ' descendant(s):<br />';
+     * foreach ($children as $child) {
+     *     echo $child->name, '<br />';
+     * }
+     * 
+     */
+    function getLinkArray($field, $table = null, $fkey = false, $fval = false, $fmethod = false)
+    {
+        
+        $ret = array();
+        if (!$table)  {
+            
+            
+            $links = $this->do->links();
+            
+            if (is_array($links)) {
+                if (!isset($links[$field])) {
+                    // failed..
+                    return $ret;
+                }
+                list($table,$link) = explode(':',$links[$field]);
+                return $this->getLinkArray($field,$table);
+            } 
+            if (!($p = strpos($field,'_'))) {
+                return $ret;
+            }
+            return $this->getLinkArray($field,substr($field,0,$p));
+
+
+        }
+        
+        $c  = $this->do->factory($table);
+        
+        if (!is_object($c) || !is_a($c,'DB_DataObject')) {
+            $this->do->raiseError(
+                "getLinkArray:Could not find class for row $field, table $table", 
+                DB_DATAOBJECT_ERROR_INVALIDCONFIG
+            );
+            return $ret;
+        }
+
+        // if the user defined method list exists - use it...
+        if (method_exists($c, 'listFind')) {
+            $c->listFind($this->id);
+            while ($c->fetch()) {
+                $ret[] = clone($c);
+            }
+            return $ret;
+        } 
+        return $c->fetchAll($fkey, $fval, $fmethod);
+        
+        
+    }
+
+}
\ No newline at end of file
old mode 100644 (file)
new mode 100755 (executable)
index d54d28c..ed2e738
@@ -16,7 +16,7 @@
 // | Author:  Alan Knowles <alan@akbkhome.com>
 // +----------------------------------------------------------------------+
 //
-// $Id: createTables.php 277015 2009-03-12 05:51:03Z alan_k $
+// $Id: createTables.php 315758 2011-08-30 08:11:59Z alan_k $
 //
 
 // since this version doesnt use overload, 
@@ -27,13 +27,17 @@ define('DB_DATAOBJECT_NO_OVERLOAD',1);
 //require_once 'DB/DataObject/Generator.php';
 require_once 'DB/DataObject/Generator.php';
 
+if (php_sapi_name() != 'cli') {
+    PEAR::raiseError("\nERROR: You must turn use the cli sapi to run this", null, PEAR_ERROR_DIE);
+}
+
 if (!ini_get('register_argc_argv')) {
     PEAR::raiseError("\nERROR: You must turn register_argc_argv On in you php.ini file for this to work\neg.\n\nregister_argc_argv = On\n\n", null, PEAR_ERROR_DIE);
     exit;
 }
 
 if (!@$_SERVER['argv'][1]) {
-    PEAR::raiseError("\nERROR: createTable.php usage:\n\nC:\php\pear\DB\DataObjects\createTable.php example.ini\n\n", null, PEAR_ERROR_DIE);
+    PEAR::raiseError("\nERROR: createTable.php usage:\n\n" .$_SERVER['argv'][0] . " example.ini\n\n", null, PEAR_ERROR_DIE);
     exit;
 }