0Pricing
PHP Academy · Aula

Eventos e serviços de domínio

Registre fatos de negócio com eventos e serviços de domínio.

Eventos e serviços de domínio é uma aula grátis de PHP Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de PHP Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de PHP Academy inclui 4 aulas no total.

Registrando fatos de negócio

Nem todo comportamento se encaixa em uma única entidade. Os eventos de domínio registram fatos de negócio significativos que já aconteceram (OrderPlaced), permitindo que outras partes do sistema reajam. Os serviços de domínio contêm a lógica de domínio que não pertence naturalmente a uma única entidade ou objeto de valor. Esta lição mostra como ambos mantêm seu modelo expressivo sem sobrecarregar os agregados.

O que é um evento de domínio

Um evento de domínio é um registro imutável de algo que ocorreu no domínio, nomeado no passado usando a linguagem ubíqua: OrderPlaced, PaymentReceived, CustomerRelocated. Ele carrega os dados que descrevem o fato e o momento em que aconteceu. É um objeto de valor: criado uma vez, nunca alterado.

<?php
final class OrderPlaced {
    public function __construct(
        public readonly string $orderId,
        public readonly int $totalCents,
        public readonly DateTimeImmutable $occurredOn = new DateTimeImmutable()
    ) {}
}
$e = new OrderPlaced('o1', 1300);
echo $e->orderId, ' @ ', $e->occurredOn->format('H:i'), PHP_EOL;

Agregados registram eventos

A raiz do agregado registra eventos como parte de seu comportamento e depois os expõe para que a camada de aplicação possa despachá-los depois da confirmação da transação. O próprio agregado não os despacha — ele apenas os registra. Isso mantém o domínio livre de preocupações de infraestrutura.

<?php
final class OrderPlaced {
    public function __construct(public readonly string $orderId) {}
}
abstract class AggregateRoot {
    private array $events = [];
    protected function record(object $e): void { $this->events[] = $e; }
    public function releaseEvents(): array {
        $out = $this->events; $this->events = []; return $out;
    }
}
final class Order extends AggregateRoot {
    public function __construct(public readonly string $id) {
        $this->record(new OrderPlaced($id));
    }
}
$o = new Order('o1');
foreach ($o->releaseEvents() as $e) { echo get_class($e), PHP_EOL; }

Despachar após a confirmação

O serviço de aplicação persiste o agregado, confirma a transação e então despacha os eventos liberados. Despachar depois da confirmação garante que os manipuladores nunca reajam a um fato cuja transação foi revertida. A ordem abaixo é o modelo seguro para efeitos colaterais, como e-mails ou chamadas externas.

<?php
final class PlaceOrderService {
    public function __construct(
        private object $repo,
        private object $dispatcher
    ) {}
    public function handle(object $order): void {
        // 1. persist inside a transaction
        $this->repo->save($order);   // commit happens here
        // 2. only AFTER commit, release and dispatch
        foreach ($order->releaseEvents() as $event) {
            $this->dispatcher->dispatch($event);
        }
    }
}
echo "order persisted, then events dispatched", PHP_EOL;

Os manipuladores reagem

Cada evento pode ter vários manipuladores, desacoplados do agregado que o gerou. Um despachante PSR-14 encaminha o evento aos ouvintes registrados. Adicionar uma nova reação (análise de dados, notificação) significa adicionar um ouvinte, sem nunca tocar no agregado.

<?php
final class OrderPlaced { public function __construct(public readonly string $orderId) {} }

final class Dispatcher {
    private array $listeners = [];
    public function on(string $event, callable $l): void { $this->listeners[$event][] = $l; }
    public function dispatch(object $event): void {
        foreach ($this->listeners[$event::class] ?? [] as $l) { $l($event); }
    }
}
$d = new Dispatcher();
$d->on(OrderPlaced::class, fn($e) => print("email for {$e->orderId}\n"));
$d->on(OrderPlaced::class, fn($e) => print("analytics for {$e->orderId}\n"));
$d->dispatch(new OrderPlaced('o1'));

Eventos entre limites

Os eventos de domínio desacoplam agregados que precisam permanecer consistentes sem compartilhar uma transação. Um OrderPlaced no contexto de vendas pode acionar a reserva de estoque em outro contexto por meio de um evento. Internamente, eles são objetos; entre serviços, frequentemente se tornam eventos de integração em um intermediário de mensagens. Mantenha os eventos de domínio internos e os eventos de integração externos distintos — o contrato público não deve ser o seu modelo interno.

O que é um serviço de domínio

