cakephp избегать множественных обратных вызовов

Предположим, у меня есть модель User, которая hasMany ItemsItem belongsTo User, конечно)

каждый раз, когда Item изменяется где-либо в моем приложении, я хочу, чтобы электронное письмо было отправлено его пользователю (или их пользователям)

Итак, в моей модели Item я написал что-то вроде

public function beforeSave($options = array())
{
    // if data is modified find User and send him email
}

Но если я редактирую более одного элемента одновременно в своем действии (т.е. в цикле foreach), то отправляется несколько электронных писем, но я хочу только одно электронное письмо или одно электронное письмо для каждого пользователя, участвующего в обновлении.

Как я могу этого добиться?

Может быть, используя систему событий cakephp?


person arilia    schedule 08.11.2013    source источник
comment
я отредактировал. В одном из моих действий я должен перебирать элементы и сохранять их один за другим. Таким образом запускается много обратных вызовов   -  person arilia    schedule 08.11.2013
comment
если вы используете saveMany, у вас может быть возможность установить для обратных вызовов значение false.   -  person Anil kumar    schedule 08.11.2013
comment
Я хочу, чтобы обратные вызовы запускались. Если я использую saveMany, вызовет ли обратный вызов beforeSave только один раз или столько раз, сколько номер элемента? (кстати, я не могу использовать saveMany, потому что мне нужно выполнить логику, которая перебирает элементы)   -  person arilia    schedule 08.11.2013
comment
Мне удалось удалить цикл foreach и вместо этого использовать вызов saveMany. Но beforeSave по-прежнему вызывается два раза, если я сохраняю два элемента.   -  person arilia    schedule 08.11.2013
comment
извините, я думаю, что мы не можем установить для обратных вызовов значение false, используя saveMany, используя saveField, вы можете установить для обратных вызовов значение false   -  person Anil kumar    schedule 08.11.2013


Ответы (2)


Вы можете установить дополнительную переменную:

public $isMultiple = false;
public function beforeSave($options = array())
{
    if(!$this->isMultiple) {
        $this->isMultiple = true;
        // if data is modified find User and send him email
    }
}
person noslone    schedule 08.11.2013

Во-первых, не отправляйте электронную почту из модели данных. Действия с электронной почтой очень изменчивы, поэтому код модели данных должен быть как можно более стабильным. Вместо этого используйте компонент и вызовите метод компонента, когда вам нужно отправить электронные письма.

Похоже, вы хотите сообщать о завершенных транзакциях, а не об отдельных изменениях записей. Один из способов справиться с этим — установить отметку даты и времени в модели пользователя, когда было отправлено последнее электронное письмо. Затем вы можете использовать эту метку даты и времени, чтобы найти записи Item, которые были изменены, и уведомить об этих изменениях.

В вашем контроллере вы просто измените элементы по мере необходимости.

public function action()
{
    foreach($record in $records)
    {
        ......
        $this->Item->save(....);
    }

    $this->MyEmailComponent->notify($user_id);
}

Затем в своем компоненте электронной почты вы должны запросить модель Item, для которой элементы изменились с момента отправки последнего электронного письма.

public function notify($user_id)
{
    $this->User->id = $user_id;
    $last_email = $this->User->field('emailed');

    $updated_items = $this->Item->find('all',array(
        'conditions'=>array('Item.updated >'=>$last_email)
    ));

    // send email about those items

    $this->User->saveField('emailed',date('Y-m-d h:i:s'));
}
person Reactgular    schedule 08.11.2013
comment
ваше решение работает, но у меня есть много действий, которые изменяют элементы, поэтому мне нужно использовать обратные вызовы: я не хочу повторять код MyEmailComponent->notify в конце каждого действия. И если я добавлю другое действие, я не хочу помнить о добавлении строки. это то, для чего предназначены обратные вызовы, я думаю - person arilia; 08.11.2013