Пример ситуации: Есть модель User.
Каждый пользователь (User) может менять личную информацию, email и пароль в отдельных action'ах соответственно. Смена пароля и email требует ввода текущего пароля пользователя, в то время как смена личной информации этого не требует. Есть еще администратор, который может менять любую информацию пользователя без ввода текущего пароля. А еще есть модераторы, которые могут менять только личную инфу и email (без ввода текущего пароля), но пароль пользователя они изменить не могут.
Обычно, для каждого действия я использую отдельный сценарий, для которого определяю rules в модели. Но в описанной выше ситуации получается полный ад. Пример даже страшно приводить:
Код: Выделить всё
class User extends CActiveRecord {
public $currentPassword;
public $retypePassword;
public function rules()
{
return array(
array('login', 'required', 'on'=>'registration, updateByAdmin'),
array('login', 'length', 'max' => 80, 'on'=>'registration, updateByAdmin'),
array('login', 'unique', 'on'=>'registration, updateByAdmin'),
array('login', 'match', 'pattern' => '~^[\da-zа-яёА-ЯЁ\.\-@_\+]+$~i', 'on'=>'registration, updateByAdmin'),
array('phone', 'length', 'max' => 12),
array('icq', 'length', 'max' => 9),
array('email', 'required', 'on'=>'registration, updateByAdmin, updateByModerator, changeEmail'),
array('email', 'length', 'max' => 200, 'on'=>'registration, updateByAdmin, updateByModerator, changeEmail'),
array('email', 'unique', 'on'=>'registration, updateByAdmin, updateByModerator, changeEmail'),
array('email', 'email', 'on'=>'registration, updateByAdmin, updateByModerator, changeEmail'),
array('password', 'required', 'on'=>'registration, updateByAdmin, changePassword'),
array('currentPassword', 'required', 'on'=>'changePassword, changeEmail'),
array('currentPassword', 'passwordValidator', 'on'=>'changePassword, changeEmail'),
array('retypePassword', 'required', 'on'=>'registration, updateByAdmin, changePassword'),
array('retypePassword', 'compare', 'compareAttribute' => 'password', 'on'=>'registration, updateByAdmin, changePassword,')
);
}
}
Код: Выделить всё
array('email', 'required', 'on'=>'registration, updateByAdmin, updateByModerator, changeEmail, ajaxRegistration, ajaxUpdateByAdmin, ajaxUpdateByModerator, ajaxChangeEmail'),
Так вот, как быть в таких ситуациях, когда одна модель может редактироваться из множества разных action'ов, и когда нужно сохранять только определенные поля используя $model->attributes = $_POST['User']? Очень хочется делать это прямиком из действий контроллера, практически везде убрав on и except из rules().
Использование $model->save(true,['password','login',...]) огорчает тем, что не сохраняются значения полей, присвоенных в beforeSave().
Можно опять же убрать on и except, прописать в rules() для нужного сценария валидатор unsafe для полей, которые не надо изменять, но тогда возникнет проблема с валидацией полей модели, которых нет во view (например, при смене пароля сработает array('login', 'required')).
В настоящее время я делаю следующим образом: Добавляю в модель метод
Код: Выделить всё
public function setAttributesByNames($values,$names)
{
if(!is_array($values)) return;
if(!is_array($names)) $names = explode(',',$names);
foreach($names as $name) if(isset($values[$name])) $this->$name = $values[$name];
}
Код: Выделить всё
$model->setAttributesByNames($_POST['User'],array('login,email'));
if ($model->validate(array('login,email'))) $model->save(false);
Пример не реальный. Он лишь иллюстрирует проблему, когда одна модель может редактироваться из нескольких разных мест, в каждом из которых можно изменять только определенные значения
А как поступаете вы?