DDD: Как правильно работать с контекстами ?

Вурдалак

Продвинутый новичок
цена это функция
Есть разные аспекты одних и тех же понятий на естественном языке. Бизнесовый, философский, потребительский, etc. Поэтому просто выкидывать такие определения без привязки к контексту — это сотрясать воздух.
 

WMix

герр M:)ller
Партнер клуба
цена это некая функция которая зависит оп продавца, покупателя, количества и момента времени. iphone7 у разных продавцов для разных людей стоит по разному, мне как простому смертному 700 в магазине А, тебе как постоянному покупателю за 650 в магазине А, а ему как мужу дочери двоюродного брата продавца в магазина А по закупочной.

если продали товар за 42, придется отчитаться перед поставщиком, почему 42. нужно найти ту самую id цены в которой указаны условия.
 

camohob

Новичок
Зачем тебе делать разделение на domain и persistence models (то, что ты называешь «моделью» и «сущностью» соответственно)? Doctrine тоже без проблем может оперировать id-шниками.
Есть у нас в системе такая штука, как фотографии отеля. Они имеют какие-то метаданные(название, описание, приоритет, ...) и сам файл. Метаданные хранятся в MySQL, а вот файлы в мускуле хранить идея плохая - поэтому мы выбрали GridFS(но на самом деле не важно, хоть просто в FS).
Т.е., получается, что у нас доменная модель фотографии отеля мапится уже на два разных хранилища.
Таких примеров в системе будет много, где то будут агрегаты, часть которых проще грузить из кэша, например...

З.Ы.: мы с @Gutsy над одним проектом работаем)
 

camohob

Новичок
Если доктриновские entities использовать как persistence models, то надо уж мапить сразу весь aggregate root целиком. А с таким подходом, по-моему, проще оставить от доктрины один только квери билдер и делать "ручной датамаппер".
Вот, именно к ручному датамаперу мы и пришли. Попробовали сделать конвертацию сущностей доктрины в доменные модели и агрегаты прямо в репозитории - ничего хорошего не вышло... ((

Может есть у кого опыт таких извращений?) Дайте посмотреть на реализацию такого "датамапера", плиз
 

Вурдалак

Продвинутый новичок
если продали товар за 42, придется отчитаться перед поставщиком, почему 42. нужно найти ту самую id цены в которой указаны условия.
Я боюсь, что тут просто подобрана ужасная терминология. Продали по $42 — это и есть цена. А подробности формирования цены можно было бы узнать, например, из offer'а. И называть это «ценой» для меня по меньшей мере странно.
 

Вурдалак

Продвинутый новичок
Есть у нас в системе такая штука, как фотографии отеля. Они имеют какие-то метаданные(название, описание, приоритет, ...) и сам файл. Метаданные хранятся в MySQL, а вот файлы в мускуле хранить идея плохая - поэтому мы выбрали GridFS(но на самом деле не важно, хоть просто в FS).
Т.е., получается, что у нас доменная модель фотографии отеля мапится уже на два разных хранилища.
Сам файл? В смысле blob? Он в виде свойства у модели что ли?

Почему в модели не может быть просто имя файла или id фотографии?
 

camohob

Новичок
Сам файл? В смысле blob? Он в виде свойства у модели что ли?

Почему в модели не может быть просто имя файла или id фотографии?
Да, сам файл в свойстве(по факту это конечно же ссылка на "ленивый" объект). Почему так?
1. Потому что файл - неотъемлемое свойство модели и модель без него не является валидной.
2. В контроллере отсутствуют операции по поискам файла в каком-либо хранилище, объект в свойстве файла описывает некий интерфейс, который умеет файл представлять в виде строки или ресурса. Таким образом мы в любой момент можем заменить хранилище файлов и не переписывать все контроллеры.

И сейчас это дело организовано через кастомный тип доктрины, DM туда просовывается в билдере бандла:
PHP:
class UploadMongoType
{
   /** @var DocumentManager */
    protected $dm;
   ....

    /**
     * @param mixed $value
     * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
     * @return null
     * @throws \Doctrine\DBAL\Types\ConversionException
     */
    public function convertToDatabaseValue($value, AbstractPlatform $platform)
    {
        if (empty($value)) {
            return null;
        }

        if ($value instanceof UploadMongo) {
            if ($this->dm->getUnitOfWork()->getDocumentState($value) === UnitOfWork::STATE_NEW) {
                $this->dm->persist($value);
            }
            $this->dm->flush();

            return $value->getId();
        }

        throw ConversionException::conversionFailed($value, self::NAME);
    }

    /**
     * @param mixed $value
     * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
     * @return null
     */
    public function convertToPHPValue($value, AbstractPlatform $platform)
    {
        if (empty($value)) {
            return null;
        }

        return $this->dm->getReference(UploadMongo::class, $value);
    }
}
Оно работает, но выглядит как костыль. Хочется именно отделить доменные Модели от ОРМ.
 

Adelf

Administrator
Команда форума
У вас содержимое файла в бизнес логике никак не участвует. И не надо это тащить туда. Вытаскиваете файл только на фронте и все. Свойства с идентификатором(именем) файла - достаточно.
 

Вурдалак

Продвинутый новичок
даже если тебе предложениями легче думать, вопрос "какое из предложений" остался
Я не знаю какие там у тебя вопросы остались, но я вёл речь про терминологию, которая тебя, судя по всему, как раз безразлична.
 

WMix

герр M:)ller
Партнер клуба
Это значит, что цены $42 и $42 — это разные цены
да, по разным договорам, предложениям как хочешь, значение одно а цена как единица с указанием "что за цена" разная!
но я вёл речь про терминологию
намешал все до кучи, не поняв смысла.
 

