YiiConf 2017 всё ближе! Не забудьте купить билет.

Обновление определённого поля модели

Часто требуется обновить только одно поле модели не затрагивая все остальные.
Ярким примером может служить форма с inline-редактированием (т.е.
данные для каждой строки сохраняются непосредственно после редактирования).

Конечно можно написать SQL напрямую без использования модели, но в этом случае
мы потеряем замечательную возможность валидации правилами, описанными там.

В моём случае при асинхронном сохранении в метод приходят POST-ом два параметра:
id (имя поля) и value (значение).

if(Yii::app()->request->isAjaxRequest) {
  // Используется та же модель формы, что и при полном сохранении
  $form = new UserForm();

  if(!in_array($_POST['id'], $form->attributeNames())){
    // Получен id, которого нет в форме… что-то тут не так.
    throw new CHttpException(500, "Wrong data passed.");
  }

  $form->{$_POST['id']} = $_POST['value'];

  // Валидируем по одному значению, а не всю форму
  if ($form->validate(array($_POST['id']))) {
    $user = new User();
    // id пользователя мы и так знаем, так что выбирать всю модель не будем
    $user->id = Yii::app()->user->id;

    // Берём значение из формы (т.к. в процессе валидации оно могло поменяться)
    $user->{$_POST['id']} = $form->$_POST['id'];

    // Проверяем, есть ли такой атрибут в нашей модели, если есть — пытаемся
    // сохранить. Второй параметр save() — массив полей, которые надо сохранять.
    if($user->hasAttribute($_POST['id']) && !$user->save(true, array($_POST['id'])){
        throw new CHttpException(500, "Unable to save user data");
    }
  }
  else {
    // Ошибки валидации поля отдаём клиенту
    echo json_encode(array('error' => $form->getErrors($_POST['id'])));
  }
}
else {
  // Хорошим тоном будет реализовать и обычное сохранение… может у пользователя
  // отключен JS.
}