PHPackages                             sbooker/domain-events - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. sbooker/domain-events

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

sbooker/domain-events
=====================

Domain events

2.0.3(5y ago)04.7k12MITPHPPHP ^7.4 || ^8.0CI failing

Since Feb 2Pushed 10mo ago1 watchersCompare

[ Source](https://github.com/sbooker/domain-events)[ Packagist](https://packagist.org/packages/sbooker/domain-events)[ RSS](/packages/sbooker-domain-events/feed)WikiDiscussions master Synced yesterday

READMEChangelog (3)Dependencies (2)Versions (6)Used By (2)

[Read in English](README_EN.MD)

Domain Events Library (`sbooker/domain-events`)
===============================================

[](#domain-events-library-sbookerdomain-events)

[![Latest Version](https://camo.githubusercontent.com/8aedb7d4a9c215e98cd0f87b35a35d5aa52e702c95738ec4d41b9c808a1c37cf/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f73626f6f6b65722f646f6d61696e2d6576656e74732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/sbooker/domain-events)[![Software License](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](https://github.com/sbooker/domain-events/blob/master/LICENSE)[![PHP Version](https://camo.githubusercontent.com/0e207d81ab1bd3668ef8fbb6f24bee1992a6548d44861f850270ec6eb07923d3/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f73626f6f6b65722f646f6d61696e2d6576656e74732e7376673f7374796c653d666c61742d737175617265)](https://php.net)[![Total Downloads](https://camo.githubusercontent.com/524e0e25a0518e7282aef1bc4c5048d4eece543a1f04d58457bb2eeab4ccfda7/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f73626f6f6b65722f646f6d61696e2d6576656e74732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/sbooker/domain-events)[![Build Status](https://camo.githubusercontent.com/648d7599a81686b2e0fffa60475838e9854eeef94a039159488e699010a64475/68747470733a2f2f7472617669732d63692e6f72672f73626f6f6b65722f646f6d61696e2d6576656e74732e7376673f6272616e63683d322e78)](https://travis-ci.org/sbooker/domain-events)[![codecov](https://camo.githubusercontent.com/8f7b127e1c4ab28dbb35ca90d583bd907a4775ac8cb2345630ab29f4487cff58/68747470733a2f2f636f6465636f762e696f2f67682f73626f6f6b65722f646f6d61696e2d6576656e74732f6272616e63682f322e782f67726170682f62616467652e7376673f746f6b656e3d337543493974304d3251)](https://codecov.io/gh/sbooker/domain-events)

Простая, но мощная библиотека для реализации паттерна "События предметной области" (Domain Events) с упором на чистую архитектуру и принципы DDD. Базовая библиотека в экосистеме `sbooker/domain`

Главная особенность — встроенный механизм для автоматического отслеживания, кто совершил действие (Actor), без загрязнения доменной модели. Экосистема `sbooker/domain` предоставляет надежные способы их асинхронной обработки — как с использованием брокера сообщений, так и без него.

Ключевые особенности
--------------------

[](#ключевые-особенности)

- **Простота интеграции:** Используйте трейт `DomainEventCollector` в ваших сущностях.
- **Автоматическое обогащение событий:** Встроенный декоратор `ActorAwarePublisher` автоматически добавляет к событию информацию о текущем пользователе (`Actor`).
- **Нулевые зависимости:** Библиотека не зависит от других библиотек или какого-либо фреймворка.
- **Гибкость:** Основана на простых интерфейсах (`Publisher`, `ActorStorage`, `DomainEventSubscriber`), которые вы реализуете в своей инфраструктуре или используете библиотеки из экосистемы `sbooker/domain`.

Установка
---------

[](#установка)

```
composer require sbooker/domain-events
```

Архитектура и компоненты
------------------------

[](#архитектура-и-компоненты)

- `DomainEvent`: Абстрактный класс, от которого наследуются все ваши события. Уже содержит ID сущности, время возникновения и опционально — `Actor`.
- `DomainEventCollector`: Трейт, который вы добавляете в свои сущности (Агрегаты). Он предоставляет метод для сбора (`publish`) и последующей отправки (`dispatchEvents`) событий.
- `Publisher`: Интерфейс для диспетчера событий. Вы должны предоставить его реализацию или использовать библиотеку [sbooker/domain-events-persistence](https://github.com/sbooker/domain-events-persistence).
- `Actor`: Простой объект, идентифицирующий пользователя, который инициировал действие.
- `ActorStorage`: Интерфейс для получения текущего `Actor` из контекста приложения (например, из сессии или токена безопасности).
- `ActorAwarePublisher`: Декоратор для вашего `Publisher`, который автоматически "внедряет" `Actor` в событие перед его публикацией.

Быстрый старт
-------------

[](#быстрый-старт)

### 1. Подготовьте вашу сущность и событие

[](#1-подготовьте-вашу-сущность-и-событие)

Используйте трейт `DomainEventCollector` в вашем агрегате и определите класс события.

```
// src/Product.php
use Sbooker\DomainEvents\DomainEventCollector;
use Sbooker\DomainEvents\DomainEntity;

class Product implements DomainEntity
{
    use DomainEventCollector;

    public function __construct(UuidInterface $id, string $name)
    {
        // ...
        // Записываем событие о том, что произошло
        $this->publish(new ProductCreated($id, $name));
    }
}

// src/ProductCreated.php
use Sbooker\DomainEvents\DomainEvent;

final class ProductCreated extends DomainEvent {
    // ... ваш код события
}
```

### 2. Реализуйте сохранение событий (Transactional Outbox)

[](#2-реализуйте-сохранение-событий-transactional-outbox)

Рекомендуется сохранять события в специальную таблицу (`event`) в той же базе данных и в той же транзакции, что и сущность.

Для этого используйте решение из [sbooker/domain-events-persistence](https://github.com/sbooker/domain-events-persistence) и [sbooker/transaction-manager](https://github.com/sbooker/transaction-manager). Или напишите собственное:

```
// src/Infrastructure/OutboxPublisher.php
use Sbooker\DomainEvents\Publisher;
use Sbooker\DomainEvents\DomainEvent;

// Этот Publisher сохраняет события в репозиторий (например, в БД)
final class OutboxPublisher implements Publisher
{
    private OutboxEventRepository $repository;

    public function __construct(OutboxEventRepository $repository)
    {
        $this->repository = $repository;
    }

    public function publish(DomainEvent $event): void
    {
        $outboxEvent = new OutboxEvent($event);
        $this->repository->add($outboxEvent);
    }
}
```

В сервисном слое вы используете `OutboxPublisher`. Весь процесс сохранения происходит внутри одной транзакции.

```
// src/UseCase/CreateProduct/Handler.php
use Sbooker\DomainEvents\ActorAwarePublisher;

// 1. Создаем Publisher, который сохраняет события в БД
$publisher = new ActorAwarePublisher(
    new OutboxPublisher($outboxEventRepository), // add($product);

// 3. Передаем события в Publisher, который тоже сохранит их в БД
$product->dispatchEvents($publisher);

// 4. Коммитим транзакцию
// Doctrine EntityManager или ваш Unit of Work сохранит И продукт, И события в одной транзакции
$entityManager->flush();
```

### 3. Асинхронно обработайте события

[](#3-асинхронно-обработайте-события)

Для обработки событий используется фоновый процесс (воркер), который читает события из таблицы. Экосистема `sbooker/domain` поддерживает два основных подхода:

#### Подход 1: Прямая обработка (без брокера сообщений)

[](#подход-1-прямая-обработка-без-брокера-сообщений)

Этот подход идеален, когда вы хотите избежать усложнения инфраструктуры (без RabbitMQ, Kafka и т.д.), но при этом обеспечить надежную **параллельную обработку событий**.

Библиотека [sbooker/domain-events-persistence](https://github.com/sbooker/domain-events-persistence) предоставляет готовые инструменты для запуска нескольких воркеров, которые не будут мешать друг другу, благодаря механизму пессимистичных блокировок.

**Пример воркера-обработчика:**

```
// src/Command/ProcessOutboxEventsCommand.php
class ProcessOutboxEventsCommand extends Command
{
    public function execute(): int
    {
        // findUnprocessed() из sbooker/domain-events-persistence может блокировать
        // события для безопасной параллельной обработки.
        $eventsToProcess = $this->outboxRepo->findUnprocessed();

        foreach ($eventsToProcess as $outboxEvent) {
            try {
                // Напрямую вызываем нужный обработчик (Subscriber)
                $this->eventSubscriber->handle($outboxEvent->getDomainEvent());

                $this->outboxRepo->markAsProcessed($outboxEvent);
            } catch (\Exception $e) {
                // Логируем ошибку, событие будет обработано повторно.
                $this->logger->error('Failed to process event', ['id' => $outboxEvent->getId(), 'error' => $e]);
            }
        }
        $this->entityManager->flush();

        return Command::SUCCESS;
    }
}
```

#### Подход 2: Ретрансляция в брокер сообщений (классический Outbox)

[](#подход-2-ретрансляция-в-брокер-сообщений-классический-outbox)

Классический паттерн для микросервисной архитектуры или когда требуется интеграция с внешними системами через брокер сообщений.

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

**Пример воркера-ретранслятора:**

```
// src/Command/RelayOutboxEventsCommand.php
class RelayOutboxEventsCommand extends Command
{
    public function execute(): int
    {
        $eventsToRelay = $this->outboxRepo->findUnprocessed();

        foreach ($eventsToRelay as $outboxEvent) {
            try {
                // Отправляем событие во внешнюю шину
                $this->realMessageBroker->publish($outboxEvent->getDomainEvent());

                $this->outboxRepo->markAsProcessed($outboxEvent);
            } catch (\Exception $e) {
                // Логируем ошибку, повторим отправку при следующем запуске.
                $this->logger->error('Failed to relay event', ['id' => $outboxEvent->getId(), 'error' => $e]);
            }
        }
        $this->entityManager->flush();

        return Command::SUCCESS;
    }
}
```

License
-------

[](#license)

See [LICENSE](https://github.com/sbooker/domain-events/blob/master/LICENSE) file.

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance39

Infrequent updates — may be unmaintained

Popularity21

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity62

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~35 days

Total

5

Last Release

1838d ago

Major Versions

1.0.0 → 2.0.02021-05-03

### Community

Maintainers

![](https://www.gravatar.com/avatar/f97b1f6ea03776dda6e0ec26d1ff3a3309972d65bd1376eb111c2b35017af339?d=identicon)[sbooker](/maintainers/sbooker)

---

Top Contributors

[![sbooker](https://avatars.githubusercontent.com/u/3658174?v=4)](https://github.com/sbooker "sbooker (7 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/sbooker-domain-events/health.svg)

```
[![Health](https://phpackages.com/badges/sbooker-domain-events/health.svg)](https://phpackages.com/packages/sbooker-domain-events)
```

###  Alternatives

[grumpydictator/firefly-iii

Firefly III: a personal finances manager.

23.9k69.5k](/packages/grumpydictator-firefly-iii)[pocketmine/pocketmine-mp

A server software for Minecraft: Bedrock Edition written in PHP

3.5k78.3k90](/packages/pocketmine-pocketmine-mp)[shlinkio/shlink

A self-hosted and PHP-based URL shortener application with CLI and REST interfaces

5.1k5.2k](/packages/shlinkio-shlink)[markocupic/calendar-event-booking-bundle

Contao Calendar Event Booking Bundle

135.2k1](/packages/markocupic-calendar-event-booking-bundle)[mynaparrot/plugnmeet-sdk

plugNmeet PHP SDK

102.8k](/packages/mynaparrot-plugnmeet-sdk)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