Вурдалак

Продвинутый новичок
Да, сам файл в свойстве(по факту это конечно же ссылка на "ленивый" объект). Почему так?
1. Потому что файл - неотъемлемое свойство модели и модель без него не является валидной.
Это культ Карго. Как уже отметили, это свойство никак в бизнес-логике не участвует, бессмысленно его туда тащить.

Я очень рекомендую попробовать записывать события в модели: https://phpclub.ru/talk/threads/Как-реализуете-репозиторий-doctrine-analogue-ручками-etc.82411/#post-747858
Тогда станет понятно, что главное в сущности — это именно отклик в виде события, а не то, какие там внутри свойства. И я боюсь, что наличие blob'а с изображением в сущности никак на отклик влиять не будет совершенно.

Второй момент, на который я хочу обратить внимание — это разделение чтения и записи (CQRS). Вот это рассуждение на тему того какие свойства могут понадобится в момент чтения будет очень сильно мешать для реализации чистой модели.
 

camohob

Новичок
У вас содержимое файла в бизнес логике никак не участвует. И не надо это тащить туда. Вытаскиваете файл только на фронте и все. Свойства с идентификатором(именем) файла - достаточно.
т.е. вот такая логика?
- при добавлении фотки - мы этот файл где-то в контроллере или обработчике команды записываем в GridFS - получаем id и создаем модель фотографии уже с этим id.
- при чтении фотки - опять же в контроллере мы идем в GridFS, ищем файл, генерируем линк на него - показываем
- при удалении фотки - в контроллере или обработчике команды удаляем файл из GridFS и модель.

Получается что просто удаления модели недостаточно чтобы были соблюдены все бизнес-правила. Бизнес правило просит удалять фотографию вместе с файлом.. а мы эту логику выносим из домена?
Или бизнес ничего не знает о файлах - для него только фотка удаляется, а файл - это уже детали реализации, так?
 

camohob

Новичок
Второй момент, на который я хочу обратить внимание — это разделение чтения и записи (CQRS). Вот это рассуждение на тему того какие свойства могут понадобится в момент чтения будет очень сильно мешать для реализации чистой модели.
вот, а как же в этом случае мапить read и write модели на одни и те же данные? или read модель строить из write модели, а мапить только её?
 

Adelf

Administrator
Команда форума
Да. Вся работа с файлами - инфраструктура. Конретно в бизнес операциях содержимое файла никак не влияет. Все эти гридфс и с3 - не должны залазить в модель. Она должна быть чиста и невинна. И не думать о суровых реалиях.
 

Adelf

Administrator
Команда форума
@camohob, потому что сущность фотография отеля на логику и не влияет особо. Ну может при рпсчете рейтингов каких нибудь их количество будет влиять. Это для сайта какойто смысл они имеют. Но не для домена.
 

Вурдалак

Продвинутый новичок
А можно какие-то реальные примеры из вашего домена, происходящие с отелем, помимо «добавить», «посмотреть», «удалить»? Потому что здесь не нужен никакой DDD, если всё сводится к этому.
 
Сверху