Eventos
Eventos permitem executar código personalizado em determinados pontos da execução, sem alterar o código que emite o evento. Você associa a um evento um código personalizado chamado listener. Quando o evento é disparado, o listener é executado.
Por exemplo, quando um usuário se cadastra, você precisa enviar um e-mail de boas-vindas. Dá para fazer isso no SignupService. Mais tarde, quando você também precisar redimensionar a imagem de avatar do usuário, o serviço vai ter que saber disso também.
Um fluxo mais limpo é disparar um evento UserSignedUp a partir do SignupService. O remetente do e-mail de boas-vindas e o processador de avatar escutam esse evento. Trabalho adicional relacionado ao cadastro pode ser incluído registrando outro listener.
O Yii usa o yiisoft/yii-event para a configuração de eventos da aplicação. Ele é construído sobre o pacote yiisoft/event-dispatcher, que fornece um event dispatcher compatível com PSR-14.
Classes de evento
Um evento é um objeto. Normalmente ele contém os dados de que os listeners precisam:
final readonly class UserSignedUp
{
public function __construct(
public SignupForm $form,
) {}
}Listeners de eventos
Um listener de evento é um callable do PHP que recebe um evento:
static function (UserSignedUp $event): void {
// Envia um e-mail de boas-vindas.
}Você também pode usar uma classe invocável:
final readonly class WelcomeEmailSender
{
public function __invoke(UserSignedUp $event): void
{
// Envia um e-mail de boas-vindas.
}
}Configurando listeners de eventos
Em uma aplicação, configure os listeners em:
config/events.phppara todos os tipos de aplicação.config/events-web.phppara eventos da aplicação web.config/events-console.phppara eventos da aplicação de console.
A configuração é um array em que as chaves são os nomes das classes de evento e os valores são listas de listeners:
<?php
declare(strict_types=1);
use App\Event\UserSignedUp;
use App\EventListener\WelcomeEmailSender;
use App\Service\AvatarProcessor;
return [
UserSignedUp::class => [
WelcomeEmailSender::class,
static fn (UserSignedUp $event, AvatarProcessor $avatarProcessor) => $avatarProcessor->resize($event->form),
],
];O listener pode ser uma closure, um array callable, um objeto invocável, o nome de uma classe invocável ou um alias de DI. Para listeners do tipo closure e array callable, os parâmetros depois do primeiro (o evento) são resolvidos pelo container de DI. Nomes de classes invocáveis são instanciados pelo container.
As dependências são resolvidas quando o evento é disparado.
Disparando eventos
Para disparar um evento, use Psr\EventDispatcher\EventDispatcherInterface:
use Psr\EventDispatcher\EventDispatcherInterface;
final readonly class SignupService
{
public function __construct(
private EventDispatcherInterface $eventDispatcher,
) {}
public function signup(SignupForm $form): void
{
// Cadastra o usuário.
$this->eventDispatcher->dispatch(new UserSignedUp($form));
}
}O dispatcher pede a um listener provider os listeners que correspondem ao evento e os chama um por um.
Ordem dos listeners
Quando vários listeners são configurados para o mesmo evento, eles são chamados na ordem em que aparecem na configuração. Se um evento implementa Psr\EventDispatcher\StoppableEventInterface, o dispatcher verifica isPropagationStopped() antes de chamar o próximo listener. Quando ele retorna true, o dispatcher para de processar o evento.
Mantenha os listeners independentes sempre que possível. A ordem é útil para necessidades técnicas, mas a lógica de negócio costuma ser mais fácil de manter quando cada listener consegue rodar sozinho.
Hierarquia de eventos
Eventos não têm nomes nem correspondência por curinga. Nomes de classes de evento, interfaces e herança podem ser usados quando um listener precisa tratar vários eventos relacionados:
interface DocumentEvent
{
}
final readonly class BeforeDocumentProcessed implements DocumentEvent
{
}
final readonly class AfterDocumentProcessed implements DocumentEvent
{
}Com a interface, você pode escutar todos os eventos relacionados a documentos:
use Yiisoft\EventDispatcher\Provider\ListenerCollection;
use Yiisoft\EventDispatcher\Provider\Provider;
$listeners = (new ListenerCollection())
->add(static function (DocumentEvent $event): void {
// Registra em log os eventos de documentos.
});
$provider = new Provider($listeners);Configuração manual do listener provider
Em uma aplicação, use a configuração de eventos. Para código de pacotes ou testes, você pode criar um listener provider manualmente:
use Yiisoft\EventDispatcher\Dispatcher\Dispatcher;
use Yiisoft\EventDispatcher\Provider\ListenerCollection;
use Yiisoft\EventDispatcher\Provider\Provider;
$listeners = (new ListenerCollection())
->add(static function (UserSignedUp $event): void {
// Envia um e-mail de boas-vindas.
});
$provider = new Provider($listeners);
$dispatcher = new Dispatcher($provider);
$dispatcher->dispatch(new UserSignedUp($form));ListenerCollection::add() retorna uma nova instância da coleção. Atribua o resultado ao montar uma coleção passo a passo:
$listeners = new ListenerCollection();
$listeners = $listeners->add(
static function (UserSignedUp $event): void {
// Envia um e-mail de boas-vindas.
},
UserSignedUp::class,
);