Show
Ignore:
Timestamp:
03/19/09 10:40:34 (3 years ago)
Author:
john
Message:

features and bug fixes from gocoffeego project

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/trax/vendor/trax/active_record.php

    r307 r308  
    147147     
    148148    /** 
    149      *  Index into the $active_connections array 
     149     *  Index into the $connection_pool array 
    150150     * 
    151151     *  Name of the index to use to return or set the current db connection 
     
    156156    public $connection_name = null; 
    157157 
     158    /** 
     159     *  Index into the $connection_pool_read_only array 
     160     * 
     161     *  Name of the index to use to return or set the current db connection 
     162     *  Mainly used if you want to force all reads(SELECT's) to goto a 
     163     *  specific database server. 
     164     *  @var string 
     165     */     
     166    public $read_only_connection_name = null; 
     167 
     168    /** 
     169     *  Index into the $connection_pool_read_only array 
     170     * 
     171     *  Same as $read_only_connection_name but set for all models globally. 
     172     *  @var string 
     173     */     
     174    public static $global_read_only_connection_name = null; 
     175 
    158176    /** 
    159177     * What environment to run in. 
     
    167185     
    168186    /** 
    169      * Stores the active connections. Indexed on $connection_name. 
     187     * Stores the active read/write connections. Indexed on $connection_name. 
    170188     */ 
    171     public static $active_connections = array(); 
     189    public static $connection_pool = array(); 
     190 
     191    /** 
     192     * Stores the active read only connections. Indexed on $connection_name. 
     193     */  
     194    public static $connection_pool_read_only = array(); 
    172195 
    173196    /** 
     
    344367     *  @var integer 
    345368     */ 
    346     public $rows_per_page_default = 20; 
     369    public static $rows_per_page_default = 20; 
    347370 
    348371    /** 
     
    355378     */     
    356379    public $pagination_count = 0; 
     380 
     381    /** 
     382     *  @todo Document this variable 
     383     */ 
     384    public $page = 0; 
     385 
     386    /** 
     387     * Sets the default options for the model. 
     388     * 
     389     * class Person extends ActiveRecord { 
     390     *     public $default_scope = array( 
     391     *         'order' => 'last_name, first_name' 
     392     *     )); 
     393     * }  
     394     * 
     395     */      
     396    public $default_scope = array(); 
     397     
     398    /** 
     399     * Adds a class method for retrieving and querying objects.  
     400     * A scope represents a narrowing of a database query, such as  
     401     * 'conditions' => "first_name = 'John'" 
     402     * 
     403     * class Person extends ActiveRecord { 
     404     *     public $named_scope = array( 
     405     *         'people_named_john' => array( 
     406     *             'conditions' => "first_name = 'John'",      
     407     *             'order' => 'last_name, first_name' 
     408     *     )); 
     409     * }  
     410     * 
     411     * $person = new Person; 
     412     * $person->people_named_john; # an array of AR objects people first_name = 'John' 
     413     * 
     414     */ 
     415    public $named_scope = array(); 
     416     
    357417 
    358418    /** 
     
    430490     *  This is for transactions only to let query() know that a 'BEGIN' has been executed 
    431491     */ 
    432     private static $begin_executed = false; 
     492    private static $in_transaction = false; 
    433493 
    434494    /** 
     
    436496     *  This will issue a rollback command if any sql fails. 
    437497     */ 
    438     public static $use_transactions = false;  
     498    public static $auto_rollback = false;  
    439499     
    440500    /** 
     
    460520     */ 
    461521    function __construct($attributes = null) {  
    462         # Open the database connection 
    463         $this->establish_connection(); 
     522        # Open the database connection for reads / writes 
     523        self::$db = $this->establish_connection(); 
     524        if($this->read_only_connection_name) { 
     525            # Open database connection for all reads 
     526            $this->establish_connection($this->read_only_connection_name, true); 
     527        } elseif(self::$global_read_only_connection_name) { 
     528            # Open database connection for all reads 
     529            $this->establish_connection(self::$global_read_only_connection_name, true);             
     530        } 
    464531 
    465532        # Set $table_name 
     
    522589                    break;             
    523590            }         
     591        } elseif(array_key_exists($key, $this->named_scope) && is_array($this->named_scope[$key])) { 
     592            $this->$key = $this->find_all($this->named_scope[$key]); 
    524593        } elseif($this->is_composite($key)) {             
    525594            $composite_object = $this->get_composite_object($key); 
     
    598667            switch($association_type) { 
    599668                case "has_many": 
     669                    $parameters = is_array($this->has_many) && @array_key_exists($method_name, $this->has_many) ?  
     670                        array_merge($this->has_many[$method_name], $parameters) : $parameters; 
    600671                    $result = $this->find_all_has_many($method_name, $parameters); 
    601672                    break; 
    602673                case "has_one": 
     674                    $parameters = is_array($this->has_one) && @array_key_exists($method_name, $this->has_one) ?  
     675                        array_merge($this->has_one[$method_name], $parameters) : $parameters; 
    603676                    $result = $this->find_one_has_one($method_name, $parameters); 
    604677                    break; 
    605678                case "belongs_to": 
     679                    $parameters = is_array($this->belongs_to) && @array_key_exists($method_name, $this->belongs_to) ?  
     680                        array_merge($this->belongs_to[$method_name], $parameters) : $parameters; 
    606681                    $result = $this->find_one_belongs_to($method_name, $parameters); 
    607682                    break; 
    608683                case "has_and_belongs_to_many":   
     684                    $parameters = is_array($this->has_and_belongs_to_many) && @array_key_exists($method_name, $this->has_and_belongs_to_many) ?  
     685                        array_merge($this->has_and_belongs_to_many[$method_name], $parameters) : $parameters; 
    609686                    $result = $this->find_all_habtm($method_name, $parameters);  
    610687                    break;             
     
    649726     */ 
    650727    private function find_all_habtm($other_table_name, $parameters = null) { 
    651         $additional_conditions = null; 
     728        $additional_conditions = $additional_joins = null; 
     729        $options = array(); 
    652730        # Use any passed-in parameters 
    653         if(!is_null($parameters)) { 
     731        if(!is_null($parameters)) {   
    654732            if(@array_key_exists("conditions", $parameters)) { 
    655733                $additional_conditions = " AND (".$parameters['conditions'].")"; 
     
    658736            } 
    659737            if(@array_key_exists("order", $parameters)) { 
    660                 $order = $parameters['order']; 
     738                $options['order'] = $parameters['order']; 
    661739            } elseif($parameters[1] != "") { 
    662                 $order = $parameters[1]; 
     740                $options['order'] = $parameters[1]; 
    663741            } 
    664742            if(@array_key_exists("limit", $parameters)) { 
    665                 $limit = $parameters['limit']; 
     743                $options['limit'] = $parameters['limit']; 
    666744            } elseif($parameters[2] != "") { 
    667                 $limit = $parameters[2]; 
    668             }     
     745                $options['limit'] = $parameters[2]; 
     746            } 
     747            if(@array_key_exists("joins", $parameters)) { 
     748                $additional_joins = $parameters['joins']; 
     749            } elseif($parameters[3] != "") { 
     750                $additional_joins = $parameters[3]; 
     751            } 
     752            if(@array_key_exists("page", $parameters)) { 
     753                $options['page'] = $parameters['page']; 
     754            } 
     755            if(@array_key_exists("per_page", $parameters)) { 
     756                $options['per_page'] = $parameters['per_page']; 
     757            } 
    669758            if(@array_key_exists("class_name", $parameters)) { 
    670759                $other_object_name = $parameters['class_name']; 
     
    697786        if(!is_null($finder_sql)) { 
    698787            $conditions = $finder_sql;     
    699             $order = null; 
    700             $limit = null; 
    701             $joins = null; 
    702788        } else { 
    703789            # Prepare the join table name primary keys (fields) to do the join on 
     
    729815            } 
    730816 
     817            if($this->habtm_sort_field) { 
     818                $options['order'] = (isset($options['order']) ? $options['order'].',':'')."{$join_table}.{$this->habtm_sort_field}"; 
     819            }  
     820             
    731821            # Set up the SQL segments 
    732822            $conditions = "{$join_table}.{$this_foreign_key} = {$this_primary_key_value}".$additional_conditions; 
    733             $joins = "LEFT JOIN {$join_table} ON {$other_table_name}.{$other_primary_key} = {$join_table}.{$other_foreign_key}"; 
    734         } 
     823            $options['joins'] = "LEFT JOIN {$join_table} ON {$other_table_name}.{$other_primary_key} = {$join_table}.{$other_foreign_key}".$additional_joins; 
     824        } 
     825        $options['conditions'] = $conditions; 
    735826         
    736827        # Get the list of other_class_name objects 
    737         return $other_class_object->find_all($conditions, $order, $limit, $joins); 
     828        return $other_class_object->find_all($options); 
    738829    } 
    739830 
     
    747838     */ 
    748839    private function find_all_has_many($other_table_name, $parameters = null) { 
    749         $additional_conditions = null; 
     840        $additional_conditions = $order = $limit = null; 
    750841        # Use any passed-in parameters 
    751842        if(is_array($parameters)) { 
     
    756847            } 
    757848            if(@array_key_exists("order", $parameters)) { 
    758                 $order = $parameters['order']; 
     849                $options['order'] = $parameters['order']; 
    759850            } elseif($parameters[1] != "") { 
    760                 $order = $parameters[1]; 
     851                $options['order'] = $parameters[1]; 
    761852            } 
    762853            if(@array_key_exists("limit", $parameters)) { 
    763                 $limit = $parameters['limit']; 
     854                $options['limit'] = $parameters['limit']; 
    764855            } elseif($parameters[2] != "") { 
    765                 $limit = $parameters[2]; 
    766             } 
     856                $options['limit'] = $parameters[2]; 
     857            } 
     858            if(@array_key_exists("joins", $parameters)) { 
     859                $options['joins'] = $parameters['joins']; 
     860            } elseif($parameters[3] != "") { 
     861                $options['joins'] = $parameters[3]; 
     862            } 
     863            if(@array_key_exists("page", $parameters)) { 
     864                $options['page'] = $parameters['page']; 
     865            } 
     866            if(@array_key_exists("per_page", $parameters)) { 
     867                $options['per_page'] = $parameters['per_page']; 
     868            } 
    767869            if(@array_key_exists("foreign_key", $parameters)) { 
    768870                $foreign_key = $parameters['foreign_key']; 
     
    773875            if(@array_key_exists("finder_sql", $parameters)) { 
    774876                $finder_sql = $parameters['finder_sql']; 
    775             } 
     877            }            
    776878        } 
    777879 
     
    788890        if(!is_null($finder_sql)) { 
    789891            $conditions = $finder_sql;   
    790             $order = null; 
    791             $limit = null; 
    792             $joins = null;  
    793892        } else {           
    794893            # This class primary key 
     
    813912            $conditions .= $additional_conditions;  
    814913        } 
    815                           
     914        $options['conditions'] = $conditions; 
     915        #error_log("has_many:".print_r($options, true)); 
    816916        # Get the list of other_class_name objects 
    817         return $other_class_object->find_all($conditions, $order, $limit, $joins); 
     917        return $other_class_object->find_all($options); 
    818918    } 
    819919 
     
    857957        $this_primary_key = $this->primary_keys[0]; 
    858958         
    859         if(!$foreign_key){ 
     959        if(!$foreign_key) { 
    860960            $foreign_key = Inflector::singularize($this->table_name)."_".$this_primary_key; 
    861961        } 
     
    9791079 
    9801080        # echo "$aggregate_type sql:$sql<br>"; 
    981         if($this->is_error($rs = $this->query($sql))) { 
     1081        //print_r($parameters[0]); 
     1082        //echo $sql; 
     1083        if($this->is_error($rs = $this->query($sql, true))) { 
    9821084            $this->raise($rs->getMessage()); 
    9831085        } else { 
     
    10781180        if($this->column_attribute_exists($column) && ($conditions = $this->get_primary_key_conditions())) { 
    10791181            # Run the query to grab a specific columns value. 
    1080             $sql = "SELECT {$column} FROM {$this->table_prefix}{$this->table_name} WHERE {$conditions}"; 
     1182            $sql = "SELECT {$column} FROM {$this->table_prefix}{$this->table_name} WHERE {$conditions} LIMIT 1"; 
    10811183            $this->log_query($sql); 
    1082             $result = self::$db->queryOne($sql); 
     1184            $db = $this->get_connection(true); 
     1185            $result = $db->queryOne($sql); 
    10831186            if($this->is_error($result)) { 
    10841187                $this->raise($result->getMessage()); 
     
    10941197     *  @todo Document this API 
    10951198     */ 
    1096     function begin() { 
    1097         self::$db->query("BEGIN"); 
    1098         $this->begin_executed = true; 
     1199    function begin($save_point = null) { 
     1200        # check if transaction are supported by this driver 
     1201        if(self::$db->supports('transactions')) {         
     1202            $rs = self::$db->beginTransaction(); 
     1203            if($this->is_error($rs)) { 
     1204                $this->raise($rs->getMessage()); 
     1205            }       
     1206            self::$in_transaction = true; 
     1207        } 
     1208    } 
     1209 
     1210    /** 
     1211     * Only used if you want to do transactions and your db supports transactions 
     1212     * 
     1213     *  @uses $db 
     1214     *  @todo Document this API 
     1215     */     
     1216    function save_point($save_point) { 
     1217        if(!is_null($save_point)) { 
     1218            # check if transaction are supported by this driver 
     1219            if(self::$db->supports('transactions')) {             
     1220                # check if we are inside a transaction and if savepoints are supported 
     1221                if(self::$db->inTransaction() && self::$db->supports('savepoints')) { 
     1222                    # Set a savepoint 
     1223                    $rs = self::$db->beginTransaction($save_point);  
     1224                    if($this->is_error($rs)) { 
     1225                        $this->raise($rs->getMessage()); 
     1226                    }                 
     1227                }  
     1228            }           
     1229        }         
    10991230    } 
    11001231 
     
    11051236     *  @todo Document this API 
    11061237     */ 
    1107     function commit() { 
    1108         self::$db->query("COMMIT");  
    1109         $this->begin_executed = false; 
     1238    function commit() {       
     1239        # check if transaction are supported by this driver 
     1240        if(self::$db->supports('transactions')) { 
     1241            # check if we are inside a transaction 
     1242            if(self::$db->inTransaction()) { 
     1243                $rs = self::$db->commit();  
     1244                if($this->is_error($rs)) { 
     1245                    $this->raise($rs->getMessage()); 
     1246                }         
     1247                self::$in_transaction = false; 
     1248            } 
     1249        } 
    11101250    } 
    11111251 
     
    11151255     *  @uses $db 
    11161256     *  @todo Document this API 
    1117      */ 
     1257     */     
    11181258    function rollback() { 
    1119         self::$db->query("ROLLBACK"); 
     1259        # check if transaction are supported by this driver 
     1260        if(self::$db->supports('transactions')) { 
     1261            $rs = self::$db->rollback();  
     1262            if($this->is_error($rs)) { 
     1263                $this->raise($rs->getMessage()); 
     1264            } 
     1265            self::$in_transaction = false; 
     1266        }                
    11201267    } 
    11211268 
     
    11311278     *  @throws {@link ActiveRecordError} 
    11321279     */ 
    1133     function query($sql) { 
     1280    function query($sql, $read_only = false) { 
    11341281        # Run the query 
    11351282        $this->log_query($sql); 
    1136         $rs =& self::$db->query($sql); 
     1283        $db = $this->get_connection($read_only); 
     1284        $rs =& $db->query($sql); 
    11371285        if ($this->is_error($rs)) { 
    1138             if(self::$use_transactions && self::$begin_executed) { 
     1286            if(self::$auto_rollback && self::$in_transaction) { 
    11391287                $this->rollback(); 
    11401288            } 
     
    12411389         
    12421390        $offset = null; 
     1391        $page = null; 
    12431392        $per_page = null; 
    12441393        $select = null; 
     1394        $paginate = false; 
    12451395 
    12461396        # this is if they passed in an associative array to emulate 
     
    12801430            # If conditions specified, include them 
    12811431            if(!is_null($conditions)) { 
     1432                if(array_key_exists('conditions', $this->default_scope)  
     1433                   && !is_null($this->default_scope['conditions'])) { 
     1434                    $conditions = " ({$conditions}) AND (".$this->default_scope['conditions'].") "; 
     1435                } 
    12821436                $sql .= "WHERE $conditions "; 
     1437            } elseif(array_key_exists('conditions', $this->default_scope)  
     1438                     && !is_null($this->default_scope['conditions'])) { 
     1439                $sql .= "WHERE ".$this->default_scope['conditions']." "; 
    12831440            } 
    12841441 
    12851442            # If ordering specified, include it 
    12861443            if(!is_null($order)) { 
     1444                if(array_key_exists('order', $this->default_scope)  
     1445                   && !is_null($this->default_scope['order'])) { 
     1446                    $order = " {$order},".$this->default_scope['order']." "; 
     1447                }                 
    12871448                $sql .= "ORDER BY $order "; 
     1449            } elseif(array_key_exists('order', $this->default_scope)  
     1450                     && !is_null($this->default_scope['order'])) { 
     1451                $sql .= "ORDER BY ".$this->default_scope['order']." "; 
    12881452            } 
    12891453 
    12901454            # Is output to be generated in pages? 
    1291             if(is_numeric($limit) || is_numeric($offset) || is_numeric($per_page)) { 
     1455            if(is_numeric($limit) || is_numeric($offset) || is_numeric($per_page) || is_numeric($page)) { 
     1456                #error_log("limit:$limit offset:$offset per_page:$per_page page:$page"); 
    12921457 
    12931458                if(is_numeric($limit)) {     
    1294                     $this->rows_per_page = $limit;         
     1459                    $this->rows_per_page = (int)$limit;         
    12951460                } 
    12961461                if(is_numeric($per_page)) { 
    1297                     $this->rows_per_page = $per_page;             
     1462                    $this->rows_per_page = (int)$per_page;  
     1463                    $paginate = true; 
    12981464                } 
    12991465                # Default for rows_per_page: 
    13001466                if ($this->rows_per_page <= 0) { 
    1301                     $this->rows_per_page = $this->rows_per_page_default; 
     1467                    $this->rows_per_page = (int)self::$rows_per_page_default; 
    13021468                } 
    13031469                 
    13041470                # Only use request's page if you are calling from find_all_with_pagination() and if it is int 
    1305                 if(strval(intval($_REQUEST['page'])) == $_REQUEST['page']) { 
    1306                     $this->page = $_REQUEST['page']; 
     1471                #if(isset($_REQUEST['page']) && strval(intval($_REQUEST['page'])) == $_REQUEST['page']) { 
     1472                    #$this->page = $_REQUEST['page']; 
     1473                #} 
     1474                if(!is_null($page)) { 
     1475                    $this->page = (int)$page; 
     1476                    $paginate = true; 
    13071477                } 
    13081478                 
     
    13191489                # $sql .= "LIMIT $offset, $this->rows_per_page"; 
    13201490                 
    1321                 # Set number of total pages in result set 
    1322                 if($count = $this->count_all($this->primary_keys[0], $conditions, $joins)) { 
    1323                     $this->pagination_count = $count; 
    1324                     $this->pages = (($count % $this->rows_per_page) == 0) 
    1325                         ? $count / $this->rows_per_page 
    1326                         : floor($count / $this->rows_per_page) + 1;  
     1491                if($paginate) { 
     1492                    #error_log("I am going to paginate."); 
     1493                    # Set number of total pages in result set 
     1494                    if($count = $this->count_all($this->primary_keys[0], $conditions, $joins)) { 
     1495                        $this->pagination_count = $count; 
     1496                        $this->pages = (($count % $this->rows_per_page) == 0) 
     1497                            ? $count / $this->rows_per_page 
     1498                            : floor($count / $this->rows_per_page) + 1;  
     1499                    } 
    13271500                } 
    13281501            } 
     
    13311504        return $sql; 
    13321505    } 
     1506     
     1507    /** 
     1508     *  Returns same as find_all 
     1509     * 
     1510     */ 
     1511    function paginate($page = 1, $per_page = 0, $options = array()) { 
     1512        if(is_array($page)) { 
     1513            $options = $page; 
     1514        } else { 
     1515            $options['page'] = (int)($page > 0 ? $page : 1); 
     1516            $options['per_page'] = (int)($per_page > 0 ? $per_page : self::$rows_per_page_default); 
     1517        } 
     1518        $options['paginate'] = true; 
     1519        return $this->find_all($options); 
     1520    }    
    13331521 
    13341522    /** 
     
    13721560        # echo "query: $sql\n"; 
    13731561        # error_log("ActiveRecord::find_all -> $sql"); 
    1374         if($this->is_error($rs = $this->query($sql))) { 
     1562        if($this->is_error($rs = $this->query($sql, true))) { 
    13751563            $this->raise($rs->getMessage()); 
    13761564        } 
    13771565 
    13781566        $objects = array(); 
    1379         while($row = $rs->fetchRow()) { 
    1380             $class_name = $this->get_class_name(); 
     1567        $class_name = $this->get_class_name(); 
     1568        while($row = $rs->fetchRow()) {     
    13811569            $object = new $class_name(); 
    13821570            $object->new_record = false; 
     
    13861574                if($field == $this->index_on) { 
    13871575                    $objects_key = $value; 
    1388                 }  
    1389             } 
    1390             if(is_null($objects_key)) { 
    1391                 $objects[] = $object; 
     1576                } 
     1577            } 
     1578            if(is_null($objects_key)) { 
     1579                $objects[] = $object; 
    13921580            } else { 
    1393                 $objects[$objects_key] = $object; 
     1581                $objects[$objects_key] = $object;    
    13941582            } 
    13951583            # If callback is defined in model run it. 
     
    17111899         
    17121900        if($this->is_error($result)) { 
    1713             $this->raise($results->getMessage()); 
     1901            $this->raise($result->getMessage()); 
    17141902        } else { 
    17151903            $habtm_result = true; 
     
    17621950        $result = $this->query($sql); 
    17631951        if($this->is_error($result)) { 
    1764             $this->raise($results->getMessage()); 
     1952            $this->raise($result->getMessage()); 
    17651953        } else { 
    17661954            $habtm_result = true; 
     
    19462134 
    19472135        if(is_null($conditions)) { 
    1948             $this->errors[] = "No conditions specified to delete on."; 
     2136            $this->add_error("No conditions specified to delete on."); 
    19492137            return false; 
    19502138        } 
    19512139 
    1952         $this->before_delete();  
    1953         if($result = $this->delete_all($conditions)) { 
    1954             foreach($deleted_ids as $id) { 
    1955                 if($this->auto_delete_habtm && $id != '') { 
    1956                     if(is_string($this->has_and_belongs_to_many)) { 
    1957                         $habtms = explode(",", $this->has_and_belongs_to_many); 
    1958                         foreach($habtms as $other_table_name) { 
    1959                             $this->delete_all_habtm_records(trim($other_table_name), $id);                              
    1960                         } 
    1961                     } elseif(is_array($this->has_and_belongs_to_many)) { 
    1962                         foreach($this->has_and_belongs_to_many as $other_table_name => $values) { 
    1963                             $this->delete_all_habtm_records($other_table_name, $id);                              
    1964                         } 
    1965                     }  
     2140        if($this->before_delete()) { 
     2141            if($result = $this->delete_all($conditions)) { 
     2142                foreach($deleted_ids as $id) { 
     2143                    if($this->auto_delete_habtm && $id != '') { 
     2144                        if(is_string($this->has_and_belongs_to_many)) { 
     2145                            $habtms = explode(",", $this->has_and_belongs_to_many); 
     2146                            foreach($habtms as $other_table_name) { 
     2147                                $this->delete_all_habtm_records(trim($other_table_name), $id);                              
     2148                            } 
     2149                        } elseif(is_array($this->has_and_belongs_to_many)) { 
     2150                            foreach($this->has_and_belongs_to_many as $other_table_name => $values) { 
     2151                                $this->delete_all_habtm_records($other_table_name, $id);                              
     2152                            } 
     2153                        }  
     2154                    } 
    19662155                } 
    1967             } 
    1968             $this->after_delete(); 
    1969         } 
    1970          
     2156                $this->after_delete(); 
     2157            }             
     2158        }         
    19712159        return $result; 
    19722160    } 
     
    19912179    function delete_all($conditions = null) { 
    19922180        if(is_null($conditions)) { 
    1993             $this->errors[] = "No conditions specified to delete on."; 
     2181            $this->add_error("No conditions specified to delete on."); 
    19942182            return false; 
    19952183        } 
     
    20462234            if($this->delete_habtm_records($this_foreign_value)) { 
    20472235                reset($this->habtm_attributes); 
     2236                if($this->habtm_sort_field) { 
     2237                    $sort_field = $this->habtm_sort_field; 
     2238                    $sort_value = 0; 
     2239                } 
    20482240                foreach($this->habtm_attributes as $other_table_name => $other_foreign_values) { 
    20492241                    $table_name = $this->get_join_table_name($this->table_name,$other_table_name); 
     
    20542246                        $attributes[$this_foreign_key] = $this_foreign_value; 
    20552247                        $attributes[$other_foreign_key] = $other_foreign_value; 
     2248                        if($sort_field) { 
     2249                            $attributes[$sort_field] = $sort_value; 
     2250                            $sort_value++; 
     2251                        } 
    20562252                        $attributes = $this->quoted_attributes($attributes); 
    20572253                        $fields = @implode(', ', array_keys($attributes)); 
    20582254                        $values = @implode(', ', array_values($attributes)); 
    20592255                        $sql = "INSERT INTO $table_name ($fields) VALUES ($values)"; 
    2060                         //echo "add_habtm_records: SQL: $sql<br>"; 
     2256                        error_log("add_habtm_records: SQL: $sql"); 
    20612257                        $result = $this->query($sql); 
    20622258                        if ($this->is_error($result)) { 
     
    21932389                } 
    21942390            } 
    2195      
     2391 
    21962392            //  If any date/time fields were found, assign the 
    21972393            //  accumulated values to corresponding attributes 
     2394            //  1i = Year, 2i = Month, 3i = Day, 4i = Hour, 5i = Minute 
    21982395            if(count($datetime_fields)) { 
    21992396                foreach($datetime_fields as $datetime_field) { 
    22002397                    $datetime_format = ''; 
    22012398                    $datetime_value = ''; 
     2399                    # Date Year / Month / Day 
    22022400                    if($attributes[$datetime_field."(1i)"] 
    22032401                        && $attributes[$datetime_field."(2i)"] 
     
    22072405                        . "-" . $attributes[$datetime_field."(3i)"]; 
    22082406                        $datetime_format = $this->date_format; 
    2209                     } 
     2407                    }  
     2408                    # for expiration dates Year & Month 
     2409                    elseif($attributes[$datetime_field."(1i)"] 
     2410                             && $attributes[$datetime_field."(2i)"]) { 
     2411                        $datetime_value = $attributes[$datetime_field."(1i)"] 
     2412                        . "-" . $attributes[$datetime_field."(2i)"];     
     2413                        $datetime_format = $this->date_format;                   
     2414                    } 
    22102415                    $datetime_value .= " "; 
     2416                    # Time Hour & Minutes 
    22112417                    if($attributes[$datetime_field."(4i)"] 
    22122418                        && $attributes[$datetime_field."(5i)"]) { 
     
    24052611    } 
    24062612 
     2613    function human_attribute_name($attribute) { 
     2614        return Inflector::humanize($attribute); 
     2615    } 
     2616 
    24072617    /** 
    24082618     *  Set {@link $table_name} from the class name of this object 
     
    24392649     *  @uses $db 
    24402650     *  @uses $content_columns 
    2441      *  @uses Inflector::humanize() 
     2651     *  @uses human_attribute_name() 
    24422652     *  @see __set() 
    24432653     *  @param string $table_name  Name of table to get information about 
     
    24582668                $i = 0; 
    24592669                foreach($this->content_columns as $column) { 
    2460                     $this->content_columns[$i++]['human_name'] = Inflector::humanize($column['name']); 
     2670                    $this->content_columns[$i++]['human_name'] = $this->human_attribute_name($column['name']); 
    24612671                }                 
    24622672                self::$table_info[$table_name] = $this->content_columns; 
     
    24962706     *   
    24972707     *  If there is a connection now open, as indicated by the saved 
    2498      *  value of a MDB2 object in $active_connections[$connection_name], and 
     2708     *  value of a MDB2 object in $connection_pool[$connection_name], and 
    24992709     *  {@link force_reconnect} is not true, then set the database 
    25002710     *  fetch mode and return. 
    25012711     * 
    25022712     *  If there is no connection, open one and save a reference to 
    2503      *  it in $active_connections[$connection_name]. 
     2713     *  it in $connection_pool[$connection_name]. 
    25042714     * 
    25052715     *  @uses $db 
    25062716     *  @uses $database_name 
    25072717     *  @uses $force_reconnect 
    2508      *  @uses $active_connections 
     2718     *  @uses $connection_pool 
    25092719     *  @uses is_error() 
    25102720     *  @throws {@link ActiveRecordError} 
    25112721     */ 
    2512     function establish_connection() { 
    2513         $this->set_connection_name(); 
    2514         $connection =& self::$active_connections[$this->connection_name]; 
     2722    function establish_connection($connection_name = null, $read_only = false) { 
     2723        $connection_name = $this->get_connection_name($connection_name); 
     2724        if($read_only) {  
     2725            $connection =& self::$connection_pool_read_only[$connection_name]; 
     2726        } else { 
     2727            $connection =& self::$connection_pool[$connection_name]; 
     2728        } 
    25152729        if(!is_object($connection) || $this->force_reconnect) { 
    25162730            $connection_settings = array(); 
    25172731            $connection_options = array(); 
    2518             if(array_key_exists($this->connection_name, self::$database_settings)) { 
     2732            if(array_key_exists($connection_name, self::$database_settings)) { 
    25192733                 # Use a different custom sections settings ? 
    2520                 if(array_key_exists("use", self::$database_settings[$this->connection_name])) { 
    2521                     $connection_settings = self::$database_settings[self::$database_settings[$this->connection_name]['use']]; 
     2734                if(array_key_exists("use", self::$database_settings[$connection_name])) { 
     2735                    $connection_settings = self::$database_settings[self::$database_settings[$connection_name]['use']]; 
    25222736                } else { 
    25232737                    # Custom defined db settings in database.ini  
    2524                     $connection_settings = self::$database_settings[$this->connection_name]; 
     2738                    $connection_settings = self::$database_settings[$connection_name]; 
    25252739                } 
    25262740            } else { 
    25272741                # Just use the current environment's db settings 
    2528                 # $this->connection_name's default value is 'development' so 
    2529                 # if should never really get here unless you override $this->connection_name 
     2742                # $connection_name's default value is 'development' so 
     2743                # it should never really get here unless you override $this->connection_name 
    25302744                # and you define a custom db section in database.ini and it can't find it. 
    2531                 $connection_settings = self::$database_settings[$this->connection_name]; 
     2745                $connection_settings = self::$database_settings[$connection_name]; 
    25322746            } 
    25332747            # Override database name if param is set 
     
    25412755            # Connect to the database and throw an error if the connect fails. 
    25422756            $connection =& MDB2::Connect($connection_settings, $connection_options); 
    2543             //static $connect_cnt;  $connect_cnt++; error_log("connection #".$connect_cnt); 
     2757            #static $connect_cnt;  $connect_cnt++; error_log("establish_connection($connection_name, $read_only) #".$connect_cnt); 
    25442758             
    25452759            # For Postgres schemas (http://www.postgresql.org/docs/8.0/interactive/ddl-schemas.html) 
     
    25532767        } 
    25542768        if(!$this->is_error($connection)) { 
    2555             self::$active_connections[$this->connection_name] =& $connection; 
    2556             self::$db =& $connection; 
    2557             self::$db->setFetchMode($this->fetch_mode); 
     2769            $connection->setFetchMode($this->fetch_mode); 
     2770            if($read_only) { 
     2771                self::$connection_pool_read_only[$connection_name] =& $connection; 
     2772                $this->read_only_connection_name = $connection_name; 
     2773            } else { 
     2774                self::$connection_pool[$connection_name] =& $connection; 
     2775                $this->connection_name = $connection_name; 
     2776            } 
    25582777        } else { 
    25592778            $this->raise($connection->getMessage()); 
    25602779        }       
    2561         return self::$db; 
     2780        return $connection; 
    25622781    } 
    25632782 
     
    25652784     *  Set the name of the database connection to use.  
    25662785     */     
    2567     function set_connection_name() { 
    2568         $connection_name = null; 
    2569         if(!is_null($this->connection_name)) { 
    2570             $connection_name = $this->connection_name;       
    2571         } else { 
    2572             $connection_name = self::$environment ? self::$environment : 'development'; 
    2573         }   
    2574         $this->connection_name = $connection_name; 
     2786    function get_connection_name($connection_name = null) { 
     2787        if(is_null($connection_name)) { 
     2788            if(!is_null($this->connection_name)) { 
     2789                $connection_name = $this->connection_name;       
     2790            } else { 
     2791                $connection_name = self::$environment ? self::$environment : 'development'; 
     2792            }  
     2793        } 
     2794        return $connection_name;  
     2795    } 
     2796    /** 
     2797     *  Gets the database connection whether its read only or read/write     
     2798     */     
     2799    function get_connection($read_only = false) { 
     2800        if($read_only && $this->read_only_connection_name &&  
     2801           array_key_exists($this->read_only_connection_name, self::$connection_pool_read_only)) { 
     2802            $db =& self::$connection_pool_read_only[$this->read_only_connection_name]; 
     2803            #error_log("get_connection($read_only) - using read only:".$this->read_only_connection_name); 
     2804        } elseif(array_key_exists($this->connection_name, self::$connection_pool)) { 
     2805            $db =& self::$connection_pool[$this->connection_name]; 
     2806            #error_log("get_connection($read_only) - using read/write from pool:".$this->connection_name); 
     2807        } else { 
     2808            $db =& self::$db; 
     2809            #error_log("get_connection($read_only) - using read/write default:".$this->connection_name); 
     2810        } 
     2811        return $db; 
    25752812    } 
    25762813 
     
    27032940                            # Mark the corresponding entry in the error array by 
    27042941                            # putting the error message in for the attribute, 
    2705                             #   e.g. $this->errors['name'] = "can't be empty" 
     2942                            #   e.g. $this->add_error("can't be empty", 'name'); 
    27062943                            #   when 'name' was an empty string. 
    2707                             $this->errors[$validate_on_attribute] = $result[1]; 
     2944                            $this->add_error($result[1], $validate_on_attribute); 
    27082945                        } 
    27092946                    } 
     
    27162953    /** 
    27172954     *  Overwrite this method for validation checks on all saves and 
    2718      *  use $this->errors[] = "My error message."; or 
    2719      *  for invalid attributes $this->errors['attribute'] = "Attribute is invalid."; 
     2955     *  use $this->add_error("My error message.", 'attribute'); 
    27202956     *  @todo Document this API 
    27212957     */ 
     
    28103046     *  @todo Document this API 
    28113047     */ 
    2812     function before_delete() {} 
     3048    function before_delete() { return true; } 
    28133049 
    28143050    /** 
     
    28453081            if(method_exists($this, $method_name) && is_array($validation_name)) { 
    28463082                foreach($validation_name as $attribute_name => $options) { 
    2847                     if(!is_array($options)) { 
     3083                    if(is_string($options)) { 
    28483084                        $attribute_name = $options; 
    28493085                        $options = array(); 
    2850                     }                
     3086                    } elseif(!is_array($options)) { 
     3087                        $options = array(); 
     3088                    }                
    28513089                    $attribute_name = trim($attribute_name);      
    28523090                    $parameters = array(); 
    2853                     $on = array_key_exists('on', $options) ?  
    2854                         $options['on'] : 'save'; 
    2855                     $message = array_key_exists('message', $options) ?  
    2856                         $options['message'] : null;                   
     3091                    $on = array_key_exists('on', $options) ? $options['on'] : 'save'; 
     3092                    $message = array_key_exists('message', $options) ? $options['message'] : null;    
    28573093                    switch($method_name) { 
    28583094                        case 'validates_acceptance_of': 
     
    29233159        foreach((array) $attribute_names as $attribute_name) {                   
    29243160            if($this->$attribute_name != $accept) { 
    2925                 $attribute_human = Inflector::humanize($attribute_name); 
    2926                 $this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3161                #$attribute_human = $this->human_attribute_name($attribute_name); 
     3162                #$this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3163                $this->add_error($message, $attribute_name);                 
    29273164            } 
    29283165        } 
     
    29413178            $attribute_confirmation = $attribute_name . '_confirmation'; 
    29423179            if($this->$attribute_confirmation != $this->$attribute_name) { 
    2943                 $attribute_human = Inflector::humanize($attribute_name); 
    2944                 $this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3180                #$attribute_human = $this->human_attribute_name($attribute_name); 
     3181                #$this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3182                $this->add_error($message, $attribute_name); 
    29453183            } 
    29463184        } 
     
    29613199                list($minimum, $maximum) = explode('..', $in); 
    29623200                if($this->$attribute_name >= $minimum && $this->$attribute_name <= $maximum) { 
    2963                     $attribute_human = Inflector::humanize($attribute_name); 
    2964                     $this->add_error("{$attribute_human} {$message}", $attribute_name);         
     3201                    #$attribute_human = $this->human_attribute_name($attribute_name); 
     3202                    #$this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3203                    $this->add_error($message, $attribute_name);        
    29653204                } 
    29663205            } elseif(is_array($in)) { 
    29673206                if(in_array($this->$attribute_name, $in)) { 
    2968                     $attribute_human = Inflector::humanize($attribute_name); 
    2969                     $this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3207                    #$attribute_human = $this->human_attribute_name($attribute_name); 
     3208                    #$this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3209                    $this->add_error($message, $attribute_name); 
    29703210                } 
    29713211            }    
     
    29873227            # Was there an error? 
    29883228            if(!preg_match($regex, $value)) { 
    2989                 $attribute_human = Inflector::humanize($attribute_name); 
    2990                 $this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3229                #$attribute_human = $this->human_attribute_name($attribute_name); 
     3230                #$this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3231                $this->add_error($message, $attribute_name); 
    29913232            } 
    29923233        } 
     
    30073248                list($minimum, $maximum) = explode('..', $in); 
    30083249                if(!($this->$attribute_name >= $minimum && $this->$attribute_name <= $maximum)) { 
    3009                     $attribute_human = Inflector::humanize($attribute_name); 
    3010                     $this->add_error("{$attribute_human} {$message}", $attribute_name);         
     3250                    #$attribute_human = $this->human_attribute_name($attribute_name); 
     3251                    #$this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3252                    $this->add_error($message, $attribute_name);       
    30113253                } 
    30123254            } elseif(is_array($in)) { 
    30133255                if(!in_array($this->$attribute_name, $in)) { 
    3014                     $attribute_human = Inflector::humanize($attribute_name); 
    3015                     $this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3256                    #$attribute_human = $this->human_attribute_name($attribute_name); 
     3257                    #$this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3258                    $this->add_error($message, $attribute_name); 
    30163259                } 
    30173260            }  
     
    30423285            # Attribute string length 
    30433286            $len = strlen($this->$attribute_name); 
    3044             $attribute_human = Inflector::humanize($attribute_name); 
     3287            #$attribute_human = $this->human_attribute_name($attribute_name); 
    30453288             
    30463289            # If you have set the min length option 
     
    30483291                $message = $this->get_error_message_for_validation($options['too_short'], 'too_short', $options['minimum']); 
    30493292                if($len < $options['minimum']) { 
    3050                     $this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3293                    #$this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3294                    $this->add_error($message, $attribute_name);                     
    30513295                } 
    30523296            } 
     
    30563300                $message = $this->get_error_message_for_validation($options['too_long'], 'too_long', $options['maximum']); 
    30573301                if($len > $options['maximum']) { 
    3058                     $this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3302                    #$this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3303                    $this->add_error($message, $attribute_name);                     
    30593304                } 
    30603305            } 
     
    30643309                $message = $this->get_error_message_for_validation($options['wrong_length'], 'wrong_length', $options['is']); 
    30653310                if($len != $options['is']) { 
    3066                     $this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3311                    #$this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3312                    $this->add_error($message, $attribute_name);                     
    30673313                } 
    30683314            } 
     
    30873333                $message = $this->get_error_message_for_validation($message, 'not_an_integer'); 
    30883334                if(!is_integer($value)) { 
    3089                     $attribute_human = Inflector::humanize($attribute_name); 
    3090                     $this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3335                    #$attribute_human = $this->human_attribute_name($attribute_name); 
     3336                    #$this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3337                    $this->add_error($message, $attribute_name); 
    30913338                } 
    30923339            } else { 
    30933340                $message = $this->get_error_message_for_validation($message, 'not_a_number'); 
    30943341                if(!is_numeric($value)) { 
    3095                     $attribute_human = Inflector::humanize($attribute_name); 
    3096                     $this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3342                    #$attribute_human = $this->human_attribute_name($attribute_name); 
     3343                    #$this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3344                    $this->add_error($message, $attribute_name); 
    30973345                } 
    30983346            } 
     
    31113359        foreach((array) $attribute_names as $attribute_name) {               
    31123360            if($this->$attribute_name === '' || is_null($this->$attribute_name)) { 
    3113                 $attribute_human = Inflector::humanize($attribute_name); 
    3114                 $this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3361                #$attribute_human = $this->human_attribute_name($attribute_name); 
     3362                #$this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3363                $this->add_error($message, $attribute_name); 
    31153364            } 
    31163365        } 
     
    31363385            }    
    31373386            if($this->find_first($conditions)) { 
    3138                 $attribute_human = Inflector::humanize($attribute_name); 
    3139                 $this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3387                #$attribute_human = $this->human_attribute_name($attribute_name); 
     3388                #$this->add_error("{$attribute_human} {$message}", $attribute_name); 
     3389                $this->add_error($message, $attribute_name);                 
    31403390            } 
    31413391        } 
     
    31843434        throw new ActiveRecordError($error_message, "ActiveRecord Error", "500"); 
    31853435    } 
     3436 
     3437    function errors_full_messages() { 
     3438        $full_messages = array(); 
     3439        foreach((array)$this->errors as $attribute => $message) { 
     3440            if(is_null($message)) { 
     3441                continue; 
     3442            } 
     3443            $full_messages[] = $this->human_attribute_name($attribute) . " " . $message; 
     3444        } 
     3445        return $full_messages; 
     3446    } 
     3447     
     3448    function errors_on($attribute) { 
     3449        $errors = isset($this->errors[$attribute]) ? $this->errors[$attribute] : null; 
     3450        return ((is_array($errors) && count($errors) == 1) ? current($errors) : $errors); 
     3451    }    
    31863452 
    31873453    /**