Drupal 8 is a Great Way of Developing a Useful and Valuable Website - Part Twenty One

feature-top

The website world is a great place to be because it offers many people so many good and useful information that they can be used to accomplish tasks to solve problems.

In today’s article, we are going to be talking about Events in Drupal 8, to understand how various system components in Drupal 8 are able to remain independent and decoupled while being able to communicate with each other, with the help of events.

Existing code doesn’t have to be modified or altered in Drupal, because module developers can just alter or extend Drupal through events. Plugins, Hooks, and Services are also other ways of extending Drupal, without altering the core code of Drupal 8.

During code execution, a known event is triggered at a specific point by an event dispatcher; this is part of the event system. Another part of the event system has to do with triggering the custom code, by consisting of a pattern for subscribing so that the user is notified whenever an event is triggered by the event dispatcher.

It is very important for components that form part of a large and complex system such as Drupal, to communicate with one another. A mediator object facilitates this communication in Drupal 8 because if objects can refer to one another explicitly, maintenance can turn into a nightmare. Various events are triggered or dispatched, by Drupal and the underlying Symphony code base, when responding to requests so that subscribers to that event can go to work and do their thing.

Actions taken by custom code can be communicated by dispatching events in the custom code, so that components of the systems, can be notified. Custom logic is performed by event subscribers when they respond to specific events being triggered.

A good example of this happens when a configuration change occurs in a module; settings in the Drupal system, which are related to that module must also make those changes. The onClick event used in JavaScript works like events, because the onClick event, sends or trigger to a custom code when a user clicks on a button, which has the onClick event.

By dispatching events and listening to them, the EventDispatcher component, of the event system. The event dispatcher allows the components applications to communicate with each other.

Through the mediator and the observer design pattern, the EventDispatcher can allow communication of components within an application, to make the custom code more flexible and truly extensible.

To create a dispatcher within your code you would follow the code below,

use Symfony\Component\EventDispatcher\EventDispatcher;
$dispatcher = new EventDispatcher();

The code below shows us how to connect an EventDispatcher to a listener, which would be triggered when the EventDispatcher is called in the customer code.

$listener = new AcmeListener();
$dispatcher->addListener('acme.foo.action', array($listener, 'onFooAction'));

The dispatcher calls the AcmeListener::onFooAction() class when the acme.foo.the action event is dispatched in the code above. The code below shows what the class would look like.

use Symfony\Component\EventDispatcher\Event;

 

class AcmeListener

{

    // ...

 

    public function onFooAction(Event $event)

    {

        // ... do something

    }

}

 

Once the listener has been added, now it’s time to know how to subscribe to events, event subscriber implementation allows modules to be notified when a specific event or events are triggered. Defining a service tagged with ‘event_subscriber’, or defining a class which implements the \Symfony\Component\EventDispatcher\EventSubscriberInterface class and subscribes to one or more events, is the way that modules can subscribe to one or more events. The (my_module).services.yml file would be the place where a new service with the tag “event_subscriber”, can be defined.  Example:

# Subscribing to an event requires you to create a new service tagged with the
# 'event_subscriber' tag. This tells the service container, and by proxy the
# event dispatcher service, that the class registered here can be queried to get
# a list of events that it would like to be notified about.
services:
  # Give your service a unique name, convention is to prefix service names with
  # the name of the module that implements them.
  events_example_subscriber:
    # Point to the class that will contain your implementation of
    # \Symfony\Component\EventDispatcher\EventSubscriberInterface
    class: Drupal\events_example\EventSubscriber\EventsExampleSubscriber
    tags:
      - {name: event_subscriber}

In order to define an event subscriber class, the \Symfony\Component\EventDispatcher\EventSubscriberInterface interface is implemented by that class.

You’ll have to know what events you need to subscribe to before you can use this class; which is responsible for defining a getSubscribedEvents() method. A list of events that a user can subscribe to is returned by the getSubscribedEvents() method. Also, the name of the method that is going to be called, when that event is called, is also defined by the getSubscribedEvents() method.

The event subscriber class is also responsible for defining a public method, which receives an event object as its argument, for each subscribed event. Also, the code we want to execute when an event is triggered is also contained in this class.  Example.

