Для начала рекомендую глянуть библиотеку для реализации доменных событий
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.
Если между покупкой и получением доступа к услуге должно пройти несколько минут, можно ввести понятие -
Активация заказанной услуги.
То есть, пользователь покупает/заказывает услугу и возможно даже видит ее в своём личном кабинете, но активация услуги и соответственно доступ к ней выполняется только после поступления средств от клиента через СМС или ещё как.