Um serviço de domínio contém uma lógica de domínio que:

  • envolve vários agregados ou entidades, portanto não se encaixa em nenhum deles; e
  • é um conceito genuíno do domínio, expresso na linguagem ubíqua.

Ele é sem estado e opera sobre objetos de domínio. Um serviço FundsTransfer que debita uma conta e credita outra é o exemplo clássico.

Um serviço de domínio no código

O serviço coordena dois agregados, mas não mantém estado próprio. A lógica não pertence a nenhuma das contas, portanto fica em um serviço nomeado de acordo com a operação do domínio.

<?php
final class Account {
    public function __construct(public readonly string $id, private int $cents) {}
    public function withdraw(int $c): void {
        if ($c > $this->cents) { throw new DomainException('insufficient funds'); }
        $this->cents -= $c;
    }
    public function deposit(int $c): void { $this->cents += $c; }
    public function balance(): int { return $this->cents; }
}
final class MoneyTransferService {
    public function transfer(Account $from, Account $to, int $cents): void {
        $from->withdraw($cents);
        $to->deposit($cents);
    }
}
$a = new Account('a', 1000); $b = new Account('b', 0);
(new MoneyTransferService())->transfer($a, $b, 400);
echo $a->balance(), '/', $b->balance(), PHP_EOL; // 600/400

Serviço de domínio versus serviço de aplicação

Não os confunda:

  • Um serviço de domínio contém lógica de negócio e vive na camada de domínio; ele não sabe nada sobre transações ou requisições da web.
  • Um serviço de aplicação coordena um caso de uso: carrega agregados dos repositórios, chama a lógica de domínio, confirma a transação e despacha eventos. É um coordenador enxuto, sem regras de negócio próprias.

Evite a armadilha dos serviços

É fácil usar serviços de domínio em excesso. Se a lógica puder residir em uma entidade ou objeto de valor, ela deverá ficar ali: é assim que você evita um modelo anêmico. Recorra a um serviço de domínio somente quando a operação realmente abranger vários agregados ou não tiver um lugar natural. Caso contrário, você retirará o comportamento das entidades e recriará um código procedural.

Coordenação pelo serviço de aplicação

Juntando tudo: um serviço de aplicação enxuto carrega agregados dos repositórios, invoca um serviço de domínio para a lógica entre agregados, persiste o resultado e despacha eventos. Ele contém apenas coordenação — nenhuma regra de negócio própria.

<?php
final class Account {
    public function __construct(public readonly string $id, public int $cents) {}
}
final class MoneyTransferService { // domain service: the rule
    public function transfer(Account $from, Account $to, int $c): void {
        if ($c > $from->cents) { throw new DomainException('insufficient'); }
        $from->cents -= $c; $to->cents += $c;
    }
}
final class TransferApp { // application service: orchestration only
    public function __construct(private MoneyTransferService $domain) {}
    public function run(Account $a, Account $b, int $c): void {
        $this->domain->transfer($a, $b, $c); // then repo->save + dispatch
    }
}
$a = new Account('a', 1000); $b = new Account('b', 0);
(new TransferApp(new MoneyTransferService()))->run($a, $b, 250);
echo $a->cents, '/', $b->cents, PHP_EOL; // 750/250

Verificação rápida

Eventos e serviços.

Recapitulação

Você capturou fatos de negócio e lógica sem um lugar definido. Eventos de domínio são registros imutáveis no passado que os agregados registram e a camada de aplicação despacha após a confirmação, desacoplando reações e atravessando limites de agregados. Serviços de domínio contêm lógica de domínio sem estado que abrange vários agregados, distinta dos serviços de aplicação enxutos que apenas coordenam casos de uso. Use ambos com moderação, para que o comportamento permaneça nas entidades e nos objetos de valor onde ele realmente pertence.

Perguntas Frequentes

A aula “Eventos e serviços de domínio” é grátis?

Sim — o texto completo de “Eventos e serviços de domínio” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de PHP Academy, atualize para CoddyKit PRO. O curso de PHP Academy inclui 4 aulas no total.

O que vou aprender em “Eventos e serviços de domínio”?

Registre fatos de negócio com eventos e serviços de domínio. Você pratica PHP Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar PHP Academy?

Nenhuma experiência prévia é necessária. PHP Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.

Quanto tempo leva a aula “Eventos e serviços de domínio”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de PHP Academy?

Sim. Cada aula de PHP Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Blocos básicos de DDD: entidades e objetos de valor
  2. Agregados, repositórios e fábricas
  3. Eventos e serviços de domínio
  4. Contextos delimitados e mapeamento de contextos
← Voltar para PHP Academy