Show
Ignore:
Timestamp:
04/16/10 10:52:31 (22 months ago)
Author:
john
Message:

Added Partial Updates to ActiveRecord?

Files:
1 modified

Legend:

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

    r329 r333  
    9494     *  primary keys in the table are listed in {@link $primary_keys}, 
    9595     *  which is maintained independently.</p> 
    96      *  @var string[] 
     96     *  @var array 
    9797     *  @see $primary_keys 
    9898     *  @see quoted_attributes() 
    9999     *  @see __set() 
    100100     */ 
    101     public $content_columns = null; # info about each column in the table 
     101    public $content_columns = array(); # info about each column in the table 
     102 
     103    /** 
     104     *  Table columns key => values array 
     105     * 
     106     *  Array to hold all the column names and values.   
     107     *  @var array 
     108     *  @see __get() 
     109     *  @see __set() 
     110     */  
     111    private $attributes = array(); 
     112 
     113    /** 
     114     *  Array to hold all the changed columns and what changed. Indexed on column name. 
     115     * 
     116     *  <p>calling $user->changes => Array( 'first_name' => array('original' => 'John', 'modified' => 'Matt') )</p> 
     117     *  <p>calling $user->changed => Array( 'first_name' )</p> 
     118     *  <p>calling $user->first_name_change => array('original' => 'John', 'modified' => 'Matt')</p> 
     119     *  <p>calling $user->first_name_changed => true</p> 
     120     *  
     121     *  @var array 
     122     *  @see __get() 
     123     *  @see __set()     
     124     */  
     125    private $changed_attributes = array(); 
     126     
     127    /** 
     128     *  Whether or not to use partial updates meaning only  
     129     *  update fields that have changed in UPDATE sql calls 
     130     * 
     131     *  @var boolean 
     132     */  
     133    public $partial_updates = true; 
    102134 
    103135    /** 
     
    522554     *  @uses $table_name 
    523555     *  @uses set_table_name_using_class_name() 
     556     *  @uses reset_attributes() 
    524557     *  @uses update_attributes() 
    525558     */ 
     
    545578        } 
    546579 
     580        # initialize the internal attributes array to all nulls 
     581        $this->reset_attributes(); 
     582 
    547583        # If $attributes array is passed in update the class with its contents 
    548584        if(!is_null($attributes)) { 
     
    570606     *  @uses find_one_belongs_to() 
    571607     *  @uses find_one_has_one() 
    572      */ 
    573     function __get($key) { 
    574         if($association_type = $this->get_association_type($key)) { 
    575             //error_log("association_type:$association_type"); 
     608     */  
     609    function __get($key) {         
     610        if(array_key_exists($key, $this->attributes)) { 
     611            #error_log("getting: {$key} = ".$this->attributes[$key]); 
     612            return $this->attributes[$key]; 
     613        } elseif($association_type = $this->get_association_type($key)) { 
     614            error_log("get key:$key association_type:$association_type"); 
    576615            switch($association_type) { 
    577616                case "has_many": 
     
    601640                $this->$key = $composite_object;     
    602641            }                                 
    603         }  
     642        } elseif($key == "changes") { 
     643            return $this->changed_attributes; 
     644        } elseif($key == "changed") { 
     645            return array_keys($this->changed_attributes); 
     646        } elseif(substr($key, -7) == "_change") { 
     647            $changes = array(); 
     648            $attribute = substr($key, 0, -7); 
     649            if(array_key_exists($attribute, $this->changed_attributes)) { 
     650                $changes = $this->changed_attributes[$attribute]; 
     651            } 
     652            return $changes; 
     653        } elseif(substr($key, -8) == "_changed") { 
     654            $attribute = substr($key, 0, -8); 
     655            return array_key_exists($attribute, $this->changed_attributes) ? true : false; 
     656        }  
    604657        //echo "<pre>getting: $key = ".$this->$key."<br></pre>"; 
    605658        return $this->$key; 
     
    621674    function __set($key, $value) { 
    622675        //echo "setting: $key = $value<br>"; 
    623         if($key == "table_name") { 
     676        if(array_key_exists($key, (array)$this->content_columns)) { 
     677            if(array_key_exists($key, $this->attributes)) { 
     678                if(array_key_exists($key, $this->changed_attributes)) { 
     679                    if($this->changed_attributes[$key]['original'] != $value) { 
     680                        $this->changed_attributes[$key]['modified'] = $value; 
     681                    } else { 
     682                        unset($this->changed_attributes[$key]); 
     683                    }    
     684                } else { 
     685                    $this->changed_attributes[$key] = array( 
     686                        'original' => $this->attributes[$key],  
     687                        'modified' => $value 
     688                    ); 
     689                }                
     690            } 
     691            $this->attributes[$key] = $value; 
     692            return; 
     693        } elseif($key == "table_name") { 
    624694            $this->set_content_columns($value);            
    625695          # this elseif checks if first its an object if its parent is ActiveRecord 
     
    638708                $this->save_associations[$association_type][] = $value; 
    639709            } 
    640         }        
    641          
     710        }      
     711        #error_log("setting $key = $value"); 
    642712        //  Assignment to something else, do it 
    643713        $this->$key = $value; 
     
    11631233    */ 
    11641234    function column_for_attribute($attribute) { 
    1165         if(is_array($this->content_columns)) { 
    1166             foreach($this->content_columns as $column) { 
    1167                 if($column['name'] == $attribute) { 
    1168                     return $column; 
    1169                 } 
    1170             } 
    1171         } 
    1172         return null; 
     1235        return array_key_exists($attribute, (array)$this->content_columns) ?  
     1236            $this->content_columns[$attribute] : null; 
    11731237    } 
    11741238 
     
    11961260     */ 
    11971261    function column_attribute_exists($attribute) { 
    1198         if(is_array($this->content_columns)) { 
    1199             foreach($this->content_columns as $column) { 
    1200                 if($column['name'] == $attribute) { 
    1201                     return true; 
    1202                 } 
    1203             } 
    1204         }  
    1205         return false;      
    1206     } 
     1262        return array_key_exists($attribute, (array)$this->content_columns) ? true : false;     
     1263    } 
     1264 
     1265    /** 
     1266     *  Resets the changed_attributes array back to empty 
     1267     * 
     1268     *  @uses changed_attributes 
     1269     */ 
     1270    private function clear_changed_attributes() { 
     1271        $this->changed_attributes = array(); 
     1272    } 
    12071273 
    12081274    /** 
     
    16461712        while($row = $rs->fetchRow()) {     
    16471713            $object = new $class_name(); 
    1648             $object->new_record = false; 
     1714            $object->new_record = false;             
    16491715            $objects_key = null; 
    16501716            foreach($row as $field => $value) { 
     
    16541720                } 
    16551721            } 
     1722            $object->clear_changed_attributes(); 
    16561723            if(is_null($objects_key)) { 
    16571724                $objects[] = $object; 
     
    18051872                $this->$key = $value; 
    18061873            } 
     1874            $this->clear_changed_attributes(); 
    18071875            return true; 
    18081876        } 
     
    18941962        $this->update_attributes($attributes); 
    18951963        if($dont_validate || $this->valid()) { 
    1896             return $this->add_record_or_update_record(); 
    1897         } else { 
    1898             return false; 
    1899         } 
     1964            if($this->add_record_or_update_record()) { 
     1965                $this->clear_changed_attributes(); 
     1966                return true; 
     1967            } 
     1968        }  
     1969        return false; 
    19001970    } 
    19011971 
     
    19602030    private function add_record() {  
    19612031        $db =& $this->get_connection(); 
    1962         $db->loadModule('Extended', null, true);                 
     2032        $db->loadModule('Extended', null, true);    
     2033        $primary_key = $this->primary_keys[0];              
    19632034        # $primary_key_value may either be a quoted integer or php null 
    1964         $primary_key_value = $db->getBeforeID("{$this->table_prefix}{$this->table_name}", $this->primary_keys[0]); 
     2035        $primary_key_value = $db->getBeforeID("{$this->table_prefix}{$this->table_name}", $primary_key); 
    19652036        if($this->is_error($primary_key_value)) { 
    19662037            $this->raise($primary_key_value->getMessage()); 
     
    19722043        $sql = "INSERT INTO {$this->table_prefix}{$this->table_name} ({$fields}) VALUES ({$values})"; 
    19732044        //echo "add_record: SQL: $sql<br>"; 
    1974         //error_log("add_record: SQL: $sql"); 
     2045        #error_log("add_record: SQL: $sql"); 
    19752046        $result = $this->query($sql);   
    19762047        $habtm_result = true; 
    1977         $primary_key = $this->primary_keys[0]; 
     2048         
    19782049        # $primary_key_value is now equivalent to the value in the id field that was inserted 
    1979         $primary_key_value = $db->getAfterID($primary_key_value, "{$this->table_prefix}{$this->table_name}", $this->primary_keys[0]); 
     2050        $primary_key_value = $db->getAfterID($primary_key_value, "{$this->table_prefix}{$this->table_name}", $primary_key); 
    19802051        if($this->is_error($primary_key_value)) { 
    19812052            $this->raise($primary_key_value->getMessage()); 
     
    20152086    private function update_record() { 
    20162087        //error_log('update_record()'); 
     2088        if($this->partial_updates && !$this->changed) { 
     2089            #error_log("update_record: nothing has changed skipping update call to database. returning true"); 
     2090            return true; 
     2091        } 
    20172092        $this->update_composite_attributes(); 
    20182093        $updates = $this->get_updates_sql(); 
     
    20202095        $sql = "UPDATE {$this->table_prefix}{$this->table_name} SET {$updates} WHERE {$conditions}"; 
    20212096        //echo "update_record:$sql<br>"; 
    2022         //error_log("update_record: SQL: $sql"); 
    2023         $result = $this->query($sql); 
    2024         $habtm_result = true; 
    2025         $primary_key = $this->primary_keys[0]; 
    2026         $primary_key_value = $this->$primary_key; 
    2027         if($primary_key_value > 0) {  
    2028             if($this->auto_save_habtm) { 
    2029                 $habtm_result = $this->update_habtm_records($primary_key_value); 
    2030             } 
    2031             $this->save_associations(); 
    2032         }          
     2097        #error_log("update_record: SQL: $sql"); 
     2098        if($updates && $conditions) {  
     2099            $result = $this->query($sql); 
     2100            $habtm_result = true; 
     2101            $primary_key = $this->primary_keys[0]; 
     2102            $primary_key_value = $this->$primary_key; 
     2103            if($primary_key_value > 0) {  
     2104                if($this->auto_save_habtm) { 
     2105                    $habtm_result = $this->update_habtm_records($primary_key_value); 
     2106                } 
     2107                $this->save_associations(); 
     2108            }          
     2109        } 
    20332110        return ($result && $habtm_result); 
    20342111    } 
     
    21592236     */ 
    21602237    private function save_association($object, $type) { 
    2161         if(is_object($object) && get_parent_class($object) == __CLASS__ && $type) { 
    2162             //echo get_class($object)." - type:$type<br>"; 
    2163             switch($type) { 
    2164                 case "has_many": 
    2165                 case "has_one": 
    2166                     $primary_key = $this->primary_keys[0]; 
    2167                     $foreign_key = Inflector::singularize($this->table_name)."_".$primary_key; 
    2168                     $object->$foreign_key = $this->$primary_key;  
    2169                     //echo "fk:$foreign_key = ".$this->$primary_key."<br>"; 
    2170                     break; 
    2171             } 
    2172             $object->save();         
     2238        if(is_object($object) && get_parent_class($object) == __CLASS__ && $type) {      
     2239            if($object->changed) { 
     2240                //echo get_class($object)." - type:$type<br>"; 
     2241                switch($type) { 
     2242                    case "has_many": 
     2243                    case "has_one": 
     2244                        $primary_key = $this->primary_keys[0]; 
     2245                        $foreign_key = Inflector::singularize($this->table_name)."_".$primary_key; 
     2246                        $object->$foreign_key = $this->$primary_key;  
     2247                        //echo "fk:$foreign_key = ".$this->$primary_key."<br>"; 
     2248                        break; 
     2249                } 
     2250                $object->save();    
     2251            }      
    21732252        }             
    21742253    } 
     
    23852464     */ 
    23862465    private function check_datetime($field, $value) { 
    2387         if($this->auto_timestamps) { 
    2388             if(is_array($this->content_columns)) { 
    2389                 foreach($this->content_columns as $field_info) { 
    2390                     if(($field_info['name'] == $field) && stristr($field_info['type'], "date")) { 
    2391                         $format = ($field_info['type'] == "date") ? $this->date_format : "{$this->date_format} {$this->time_format}"; 
    2392                         if($this->new_record) { 
    2393                             if(in_array($field, $this->auto_create_timestamps)) { 
    2394                                 return date($format); 
    2395                             } elseif($this->preserve_null_dates && is_null($value) && !stristr($field_info['flags'], "not_null")) { 
    2396                                 return null;     
    2397                             } 
    2398                         } elseif(!$this->new_record) { 
    2399                             if(in_array($field, $this->auto_update_timestamps)) { 
    2400                                 return date($format); 
    2401                             } elseif($this->preserve_null_dates && is_null($value) && !stristr($field_info['flags'], "not_null")) { 
    2402                                 return null;     
    2403                             } 
     2466        if($this->auto_timestamps) {     
     2467            if(array_key_exists($field, (array)$this->content_columns)) { 
     2468                if(stristr($this->content_columns[$field]['type'], "date")) { 
     2469                    $format = ($this->content_columns[$field]['type'] == "date") ? $this->date_format : "{$this->date_format} {$this->time_format}"; 
     2470                    if($this->new_record) { 
     2471                        if(in_array($field, $this->auto_create_timestamps) || in_array($field, $this->auto_update_timestamps)) { 
     2472                            $date = date($format); 
     2473                            $this->$field = $date; 
     2474                            return $date; 
     2475                        } elseif($this->preserve_null_dates && is_null($value) && !stristr($this->content_columns[$field]['flags'], "not_null")) { 
     2476                            return null;     
    24042477                        } 
    2405                     }   
    2406                 } 
    2407             } 
     2478                    } elseif(!$this->new_record) { 
     2479                        if(in_array($field, $this->auto_update_timestamps)) { 
     2480                            return date($format); 
     2481                        } elseif($this->preserve_null_dates && is_null($value) && !stristr($this->content_columns[$field]['flags'], "not_null")) { 
     2482                            return null;     
     2483                        } 
     2484                    } 
     2485                }                
     2486            } 
    24082487        } 
    24092488        return $value; 
     
    24782557                             && $attributes[$datetime_field."(2i)"]) { 
    24792558                        $datetime_value = $attributes[$datetime_field."(1i)"] 
    2480                         . "-" . $attributes[$datetime_field."(2i)"];     
     2559                        . "-" . $attributes[$datetime_field."(2i)"]."-01" 
    24812560                        $datetime_format = $this->date_format;                   
    24822561                    } 
     
    25352614        $attributes = array(); 
    25362615        if(is_array($this->content_columns)) { 
    2537             foreach($this->content_columns as $column) { 
     2616            foreach(array_keys($this->content_columns) as $column_name) { 
    25382617                //echo "attribute: $info[name] -> {$this->$info[name]}<br>"; 
    2539                 $attributes[$column['name']] = $this->$column['name']; 
     2618                $attributes[$column_name] = $this->$column_name; 
    25402619            } 
    25412620        } 
     
    26022681 
    26032682    /** 
    2604      *  Return column values for SQL insert statement 
    2605      * 
    2606      *  Return an array containing the column names and values of this 
    2607      *  object, filtering out the primary keys, which are not set. 
    2608      * 
    2609      *  @uses $primary_keys 
    2610      *  @uses quoted_attributes() 
    2611      */ 
    2612     function get_inserts() { 
    2613         $attributes = $this->quoted_attributes(); 
    2614         $inserts = array(); 
    2615         foreach($attributes as $key => $value) { 
    2616             if(!in_array($key, $this->primary_keys) || ($value != "''" && isset($value))) { 
    2617                 $inserts[$key] = $value; 
    2618             } 
    2619         } 
    2620         return $inserts; 
    2621     } 
    2622  
    2623     /** 
    26242683     *  Return argument for a "WHERE" clause specifying this row 
    26252684     * 
     
    26542713 
    26552714    /** 
     2715     *  Return column values for SQL insert statement 
     2716     * 
     2717     *  Return an array containing the column names and values of this 
     2718     *  object, filtering out the primary keys, which are not set. 
     2719     * 
     2720     *  @uses $primary_keys 
     2721     *  @uses quoted_attributes() 
     2722     */ 
     2723    function get_inserts() { 
     2724        $attributes = $this->quoted_attributes(); 
     2725        $inserts = array(); 
     2726        foreach($attributes as $key => $value) { 
     2727            if(!in_array($key, $this->primary_keys) || ($value != "''" && isset($value))) { 
     2728                $inserts[$key] = $value; 
     2729            } 
     2730        } 
     2731        return $inserts; 
     2732    } 
     2733 
     2734    /** 
    26562735     *  Return column values of object formatted for SQL update statement 
    26572736     * 
     
    26652744    function get_updates_sql() { 
    26662745        $updates = null; 
    2667         $attributes = $this->quoted_attributes(); 
     2746        $attributes = null; 
     2747        if($this->partial_updates && $this->changed) { 
     2748            foreach($this->changed_attributes as $key => $changes) { 
     2749                $attributes[$key] = $changes['modified']; 
     2750            } 
     2751            #error_log("modified attributes:".print_r($attributes, true)); 
     2752            # make sure the auto timestamps are in there  
     2753            foreach($this->content_columns as $column_name => $column) { 
     2754                if(stristr($column['type'], "date") && in_array($column_name, $this->auto_update_timestamps) && !array_key_exists($column_name, $attributes)) { 
     2755                    $attributes[$column_name] = $this->$column_name; 
     2756                } 
     2757            } 
     2758            #error_log("modified attributes with dates:".print_r($attributes, true));                         
     2759        } 
     2760        $attributes = $this->quoted_attributes($attributes); 
    26682761        if(count($attributes) > 0) { 
    26692762            $updates = array(); 
     
    27262819        } 
    27272820        if(isset(self::$table_info[$table_name])) { 
    2728             $this->content_columns = self::$table_info[$table_name];   
     2821            $this->content_columns = self::$table_info[$table_name]; 
     2822            #error_log("using cached content_columns"); 
    27292823        } else {        
    27302824            $db =& $this->get_connection(true);                                       
    27312825            $db->loadModule('Reverse', null, true); 
    2732             $this->content_columns = $db->reverse->tableInfo($table_name); 
    2733             if($this->is_error($this->content_columns)) { 
    2734                 $this->raise($this->content_columns->getMessage());         
    2735             } 
    2736             if(is_array($this->content_columns)) { 
    2737                 $i = 0; 
    2738                 foreach($this->content_columns as $column) { 
    2739                     $this->content_columns[$i++]['human_name'] = $this->human_attribute_name($column['name']); 
    2740                 }                 
     2826            $content_columns = $db->reverse->tableInfo($table_name); 
     2827            if($this->is_error($content_columns)) { 
     2828                $this->raise($content_columns->getMessage());         
     2829            } 
     2830            if(is_array($content_columns)) { 
     2831                $this->content_columns = array(); 
     2832                foreach($content_columns as $column) { 
     2833                    $column['human_name'] = $this->human_attribute_name($column['name']); 
     2834                    $this->content_columns[$column['name']] = $column; 
     2835                }         
    27412836                self::$table_info[$table_name] = $this->content_columns; 
    27422837            } 
    27432838        } 
    27442839    } 
     2840 
     2841    /** 
     2842     *  Resets the attributes array to keys of the columns from the database 
     2843     *  and sets all the values to null 
     2844     * 
     2845     *  @uses $content_columns 
     2846     *  @uses $attributes 
     2847     */ 
     2848    function reset_attributes() { 
     2849        if(is_array($this->content_columns)) { 
     2850            $this->attributes = array(); 
     2851            #error_log("resetting attributes to null"); 
     2852            foreach($this->content_columns as $column_name => $column) { 
     2853                $this->attributes[$column_name] = null; 
     2854            } 
     2855        }        
     2856    } 
    27452857 
    27462858    /**