Проблемы С Архитектурой В Yii-Приложении

Добрый день.

Делаю свой первый проект на yii. Поэтому есть некоторые проблемы с выбором правильной архитектуры приложения.

1) Регистрация пользователя.

У пользователя есть login, email, hash и другие поля (поля password – нет!). Для регистрации пользователя я создаю (генерирую) модель типа Active Record.

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

Вопрос первый в том, где генерировать хэш и соль. Можно прямо в контроллере, можно в методе beforeSave() модели User.

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

Плюсы генерации в модели: контроллер невероятно тонкий – а вроде бы это круто.

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

2) Парсинг данных.

Пользователь передаёт ссылку на ресурс в контроллер. Далее должен выполняться такой алгоритм:

[list=1]

[*]Валидация ссылки. Если ссылка ведёт на неразрешенный источник, заканчиваем работу.

[*]

[list=2]

[*] Парсинг фильма.

[*] Если фильм есть в БД, ищем его ид и увеличиваем referenseCount на 1.

[*] Если фильма нет в БД, добавляет его туда, получаем ид фильма и устанавливаем полю referenseCount значение 1.

[*]Проверяем жанры нового фильма. Если каких-то жанров нет, добавляем их в БД.

[/list]

[*] Создаём запись в таблице usermovies с ид текущего пользователя и ид фильма.

[/list]

Вопрос: уместно ли выполнять такое большое количество действий в контроллере?

Второй вопрос: если все эти действия выполнять в контроллере, где делать валидацию ссылки? Опять тут же?

3) Вью модели.

Принято ли в yii обмениваться данными между контроллером и вьюхой с помощью вью моделей?

Буду очень благодарен за ответы и советы.

Спасибо!

Они пароль и повтор пароля должны быть в моделе, вот в чем прикол. Все поля что отображаются в форме пользователю, как правило должны быть в моделе, хотя и не обязательно должны быть в таблице БД. Объявите в моделе публичные поля $pass, $pass2, сделайте для них rules ‘safe’ что бы они назначались при mass assigment и обрабатывайте в зависимости от сценария.

Смысл в том, что контроллер указывает модели сценарий, а модель реализует те или иные правила в зависимости от сценария. Хотя я только что глянул на свою старую реализацию, и понял, что делал хеширование пароля в контроллере… может не знал о чем-то о чем знаю сейчас. Или наоборот знал причину, а теперь забыл.

Не вижу тут ничего особо страшного, если все действия связаны друг с другом.

Можно и тут же, но более красиво было бы использовать before-фильтр что бы не смешивать функционал действия и функционал проверки прав доступа.

А что такое вью-модель?

1а) В модели. Избавит от дублирования кода в случае, если юзер редактируется из нескольких мест (пользовательская часть + админка к примеру)

1б) В модели. Необходимые поля можно добавить. (public $password; public $passwordConfirmation).

На них и валидацию сразу навесить.

  1. Если пользователь что-то там сабмитит - это форма. Валидацию проще делать именно в ней. См. CForm, CActiveForm. Ну или CActiveRecord, если уж на то пошло.

Всю бадягу с "есть фильм/нет фильма" лично я бы повесил в модель, а в контроллере оставил бы тупо вызов save().

То есть, задача контроллера - сохранить. Как именно сохранить - это уже пусть модель разгребает.

Но возможно это уже маньячество, смотрите сами.

1-1. Сделайте функцию хеширования (так вам нужно). Далее в контроллере перед save() выполняйте данную функцию (соль). Это убережет вас от дублирования кода (вам ведь не только при регистрации ее использовать).

1-2. Для этого у меня есть отдельная модель RegistrationForm. В ней мы обьявим например повтор пароля (капчу если надо), что-то вроде


public $verifycode;

//добавим в rules

array('verifyPassword', 'compare', 'compareAttribute'=>'password', 'message' => UserModule::t(" Passwords don't match")),



Собственно кроме rules у нас здесь и нет ничего. Далее в контроллере мы можем делать валидации моделей (validate()). Возможно этот подход не очень изящный но при большом количестве моделей при регистрации ничего лутше я не нашел (у меня например 4 модели на регистрационной форме, и нужно делать запись в 3 таблицы). Почему я сделал так - у меня разделены данные для входа в систему (логин - пароль …), данные пользователя (профиль), роль пользователя.

  1. Снова же рекомендую сделать модель без таблицы. У вас ведь будет форма , и сделайте валидацию в модели. В контроллере делайте validate(). Если вы так тянетесь к тонким контроллерам , что вам мешает сделать как-то так:



public function actionFilmparse123()

{

  $model=new Validationmodel;

  $model->attributes=$_POST;

  if ($model->validate())

  {

    $film=MyparseModel::model()->parse($model->url);

    $film_id=Myfilmsmodel::model->savefilm($film);

    Myusermoviesmodel::model()->saveuser_film(Yii::app()->user->id,$film_id);

  }

}



Вот по сути и все что будет у вас в контроллере. Все действия с базой вынесем в модели.

  1. Если я правильно понял вы имеете ввиду паттерн MVVM. Yii является MVC фреймворком. Поетому это неуместно (да и с реализацией вы замучаетесь). Если сделаете в виде MVVM выложите пожалуйста примеры, очень интересно будет посмотреть.

Спасибо всем за советы.

Вью модели – это классы, содержащие в себе лишь свойства, а также их валидацию. Они широко используются в ASP.NET MVC для передачи данных между контроллерами и вьюхами. И да, это немного не те вью модели, что используются в MVVM (у них разное назначение).

В Yii принято передавать AR модель из контроллера во вьюху.

Если это вьюмодели из ASP то в yii это просто модели. Если вы реализуете тонкие модели то они и будут содержать лишь свойства и валидацию. Если подробнее с контроллером, код на ASP:




public ActionResult Register()

{

    var model = new RegisterViewModel();

    .....

    return View(model);

}



Будет идентичен коду в Yii




public function actionRegister()

{

  $model=new RegistrationForm;

  ....

  $this->render('register',array('model'=>$model));

}