Какой механизм позволяет быстро выполнить действие при создании сущности?

Ответ

В архитектуре приложений для выполнения действий при создании сущности я использую события (Events) или хуки жизненного цикла (Lifecycle Hooks) в ORM. Это позволяет отделить побочную логику (логирование, отправку уведомлений, вычисление производных полей) от основной бизнес-логики создания.

Пример с событиями в рамках чистой архитектуры:

// 1. Создаем событие
class ProductWasCreated {
    public function __construct(public Product $product) {}
}

// 2. Сервис создания продукта генерирует событие
class CreateProductService {
    public function __construct(private EventDispatcher $dispatcher) {}

    public function execute(CreateProductCommand $command): Product {
        $product = new Product($command->name, $command->price);
        // ... сохранение в репозитории

        $this->dispatcher->dispatch(new ProductWasCreated($product));
        return $product;
    }
}

// 3. Отдельный обработчик реагирует на событие
class SendWelcomeEmailOnProductCreation {
    public function __invoke(ProductWasCreated $event): void {
        $product = $event->product;
        // Отправка email, запись в аудит-лог и т.д.
    }
}

Плюсы подхода:

  • Гибкость и расширяемость: Новые действия добавляются как независимые обработчики, не изменяя основной код.
  • Тестируемость: Логику создания и побочные действия можно тестировать изолированно.
  • Асинхронность: Обработчики можно вынести в очередь задач (например, через RabbitMQ), чтобы не блокировать ответ пользователю.

Для простых случаев в рамках фреймворка (например, Laravel Eloquent или Doctrine) можно использовать встроенные хуки creating/created или аннотации @PrePersist.

Ответ 18+ 🔞

Ну и хули тут думать, архитектура же, ёпта! Когда сущность создаётся, а тебе надо ещё кучу всякой хуйни по сторонам сделать — логирование там, письма разослать, соседям сообщить — то самый отстойный вариант — это всё впихнуть в один сервис. Получится пиздопроебибна каша, в которой через полгода нихуя не разберёшься.

Вот смотри, нормальные пацаны для этого используют события (Events) или хуки жизненного цикла (Lifecycle Hooks) в ORM. Суть простая: основная логика делает своё дело — создаёт продукт, а потом кричит на всю деревню: «Эй, мужики, продукт создан!». А уже кто хочет — тот и реагирует. Чисто, изящно, волнение ебать как снижается.

Вот тебе пример, как это в чистой архитектуре выглядит, чтобы мозг не взорвался:

// 1. Сначала объявляем событие. Типа, официальная бумажка.
class ProductWasCreated {
    public function __construct(public Product $product) {}
}

// 2. Сервис, который создаёт продукт. Он тупо работает и шумит.
class CreateProductService {
    public function __construct(private EventDispatcher $dispatcher) {}

    public function execute(CreateProductCommand $command): Product {
        $product = new Product($command->name, $command->price);
        // ... тут он сохраняет это добро в базу через репозиторий

        // А вот тут магия! Кидаем событие в мир.
        $this->dispatcher->dispatch(new ProductWasCreated($product));
        return $product;
    }
}

// 3. А это уже какой-то другой мудак, который подслушал событие и делает свою фигню.
class SendWelcomeEmailOnProductCreation {
    public function __invoke(ProductWasCreated $event): void {
        $product = $event->product;
        // И пошло-поехало: письма, логи, оповещения — делай что хочешь.
    }
}

А теперь, бля, почему это овердохуища круто:

  • Гибкость пиздец: Захотел добавить новое действие — написал новый обработчик и подписал его на событие. Основной код сервиса даже не чихнул. Никакого «а давайте сюда ещё строчку».
  • Тестируется на ура: Сервис создания тестируешь отдельно, каждый обработчик — отдельно. Никаких танцев с бубном вокруг монолита.
  • Можно не тормозить пользователя: Обработчики-то можно в очередь задач засунуть (типа RabbitMQ). Создал продукт — сразу отдал ответ, а письма там пусть в фоне шлются, хоть минуту. Пользователь доволен, удивление пиздец какое.

Ну а если проект маленький и навороченный фреймворк под капотом (Laravel Eloquent или Doctrine), то можно и родными хуками воспользоваться — creating/created или там аннотациями @PrePersist. Но это уже как бы для лёгких случаев, когда не хочется заморачиваться с полноценной шиной событий. Главное — принцип понял? Отделяй мух от котлет, основную логику от побочной, и жить станет проще.