Change record status: 
Project: 
Introduced in branch: 
8.x
Description: 

As of Drupal 8, hook_init() no longer exists, since, after introducing the Symfony kernel and events it was not serving any specific need.

  • If your module needs to perform changes on the request/response object very early to the request an event subscriber should be used listening to the kernel.request event.

    D7:

    function mymodule_init() {
      if (!empty($_GET['redirect-me'])) {
        drupal_goto('http://example.com/');
      }
    }
    

    D8:
    Register your Event Subscriber in your mymodule.services.yml and tag it as such:

    services:
      mymodule.event_subscriber:
        class: Drupal\mymodule\EventSubscriber\MymoduleSubscriber
        tags:
          - {name: event_subscriber}
    

    Your MymoduleSubscriber should be placed in folder structure of modules/src/EventSubscriber/MymoduleSubscriber.php and should implement the EventSubscriberInterface interface and in its getSubscribedEvents() point to the method that should be executed:

    namespace Drupal\mymodule\EventSubscriber;
    
    use Symfony\Component\HttpFoundation\RedirectResponse;
    use Symfony\Component\HttpKernel\KernelEvents;
    use Symfony\Component\HttpKernel\Event\GetResponseEvent;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    
    class MymoduleSubscriber 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;
      }
    
    }
    
  • If your module just needs to add css and/or javascript, hook_page_attachments should be used instead
Impacts: 
Module developers

Comments

tbisciglia’s picture

This one tripped me up for a while. The service name needs to be:

mymodule.event_subscriber

Notice there's a dot, not an underscore, between the module name and event_subscriber. Otherwise, the code will not be connected. Otherwise, spot on and very helpful!

neograph734’s picture

Well spot. Example has been updated.

sashken2’s picture

I use this code in Drupal 7. How do I make it work in Drupal 8?

function MYMODULE_init(){
    $arg = arg();
    $last_key = key(array_slice($arg, -1, 1, TRUE));
	
	if ($arg[$last_key] == 'all') {
        unset($arg[$last_key]);

        drupal_goto(implode('/', $arg), array(), 301);
    }
}
pinesh’s picture

In Drupal 8 and later, you can use an event subscriber to achieve similar functionality. Here's an example of how you can convert your code to work in Drupal 8/9/10:

1. Create a file for your custom module:
Create a file named MYMODULE.services.yml in your module's src directory (create the src directory if it doesn't exist yet).
2. Define the service:
Add the following code to MYMODULE.services.yml to define the service and the class that will handle the event:

services:
  MYMODULE.event_subscriber:
    class: '\Drupal\MYMODULE\EventSubscriber\RedirectEventSubscriber'
    tags:
      - { name: 'event_subscriber' }

3. Create the event subscriber class:
Create a file named RedirectEventSubscriber.php in your module's src/EventSubscriber directory (create the EventSubscriber directory if it doesn't exist yet). Add the following code to the file:

<?php

namespace Drupal\MYMODULE\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;

class RedirectEventSubscriber implements EventSubscriberInterface {

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events[KernelEvents::REQUEST][] = ['onRequest'];
    return $events;
  }

  /**
   * Redirect logic.
   */
  public function onRequest(GetResponseEvent $event) {
    $request = $event->getRequest();
    $path = \Drupal::service('path.current')->getPath();

    $arg = explode('/', trim($path, '/'));

    $last_key = key(array_slice($arg, -1, 1, TRUE));

    if ($arg[$last_key] == 'all') {
      unset($arg[$last_key]);

      $redirect_path = implode('/', $arg);

      $response = new \Symfony\Component\HttpFoundation\RedirectResponse($redirect_path, 301);
      $event->setResponse($response);
    }
  }
}

Now, the logic from your MYMODULE_init() function has been moved to the RedirectEventSubscriber class. This class listens for the KernelEvents::REQUEST event and checks for the 'all' path component, redirecting as needed.

imclean’s picture

Symfony\Component\HttpKernel\Event\GetResponseEvent has been replaced by Symfony\Component\HttpKernel\Event\RequestEvent. See #3094398: Update Symfony response and request events to new classes