Где и кто должен делать валидацию?

В общем пытаюсь освоить Di, сервисы, репозитории - правильную архитектуру. Делаю тренировочный проект, но возникли вопросы:

Раньше была модель User extend ActiveRecord, и была модель RegistrationForm extend Model
При получении данных, в экшене создавал вторую модель и выполнял метод валидации: $form->load($this->getRequest()->post()) && $form->validate(), далее вызывал метод регистрации. В общем-то все, все это можно было увидеть в примерах yii2.
class AccountController extend BaseController
{
    public function actionRegistration()
    {
        $form = new RegistrationForm($this->getRequest()->post());
        if ($form->validate()) {
            $user = $form->registration();
            return $user->id;
        } else {
            throw new BadRequestHttpException(implode(';, $registration->getFirstErrors()));
        }
    }
}


Сейчас логику регистрации вынес в сервис AccountService, работу с моделью User (поиск, создание, сохранение..) вынес в UserRepository. Сама модель ничего не содержит кроме rules. Но вот куда теперь девать RegistrationForm в которой была валидация пришедших данных?

1) В контроллере валидировать?
$email = Yii::$app->getRequest()->post['email']; 
if (!EmailValidator::validate($email)) {
     throw new BadRequestHttpException('Wrong email');
}


2) Оставить RegistrationForm, но сделать унаследованной от User c переопределенными rules. Передавать заполненную модель в сервис и в сервисе вызывать валидацию. Так пока и сделал:
public function actionRegistration()
    {
        $registrationForm = new RegistrationForm($this->getRequest()->post());
        $user = $this->accountService->registrationUser($registrationForm);
        if ($user) {
            return $this->accountService->generateToken($user)->token;
        } else {
            throw new BadRequestHttpException(implode('; ', $registrationForm->getFirstErrors()));
        }
    }


3) Передавать в сервис массив пришедших данных и там уже каким-нибудь способом валидировать.

В общем хочу понять как правильно делать, где-что должно лежать и запускаться.
  • Вопрос задан
  • 1012 просмотров
Решения вопроса 1
iiifx
@iiifx
PHP, OOP, SOLID, Yii2, Composer, PHPStorm
1. Да, но не вручную, а через форму, которая за это отвечает - через RegistrationForm. Это же замечательный функционал, глупо его игнорировать. Один раз описываете правила валидации и форма работает.

2. Нет, они выполняют разные роли: форма занимается валидацией входящих данных, а AR-модель хранением. Я настоятельно не рекомендую тесно связывать формы с сущностями, т.е. наследовать одни от других. Их нужно держать раздельно: изменение AR-сущности User никогда не создаст вам проблем в формах, а изменение данных запроса и правил валидации формы RegistrationForm не навредит AR-сущности. Вы сможете менять их независимо друг от друга.

3. Вы должны передать провалидированные данные от контроллера в сервис. А вот как вы это сделаете полностью на ваше усмотрение: грубо массивом, особым value-объектом или предусмотреть передачу заполненной формы RegistrationForm в сервис, который сам сможет извлечь данные и выполнить работу. Важный момент: данные должны быть полностью проверены. Сервис при этом может даже не знать кто его использует, главное соблюдать публичный интерфейс.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
FanatPHP
@FanatPHP
Чебуратор тега РНР
Это хороший вопрос.

Когда форма сама занимается своей валидацией, то тут вариантов немного. Остаемся в контроллере.

Но по-хорошему, если отвлечься от конкретных велосиепедов, плотно увязывающих вывод ХТМЛ и валидацию входящих в модель данных, то в AccountService должен быть метод validate().

Соответственно, из любого места, где нам надо создать юзера, сначала дергаем validate(), а потом по результатам либо выдаем ошибку, либо дергаем create()
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы