Events
From drupal.org - Events:
Events are part of the Symfony framework: they allow for different components of the system to interact and communicate with each other. Each event has a unique string name. One system component dispatches the event at an appropriate time; many events are dispatched by Drupal core and the Symfony framework in every request. Other system components can register as event subscribers; when an event is dispatched, a method is called on each registered subscriber, allowing each one to react.
Dispatching Events
Drupal's default event dispatcher is \Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher
.
To alert the dispatcher about an event:
ContainerAwareEventDispatcher::dispatch($eventName, Event $event = null);
The base event class is \Symfony\Component\EventDispatcher\Event
.
You will probably need to extend this class to provide necessary data to event subscribers.
For example - core/lib/Drupal/Core/Render/PageDisplayVariantSelectionEvent.php
:
<?php
namespace Drupal\Core\Render;
use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
use Drupal\Core\Cache\RefinableCacheableDependencyTrait;
use Drupal\Core\Routing\RouteMatchInterface;
use Symfony\Component\EventDispatcher\Event;
/**
* Event fired when rendering main content, to select a page display variant.
*
* Subscribers of this event can call the following setters to pass additional
* information along to the selected variant:
* - self::setPluginConfiguration()
* - self::setContexts()
* - self::addCacheableDependency()
*
* @see \Drupal\Core\Render\RenderEvents::SELECT_PAGE_DISPLAY_VARIANT
* @see \Drupal\Core\Render\MainContent\HtmlRenderer
*/
class PageDisplayVariantSelectionEvent extends Event implements RefinableCacheableDependencyInterface {
// ...
/**
* The selected page display variant plugin ID.
*
* @var string
*/
protected $pluginId;
// ...
/**
* The selected page display variant plugin ID.
*
* @param string $plugin_id
* The ID of the page display variant plugin to use.
*
* @return $this
*/
public function setPluginId($plugin_id) {
$this->pluginId = $plugin_id;
return $this;
}
// ...
}
Subscribing to Events
- Define a service in your module and tag it with
event_subscriber
.
For example - core/modules/block/block.services.yml
:
services:
# ...
block.page_display_variant_subscriber:
class: Drupal\block\EventSubscriber\BlockPageDisplayVariantSubscriber
tags:
- { name: event_subscriber }
# ...
- Define a class for your subscriber service that implements
Symfony\Component\EventDispatcher\EventSubscriberInterface
.
For example - core/modules/block/src/EventSubscriber/BlockPageDisplayVariantSubscriber.php
<?php
namespace Drupal\block\EventSubscriber;
use Drupal\Core\Render\PageDisplayVariantSelectionEvent;
use Drupal\Core\Render\RenderEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Selects the block page display variant.
*
* @see \Drupal\block\Plugin\DisplayVariant\BlockPageVariant
*/
class BlockPageDisplayVariantSubscriber implements EventSubscriberInterface {
// ...
}
- Return a list of events mapped to methods within the same class to call when the event is triggered.
For example - core/modules/block/src/EventSubscriber/BlockPageDisplayVariantSubscriber.php
:
<?php
// ...
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events[RenderEvents::SELECT_PAGE_DISPLAY_VARIANT][] = ['onSelectPageDisplayVariant'];
return $events;
}
// ...
- Write the callback methods declared above.
For example - core/modules/block/src/EventSubscriber/BlockPageDisplayVariantSubscriber.php
:
<?php
// ...
/**
* Selects the block page display variant.
*
* @param \Drupal\Core\Render\PageDisplayVariantSelectionEvent $event
* The event to process.
*/
public function onSelectPageDisplayVariant(PageDisplayVariantSelectionEvent $event) {
$event->setPluginId('block_page');
}
// ...
Subscriber Priority
You can also set priority for your subscribed events. Higher priority numbers are executed first.
Example from drupal.org - Events:
<?php
public static function getSubscribedEvents() {
// Subscribe to kernel terminate with priority 100.
$events[KernelEvents::TERMINATE][] = array('onTerminate', 100);
// Subscribe to kernel request with default priority of 0.
$events[KernelEvents::REQUEST][] = array('onRequest');
return $events;
}
If two event subscribers have the same priority the module with the lower weight fires first.
Symfony uses higher numbers as higher priority but Drupal uses the reverse. This is why for Event
priority it uses higher numbers, but for module handling the lower number receives priority.
If multiple subscribers exist in the same module, they are fired in the order they are defined, but if order is important, it's recommended to explicitly define a priority instead of relying on the default conventions in the event they ever change.
Questions
What two things do you need to subscribe to events?
- Create a class which implements
Symfony\Component\EventDispatcher\EventSubscriberInterface
- Define a service in your module for the class you created, and give it the
event_subscriber
tag
How can you dispatch an event with Drupal's default class?
ContainerAwareEventDispatcher::dispatch($eventName, Event $event = null)