Валидация данных
Валидация данных
Кто как считает, должна ли она быть фреймворко-зависимой или нет? У меня такое впечатление сложилось, что многие отделяют валидацию данных от тру бизнес-логики и считают, что она не так важна и может зависеть от слоя фреймворка. Тогда получается, что при миграции на другой фреймворк нужно будет написать не только новые контроллеры и репозитории, но также еще и правила валидации.
Вместе с тем я думаю, что внутри себя валидация вполне может содержать сложные бизнес-правила, но я не встречал еще такой информации в сети, чтобы её делали каким-то отдельным независимым слоем и объясняли бы какие проблемы это решает и насколько проще становится поддержка проекта или же наоборот, что это не имеет смысла и только всё усложняет.
У меня на текущий момент, валидация данных зависит от фреймворка, данные просто валидируются в контроллере, а затем закидываются в сервис. Если говорить в контексте Yii, то это выглядело бы как создание наследника от \yii\base\Model с описанием своих правил валидации и затем вызов его метода validate в контроллере, после чего в случае boolean true данные ушли бы в сервис.
В общем расскажите как у вас и как вы считаете, должно зависеть от фреймворка или не должно. Постарайтесь сильно не усложнять, чтобы было понятно всем, а если усложняете, тогда давайте ссылку на источник откуда вы это взяли, поскольку если это действительно стоящая идея, то она должна уже была быть кем-то описана и носить какое-то название. Спасибо.
Вместе с тем я думаю, что внутри себя валидация вполне может содержать сложные бизнес-правила, но я не встречал еще такой информации в сети, чтобы её делали каким-то отдельным независимым слоем и объясняли бы какие проблемы это решает и насколько проще становится поддержка проекта или же наоборот, что это не имеет смысла и только всё усложняет.
У меня на текущий момент, валидация данных зависит от фреймворка, данные просто валидируются в контроллере, а затем закидываются в сервис. Если говорить в контексте Yii, то это выглядело бы как создание наследника от \yii\base\Model с описанием своих правил валидации и затем вызов его метода validate в контроллере, после чего в случае boolean true данные ушли бы в сервис.
В общем расскажите как у вас и как вы считаете, должно зависеть от фреймворка или не должно. Постарайтесь сильно не усложнять, чтобы было понятно всем, а если усложняете, тогда давайте ссылку на источник откуда вы это взяли, поскольку если это действительно стоящая идея, то она должна уже была быть кем-то описана и носить какое-то название. Спасибо.
Re: Валидация данных
Несколько подходов уже обсуждали здесь. Зависит от степени недоверия к данным и от числа их источников.
Re: Валидация данных
Третий вариант довольно интересный, но получается, что я не могу напрямую использовать дефолтные валидаторы самого фреймворка. Скажите, можно же создать какую-то абстракцию, которая будет описывать методы для общих правил валидации типа required, isString, isEmail и т.д. и внедряться в другие как-то вот так
Внутри конкретной реализации DefaultValidatorInterface можно уже использовать дефолтные валидаторы самого фреймворка. Тогда вроде как получается, что при переезде на другой фреймворк нужно будет только написать новую реализацию DefaultValidatorInterface, что должно быть довольно таки простым занятием даже не включая мозг. А сложные/не сложные индивидуальные правила валидации останутся нетронутыми в UserSignupValidator и у нас не будет необходимости их переписывать каждый раз при переезде на новый фреймворк или на новую мажорную версию этого же фреймворка, как при втором варианте, который вы описали.
Кароче абстрагироваться от конкретных реализаций дефолтных валидаторов, так же как мы абстрагировались от конктерного хранилища с помощью репозиториев.
Что скажете Дмитрий?
Код: Выделить всё
class UserSignupValidator
{
private $userRepository;
public function __construct(DefaultValidatorInterface $defaultValidator, UserRepositoryInterface $userRepository)
{
$this->defaultValidator = $defaultValidator;
$this->userRepository = $userRepository;
}
public function validate(UserSignupCommand $command)
{
$errors = [];
...
if ($this->defaultValidator->required($command->username)) {
$errors['username'][] = 'This field is required.';
}
if ($this->userRepository->existsByUsername($command->username)) {
$errors['username'][] = 'This username has already been taken.';
}
if ($this->userRepository->existsByEmail($command->email)) {
$errors['email'][] = 'This email has already been taken.';
}
return $errors;
}
}
Кароче абстрагироваться от конкретных реализаций дефолтных валидаторов, так же как мы абстрагировались от конктерного хранилища с помощью репозиториев.
Что скажете Дмитрий?
Re: Валидация данных
Да, как раз можно.sda писал(а):Скажите, можно же создать какую-то абстракцию, которая будет описывать методы для общих правил валидации типа required, isString, isEmail и т.д...
Re: Валидация данных
Дмитрий, у меня еще вопрос по автозагрузке. Сейчас когда мы пишем неймспейс типа \app\path\to\my\Class то класс услужливо подхватывается встроенным автозагрузчиком Yii вот здесь https://github.com/yiisoft/yii2/blob/ma ... i.php#L279 и превращается в алиас вида @app/path/to/my/Class.php
А сам алиас @app является предопределенным http://www.yiiframework.com/doc-2.0/gui ... ed-aliases и соответственно разворачивается в basePath. Затем инклюдится файл по получившемуся пути. Это всё понятно.
Но когда мы уйдем на другой фреймворк, то там никаких предопределенных алиасов не будет, но получается так, что мы уже завязали весь свой код на неймспейс \app, который нам потихому подсунул Yii фреймворк. Конечно мы сможем потом в другом фреймворке в autoload прописать этот неймспейс \app и вроде как всё должно заработать, но не считаете ли вы, что логичнее было бы сразу приложению прописать тот неймспейс, который мы сами захотим в composer.json и загружать наш код автозагрузчиком композера, а не встроенным автозагрузчиком Yii. Например вот так:
То есть если отвязываться от фреймворка, то отвязываться полностью. Как вы считаете?
А сам алиас @app является предопределенным http://www.yiiframework.com/doc-2.0/gui ... ed-aliases и соответственно разворачивается в basePath. Затем инклюдится файл по получившемуся пути. Это всё понятно.
Но когда мы уйдем на другой фреймворк, то там никаких предопределенных алиасов не будет, но получается так, что мы уже завязали весь свой код на неймспейс \app, который нам потихому подсунул Yii фреймворк. Конечно мы сможем потом в другом фреймворке в autoload прописать этот неймспейс \app и вроде как всё должно заработать, но не считаете ли вы, что логичнее было бы сразу приложению прописать тот неймспейс, который мы сами захотим в composer.json и загружать наш код автозагрузчиком композера, а не встроенным автозагрузчиком Yii. Например вот так:
Код: Выделить всё
//composer.json
...
"autoload": {
"psr-4": {
"AppName\\": "src/"
}
}
...
Re: Валидация данных
ну зачем завязываться в такой мелочи на фреймворк? Напишите пяток валидаторов типа StringValidator, NumberValidator, и юзайте их в UserDtoValidator.sda писал(а):Третий вариант довольно интересный, но получается, что я не могу напрямую использовать дефолтные валидаторы самого фреймворка. Скажите, можно же создать какую-то абстракцию, которая будет описывать методы для общих правил валидации типа required, isString, isEmail и т.д. и внедряться в другие как-то вот такВнутри конкретной реализации DefaultValidatorInterface можно уже использовать дефолтные валидаторы самого фреймворка. Тогда вроде как получается, что при переезде на другой фреймворк нужно будет только написать новую реализацию DefaultValidatorInterface, что должно быть довольно таки простым занятием даже не включая мозг. А сложные/не сложные индивидуальные правила валидации останутся нетронутыми в UserSignupValidator и у нас не будет необходимости их переписывать каждый раз при переезде на новый фреймворк или на новую мажорную версию этого же фреймворка, как при втором варианте, который вы описали.Код: Выделить всё
class UserSignupValidator { private $userRepository; public function __construct(DefaultValidatorInterface $defaultValidator, UserRepositoryInterface $userRepository) { $this->defaultValidator = $defaultValidator; $this->userRepository = $userRepository; } public function validate(UserSignupCommand $command) { $errors = []; ... if ($this->defaultValidator->required($command->username)) { $errors['username'][] = 'This field is required.'; } if ($this->userRepository->existsByUsername($command->username)) { $errors['username'][] = 'This username has already been taken.'; } if ($this->userRepository->existsByEmail($command->email)) { $errors['email'][] = 'This email has already been taken.'; } return $errors; } }
Кароче абстрагироваться от конкретных реализаций дефолтных валидаторов, так же как мы абстрагировались от конктерного хранилища с помощью репозиториев.
Что скажете Дмитрий?
Re: Валидация данных
так и надоsda писал(а):Дмитрий, у меня еще вопрос по автозагрузке. Сейчас когда мы пишем неймспейс типа \app\path\to\my\Class то класс услужливо подхватывается встроенным автозагрузчиком Yii вот здесь https://github.com/yiisoft/yii2/blob/ma ... i.php#L279 и превращается в алиас вида @app/path/to/my/Class.php
А сам алиас @app является предопределенным http://www.yiiframework.com/doc-2.0/gui ... ed-aliases и соответственно разворачивается в basePath. Затем инклюдится файл по получившемуся пути. Это всё понятно.
Но когда мы уйдем на другой фреймворк, то там никаких предопределенных алиасов не будет, но получается так, что мы уже завязали весь свой код на неймспейс \app, который нам потихому подсунул Yii фреймворк. Конечно мы сможем потом в другом фреймворке в autoload прописать этот неймспейс \app и вроде как всё должно заработать, но не считаете ли вы, что логичнее было бы сразу приложению прописать тот неймспейс, который мы сами захотим в composer.json и загружать наш код автозагрузчиком композера, а не встроенным автозагрузчиком Yii. Например вот так:
То есть если отвязываться от фреймворка, то отвязываться полностью. Как вы считаете?Код: Выделить всё
//composer.json ... "autoload": { "psr-4": { "AppName\\": "src/" } } ...
Re: Валидация данных
Выходит нам нужно просто обложиться абстракциями со всех флангов, с которых есть угроза проникновения врага в наш девственно чистый код и проблемы фреймворкозависимости решены? Ну кроме проблемы самой абстракции.
Re: Валидация данных
Да, как и обсуждали в соседней теме: пользуясь принципами ООП написать чистое ядро, принимающее чётко определённые команды и запросы и взаимодействующее с инфраструктурой через адаптеры.sda писал(а):Выходит нам нужно просто обложиться абстракциями со всех флангов, с которых есть угроза проникновения врага в наш девственно чистый код и проблемы фреймворкозависимости решены?
Получаем быстрые тесты, стопроцентную независимость от чего угодно и переносимость на любой фреймворк, CMS и прочую инфраструктуру. Заодно получаем возможность разработки всей системы ещё до выбора фреймворка и БД. И, кстати, если PHP затормозит, получаем портируемость на любой ООП-язык простой правкой синтаксиса.
Вот мы и изобрели заново ту самую архитектуру.
Какой именно проблемы?sda писал(а):Ну кроме проблемы самой абстракции.
Re: Валидация данных
"Любую проблему можно решить введением дополнительного уровня абстракции … кроме проблемы слишком большого количества уровней абстракции."ElisDN писал(а):Какой именно проблемы?sda писал(а):Ну кроме проблемы самой абстракции.
Re: Валидация данных
Ну есть такая поговорка или высказывание, я о ней давно статью находил в англ вики, но уже забыл. Звучит примерно так "Любую проблему можно решить дополнительным уровнем абстрации, кроме проблемы слишком большого количества абстракций".ElisDN писал(а):Какой именно проблемы?sda писал(а):Ну кроме проблемы самой абстракции.
SamDark частенько её на этом форуме упоминал.
Мне еще вот, что интересно. Если приложение это api, то всё понятно, а вот если это веб-сайт, то еще интересны правила, которыми стоит руководствоваться при разработке html шаблонов, чтобы они тоже были независимы и их можно было бы взять и унести в другой фреймворк. Понятно, что не стоит использовать всякого рода виджеты. Но еще есть csrf токен например и может что-то еще, что также нужно как-то решить, чтобы не привязывать html шаблоны к фреймворку. Но я помню, что Yii довольно плотно участвует в жизни html шаблонов, всякие там ассеты и прочее.
Re: Валидация данных
Как недавно говорил, архитектуру придумали для упрощения сложного кода, а не для усложнения лёгкого.sda писал(а):Ну есть такая поговорка или высказывание, я о ней давно статью находил в англ вики, но уже забыл. Звучит примерно так "Любую проблему можно решить дополнительным уровнем абстрации...".
А слишком большое количество - это сколько?sda писал(а):"...кроме проблемы слишком большого количества абстракций".
У него своя альтернативная позиция по отношению к ООП и архитектуре.sda писал(а):SamDark частенько её на этом форуме упоминал.
HTML - он и в Африке HTML. В чём проблема перенести и немного переписать вёрстку? Или сложно будет потом вместо GridView написать <table> с foreach? А так вполне универсален Twig.sda писал(а):а вот если это веб-сайт, то еще интересны правила, которыми стоит руководствоваться при разработке html шаблонов, чтобы они тоже были независимы и их можно было бы взять и унести в другой фреймворк... Понятно, что не стоит использовать всякого рода виджеты.
У каждого фреймворка есть свои конструкторы форм с CSRF и прочими заморочками. Проблем с ними нет.sda писал(а):Но еще есть csrf токен например и может что-то еще, что также нужно как-то решить, чтобы не привязывать html шаблоны к фреймворку.
Не мелочитесь шаблонами и ассетами. Ассеты - это просто пару js-файлов подключить. Дел на один день.sda писал(а):Но я помню, что Yii довольно плотно участвует в жизни html шаблонов, всякие там ассеты и прочее.
Или Вы думаете, что когда пять человек в команде полгода программируют сервис бронирования билетов или ERP для местного бизнеса их сильно волнует вёрстка? Так что программируйте чистым изначально только ядро.
Последний раз редактировалось ElisDN 2016.08.06, 20:06, всего редактировалось 10 раз.
Re: Валидация данных
в ddd есть 4 слоя - один из них это слой представления (контроллеры плюс вьюхи). Он единственный фреймворкозависимый, хотя в случае продуманного выбора и он может быть переносимым. Например в psr7-совместимых фреймворках твой экшн будет являться стандартизированной мидлварью с зависимостью от рендерера темплейтов
в данном случае рендерер от зенд экспрессив, и реализован в виде 3 адаптеров над сторонними системами рендеринга. Я уверен что менять фреймворк не буду, т.к. он мне предоставляет самый минимум - di + мидлвари - ничего из этого я 100% не захочу заменить, т.к. это простО как кирпич. (если бы закладывал возможность переноса, то обернул бы TemplateRendererInterface зенда в свой TemplateRendererInterface)
Экшны переносимы в любой другой psr7-фреймворк без правок, шаблоны у меня на твиге - также переносимы (без всяких ассетсов и прочих улучшений фреймворка).
В случае с yii ты ничего не перенесешь, т.к. контроллеры - свои, а не стандартизированные, шаблон - с кучей хаков от фреймворка, итд.
Вывод: для слоистой архитектуры выбрать psr7-микро-фреймворк, чтобы последний презентационный слой по максимуму развязать, и не тащить с собой 90% ненужного кода.
Код: Выделить всё
<?php
namespace Zelenin\Sport\Presentation\Action\Federation;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zelenin\MessageBus\Contract\Bus;
use Zelenin\Sport\Application\Dto\Federation\FederationDto;
use Zend\Expressive\Template\TemplateRendererInterface;
final class Create
{
/**
* @var TemplateRendererInterface
*/
private $template;
/**
* @var Bus
*/
private $commandBus;
/**
* @param TemplateRendererInterface $template
* @param Bus $commandBus
*/
public function __construct(TemplateRendererInterface $template, Bus $commandBus)
{
$this->template = $template;
$this->commandBus = $commandBus;
}
/**
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param callable|null $next
*
* @return ResponseInterface
*/
public function __invoke(
ServerRequestInterface $request,
ResponseInterface $response,
callable $next = null
): ResponseInterface
{
$federationDto = new FederationDto();
$response->getBody()->write($this->template->render('@sport/federation/create', [
'federationDto' => $federationDto
]));
return $response
->withHeader('Content-Type', 'text/html; charset=utf-8');
}
}
Экшны переносимы в любой другой psr7-фреймворк без правок, шаблоны у меня на твиге - также переносимы (без всяких ассетсов и прочих улучшений фреймворка).
В случае с yii ты ничего не перенесешь, т.к. контроллеры - свои, а не стандартизированные, шаблон - с кучей хаков от фреймворка, итд.
Вывод: для слоистой архитектуры выбрать psr7-микро-фреймворк, чтобы последний презентационный слой по максимуму развязать, и не тащить с собой 90% ненужного кода.
Re: Валидация данных
Ну, например, перепишу я всеми любимый классический код без абстракций:nootropil писал(а):Любую проблему можно решить введением дополнительного уровня абстракции… кроме проблемы слишком большого количества уровней абстракции.
Код: Выделить всё
if ($order->status == 1 || ($order->status == 2 && $order->deliveryDate > time() + 86400) || ($order->status == 4 && $order->paymentDate < time())) {
...
}
Код: Выделить всё
if ($order->isCancelable()) {
...
}
Re: Валидация данных
Тут лишь первый уровень абстракции, надо больше что бы стало плохо. Нужна обёртка для обёртки обёртки обёртки ... и т.д.ElisDN писал(а): Ну, например, перепишу я всеми любимый классический код без абстракций:
Да и цитата, как мне кажется, скорее о кровавом ентерпрайзе на Java.
Re: Валидация данных
Да, такое у новичков часто бывает. Скиньте пример в личку, если встретите.nootropil писал(а):Тут лишь первый уровень абстракции, надо больше что бы стало плохо. Нужна обёртка для обёртки обёртки обёртки ... и т.д
Re: Валидация данных
это цитата для тех, кто не понимает зачем в проект вводятся абстракции.nootropil писал(а):Тут лишь первый уровень абстракции, надо больше что бы стало плохо. Нужна обёртка для обёртки обёртки обёртки ... и т.д.ElisDN писал(а): Ну, например, перепишу я всеми любимый классический код без абстракций:
Да и цитата, как мне кажется, скорее о кровавом ентерпрайзе на Java.
- samdark
- Администратор
- Сообщения: 9489
- Зарегистрирован: 2009.04.02, 13:46
- Откуда: Воронеж
- Контактная информация:
Re: Валидация данных
И для тех, кто понимает зачем, но перебарщивает. Дмитрий выше верно заметил, что "архитектуру придумали для упрощения сложного кода, а не для усложнения лёгкого".
Нравится Yii? Давайте сделаем его лучше!.
Re: Валидация данных
ElisDN имеет ли смысл делать двойную валидацию, первую на уровне доменных объектов, когда домен кидает исключения если пришли плохие данные, а вторую уже исключительно для пользователей (для отображения ошибок на сайте) с помощью инструментов которые предлагает фреймворк?
Re: Валидация данных
Если хотите красивую Ajax-валидацию, то придётся клиентскую делать. А так я в своём ответе несколько вариантов рассматривал.sda писал(а):ElisDN имеет ли смысл делать двойную валидацию, первую на уровне доменных объектов, когда домен кидает исключения если пришли плохие данные, а вторую уже исключительно для пользователей (для отображения ошибок на сайте) с помощью инструментов которые предлагает фреймворк?