logo
Submitted by Ivan Abramenko on Thu, 10/03/2019 - 16:44

The events system allows you to build more complex systems with the ability to change functionality using custom code for certain events. Many hooks from Drupal 7 have been replaced by events. This allowed to unify the work of many parts of Drupal and additional copy modules. The events system itself came from Symfony and consists of the following parts:

Event Subscribers - “Subscribers” to specific events are functions or methods that fire on certain events. In code, is a class that implements the class:

\Symfony\Component\EventDispatcher\EventSubscriberInterface

Event Registry - Collects and sorts according to the sequence of triggering Event Subscribers. Registry for subscribers stored in the Event Dispatcher object as an array of key-value of the event name and priority of the event (order). When an event is logged as service, the event is logged as a globally available dispatcher.

Event Dispatcher - The mechanism in which the event is triggered and allows you to call Event Subscribers at the right time. Mostly at least one of the Event Dispatcher instances is represented as service. The Event Dispatcher class implements: 

\Symfony\Component\EventDispatcher\EventDispatcherInterface

Event Context - Many events require a specific data set, which may be important for the event subscriber. This may be a simple value passed to Event Subscriber, or it may be a class that contains the necessary data. The Event Context class extends the class:

 \Symfony\Component\EventDispatcher\Event

Let's look at examples of working with events to make it clear how this works.

I added all the code on github to the drupalbook_examples module, you can download the module and add it to your website:

https://github.com/levmyshkin/drupalbook8

Drupal 8 doesn't have hook_init() anymore:

https://www.drupal.org/node/2013014

Now you can execute the necessary code when loading the page using Event Subscriber:

modules/custom/drupalbook_examples/drupalbook_examples.services.yml

services:
  drupalbook_examples.event_subscriber:
    class: Drupal\drupalbook_examples\EventSubscriber\DrupalbookExamplesSubscriber
    tags:
    - {name: event_subscriber}

In order to connect Event Subscriber you need to add the service to the module file *.services.yml. Here we describe what class the Event subscriber will be and write the name event_subscriber in the tags. Now we need to create the event subscriber class:

modules/custom/drupalbook_examples/src/EventSubscriber/DrupalbookExamplesSubscriber.php

<?php
 
namespace Drupal\drupalbook_examples\EventSubscriber;
 
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 
class DrupalbookExamplesSubscriber implements EventSubscriberInterface {
 
  public function checkForRedirection(GetResponseEvent $event) {
    if ($event->getRequest()->query->get('redirect-me')) {
      $event->setResponse(new RedirectResponse('http://example.com/'));
    }
  }
 
  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events[KernelEvents::REQUEST][] = array('checkForRedirection');
    return $events;
  }
 
}

?>

Let's look at the main points of this code. The class of our event subscriber implements the EventSubscriberInterface interface, the main method of this interface is getSubscribedEvents(), it determines which events our subscriber will respond to and what methods it will call in case the event occurs. In our case, an event will occur at the very beginning of the Drupal’s work after processing the request. Here we call the checkForRedirection () method if an event occurs. In the method itself, if we have get the redirect-me parameter, then it redirects the user to example.com. 

This code will work whenever you load a page, or almost always. The fact is, if your page is cached, then it can be given from the cache and Drupal will not work out all the pieces of code and the cache will immediately work. 

In this case, you can use the hook_boot () hook analog, which, like hook_init (), has been removed from Drupal 8:

https://www.drupal.org/node/1909596

Let's add another redirectBeforeWithoutCache() method

modules/custom/drupalbook_examples/src/EventSubscriber/DrupalbookExamplesSubscriber.php:

<?php
 
namespace Drupal\drupalbook_examples\EventSubscriber;
 
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 
class DrupalbookExamplesSubscriber implements EventSubscriberInterface {
 
  public function checkForRedirection(GetResponseEvent $event) {
    if ($event->getRequest()->query->get('redirect-me')) {
      $event->setResponse(new RedirectResponse('http://example.com/'));
    }
  }
 
  public function redirectBeforeWithoutCache(GetResponseEvent $event) {
    if ($event->getRequest()->query->get('redirect-me')) {
      $event->setResponse(new RedirectResponse('http://example.com/'));
    }
  }
 
  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events[KernelEvents::REQUEST][] = array('checkForRedirection');
    $events[KernelEvents::REQUEST][] = array('redirectBeforeWithoutCache', 300);
    return $events;
  }
 
}


?>

In the getSubscribedEvents () method, we registered the response to the same KernelEvents :: REQUEST event, only in this case we set the priority to 300, which allows this method to work earlier than the methods that fire for this event, but which have lower priority. Now the redirect will work even for a cached page. 

There are quite a few events in Drupal that can be added to Subscriber, you can find more examples in the official documentation:

https://www.drupal.org/docs/8/creating-custom-modules/event-systems-overview-how-to-subscribe-to-and-dispatch-events