<?php
// By convention, classes subscribing to an event live in the
// Drupal/{module_name}/EventSubscriber namespace.
namespace Drupal\events_example\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Messenger\MessengerTrait;
use Drupal\events_example\Event\IncidentEvents;
use Drupal\events_example\Event\IncidentReportEvent;
/**
 * Subscribe to IncidentEvents::NEW_REPORT events and react to new reports.
 *
 * In this example we subscribe to all IncidentEvents::NEW_REPORT events and
 * point to two different methods to execute when the event is triggered. In
 * each method we have some custom logic that determines if we want to react to
 * the event by examining the event object, and the displaying a message to the
 * user indicating whether or not that method reacted to the event.
 *
 * @ingroup events_example
 */
class EventsExampleSubscriber implements EventSubscriberInterface {
  use StringTranslationTrait;
  use MessengerTrait;
  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    // Return an array of events that you want to subscribe to mapped to the
    // method on this class that you would like called whenever the event is
    // triggered. A single class can subscribe to any number of events. For
    // organization purposes it's a good idea to create a new class for each
    // unique task/concept rather than just creating a catch all class for all
    // event subscriptions. 
    // See EventSubscriberInterface::getSubscribedEvents() for an explanation
    // of the array's format. 
    // The array key is the name of the event your want to subscribe to. Best
    // practice is to use the constant that represents the event as defined by
    // the code responsible for dispatching the event. This way if for example
    // the string name of an event changes your code will continue to work.
    // You can get a list of event constants for all events triggered by core
    // here https://api.drupal.org/api/drupal/core%21core.api.php/group/events/8.2.x.
    //
    // Since any module can define and trigger new events there may be
    // additional events available in your application. Look for classes with
    // the special @Event docblock indicator to discover other events.
    //
    // For each event key define an array of arrays composed of the method names
    // to call and optional priorities. The method name here refers to a method
    // on this class to call whenever the event is triggered.
    $events[IncidentEvents::NEW_REPORT][] = array('notifyMario'); 
    // Subscribers can optionally set a priority. If more than one subscriber is
    // listening to an event when it is triggered they will be executed in order
    // of priority. If no priority is set the default is 0.
    $events[IncidentEvents::NEW_REPORT][] = array('notifyBatman', -100); 
    return $events;
  } 
  /**
   * If this incident is about a missing princess notify Mario.
   *
   * Per our configuration above, this method is called whenever the
   * IncidentEvents::NEW_REPORT event is dispatched. This method is where you
   * place any custom logic that you want to perform when the specific event is
   * triggered.
   *
   * These responder methods receive an event object as their argument. The
   * event object is usually, but not always, specific to the event being
   * triggered and contains data about application state and configuration
   * relative to what was happening when the event was triggered.
   *
   * For example, when responding to an event triggered by saving a
   * configuration change you'll get an event object that contains the relevant
   * configuration object.
   *
   * @param \Drupal\events_example\Event\IncidentReportEvent $event
   */
  public function notifyMario(IncidentReportEvent $event) {
    // You can use the event object to access information about the event passed
    // along by the event dispatcher.
    if ($event->getType() == 'stolen_princess') {
      $this->messenger->addStatus($this->t('Mario has been alerted. Thank you. This message was set by an event subscriber. See \Drupal\events_example\EventSubscriber\EventsExampleSubscriber::notifyMario()'));
    }
  } 
  /**
   * Let Batman know about any events involving the Joker.
   *
   * @param \Drupal\events_example\Event\IncidentReportEvent $event
   */
  public function notifyBatman(IncidentReportEvent $event) {
    if ($event->getType() == 'joker') {
      $this->messenger->addStatus($this->t('Batman has been alerted. Thank you. This message was set by an event subscriber. See \Drupal\events_example\EventSubscriber\EventsExampleSubscriber::notifyBatman()'));
      // Optionally use the event object to stop propagation.
      // If there are other subscribers that have not been called yet this will
      // cause them to be skipped.
      $event->stopPropagation();
    }
  }
}

Thank you for reading this article!!!

feature-top
feature-top

Add a Comment

Hernando Cadet

Hi every one, I obtained a bachelor's degree in Bioinformatics back in 2006, from Claflin University, after I received my bachelor's degree, I gained full time employment as a software engineer at a Video Relay Service company, maintaining databases and developing software for a new developed device called the VPAD.

I worked at that company for two years, then I became a web developer, and worked for a magazine for three years. After that job, I worked as a Drupal web developer, as a subcontractor for the NIH, for a year and then left the job to go back to school.

Hernando Cadet

Collaboratively administrate empowered markets via plug-and-play networks. Dynamically procrastinate B2C users after installed base benefits. Dramatically visualize customer directed convergence without

Collaboratively administrate empowered markets via plug-and-play networks. Dynamically procrastinate B2C users after installed base benefits. Dramatically visualize customer directed convergence without revolutionary ROI.