maleks писал(а): ↑2017.10.17, 15:58
За холиваром DM vs AR там, остался без внимания ваш тот рецепт насчет AR. Я его прочел и вот не понял - это у вас ваш рабочий "боевой" вариант или просто вы предполагаете что этим способом будет лучше? Сложно зацепиться там за мысли. Вы делаете некое утверждение, но не обосновываете как вы к нему пришли.
Да, с недавнего времени это рабочий вариант. Как к нему пришли? Рефакторили большой и старый проект на Yii 1, где все на все завязано, монолитно и с разделением обязанностей все плохо. Была поставлена задача переписать UI. Заодно решили попробовать отделить UI и работу с данными. Попробовали закрыть AR интерфейсами, чтобы между Ui и логикой приложения с данными появился четко определенный интерфейс. Бизнес-логику от данных отделять не стали, так как это какая-то неоправданная задача (да и с AR нерешаемая). Пришли к тому, что с AR работать не так уж плохо, нужно соблюдать такие вот правила:
1. Создание экземпляров делать в классе, который принадлежит к персистентному слою - $user = $users->add($email, $name .....). Позволяет закрыть AR интерфейсом и мокать/декорировать ее. Класс для $user может не наследовать от AR, а включать объект AR, что даст больше гибкости и освободит конструкторы - станет возможной инжекция в конструктор. DAO к множетсву юзеров инжектится через контейнер и также закрыт интерфейсом.
2. Создание экземпляра AR это связанные операции. Из метода добавления add() не должна выходить AR, не предвтавляющая реальную сроку в БД. На то она и record, чтобы представлять запись. В методе add() лучше избегать бизнес-логики - только вставка. Все необходимое рассчитывать в клиентских классах.
3. Не использовать метод save(). Все изменения в БД производить сразу при обращении к методам объекта, типа $user->rename($name), $promocode->activate() и пр. Эти операции должны быть самодостаточными, и должны быть атомарными с точки зрения модификации данных в БД.
4. С реляциями работать также как в п.3 $user->addPhone(), $user->removePhone(). Никаких withRelated и сборки графа из AR в памяти и сохранения одним save(). Если нужно сначала все в памяти - тогда DM + программный UoW.
5. Для объединения нескольких операций и атомарности между ними использовать транзакции (тот же UoW, только на стороне БД). Оборачивать последовательные вызовы в транзакцию.
6. Никакой встренной валидации AR в слое работы с данными - валидация форм в классах форм, В методах объектов с бизнес-логикой и данными - исключения. Никаких сценариев.
7. Из DDD взяли себе на вооружение только доменные события - они очень удобны для уведомлений, аудита, репликации в индексы.
8. Естественно, никаких Yii:app().
Думали и про Doctrine ORM. так как у меня был опыт использования ORM и ODM в других проектах. После пробного переписывания одного модуля, стало понятно что ясности это не добавило, а добавило неявность, больше мест (маппинги, кастомные типы) для редактирования и убавило скорость отклика.
Все получается. Ну, провайдеры и data-виджеты выкинули, да без них и проще. Используем Twig. Теперь по возможности, будем переписывать слой логики и данных на AR из Yii2, Eloquent или на что-то другое, что окажется удобнее (если подберем).
Для наших задач оказалось нормально, все становится понятнее. Очень не хватает метода resetRelation() для сброса загруженных связей в AR.