Валидация данных

Обсуждаем, как правильно строить приложения
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Re: Валидация данных

Сообщение sda »

Я хочу пока только на сервере сделать, одну которая вызывается внутри контроллера до того как обратиться к сервису и если есть ошибки, то отправляет их клиенту, а другая это уже правила валидации внутри самого домена, которые кидают DomainException. Если валидация которая вызывается внутри контроллера пропустит не совсем валидные данные, то система выбросит DomainException и умрет отправив клиенту статус 500. Хочу выяснить это адекватное решение или нет?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Валидация данных

Сообщение ElisDN »

sda писал(а):Я хочу пока только на сервере сделать, одну которая вызывается внутри контроллера до того как обратиться к сервису и если есть ошибки, то отправляет их клиенту, а другая это уже правила валидации внутри самого домена, которые кидают DomainException. Если валидация которая вызывается внутри контроллера пропустит не совсем валидные данные, то система выбросит DomainException и умрет отправив клиенту статус 500. Хочу выяснить это адекватное решение или нет?
Только не переусердствуйте. Проверяйте в домене только действительно важные условия. А то так можно весь домен сотнями проверок загадить.

Если не понравится дублировать, то можно всю валидацию в домен перенести:

viewtopic.php?f=34&t=36725&p=188542#p188542
viewtopic.php?f=34&t=38618&p=198029#p198029

или в контроллере при Ajax-валидации вызывать вроде $errors = $this->validator->validate($dto).
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Re: Валидация данных

Сообщение sda »

ElisDN есть бизнес-правила, которые нельзя смаппить на правила валидации. Например такое "Нельзя создать новую комнату для игры в покер, если пользователь уже присоединился к какой-либо комнате". Я думаю это бизнес-правило должно жить в доменном сервисе и кидать DomainException. Если клиент это обычный пользователь, он просто не увидит в своем интерфейсе кнопки "Создать новую комнату" пока находится в какой-либо другой комнате. Но хакер, который делает прямой запрос должен быть остановлен на DomainException. Очевидно, что DomainException это не ошибка сервера, а ошибка клиента. Соответственно я хочу отдавать HTTP статус 400, но не 500.

Тогда получается, что мне нужно создать DomainExceptionInterface в доменном слое и затем соорудить реализацию интерфейса в инфраструктурном слое и отнаследоваться от yii\web\BadRequestHttpException

Но не всегда требуется создавать доменные сервисы, часто DomainException разумнее бросать прямо в доменном объекте и вот как быть в этом случае? С одной стороны я не хочу завязывать доменный объект на конкретную реализацию DomainException, с другой, я все еще хочу чтобы фреймворк меня понимал и отправлял клиенту статус 400, а не 500. Какой выход?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Валидация данных

Сообщение ElisDN »

sda писал(а):ElisDN есть бизнес-правила, которые нельзя смаппить на правила валидации.
Ну да. Эти бизнес-правила и проверяйте с DomainException. А не банальную длину строки.
sda писал(а):Соответственно я хочу отдавать HTTP статус 400, но не 500.
Используйте встроенный \DomainException и преобразовывайте в контроллере:

Код: Выделить всё

try {
    $this->service->createGame(...);
} catch (\DomainException $e) {
    throw new \yii\base\BadRequestHttpException($e->getMessage());
}  
или глобальньо переопределите eventHandler фреймворка.
sda
Сообщения: 334
Зарегистрирован: 2013.12.19, 09:29

Re: Валидация данных

Сообщение sda »

Ну ладно. А вот если у меня есть свойство объекта, которое может принимать одно из заранее известных значений, скажем пускай будет 1, 2 и 3. При этом валидация на уровне фреймворка тоже хочет проверять, что значение верное, но проблема в том, что к этому моменту доменного объекта еще не существует.

Вопрос. Я могу создать такое свойство как ValueObject со статичным методом, который будет возвращать все возможные значения и потом использовать этот статичный метод в валидации на уровне фреймворка? То есть сделать что-то такое

Код: Выделить всё

class FooValueObject {
    const VALUE_FOO = 1;
    const VALUE_BAR = 2;
    const VALUE_OTHER = 3;

    private $value;
    
    public function __construct($value) {
        $this->value = $value;
    }
    public function __toString() {
        return $this->value;
    }
    public static function getValueList() {
        return [self::VALUE_FOO, self::VALUE_BAR, self::VALUE_OTHER];
    }
}
 
и затем использовать для валидации на уровне фреймворка вот так

Код: Выделить всё

class SomeModel extends \yii\base\Model {
    public $foo;
    
    public function rules() {
        return [
            ['foo', 'validateFoo']
        ];
    }
    public function validateFoo($attribute, $params) {
        if (!in_array($this->$attribute, \domain\FooValueObject::getValueList())) {
                    $this->addError($attribute, 'Invalid value');
            }
    }
}
 
Это ок или не ок?
anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: Валидация данных

Сообщение anton_z »

Не не, VO пусть лучше в конструкторе проверяет. В контроллере по идее VO не надо использовать. VO будет создаваться в домене.
P.S. Для валидации небольшое дублирование - практически неизбежная вещь.
Ответить