Attention
TYPO3 v11 has reached end-of-life as of October 31th 2024 and is no longer being maintained. Use the version switcher on the top left of this page to select documentation for a supported version of TYPO3.
Need more time before upgrading? You can purchase Extended Long Term Support (ELTS) for TYPO3 v11 here: TYPO3 ELTS.
Event dispatcher (PSR-14 events)
The event dispatcher system was added to extend TYPO3's Core behaviour in TYPO3 v10.0. In the past, this was done via Extbase's signal/slot and TYPO3's custom hook system. The event dispatcher system is a fully-capable replacement for new code in TYPO3, as well as a possibility to migrate away from previous TYPO3 solutions.
Don't get hooked, listen to events! PSR-14 within TYPO3 v10.
-- Benni Mack @ TYPO3 Developer Days 2019
For a basic example on listening to an event, see the chapter Listen to an event in the extension development how-to section.
Hint
Additional background information on the implementation can be found at https://usetypo3.com/psr-14-events.html
Quick start
Dispatching an event
-
Create an event class.
An event class is basically a plain PHP object with getters for immutable properties and setters for mutable properties. It contains a constructor for all properties:
<?php declare(strict_types=1); namespace MyVendor\MyExtension\Event; final class DoingThisAndThatEvent { public function __construct( private string $mutableProperty, private readonly int $immutableProperty, ) { } public function getMutableProperty(): string { return $this->mutableProperty; } public function setMutableProperty(string $mutableProperty): void { $this->mutableProperty = $mutableProperty; } public function getImmutableProperty(): int { return $this->immutableProperty; } }
Read more about implementing event classes.
-
Inject the event dispatcher
If you are in a controller, the event dispatcher has already been injected, and in this case you can omit this step.
If the event dispatcher is not yet available, you need to inject it:
-
Dispatch the event
Create an event object with the data that should be passed to the listeners. Use the data of mutable properties as it suits your business logic:
<?php declare(strict_types=1); namespace MyVendor\MyExtension; use MyVendor\MyExtension\Event\DoingThisAndThatEvent; use Psr\EventDispatcher\EventDispatcherInterface; final class SomeClass { public function __construct( private readonly EventDispatcherInterface $eventDispatcher, ) { } public function doSomething(): void { // .. /** @var DoingThisAndThatEvent $event */ $event = $this->eventDispatcher->dispatch( new DoingThisAndThatEvent('foo', 2) ); $someChangedValue = $event->getMutableProperty(); // ... } }
Description of PSR-14 in the context of TYPO3
PSR-14 is a lean solution that builds upon wide-spread solutions for hooking into existing PHP code (Frameworks, CMS, and the like).
PSR-14 consists of the following four components:
The event dispatcher object
The Event
object is used to trigger an event. TYPO3 has a
custom event dispatcher implementation. In PSR-14 all event dispatchers of all
frameworks are implementing
\Psr\
, thus it is possible to
replace the event dispatcher with another. The Event
's main
method dispatch
is called in TYPO3 Core or extensions. It receives a
PHP object which will then be handed to all available listeners.
The listener provider
A Listener
object that contains all listeners which have been
registered for all events. TYPO3 has a custom listener provider that collects
all listeners during compile time. This component is not exposed outside of
TYPO3's Core Framework.
The events
An Event
object can be any PHP object and is called from TYPO3 Core or
an extension ("emitter") containing all information to be transported to the
listeners. By default, all registered listeners get triggered by an event,
however, if an event has the interface
\Psr\
implemented, a listener can
stop further execution of other event listeners. This is especially useful, if
the listeners are candidates to provide information to the emitter. This allows
to finish event dispatching, once this information has been acquired.
If an event can be modified, appropriate methods should be available, although due to PHP's nature of handling objects and the PSR-14 listener signature, it cannot be guaranteed to be immutable.
See also
The listeners
Extensions and PHP packages can add listeners that are registered via YAML. They
are usually associated to Event
objects by the fully-qualified class name
of the event to be listened on. It is the task of the listener provider to
provide configuration mechanisms to represent this relationship.
Advantages of the EventDispatcher over hooks and signals and slots
The main benefits of the EventDispatcher approach over Hooks and Extbase's SignalSlot dispatcher is an implementation which helps extension authors to better understand the possibilities by having a strongly typed system based on PHP. In addition, it serves as a bridge to also incorporate other events provided by frameworks that support PSR-14.
Impact on TYPO3 Core development in the future
TYPO3's event dispatcher serves as the basis to replace all signal/slots and hooks in the future,
however for the time being, hooks and registered Slots work the same way as before, unless migrated
to an event dDispatcher-like code, whereas a PHP E_
error can be triggered.
Some hooks / signal/slots might not be replaced 1:1 to event dispatcher, but rather superseded with a more robust or future-proof API.
Implementing an event listener in your extension
Hint
For a basic example on listening to an event, see the chapter Listen to an event in the extension development how-to section.
Registering the event listener
If an extension author wants to provide a custom event listener, an according
entry with the tag event.
can be added to the
Configuration/
file of that extension.
services:
# Place here the default dependency injection configuration
MyVendor\MyExtension\EventListener\NullMailer:
tags:
- name: event.listener
method: handleEvent
identifier: 'myListener'
before: 'redirects, anotherIdentifier'
event: TYPO3\CMS\Core\Mail\Event\AfterMailerInitializationEvent
Read how to configure dependency injection in extensions.
The tag name event.
identifies that a listener should be registered.
The custom PHP class \My
serves as the listener whose handle
method is called, once the
event
is dispatched. The identifier
is a common name, so
orderings can be built upon the identifier, the optional before
and
after
attributes allow for custom sorting against the identifier
of other listeners.
If no attribute method
is given, the class is treated as invokable, thus
its __
method will be called:
services:
# Place here the default dependency injection configuration
MyVendor\MyExtension\EventListener\NullMailer:
tags:
- name: event.listener
identifier: 'myListener'
before: 'redirects, anotherIdentifier'
event: TYPO3\CMS\Core\Mail\Event\AfterMailerInitializationEvent
Read how to configure dependency injection in extensions.
Changed in version 11.3
The event
tag can be omitted if the listener implementation has a corresponding
event type in the method signature. In that case the event class is automatically derived
from the method signature of the listener implementation.
The event listener class
An example listener, which hooks into the Mailer API to modify mailer settings to not send any emails, could look like this:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\EventListener;
use TYPO3\CMS\Core\Mail\Event\AfterMailerInitializationEvent;
final class NullMailer
{
public function __invoke(AfterMailerInitializationEvent $event): void
{
$event->getMailer()->injectMailSettings(['transport' => 'null']);
}
}
An extension can define multiple listeners.
Once the emitter is triggering an event, this listener is called automatically. Be sure to inspect the event's PHP class to fully understand the capabilities provided by an event.
Best practices
- When configuring listeners, it is recommended to add one listener class per
event type, and have it called via
__
.invoke () - When creating a new event PHP class, it is recommended to add an
Event
suffix to the PHP class, and to move it into an appropriate folder likeClasses/
to easily discover events provided by a package. Be careful about the context that should be exposed.Event - Emitters (TYPO3 Core or extension authors) should always use
Dependency Injection to receive the event
dispatcher object as a constructor argument, where possible, by adding a
type declaration for
\Psr\
.Event Dispatcher\ Event Dispatcher Interface
Any kind of event provided by TYPO3 Core falls under TYPO3's Core API
deprecation policy, except for its constructor arguments, which may vary. Events
that should only be used within TYPO3 Core, are marked as @internal
, just
like other non-API parts of TYPO3. Events marked as @internal
should be
avoided whenever technically possible.
Debugging event handling
A complete list of all registered event listeners can be viewed in the the
module System > Configuration > Event Listeners (PSR-14). The
system extension lowlevel
has to be installed for this module to be available.
To debug all events that are actually dispatched during a frontend request you can use the admin panel:
Go to Admin Panel > Debug > Events and see all dispatched events.
The system extension adminpanel
has to be installed for this module to be
available.