Сохраните экземпляр модели в afterSave(), не будет ли он работать рекурсивно?

Мне нужно подсчитать некоторые данные дочерней модели и сохранить их в атрибуте экземпляра родительской модели. Но для сохранения значения атрибута мне нужно позвонить $this->save() или же $this->saveAttributes(array('<attr name>')); Разве это не будет работать save() процедура рекурсивно навсегда и, если нет, то почему бы и нет? Внутри модели Event:

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'));
    }

}

Обновление 1

Как предположил Джон, я мог бы сделать это следующим образом:

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(); 
}

Обновление 2

Я обновил свой вопрос, чтобы показать соответствующий код модели. Я только накапливаю итоговую сумму из дочерней модели в родительский атрибут. Как спросил Лин, я делюсь моделями. Главное здесь - это их отношение: Event (родительская модель) и EventContent (дочерняя модель) связаны этим отношением:

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

1 ответ

Решение

Ваша реализация afterSave() неправильно и приведет к бесконечным вызовам методов save() а также afterSave() пока PHP не достигнет своего времени выполнения скрипта.

У вас есть два варианта:

  1. Реализуйте свой код в соответствии с предложением Джона (ваше обновление 1)
  2. Оставаться с afterSave() и использовать saveAttributes() внутри, чтобы сохранить модель. saveAttributes() не буду звонить beforeSave() а также afterSave() как описано в официальных API-документах

На мой взгляд, лучший подход - переместить ваш код в save() как Джон уже предложил.

Другие вопросы по тегам