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.

Download sample module here

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.

https://api.drupal.org/api/drupal/vendor%21symfony%21http-kernel%21KernelEvents.php/class/KernelEvents/9.3.x

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.

You can download above discussed sample module here.

Get Free E-book
Get a free Ebook on Drupal 8 -theme tutorial
I agree to have my personal information transfered to MailChimp ( more information )
if you like this article Buy me a Coffee this will be an ispiration for me to write articles like this.

You may also like...