RelationsActiveRecord.php
Current file: /home/magister/git/yii-example/example/protected/components/RelationsActiveRecord.php
Legend: executed not executed dead code

  Coverage
  Classes Functions / Methods Lines
Total
0.00% 0 / 1
64.71% 11 / 17 CRAP
86.10% 254 / 295
RelationsActiveRecord
0.00% 0 / 1
64.71% 11 / 17 123.78
86.10% 254 / 295
 many_many_map ()
0.00% 0 / 1 2
0.00% 0 / 1
 idPresent ($check_for_id)
100.00% 1 / 1 3
100.00% 10 / 10
 refresh ()
100.00% 1 / 1 1
100.00% 2 / 2
 expandCallables($array)
100.00% 1 / 1 4
100.00% 7 / 7
 magicRelationEligibleForDelete ($relation_name, $relation_object)
100.00% 1 / 1 2
100.00% 7 / 7
 magicRelationUpdated ($relation_name, $relation_object)
0.00% 0 / 1 4.03
88.24% 15 / 17
 setPost_Attributes($POST)
0.00% 0 / 1 32
95.79% 91 / 95
 anonymous function ()
100.00% 1 / 1 1
100.00% 1 / 1
 magicRelationManyManySelectedRead ($relation_name)
0.00% 0 / 1 12.76
18.18% 2 / 11
 magicRelationManyManySelectedWrite ($relation_name, $selected_list)
100.00% 1 / 1 1
100.00% 2 / 2
 getAllErrors ()
0.00% 0 / 1 110
0.00% 0 / 21
 beforeValidate()
0.00% 0 / 1 10.46
83.33% 20 / 24
 beforeSave ()
100.00% 1 / 1 3
100.00% 7 / 7
 afterSave ()
100.00% 1 / 1 12
100.00% 40 / 40
 cascade ($cascade_setting)
100.00% 1 / 1 1
100.00% 2 / 2
 beforeDelete ()
100.00% 1 / 1 8
100.00% 27 / 27
 afterDelete ()
