How to create custom event and subscribe to core events in Drupal 9
Events in Drupal help to communicate between various modules and components in a decoupled manner.
When request received in Drupal there are multiple events dispatched by the Drupal instance.
We can Subscribe to events and when an event occurs(dispatches), code snippets in subscribe will execute.
There will be inbuilt events in Drupal and in contributed modules. We can also create custom events.
Events are like advanced version of hooks in Drupal, Events have more advantages, like events can be dispatched multiple times in request cycle,
In order to understand more, for example in Java script onClick function is event subscriber , whenever an event click occurs , code snippet in onClick function will execute.
Here we are going to create below event components.
- Event Subscriber – A function which reacts to an event.
- Event Dispatcher – process of triggering events throughout the system
You have to understand the below points about event concept in Drupal.
- Event Subscribers – Sometimes called “Listeners”, are callable methods or functions that react to an event being propagated throughout the Event Registry.
- Event Registry – Where event subscribers are collected and sorted.
- Event Dispatcher – The mechanism in which an event is triggered, or “dispatched”, throughout the system.
- Event Context – Many events require a specific set of data that is important to the subscribers to an event. This can be as simple as a value passed to the Event Subscriber, or as complex as a specially created class that contains the relevant data.
Here we are going to discuss the topics below in this article.
- How to define a event in Drupal 9?
- How dispatch an event in Drupal 9?
- How to subscribe the dispatched event in Drupal9?
- How to subscribe to Core events in Drupal 9?
Here we are experimenting with the custom module dn_event.
How to define an event in Drupal 9?
In order to define an event , create a class SampleEvent in your custom module /src path.
/src/SampleEvent.php
Extend class from Symfony\Component\EventDispatcher\Event
So sampleEvent class will look like below,
namespace Drupal\dn_event\Form; use Symfony\Component\EventDispatcher\Event; class SampleEvent extends Event { const SUBMIT = 'event.submit'; protected $referenceID; public function __construct($referenceID) { $this->referenceID = $referenceID; } public function getReferenceID() { return $this->referenceID; } public function myEventDescription() { return "This is as an example event"; } }
You can define multiple custom functions and that can be called while dispatching or subscribing events.
How to dispatch an event in Drupal 9?
We can define events anywhere in our module code. First we have to include namespace.
use Drupal\dn_event\SampleEvent;
Then when you want to dispatch an event, add below code snippets in that place, here we are dispatching SampleEvent in a form submission function. Here fname is the one of the form field.
// load the Symfony event dispatcher object through services $dispatcher = \Drupal::service('event_dispatcher'); // creating our event class object. $event = new SampleEvent($form_state->getValue('fname')); // dispatching the event through the ‘dispatch’ method, // passing event name and event object ‘$event’ as parameters. $dispatcher->dispatch(SampleEvent::SUBMIT, $event);
In Above code we are setting referenceID value as fname,
How to subscribe to the dispatched event in Drupal 9?
Create the class file in module path /src/EventSubscriber/SampleEventSubScriber.php
We have to extend this class with EventSubscriberInterface
In this class we have to define function getSubscribedEvents function
This function will return events array with event and callback function details as below,
public static function getSubscribedEvents() { $events[SampleEvent::SUBMIT][] = array('doSomeAction', 800); return $events; }
Here 800 is the priority.
Complete code of SampleEventSubScriber.php provided below.
<?php /** * @file * Contains \Drupal\dn_event\ExampleEventSubScriber. */ namespace Drupal\dn_event\EventSubscriber; use Drupal\Core\Config\ConfigCrudEvent; use Drupal\Core\Config\ConfigEvents; use Drupal\dn_event\SampleEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** * Class ExampleEventSubScriber. * * @package Drupal\dn_event */ class SampleEventSubScriber implements EventSubscriberInterface { /** * {@inheritdoc} */ public static function getSubscribedEvents() { $events[SampleEvent::SUBMIT][] = array('doSomeAction', 800); return $events; } /** * Subscriber Callback for the event. * @param SampleEvent $event */ public function doSomeAction(SampleEvent $event) { \Drupal::messenger()->addMessage("The Example Event has been subscribed, which has bee dispatched on submit of the form with " . $event->getReferenceID() . " as Reference"); } }
So in doSomeAction function we are getting fname that we passed in form submission in variable $event->getReferenceID().
Tag event subscriber with event_subscriber
Create dn_event.services.yml file in module path. Add below in this file.
services: sample_events.event_subscriber_sample: class: Drupal\dn_event\EventSubscriber\SampleEventSubScriber tags: - { name: 'event_subscriber' }
So in this sample module, we have one form , which can bee accessed using /student/add page.
In routing.yml
dn_event.add_student: path: '/students/add' defaults: _title: 'Add Students' _form: '\Drupal\dn_event\Form\StudentForm' requirements: _access: 'TRUE'
Clear the cache. The event will be dispatched while submitting this form and the subscribe handler captures the event.
Access the page /students/add
You can see the form below.
Upon submission you can see below message that we are displaying from doSomeAction function in our event subscriber class (SampleEventSubscriber).
How to subscribe to Core events in Drupal 9?
Below page provides list of events already available in Drupal Core,
https://api.drupal.org/api/drupal/core%21core.api.php/group/events/
So in this section we are going to create a subscriber that subscribes KernelEvents::REQUEST
You can see list of available kernel events in Drupal in below page.
So this kernel request event will be dispatched when a Request event occurs at the very beginning of request dispatching. For example if hitting a custom form URL in your browser Kernel Request event occurs first before redirection to the page.
So here, we are redirecting to log in page if user is not logged in while accessing the URL – /students/add
So we will subscribe to the kernel request event,
Create class RedirectEventSubscriber class in module path /src/EventSubscriber/RedirectEventSubscriber.php
In this class below provided getSubscribedEvents() function.
public static function getSubscribedEvents() { $events[KernelEvents::REQUEST][] = array('checkAuthStatus'); return $events; }
Here checkAuthStatus is the call back function like doSomeAction in the previous example, so in this we are writing our actual action when a kernel request event occurs. Based on the below condition we are redirecting to the login page.
public function checkAuthStatus(GetResponseEvent $event) { global $base_url; if(\Drupal::routeMatch()->getRouteName() == 'dn_event.add_student' && \Drupal::currentUser()->isAnonymous()){ $response = new RedirectResponse($base_url . '/user/login', 301); $event->setResponse($response); $event->stopPropagation(); return; } }
Here dn_event.add_student is the route name of path /students/add in routing.yml file.
See full source code of the file /src/EventSubscriber/RedirectEventSubscriber.php
<?php namespace Drupal\dn_event\EventSubscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; /** * Event subscriber subscribing to KernelEvents::REQUEST. */ class RedirectEventSubscriber implements EventSubscriberInterface { public function checkAuthStatus(GetResponseEvent $event) { global $base_url; if(\Drupal::routeMatch()->getRouteName() == 'dn_event.add_student' && \Drupal::currentUser()->isAnonymous()){ $response = new RedirectResponse($base_url . '/user/login', 301); $event->setResponse($response); $event->stopPropagation(); return; } } public static function getSubscribedEvents() { $events[KernelEvents::REQUEST][] = array('checkAuthStatus'); return $events; } }
Finally update services.yml with RedirectEventSubscriber class.
services: sample_events.event_subscriber_sample: class: Drupal\dn_event\EventSubscriber\SampleEventSubScriber tags: - { name: 'event_subscriber' } dn_event.redirect_subscriber: class: Drupal\dn_event\EventSubscriber\RedirectEventSubscriber arguments: [] tags: - {name: event_subscriber}
Clear the cache, you can see event works, access the page /students/add as a logged in user and also as an anonymous user. As an anonymous user link will redirect to the login page.