Правильное разделение ответственности

Духовность™

Продвинутый новичок
Ragazzo
аргументы по теме у тебя есть или ты только хамство понимаешь?

Я просто бешусь, когда мне хамят и/или кидают ссылки на туториалы по фреймворку.
Модель программы - это бизнес логика и валидация, которая происходит на этапе наполнения модели данными. Всё.
Считать форму (считай - представление) моделью, это чудовищьно. Форма - это форма, это лишь html текст, который с помощью браузера
свои свойства превращает в данные запроса. Итого мы имеем лишь запрос (данные) и программу. Слой, оперирующий этими входящими данными моделью называться не может.
Также как и заливная горловина автомобиля (модель) никак не связана с заправочным шлангом или канистрой. В случае веб-приложения канистра - это браузер, инициирующий запрос.
 

varan

Б̈́̈̽ͮͣ̈Л̩̲̮̻̤̹͓ДͦЖ̯̙̭̥̑͆А͇̠̱͓͇̾ͨД͙͈̰̳͈͛ͅ
Я тут про DDD почитал. Звучит заманчиво, оказывается я уже начал приходить к нему сам (ввел объект сущности с поведением), есть всякие аспекты которые я не совсем понимаю. Но походу именно это мне и надо. Но все же интересно кто занимается валидацие (фабрика? репозиторий? сама сущность?)
Фиг его знает, я сам книжку прочитал, на практике не успел осознать, тоже сейчас экспериментирую. Похоже по DDD фабрика должна какую-то валидацию делать, потому что она возвращает только валидные объекты. Сама сущность наврядли должна зависеть от способов ее создания. Но проверку повторного ввода пароля фабрика делать имхо не должна. Видимо это должно быть до того как.
Ну и если репозиторий при сохранении обнаружил, что юзер с таким логином уже есть, должен выдавать ошибку.

Если подытожить, то похоже, если всё делать по православному, нужен некий объект form, который знает какие у него поля и умеет их тримать и первично валидировать, включая повторный ввод пароля и всякую капчу (как в Zend Framework), затем массив данных этой форы поступает в фабрику, которая создает объект User и также валидирует некоторые вещи, о которых Form не знает, затем объект User поступает в репозиторий, где валидируется на предмет уникальности логина. Потому что если пихнуть проверку уникальности логина в фабрику, то параллельный поток все равно может попытаться зарегаться с таким логином пока объект идет из фабрики в репозиторий.

И как быть с User-ом и ActivationCode-ом, так:
PHP:
$user = new UserFactory::create($data);
$aCode = new ActivationCodeFactory::create($data);
$user->setActivationCode($aCode);
(new UserRepository())->persist($user);
Но в таком случае кто сохраняет код активации?
если я правильно помню книжку, то фабрика должна создавать юзера вместе с активационным кодом и всеми другими объектами, необходимыми для существования сущности User. А все это дело сохраняет репозиторий.
 

varan

Б̈́̈̽ͮͣ̈Л̩̲̮̻̤̹͓ДͦЖ̯̙̭̥̑͆А͇̠̱͓͇̾ͨД͙͈̰̳͈͛ͅ
Ragazzo
аргументы по теме у тебя есть или ты только хамство понимаешь?

Я просто бешусь, когда мне хамят и/или кидают ссылки на туториалы по фреймворку.
Модель программы - это бизнес логика и валидация, которая происходит на этапе наполнения модели данными. Всё.
Считать форму (считай - представление) моделью, это чудовищьно. Форма - это форма, это лишь html текст, который с помощью браузера
свои свойства превращает в данные запроса. Итого мы имеем лишь запрос (данные) и программу. Слой, оперирующий этими входящими данными моделью называться не может.
Также как и заливная горловина автомобиля (модель) никак не связана с заправочным шлангом или канистрой. В случае веб-приложения канистра - это браузер, инициирующий запрос.
форма - это не только html код, но и набор правил по ее валидации. html - часть представления, набор правил может быть частью модели
 

Absinthe

жожо
Форма - это форма, это лишь html текст, который с помощью браузера
свои свойства превращает в данные запроса
В форме нет HTML. Она только в шаблоне, отображающем форму. А форма - это чистая логика(валидация, фильтрация, подстановки).
Как правило форма умеет отдавать данные прямо в связанную модель-запись.
 

AmdY

Пью пиво
Команда форума
вот мой вишлист по току как должна работать форма с моделью.
PHP:
$obj = new Kiss_Db_Table();
//FORM
$form = $obj->getForm('admin'); // return Kiss_Form
$form = $obj->getForm('user'); // return Kiss_Form
$form = $obj->getForm('user')->clear(); // return Kiss_Form

$form->removeField('password');
$form->addFiled('array of description');
$form->get('updated_at')->set('type', 'text');
$form->get('updated_at')->render();

$form->isPost();
$form->isSubmit();
$form->validate($data); // $data по ссылке и заполняется
$obj->save($data); // сохранили массив полученный из формы
$form->getValue();

$form->beginForm();
$errors = $Form->getValidated(); // id, caption, text
$form->get('field_name')->getValue();
$form->get()->getCaption();
$form->get()->isRequired();
$form->get()->isValidate();
$form->get()->isSave();
$form->endForm();
 

skwee

Новичок
// Форма - это лишь способ передать в модель данные. Данные в модель можно передать как из формы, так и из командной строки или с помощью телепортации.
+- согласен, думаю считать форму моделью не удобно...

