PHP code example of sbooker / domain-events

1. Go to this page and download the library: Download sbooker/domain-events library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

sbooker / domain-events example snippets


// 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 {
    // ... ваш код события
}

// 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);
    }
}

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

// 1. Создаем Publisher, который сохраняет события в БД
$publisher = new ActorAwarePublisher(
    new OutboxPublisher($outboxEventRepository), // <-- Используем наш новый Publisher
    new SymfonyActorStorage($security)
);

// 2. Выполняем бизнес-логику
$product = new Product(Uuid::uuid4(), 'Ноутбук');
$productRepository->add($product);

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

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

// 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;
    }
}

// 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;
    }
}