Drupal
min read
October 13, 2014

Porting hook_init() to Drupal8

Porting hook_init() to Drupal8
Table of contents

D8 beta is launched and its time to port modules from Drupal 7 to Drupal 8. One of the very widely used hooks hook_init() has been removed from Drupal 8. This has been replaced in favor of Symfony Kernel and events. Hook_init() was was a system level hook defined at core module system/system.api.php.

What hook_init() does?


This hook is run at the beginning of the page request. It is typically used to set up global parameters that are needed later in the request. When this hook is called, the theme and all modules are already loaded in memory.

How does it work in Drupal 8 now?


Drupal 8 has adopted symfony as a part of its core. It uses Symfony kernel and events to do the same now. List of kernel events available in Drupal 8 are as follows:

  • KernelEvents::CONTROLLER
    The CONTROLLER event occurs once a controller was found for handling a request.
     
  • KernelEvents::EXCEPTION
    The EXCEPTION event occurs when an uncaught exception appears.
     
  • KernelEvents::FINISH_REQUEST 
    The FINISH_REQUEST event occurs when a response was generated for a request.
     
  • KernelEvents::REQUEST 
    The REQUEST event occurs at the very beginning of request dispatching.
     
  • KernelEvents::RESPONSE
    The RESPONSE event occurs once a response was created for replying to a request.
     
  • KernelEvents::TERMINATE
    The TERMINATE event occurs once a response was sent.
     
  • KernelEvents::VIEW
    The VIEW event occurs when the return value of a controller is not a Response instance.

Drupal 8 provides a way to subscribe to all these events and attach callbacks to be executed when these events occur. If our module needs to perform changes on the request/response object very early to the request an event subscriber should be used listening to the KernelEvents::REQUEST event. Same goes for the other events as well. 

How to create an Event Subscriber?


The example below shows a Drupal 7 hook_init() implementation which appends Access-Control-Allow-Origin to the response headers to allow CORS(Cross Origin Resource Sharing).


mymodule.module
/**
 * Implements hook_init()
 */
function mymodule_init() {
  drupal_add_http_header('Access-Control-Allow-Origin', '*', TRUE);
}

Steps to convert hook_init into an event subscriber in Drupal 8

  • Create a new Service for Event Subscriber
  • Attach a callback to the KernelEvents::RESPONSE event in Event Subscriber Class.
  • Port the above code inside the attached callback function.

Creating a new service


Create a yml file named <module_name>.services.yml as follows:


mymodule.services.yml
services:
  cors.allow_access_origin:
    class: Drupal\mymodule\EventSubscriber\mymoduleSubscriber
    tags:
      - {name: event_subscriber}

 class: defines the class implementing EventSubscriberInterface.
tags: Parsing these services is an expensive task for Drupal. It parses all the services.yml files and stores the service definitions in a cached PHP file. These tags help categorize the services.

Attach a callback to the KernelEvents::RESPONSE event
EventSubscriberInterface provides a static function which can be used to attach callable functions to the above mentioned kernel events as shown in the below example.


mymoduleSubscriber.inc
namespace Drupal\mymodule\EventSubscriber;
 
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\Component\Utility\Unicode;
 
class mymoduleSubscriber implements EventSubscriberInterface {
  /**
  * {@inheritdoc}
  */
  static function getSubscribedEvents() {
    $events[KernelEvents::RESPONSE][] = array('addAccessAllowOriginHeaders');
    return $events;
  }
}

Porting the logic inside hook_init to the callback function attached to  KernelEvents::RESPONSE


mymoduleSubscriber.inc
namespace Drupal\mymodule\EventSubscriber;
 
+ use ...
 
class mymoduleSubscriber implements EventSubscriberInterface {
  public function addAccessAllowOriginHeaders(FilterResponseEvent $event) {
    $response= $event->getResponse();
    $response->headers->set('Access-Control-Allow-Origin', '*');
  }
 
  /**
  * {@inheritdoc}
  */
  static function getSubscribedEvents() {
    $events[KernelEvents::RESPONSE][] = array('addAccessAllowOriginHeaders');
    return $events;
  }
}

Conclusion


In this post, we learned how to replace hook_init() with event subscriber & how symfony kernel events play with event subscribers. We have a better understanding on how Kernel events & callbacks work in Drupal8.

Next article, we’ll have a look at how to port routing access Callbacks to Drupal 8.

Written by
Artwork by
No art workers.
We'd love to talk about your business objectives