varan
Вот кстати интересный вопрос. Ведь мой юзер это то что в ДДД называется Aggregate, ведь он содержит код активации, ну и еше всякие данные юзера (список постов, комментов и тд). Я согласен с тобой что ЮзерРепоситори должен создавать (тут имеется введу не нового юзера а например по айди) юзера уже со всеми связями (можно делать связи lazy initiation чтоб например не грузит из базы\кеша все посты юзера на каждой странице), но как написано в википедии
Aggregate: A collection of objects that are bound together by a root entity, otherwise known as an aggregate root. The aggregate root guarantees the consistency of changes being made within the aggregate by forbidding external objects from holding references to its members.
То есть не может быть таких функции
PHP:
public function getPosts() {
    return $this->_posts;
}

public function getActivationCode() {
    return $this->_activationCode;
}
а как тогда? тот же репоситори должен как то получать эти данные чтобы записать их в базу и тд. Что я упускаю? или возможно мне надо ввести границу между АПИ функциями и внутренними функциями?

В форме нет HTML. Она только в шаблоне, отображающем форму. А форма - это чистая логика(валидация, фильтрация, подстановки).
Как правило форма умеет отдавать данные прямо в связанную модель-запись.
Ну вот не клеиться у меня.. Модель это данные из базы, из кеша, из файла, из сети или из космоса. Форма это всего лишь способ создать модель а система где модели не могут прождать другие модели - форма это скорее фабрика. У тебя же модель юзера не отвечает за создания и валидацию поста? Пост создает кто то другой, некий EntityManager или PostFactory или сервис хз, а потом он привязывается к конкретному юзеру.
 

fixxxer

К.О.
Партнер клуба
AmdY
Ну не у каждой модели может быть представление в виде формы. А вот список полей и валидаторов - у каждой.

Может, так
PHP:
$Model = new FooModel; // implements FieldSet
...
$Form = new Form; // implements FieldSet
$Form->mergeFieldsetFrom($Model); // shares fields with Model FieldSet
$Form->addField('password2')->addValidator('password2', Validator::valueEqualsTo($Form->getField('password'));
$Captcha = new Captcha($this->Session);
$Form->addField('captcha')->addValidator('captcha', Validator::captchaMatches($Captcha));
....
$Form->fetchFrom($this->Request->Post); // updates relevant model field values too
if ($Form->validate()) { // triggers shared validators too
    $Model->save();
}
 
  • Like
Реакции: AmdY

AmdY

Пью пиво
Команда форума
Хм, а мне в голову даже не приходило поменять местами. Твой вариант логичнее.
 

fixxxer

К.О.
Партнер клуба
Надо бы его еще сделать. А то у меня это место совсем через жопу :(
 

AmdY

Пью пиво
Команда форума
Вот у меня тоже в вишлисте, а код писать времени нет, да и домашний фреймворк в основном для испробывания подходов, а не как конечный продукт.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
AmdY
Ну не у каждой модели может быть представление в виде формы. А вот список полей и валидаторов - у каждой.

Может, так
PHP:
$Form = new Form; // implements FieldSet
$Form->mergeFieldsetFrom($Model); // shares fields with Model FieldSet
$Form->addField('password2')->addValidator('password2', Validator::valueEqualsTo($Form->getField('password'));
if ($Form->validate()) { // triggers shared validators too
    $Model->save();
}
$Form->addField - по сути нарушение инкапсуляции :) реально ведь не стоит валидацию делать в контроллере.
Зачем разбивать правила валидации по нескольким классам - часть импортировать из модели $Model, другую часть руками вбивать через контроллер?
Почему бы не отвалидировать их одной моделью $Model, которая все знает о данных?
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
grigori, с чего бы это является нарушением инкапсуляции?
технически - нет, но по логике - да
часть правил валидации берутся из модели $Model, другая часть задается в контроллере, без правил контроллера правила модели неполны
классический ТТУК, завязывание модели на контроллер
 

Вурдалак

Продвинутый новичок
часть правил валидации берутся из модели $Model, другая часть задается в контроллере, без правил контроллера правила модели неполны
А я вот считаю иначе: $Model о подтверждении пароля знать ничего не должна. Аналогично с CAPTCHA. Ты считаешь, что все данные, отправленные пользователем (форма) являются данными одной и только одной сущности. На практике мы видим, что форма может содерждать данные для разных сущностей. Поэтому и проще ввести новый слой, называемый Form.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Form - это тоже модель, только под данные из формы, а не из базы
и она может знать все про свои данные
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Вурдалак
с 2-мя моделями для одной сущности без причины на то,
с размыванием логики одной логической операции с данными одной сущности между несколькими классами,
и вынесением части логики обработки данных в контроллер

если очень хочется выделить модель для работы с формой - сделайте нормально:
PHP:
$form = new UserRegistrationForm;
$form->fetchFrom($POST);
if ($form->validate()){
    $User = new Users;
    $User->fetchFrom($form);
    $User->save();
/*
    тут я бы написал 
    $form->exportTo($User = new Users);
    $User->save();
    по принципу tell don't ask, но это уже дело вкуса
*/
}
 

fixxxer

К.О.
Партнер клуба
Ну да, формы используемые более чем в 1 месте либо с кучей полей я так и выношу.
В случае с регистрацией не вижу ничего криминального прям в контроллере это сделать. Но если бы писал гайдлайны - написал бы "выносить всегда", да =)
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
так мы же в "теории"! :)

ну, а чтобы еще проще и быстрее и не выходить в контроллер - можно просто выставлять контекст для Users и валидировать в ней,
причем генерить эту Users прямо по таблице вместе с правилами
 
Сверху