Ответы пользователя по тегу Предметно-ориентированное проектирование
  • Как быть с событиями из агрегата, который используется в агрегате уровнем выше?

    ghost404
    @ghost404
    PHP Developer
    Для начала рекомендую глянуть библиотеку для реализации доменных событий
    https://github.com/gpslab/domain-event

    Еще рекомендую определится с терминологией. "Покупка лучшего фильма", "Лучшие фильмы" и "Покупка фильма" это не домены, а ограниченные контексты (Bounded Context).

    Не может быть агрегата уровнем выше. У вас неправильное понимание термина Агрегат. И с доменными событиями тоже самое. Доменные события должны бросаться в сущностях, а не сервисах прикладного уровня.

    Далее. Вы списываете баланс со счета пользователя, потом выдаёте ему доступ к фильму и потом бросаете событие и все это делаете последовательно, да ещё и заварачиваете в БД транзакцию, хотя это бизнес транзакция.

    Бизнес логика должна быть все таки на уровне предметной области.

    И все же вернёмся к вашей проблеме.
    > пользователь может подписаться на услугу "Дайте мне доступ к лучшему фильму недели"

    Вы явно описали понятие Услуга. И у вас есть две, скажем так, услуги:
    - Лучшие фильмы недели
    - Покупка одного фильма

    Отсюда у вас появляется:
    interface Service
    {
        public function price(): Money;
    
        // ...
    }
    
    class OneFilmService implements Service
    {
        public function __construct(Film $film)
        {
            // ...
        }
    
       // ...
    }
    
    class BestFilmsService implements Service
    {
        // ...
    }
    
    class User
    {
       // ...
    
        public function buyService(
            AccountRepository $repository,
            Service $service
        ) {
            // получаем текущий счёт пользователя
            // и выполняем покупку
            $repository
                ->get($this->id)
                ->buy($service->price())
            ;
    
            // добавляем пользователю
            // преобретенную услугу
            $this->services[] = $service;
    
            // бросаем доменное событие
            $this->raise(new ServicePurchased(
                $this->id,
                $service->id()
            );
        }
    }

    Простой и наглядный способ покупки услуги.

    Получение денег от клиента по средствам СМС инкапсулированно в UserAccount.

    Если между покупкой и получением доступа к услуге должно пройти несколько минут, можно ввести понятие -
    Активация заказанной услуги.

    То есть, пользователь покупает/заказывает услугу и возможно даже видит ее в своём личном кабинете, но активация услуги и соответственно доступ к ней выполняется только после поступления средств от клиента через СМС или ещё как.
    Ответ написан