phprecursionyiiafter-save

Save a model instance in afterSave(), won't it run recursive?


I need to sum count some child model data and store it in the parent model instance attribute. But for saving the attribute value I need to call $this->save() or $this->saveAttributes(array('<attr name>')); Won't it run save() procedure recursively forever and, if not, why not? Inside of Event model:

protected function afterSave() 
{
    parent::afterSave();
    $contents = EventContent::model()->findAllByAttributes(array('eventId'=>$this->id));
    if ($contents) 
    {   
        $sum=0;
        foreach($contents as $content)              
            $sum += $content->cost;  

        $this->totalSum = $sum;
        $this->save(); 
        // or $this->saveAttributes(array('totalSum'));
    }

}

Update 1

As suggested by Jon, I might do it in this way:

protected function save() 
{    
    $contents = EventContent::model()->findAllByAttributes(array('eventId'=>$this->id));
    if ($contents) 
    {   
        $sum=0;
        foreach($contents as $content)              
            $sum += $content->cost;  

        $this->totalSum = $sum; // no need to run $this->save() here            
    } 
    parent::save(); 
}

Update 2

I've updated my question to show the models' relevant code. I only accumulate sum total from child model into parent attribute. As asked by lin i share the models. The main thing here is their relation: Event (parent model) and EventContent (child model) are bound with this relation:

Class EventContent extends CActiveRecord {
  ...
  public function relations()
  {
     return array(
        'event'=>array(self::BELONGS_TO, 'Event', 'eventId'),
     );
  }
}

Solution

  • Your implementation of afterSave() is wrong and will result in endless method calls of save() and afterSave() until PHP reaches its script execution time limit.

    You have two options:

    1. Implement your code as suggested by Jon (your Update 1)
    2. Stay with afterSave() and use saveAttributes() inside to save the model. saveAttributes() will not call beforeSave() and afterSave() as described in the official API-docs

    In my opinion the best approach is to move your code to save() as Jon already suggested.