100.00% 1 / 1 1
100.00% 1 / 1


       1                 : <?php                                                                                                                                 
       2                 :                                                                                                                                       
       3                 : /**                                                                                                                                   
       4                 :  * The BasicRelationsModel class implements some helper methods that will be                                                          
       5                 :  * needed by several of the children classes.                                                                                         
       6                 :  */                                                                                                                                   
       7                 : class RelationsActiveRecord extends CActiveRecord {                                                                                   
       8                 :     // Used to cache the computed values of the magic attributes.                                                                     
       9                 :     protected $_magic_attributes=array();                                                                                             
      10                 :                                                                                                                                       
      11                 :     // A list of AR's that are eligible for deletion. Updated with the                                                                
      12                 :     // magicRelation*Write methods. It is used when calling save() to delete                                                          
      13                 :     // unused related AR records.                                                                                                     
      14                 :     protected $_eligible_for_delete=array();                                                                                          
      15                 :                                                                                                                                       
      16                 :     // Track a list of relations that were updated with the                                                                           
      17                 :     // magicRelation*Write methods. Used to cascade the save() operations only                                                        
      18                 :     // to objects that have actually changed.                                                                                         
      19                 :     protected $_relation_updated=array();                                                                                             
      20                 :                                                                                                                                       
      21                 :     // Issued in the afterSave() behavior. Must contain arrays with the following format:                                             
      22                 :     // array (                                                                                                                        
      23                 :     //   'table' => string,                                                                                                           
      24                 :     //   'conditions' => mixed,                                                                                                       
      25                 :     //   'params' => array (),                                                                                                        
      26                 :     // ),                                                                                                                             
      27                 :     // table - The table that new rows will be inserted into.                                                                         
      28                 :     // conditions - the conditions that will be put in the WHERE part.                                                                
      29                 :     // params - the parameters to be bound to the query.                                                                              
      30                 :     protected $_delete_commands=array ();                                                                                             
      31                 :                                                                                                                                       
      32                 :     // Issued in the afterSave() behavior. Must contain arrays with the following format:                                             
      33                 :     // array (                                                                                                                        
      34                 :     //   'table' => string,                                                                                                           
      35                 :     //   'columns' => array (),                                                                                                       
      36                 :     // ),                                                                                                                             
      37                 :     // table - The table that new rows will be inserted into.                                                                         
      38                 :     // columns - The column data (name=>value) to be inserted into the table.                                                         
      39                 :     protected $_insert_commands=array ();                                                                                             
      40                 :                                                                                                                                       
      41                 :     // Emulate cascade on delete if the DB does not support it.                                                                       
      42                 :     protected $cascade_on_delete=false;                                                                                               
      43                 :                                                                                                                                       
      44                 :     /**                                                                                                                               
      45                 :      * Used for mapping the many to many relations with a pivot class and/or a                                                        
      46                 :      * attribute. The class will be used to merge the changes instead of just                                                         
      47                 :      * deleting all existing entries and recreating them. The attribute will                                                          
      48                 :      * be used for the magic attribute post_attributes to map the array of                                                            
      49                 :      * ID's from a form so in order to use the post_attributes the 'attribute'                                                        
      50                 :      * must be specified. If you do not want to use the merging the class name                                                        
      51                 :      * can be left out.                                                                                                               
      52                 :      *                                                                                                                                 
      53                 :      * Entries in this array must be in the following format:                                                                         
      54                 :      * '<relation name>' => array (                                                                                                   
      55                 :      *   'class' => '<pivot class name>',                                                                                             
      56                 :      *   'attribute' => '<attribute name>'                                                                                            
      57                 :      * ),                                                                                                                             
      58                 :      */                                                                                                                               
      59                 :     public function many_many_map () {                                                                                                
      60               0 :         return array();                                                                                                               
      61                 :     }                                                                                                                                 
      62                 :                                                                                                                                       
      63                 :     /**                                                                                                                               
      64                 :      * Runs a SQL statement to determine if the AR id specified exists in the                                                         
      65                 :      * table for this class. Lighter than findByPk cause a new object is not                                                          
      66                 :      * instantiated.                                                                                                                  
      67                 :      * TODO: Implement support for composite primary keys.                                                                            
      68                 :      */                                                                                                                               
      69                 :     public function idPresent ($check_for_id) {                                                                                       
      70               4 :         if (empty ($check_for_id))                                                                                                    
      71               4 :             return false;                                                                                                             
      72               4 :         $primary_key=$this->tableSchema->primaryKey;                                                                                  
      73               4 :         if (Yii::app()->db->createCommand()                                                                                           
      74               4 :             ->select($primary_key)                                                                                                    
      75               4 :             ->from($this->tableName())                                                                                                
      76               4 :             ->where($primary_key.'=:id', array (':id'=>$check_for_id))                                                                
      77               4 :             ->queryRow() )                                                                                                            
      78               4 :             return true;                                                                                                              
      79               1 :         return false;                                                                                                                 
      80                 :     }                                                                                                                                 
      81                 :                                                                                                                                       
      82                 :     /**                                                                                                                               
      83                 :      * Overload the refresh() method so the magic attributes cache can be                                                             
      84                 :      * cleared.                                                                                                                       
      85                 :      */                                                                                                                               
      86                 :     public function refresh () {                                                                                                      
      87               2 :         $this->_magic_attributes=array();                                                                                             
      88               2 :         return parent::refresh();                                                                                                     
      89                 :     }                                                                                                                                 
      90                 :                                                                                                                                       
      91                 :     public function expandCallables($array) {                                                                                         
      92               2 :         foreach ($array as $key => $entry) {                                                                                          
      93               2 :             if (is_callable ($entry))                                                                                                 
      94               2 :                 $array[$key]=call_user_func ($entry);                                                                                 
      95               2 :             if (is_array ($entry))                                                                                                    
      96               2 :                 $array[$key]=$this->expandCallables ($entry);                                                                         
      97               2 :         }                                                                                                                             
      98               2 :         return $array;                                                                                                                
      99                 :     }                                                                                                                                 
     100                 :                                                                                                                                       
     101                 :     /************************************************************************/                                                        
     102                 :                                                                                                                                       
     103                 :     /**                                                                                                                               
     104                 :      * Marks a object a eligible for delete. Checks to see if the object is                                                           
     105                 :      * already in the list of objects to be updated and removes it.                                                                   
     106                 :      */                                                                                                                               
     107                 :     public function magicRelationEligibleForDelete ($relation_name, $relation_object) {                                               
     108               1 :         $relations=$this->relations();                                                                                                
     109               1 :         $relation_primary_key=$relation_object->tableSchema->primaryKey;                                                              
     110                 :         // TODO: add support for composite primary keys.                                                                              
     111               1 :         $pk=$relation_object->$relation_primary_key;                                                                                  
     112               1 :         if (isset ($this->_relation_updated[$relation_name][$pk]))                                                                    
     113               1 :             unset ($this->_relation_updated[$relation_name][$pk]);                                                                    
     114               1 :         $this->_eligible_for_delete[]=$relation_object;                                                                               
     115               1 :     }                                                                                                                                 
     116                 :                                                                                                                                       
     117                 :     /**                                                                                                                               
     118                 :      * Mark a object as changed, and trigger a save() when the main object is                                                         
     119                 :      * saved(). (Cascade Save). If the object's attributes are empty it marks                                                         
     120                 :      * it as eligible for delete.                                                                                                     
     121                 :      */                                                                                                                               
     122                 :     public function magicRelationUpdated ($relation_name, $relation_object) {                                                         
     123                 :         // first check to see if the object's attributes are empty.                                                                   
     124               2 :         $relations=$this->relations();                                                                                                
     125               2 :         $relation_settings=$relations[$relation_name];                                                                                
     126               2 :         $relation_primary_key=$relation_object->tableSchema->primaryKey;                                                              
     127               2 :         $attributes=$relation_object->attributes;                                                                                     
     128                 :         // TODO: add support for composite primary keys.                                                                              
     129               2 :         unset ($attributes[$relation_primary_key]);                                                                                   
     130                 :         // TODO: add support for composite foreign keys.                                                                              
     131               2 :         unset ($attributes[$relation_settings[2]]);                                                                                   
     132               2 :         if (empty ($attributes)) {                                                                                                    
     133                 :             // eligible for delete.                                                                                                   
     134               0 :             $this->magicRelationEligibleForDelete ($relation_name, $relation_object);                                                 
     135               0 :             return;                                                                                                                   
     136                 :         }                                                                                                                             
     137                 :         // tag for update.                                                                                                            
     138               2 :         if (!isset ($this->_relation_updated[$relation_name]))                                                                        
     139               2 :             $this->_relation_updated[$relation_name]=array ('new' => array());                                                        
     140               2 :         if ($relation_object->isNewRecord) {                                                                                          
     141               2 :             $this->_relation_updated[$relation_name]['new'][]=$relation_object;                                                       
     142               2 :         } else {                                                                                                                      
     143               1 :             $pk=$relation_object->$relation_primary_key;                                                                              
     144               1 :             $this->_relation_updated[$relation_name][$pk]=$relation_object;                                                           
     145                 :         }                                                                                                                             
     146               2 :     }                                                                                                                                 
     147                 :                                                                                                                                       
     148                 :     /**                                                                                                                               
     149                 :      * A magic setter used for processing the $_POST variable for this class                                                          
     150                 :      * and all the related classes.                                                                                                   
     151                 :      */                                                                                                                               
     152                 :     public function setPost_Attributes($POST) {                                                                                       
     153               2 :         if (!isset ($POST[get_class ($this)]))                                                                                        
     154               2 :             return;                                                                                                                   
     155               2 :         $this->attributes=$POST[get_class ($this)];                                                                                   
     156               2 :         foreach ($this->relations() as $relation_name => $relation_settings) {                                                        
     157               2 :             $relation_type=$relation_settings[0];                                                                                     
     158               2 :             $relation_class=$relation_settings[1];                                                                                    
     159               2 :             $relation_fk=$relation_settings[2];                                                                                       
     160                 :             switch ($relation_type) {                                                                                                 
     161                 :                                                                                                                                       
     162               2 :                 case 'CHasOneRelation':                                                                                               
     163               2 :                     if ($this->isNewRecord || empty ($this->$relation_name)) {                                                        
     164               1 :                         if (!isset ($POST[$relation_class]))                                                                          
     165               1 :                             continue;                                                                                                 
     166                 :                         // Has One is new or not attached.                                                                            
     167               1 :                         $this->$relation_name=new $relation_class;                                                                    
     168               2 :                     } elseif (!isset ($POST[$relation_class])) {                                                                      
     169               0 :                         $this->$relation_name->unsetAttributes();                                                                     
     170               0 :                         $this->magicRelationUpdated ($relation_name, $this->$relation_name);                                          
     171               0 :                         $this->$relation_name=null;                                                                                   
     172               0 :                         continue;                                                                                                     
     173                 :                     }                                                                                                                 
     174               2 :                     $this->$relation_name->attributes=$POST[$relation_class];                                                         
     175               2 :                     $this->magicRelationUpdated ($relation_name, $this->$relation_name);                                              
     176               2 :                     break;                                                                                                            
     177                 :                                                                                                                                       
     178               2 :                 case 'CHasManyRelation':                                                                                              
     179               2 :                     if ($this->isNewRecord || empty ($this->$relation_name)) {                                                        
     180               1 :                         if (!isset ($POST[$relation_class]))                                                                          
     181               1 :                             continue;                                                                                                 
     182                 :                         // Has Many is new or none are attached.                                                                      
     183               1 :                         $model_list=array ();                                                                                         
     184               1 :                         foreach ($POST[$relation_class] as $post_attributes) {                                                        
     185               1 :                             $model=new $relation_class;                                                                               
     186               1 :                             $model->attributes=$post_attributes;                                                                      
     187               1 :                             $this->magicRelationUpdated ($relation_name, $model);                                                     
     188               1 :                             $model_list[]=$model;                                                                                     
     189               1 :                         }                                                                                                             
     190               1 :                         $this->$relation_name=$model_list;                                                                            
     191               1 :                     } else {                                                                                                          
     192               1 :                         $model_list=array ();                                                                                         
     193               1 :                         $delete_models=$this->$relation_name;                                                                         
     194                 :                         // Has Many is present and needs to be merged with the incomming data.                                        
     195               1 :                         $relation_pk=$relation_class::model()->tableSchema->primaryKey;                                               
     196               1 :                         if (!empty ($POST[$relation_class])) {                                                                        
     197               1 :                             $post_attribute_list=$POST[$relation_class];                                                              
     198               1 :                             foreach ($delete_models as $delete_models_key => $model) {                                                
     199               1 :                                 foreach ($post_attribute_list as $post_attributes_key => $post_attributes) {                          
     200                 :                                     // Check to see if any of the incoming entries match the PK of the current entry.                 
     201               1 :                                     if (isset ($post_attributes[$relation_pk]) &&                                                     
     202               1 :                                         $post_attributes[$relation_pk] === $model->$relation_pk) {                                    
     203                 :                                         // Match found.                                                                               
     204               1 :                                         $model->attributes=$post_attributes;                                                          
     205               1 :                                         $this->magicRelationUpdated ($relation_name, $model);                                         
     206               1 :                                         $model_list[]=$model;                                                                         
     207                 :                                         // Pop the model off the delete list and off the incoming entries                             
     208               1 :                                         unset ($delete_models[$delete_models_key]);                                                   
     209               1 :                                         unset ($post_attribute_list[$post_attributes_key]);                                           
     210               1 :                                         continue 2;                                                                                   
     211                 :                                     }                                                                                                 
     212               1 :                                 }                                                                                                     
     213               1 :                             }                                                                                                         
     214                 :                             // Matching complete.                                                                                     
     215                 :                             // Create remaining new models.                                                                           
     216               1 :                             if (!empty ($post_attribute_list)) {                                                                      
     217               1 :                                 foreach ($post_attribute_list as $post_attributes) {                                                  
     218               1 :                                     $model=new $relation_class;                                                                       
     219               1 :                                     $model->attributes=$post_attributes;                                                              
     220               1 :                                     $this->magicRelationUpdated ($relation_name, $model);                                             
     221               1 :                                     $model_list[]=$model;                                                                             
     222               1 :                                 }                                                                                                     
     223               1 :                             }                                                                                                         
     224               1 :                             $this->$relation_name=$model_list;                                                                        
     225                 : // This behavior may not be desirable                                                                                                 
     226                 : //                        } else {                                                                                                    
     227                 : //                            $delete_models=$this->$relation_name;                                                                   
     228                 : //                            $this->$relation_name=array ();                                                                         
     229               1 :                         }                                                                                                             
     230                 :                         // Delete left over models.                                                                                   
     231               1 :                         if (!empty ($delete_models)) {                                                                                
     232               1 :                             foreach ($delete_models as $model) {                                                                      
     233               1 :                                 $this->magicRelationEligibleForDelete ($relation_name, $model);                                       
     234               1 :                             }                                                                                                         
     235               1 :                         }                                                                                                             
     236                 :                     }                                                                                                                 
     237               2 :                     break;                                                                                                            
     238                 :                                                                                                                                       
     239               2 :                 case 'CManyManyRelation':                                                                                             
     240               2 :                     $many_many_map=$this->many_many_map();                                                                            
     241                 :                     // If the mapping is not setup correctly ignore this relation                                                     
     242                 :                     // because there is no way to identify the incoming data.                                                         
     243               2 :                     if (empty ($many_many_map[$relation_name]) ||                                                                     
     244               2 :                         empty ($many_many_map[$relation_name]['attribute']))                                                          
     245               2 :                         continue;                                                                                                     
     246               2 :                     $delete_ids=array ();                                                                                             
     247               2 :                     $insert_ids=array ();                                                                                             
     248               2 :                     $relation_pk=$relation_class::model()->tableSchema->primaryKey;                                                   
     249               2 :                     $list_attribute=$many_many_map[$relation_name]['attribute'];                                                      
     250                 :                     // Retrieve the new list of ID's                                                                                  
     251               2 :                     $selection=$this->$list_attribute;                                                                                
     252                 :                     // Determine the current attached ID's                                                                            
     253               2 :                     if (!empty ($this->$relation_name)) {                                                                             
     254               1 :                         foreach ($this->$relation_name as $related_model) {                                                           
     255               1 :                             if (in_array ($related_model->$relation_pk, $selection))                                                  
     256               1 :                                 unset ($selection[array_search ($related_model->$relation_pk, $selection)]);                          
     257                 :                             else                                                                                                      
     258               1 :                                 $delete_ids[]=$related_model->$relation_pk;                                                           
     259               1 :                         }                                                                                                             
     260               1 :                         $insert_ids=$selection;                                                                                       
     261               1 :                     } else {                                                                                                          
     262               1 :                         $insert_ids=$selection;                                                                                       
     263                 :                     }                                                                                                                 
     264               2 :                     $pivot_table=$this->metaData->relations[$relation_name]->getJunctionTableName();                                  
     265               2 :                     $foreign_keys=$this->metaData->relations[$relation_name]->getJunctionForeignKeys();                               
     266               2 :                     $relation_key_column=array_shift ($foreign_keys);                                                                 
     267               2 :                     $remote_key_column=array_shift ($foreign_keys);                                                                   
     268               2 :                     $primary_key=$this->tableSchema->primaryKey;                                                                      
     269                 :                     // Build insert commands                                                                                          
     270               2 :                     if (!empty ($insert_ids)) {                                                                                       
     271               2 :                         $this_var=$this;                                                                                              
     272               2 :                         foreach ($insert_ids as $id) {                                                                                
     273               2 :                             $this->_insert_commands[]=array (                                                                         
     274               2 :                                 'table' => $this->metaData->relations[$relation_name]->getJunctionTableName(),                        
     275                 :                                 'columns' => array (                                                                                  
     276               2 :                                     $relation_key_column => function () use ($this_var, $primary_key) { return $this->$primary_key; },
     277               2 :                                     $remote_key_column => $id,                                                                        
     278               2 :                                 ),                                                                                                    
     279                 :                             );                                                                                                        
     280               2 :                         }                                                                                                             
     281               2 :                     }                                                                                                                 
     282                 :                     // Build delete commands.                                                                                         
     283               2 :                     if (!empty ($delete_ids)) {                                                                                       
     284               1 :                         foreach ($delete_ids as $id) {                                                                                
     285               1 :                             $this->_delete_commands[]=array (                                                                         
     286               1 :                                 'table' => $this->metaData->relations[$relation_name]->getJunctionTableName(),                        
     287                 :                                 'conditions' => array (                                                                               
     288               1 :                                     'and',                                                                                            
     289               1 :                                     $relation_key_column.' = :this_id',                                                               
     290               1 :                                     $remote_key_column.' = :remote_id',                                                               
     291               1 :                                 ),                                                                                                    
     292                 :                                 'params' => array (                                                                                   
     293               1 :                                     ':this_id' => $this->$primary_key,                                                                
     294               1 :                                     ':remote_id' => $id,                                                                              
     295               1 :                                 ),                                                                                                    
     296                 :                             );                                                                                                        
     297               1 :                         }                                                                                                             
     298               1 :                     }                                                                                                                 
     299               2 :                     break;                                                                                                            
     300                 :             }                                                                                                                         
     301               2 :         }                                                                                                                             
     302               2 :     }                                                                                                                                 
     303                 :                                                                                                                                       
     304                 :     /************************************************************************/                                                        
     305                 :                                                                                                                                       
     306                 :     public function magicRelationManyManySelectedRead ($relation_name) {                                                              
     307               2 :         if (isset ($this->_magic_attributes[$relation_name.'_selected']))                                                             
     308               2 :             return $this->_magic_attributes[$relation_name.'_selected'];                                                              
     309               0 :         if (empty ($this->$relation_name))                                                                                            
     310               0 :             return null;                                                                                                              
     311               0 :         $relations=$this->relations();                                                                                                
     312               0 :         $relation_settings=$relations[$relation_name];                                                                                
     313               0 :         $primary_key=$relation_settings[1]::model()->tableSchema->primaryKey;                                                         
     314               0 :         $selected_list=array ();                                                                                                      
     315               0 :         foreach ($this->$relation_name as $model)                                                                                     
     316               0 :             $selected_list[]=$model->$primary_key;                                                                                    
     317               0 :         return $this->_magic_attributes[$relation_name.'_selected']=$selected_list;                                                   
     318                 :     }                                                                                                                                 
     319                 :                                                                                                                                       
     320                 :     public function magicRelationManyManySelectedWrite ($relation_name, $selected_list) {                                             
     321               2 :         $this->_magic_attributes[$relation_name.'_selected']=$selected_list;                                                          
     322               2 :     }                                                                                                                                 
     323                 :                                                                                                                                       
     324                 :     /************************************************************************/                                                        
     325                 :                                                                                                                                       
     326                 :     public function getAllErrors () {                                                                                                 
     327               0 :         $errors=$this->getErrors();                                                                                                   
     328               0 :         $relations=$this->relations();                                                                                                
     329               0 :         if (empty ($relations))                                                                                                       
     330               0 :             return $errors;                                                                                                           
     331               0 :         foreach ($relations as $relation_name => $relation_settings) {                                                                
     332               0 :             if (empty ($this->$relation_name))                                                                                        
     333               0 :                 continue;                                                                                                             
     334               0 :             if (is_object ($this->$relation_name)) {                                                                                  
     335               0 :                 if (!empty ($this->$relation_name->errors))                                                                           
     336               0 :                     $errors[$relation_name]=$this->$relation_name->getErrors ();                                                      
     337               0 :             } elseif (is_array ($this->$relation_name)) {                                                                             
     338               0 :                 $errors[$relation_name]=array ();                                                                                     
     339               0 :                 foreach ($this->$relation_name as $related_key => $related_model) {                                                   
     340               0 :                     if (!empty ($related_model->errors))                                                                              
     341               0 :                         $errors[$relation_name][$related_key]=$related_model->getErrors ();                                           
     342               0 :                 }                                                                                                                     
     343               0 :                 if (empty ($errors[$relation_name]))                                                                                  
     344               0 :                     unset ($errors[$relation_name]);                                                                                  
     345               0 :             }                                                                                                                         
     346               0 :         }                                                                                                                             
     347               0 :         return $errors;                                                                                                               
     348                 :     }                                                                                                                                 
     349                 :                                                                                                                                       
     350                 :     /************************************************************************/                                                        
     351                 :                                                                                                                                       
     352                 :     /**                                                                                                                               
     353                 :      * If any models have been updated, itterate over them and issue the                                                              
     354                 :      * validate() method. Assign any errors to their relation name.                                                                   
     355                 :      */                                                                                                                               
     356                 :     public function beforeValidate() {                                                                                                
     357               6 :         if (empty ($this->_relation_updated))                                                                                         
     358               6 :             return parent::beforeValidate();                                                                                          
     359               2 :         $primary_key=$this->tableSchema->primaryKey;                                                                                  
     360               2 :         $relations=$this->relations();                                                                                                
     361               2 :         $isValid=true;                                                                                                                
     362               2 :         foreach ($this->_relation_updated as $relation_name => $related_models) {                                                     
     363               2 :             if (empty ($related_models))                                                                                              
     364               2 :                 continue;                                                                                                             
     365               2 :             $relation_settings=$relations[$relation_name];                                                                            
     366               2 :             if (!empty ($related_models['new'])) {                                                                                    
     367               2 :                 foreach ($related_models['new'] as $new_models)                                                                       
     368               2 :                     $related_models[]=$new_models;                                                                                    
     369               2 :             }                                                                                                                         
     370               2 :             unset ($related_models['new']);                                                                                           
     371               2 :             foreach ($related_models as $key => $model) {                                                                             
     372               2 :                 $isValid=$isValid & $model->validate();                                                                               
     373               2 :                 if ($model->hasErrors()) {                                                                                            
     374                 :                     // Validation failed, bubble the errors up.                                                                       
     375               0 :                     foreach ($model->errors as $attribute => $error_messages)                                                         
     376                 :                         // Map the related model errors onto the related attribute.                                                   
     377               0 :                         foreach ($error_messages as $message)                                                                         
     378               0 :                             $this->addError ($relation_name, $message);                                                               
     379               0 :                 }                                                                                                                     
     380               2 :             }                                                                                                                         
     381               2 :         }                                                                                                                             
     382               2 :         return $isValid & parent::beforeValidate();                                                                                   
     383                 :     }                                                                                                                                 
     384                 :                                                                                                                                       
     385                 :     /**                                                                                                                               
     386                 :      * Start a DB transaction and cleans up all the objects that are eligible                                                         
     387                 :      * for delete.                                                                                                                    
     388                 :      */                                                                                                                               
     389                 :     public function beforeSave () {                                                                                                   
     390                 :         // Start a transaction                                                                                                        
     391                 :         // Issue the delete() on all eligible objects.                                                                                
     392               3 :         if (!empty ($this->_eligible_for_delete)) {                                                                                   
     393               1 :             foreach ($this->_eligible_for_delete as $related_object) {                                                                
     394               1 :                 $related_object->delete();                                                                                            
     395               1 :             }                                                                                                                         
     396               1 :             $this->_eligible_for_delete=array ();                                                                                     
     397               1 :         }                                                                                                                             
     398               3 :         return parent::beforeSave();                                                                                                  
     399                 :     }                                                                                                                                 
     400                 :                                                                                                                                       
     401                 :     /**                                                                                                                               
     402                 :      * Cascaed the save() to all related objects that changed and commit the                                                          
     403                 :      * transaction.                                                                                                                   
     404                 :      */                                                                                                                               
     405                 :     protected function afterSave () {                                                                                                 
     406                 :         // Issue delete commands                                                                                                      
     407               3 :         if (!empty ($this->_delete_commands)) {                                                                                       
     408               1 :             foreach ($this->_delete_commands as $delete_command) {                                                                    
     409               1 :                 $delete_command=$this->expandCallables ($delete_command);                                                             
     410               1 :                 Yii::app()->db->createCommand()->delete (                                                                             
     411               1 :                     $delete_command['table'],                                                                                         
     412               1 :                     $delete_command['conditions'],                                                                                    
     413               1 :                     $delete_command['params']                                                                                         
     414               1 :                 );                                                                                                                    
     415               1 :             }                                                                                                                         
     416               1 :         }                                                                                                                             
     417                 :         // Issue insert commands                                                                                                      
     418               3 :         if (!empty ($this->_insert_commands)) {                                                                                       
     419               2 :             foreach ($this->_insert_commands as $insert_command) {                                                                    
     420               2 :                 $insert_command=$this->expandCallables ($insert_command);                                                             
     421               2 :                 Yii::app()->db->createCommand()->insert (                                                                             
     422               2 :                     $insert_command['table'],                                                                                         
     423               2 :                     $insert_command['columns']                                                                                        
     424               2 :                 );                                                                                                                    
     425               2 :             }                                                                                                                         
     426               2 :         }                                                                                                                             
     427                 :         // Issue the save() on all changed objects.                                                                                   
     428               3 :         if (!empty ($this->_relation_updated)) {                                                                                      
     429               2 :             $primary_key=$this->tableSchema->primaryKey;                                                                              
     430               2 :             $relations=$this->relations();                                                                                            
     431               2 :             foreach ($this->_relation_updated as $relation_name => $related_models) {                                                 
     432               2 :                 if (empty ($related_models))                                                                                          
     433               2 :                     continue;                                                                                                         
     434               2 :                 $relation_settings=$relations[$relation_name];                                                                        
     435                 :                 // models are seperated into 2 groups, new object and models that                                                     
     436                 :                 // already existed in the db, but were changed.                                                                       
     437               2 :                 foreach ($related_models as $pk_or_new => $r_model) {                                                                 
     438               2 :                     if ($pk_or_new === 'new') {                                                                                       
     439               2 :                         foreach ($r_model as $new_model) {                                                                            
     440               2 :                             if (empty($new_model->$relation_settings[2]))                                                             
     441               2 :                                 $new_model->$relation_settings[2]=$this->$primary_key;                                                
     442               2 :                             $new_model->save();                                                                                       
     443               2 :                         }                                                                                                             
     444               2 :                         continue;                                                                                                     
     445                 :                     }                                                                                                                 
     446               1 :                     $r_model->save();                                                                                                 
     447               2 :                 }                                                                                                                     
     448               2 :             }                                                                                                                         
     449               2 :             $this->_relation_updated=array ();                                                                                        
     450               2 :         }                                                                                                                             
     451                 :         // end transaction/commit.                                                                                                    
     452               3 :         return parent::afterSave();                                                                                                   
     453                 :     }                                                                                                                                 
     454                 :                                                                                                                                       
     455                 :     public function cascade ($cascade_setting) {                                                                                      
     456               1 :         $this->cascade_on_delete=$cascade_setting;                                                                                    
     457               1 :     }                                                                                                                                 
     458                 :                                                                                                                                       
     459                 :     /**                                                                                                                               
     460                 :      * Emulates the cascade delete if the cascade variable is set to true.                                                            
     461                 :      */                                                                                                                               
     462                 :     protected function beforeDelete () {                                                                                              
     463               2 :         if (!$this->cascade_on_delete)                                                                                                
     464               2 :             return parent::beforeDelete();                                                                                            
     465                 :         // start transation.                                                                                                          
     466                 :         // Itterate through the relations, issue deletes for Has One, Has                                                             
     467                 :         // Manies, and the pivot table for the Many Manies.                                                                           
     468               1 :         foreach ($this->relations () as $relation_name => $relation_settings) {                                                       
     469               1 :             if (empty ($this->$relation_name))                                                                                        
     470               1 :                 continue;                                                                                                             
     471               1 :             switch ($relation_settings[0]) {                                                                                          
     472               1 :                 case 'CHasOneRelation':                                                                                               
     473               1 :                     $this->$relation_name->delete();                                                                                  
     474               1 :                     break;                                                                                                            
     475               1 :                 case 'CHasManyRelation':                                                                                              
     476               1 :                     foreach ($this->$relation_name as $relation_entry)                                                                
     477               1 :                         $relation_entry->delete();                                                                                    
     478               1 :                     break;                                                                                                            
     479               1 :                 case 'CManyManyRelation':                                                                                             
     480               1 :                     $primary_key=$this->tableSchema->primaryKey;                                                                      
     481               1 :                     $pivot_table=$this->metaData->relations[$relation_name]->getJunctionTableName();                                  
     482               1 :                     $foreign_keys=$this->metaData->relations[$relation_name]->getJunctionForeignKeys();                               
     483               1 :                     $primary_key_column=array_shift ($foreign_keys);                                                                  
     484               1 :                     $conditions="$primary_key_column = :id";                                                                          
     485               1 :                     $params=array (':id' => $this->$primary_key);                                                                     
     486               1 :                     $rows_affected=Yii::app()->db->createCommand()->delete ($pivot_table, $conditions, $params);                      
     487               1 :                     break;                                                                                                            
     488               1 :                 default:                                                                                                              
     489               1 :                     continue;                                                                                                         
     490               1 :             }                                                                                                                         
     491               1 :         }                                                                                                                             
     492               1 :         return parent::beforeDelete();                                                                                                
     493                 :     }                                                                                                                                 
     494                 :                                                                                                                                       
     495                 :     public function afterDelete () {                                                                                                  
     496                 :         // end transaction                                                                                                            
     497               2 :         return parent::afterDelete();                                                                                                 
     498                 :     }                                                                                                                                 
     499                 :                                                                                                                                       
     500                 : }                                                                                                                                     

Generated by PHP_CodeCoverage 1.1.2 using PHP 5.4.4-14+deb7u2 and PHPUnit 3.6.10 at Wed Aug 14 22:01:23 CDT 2013.