Various Yii 3.0 related documentation
Events allow you to make custom code executed at certain execution points without modifying existing code. You can attach a custom code called “handler” to an event so that when the event is triggered, the handler gets executed automatically.
For example, when a user is signed up, you need to send a welcome email. You can do it right in
the SignupService
but then when you will additionally need to resize user’s avatar image you’ll have
to change SignupService
code again. In other words, SignupService
will be coupled to both code sending
welcome email and code resizing avatar image.
To avoid it, instead of telling what do after signup explicitly you can, instead, raise UserSignedUp
event
and then finish a signup process. The code sending an email and the code resizing avatar image, will attach to the event
and, therefore, will be executed. If you’ll ever need to do more on signup, you’ll be able to attach extra event
handlers without modifying SignupService
.
For raising events and attaching handlers to these events, Yii has a special service called event dispatcher. It’s available from yiisoft/event-dispatcher package.
An event handler is PHP callable that gets executed when the event it’s attached to is triggered.
The signature of an event handler is:
function (EventClass $event) {
// handle it
}
You can attach a handler to an event like the following:
use Yiisoft\EventDispatcher\Provider\Provider;
class WelcomeEmailSender
{
public function __construct(Provider $provider)
{
$provider->attach([$this, 'handleUserSignup']);
}
public function handleUserSignup(UserSignedUp $event)
{
// handle it
}
}
The attach()
method is accepting a callback. Based on a type of this callback argument event type is
determined.
You may attach one or more handlers to a single event. When an event is triggered, the attached handlers
will be called in the order that they were attached to the event. In case an event implements
Psr\EventDispatcher\StoppableEventInterface
, event handler can stop executing the rest of the handlers
that follow it if isPropagationStopped()
returns true
.
In general, it’s better not to rely on the order of event handlers.
Events are raised like the following:
use Psr\EventDispatcher\EventDispatcherInterface;
class SignupService
{
private EventDispatcherInterface $eventDispatcher;
public function __construct(EventDispatcherInterface $eventDispatcher)
{
$this->eventDispatcher = $eventDispatcher;
}
public function signup(SignupForm $form)
{
// handle signup
$event = new UserSignedUp($form);
$this->eventDispatcher->dispatch($event);
}
}
First, you create an event supplying it with data that may be useful for handlers. Then you dispatch the event.
The event class itself may look like the following:
final class UserSignedUp
{
private SignupForm $form;
public function __construct(SignupForm $form)
{
$this->form = $form;
}
public function getSignupForm(): SignupForm
{
return $this->form;
}
}
Events don’t have any name or wildcard matching on purpose. Event class names and class/interface hierarchy and composition could be used to achieve great flexibility:
interface DocumentEvent
{
}
class BeforeDocumentProcessed implements DocumentEvent
{
}
class AfterDocumentProcessed implements DocumentEvent
{
}
With the interface, you can listen to all document-related events:
$provider->attach(function (DocumentEvent $event) {
// log events here
});
To detach a handler from an event you can call detach()
method:
$provider->detach(DocmentEvent::class);
Event handlers are usually assigned via application config. See “Configuration” for details.