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

In Drupal 7 hook_boot() was being fired on the beginning of all page requests, providing modules the ability to run code on cached pages.

In Drupal 8 hook_boot() was removed since the same results can be achieved with other ways, for example:

- A module that needs to interrupt the request very early based on certain conditions can use an event listener (see #1794754: Convert ban_boot() to an event listener) (Note that modules are loaded by this stage unlike in Drupal 7.)
- A module that needs to run on cached pages should prompt its users to add code in settings.php

Drupal 7

 /**
 * Implementation of hook_boot(). Runs even for cached pages.
 */
function mymodule_boot() {
  // @todo remove this debug code
  drupal_set_message('mymodule_boot executed');
}

Drupal 8:

# file should be in /mymodule/mymodule.services.yml
services:
  mymodule.mymodule_subscriber:
    class: Drupal\mymodule\MyModuleSubscriber
    tags:
      - { name: 'event_subscriber' }
// file shoud be in /mymodule/src/MyModuleSubscriber.php
/**
 * @file
 * Contains \Drupal\mymodule\MyModuleSubscriber.
 */

namespace Drupal\mymodule;

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

/**
 * Provides a MyModuleSubscriber.
 */
class MyModuleSubscriber implements EventSubscriberInterface {

  /**
   * // only if KernelEvents::REQUEST !!!
   * @see Symfony\Component\HttpKernel\KernelEvents for details
   *
   * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event
   *   The Event to process.
   */
  public function MyModuleLoad(GetResponseEvent $event) {
    // @todo remove this debug code
    drupal_set_message('MyModule: subscribed');
  }

  /**
   * {@inheritdoc}
   */
  static function getSubscribedEvents() {
    $events[KernelEvents::REQUEST][] = array('MyModuleLoad', 20);
    return $events;
  }
}
Impacts: 
Module developers
Updates Done (doc team, etc.)
Online documentation: 
Not done
Theming guide: 
Not done
Module developer documentation: 
Not done
Examples project: 
Not done
Coder Review: 
Not done
Coder Upgrade: 
Not done
Other: 
Other updates done

Comments

mradcliffe’s picture

Does this even work? Define class = magic?

I can't seem to get Drupal to recognize my Bundle class extension just by creating a class in myModule/lib/Drupal/myModule/myModuleBundle.php. Uninstalled, enabled, refreshed cache, added exit calls in the build method, etc... Nothing.

Edit: Yes, this does nothing. It is broken.

mradcliffe’s picture

Okay, yeah, this documentation is bad, but there is a different way now.

The first class is not needed and the event subscriber should be defined in "mymodule.services.yml".

levmyshkin’s picture

I used StackMiddleware plugin instead of hook_boot():

mymodule/mymodule.services.yml

services:
  http_middleware.mymodule:
    class: Drupal\mymodule\StackMiddleware\MyModule
    tags:
      - { name: http_middleware, priority: 180, responder: true }

mymodule/src/StackMiddleware/MyModule.php

<?php

namespace Drupal\mymodule\StackMiddleware;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;

/**
 * Provides a HTTP middleware.
 */
class MyModule implements HttpKernelInterface {

  /**
   * The wrapped HTTP kernel.
   *
   * @var \Symfony\Component\HttpKernel\HttpKernelInterface
   */
  protected $httpKernel;

  /**
   * Constructs a MyModule object.
   *
   * @param \Symfony\Component\HttpKernel\HttpKernelInterface $kernel
   *   The decorated kernel.
   * @param mixed $optional_argument
   *   (optional) An optional argument.
   */
  public function __construct(HttpKernelInterface $http_kernel) {
    $this->httpKernel = $http_kernel;
  }

  /**
   * {@inheritdoc}
   */
  public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
    // Your code here.
    return $this->httpKernel->handle($request, $type, $catch);
  }
}

You also can see an example of StackMiddleware plugin in Page Cache module:
/core/modules/page_cache/src/StackMiddleware/PageCache.php
/core/modules/page_cache/page_cache.servcies.yml
https://api.drupal.org/api/drupal/core%21modules%21page_cache%21src%21St...

j. ayen green’s picture

Is this still valid, with Drupal 8/9? And if so, please explain how handle() returns whatever the custom code needs returned. It seems to be returning something without any nexus to the whatever the custom code is doing.

levmyshkin’s picture

I'm not sure it's working now, it was 5 years ago. You'd better use priority 300 to avoid cache.
But if you want example, I used this code for this module:
https://www.drupal.org/project/cleanpager/releases/8.x-1.x-dev

Aporie’s picture

I confirm that the middleware approach still works (and not the event subscriber one, which will never be hit before page cache is generated).

The only thing to do on Drupal 10 is to raise the priority of it to above 200 (as it's the weight of page_cache http_middleware). I'm using 210 and managed to invalidate a block cache on each request.

services:
  http_middleware.your_module:
    class: Drupal\your_module\StackMiddleware\YourModule
    tags:
      - { name: http_middleware, priority: 210, responder: true }
alexdmccabe’s picture

Setting the priority greater than 200 also let me skip caching and replicate the functionality of hook_boot, without needing StackMiddleware.

$events[KernelEvents::REQUEST][] = array('MyModuleLoad', 300);

Apparently the page cache injects itself at priority 200, so a higher priority will beat the cache.

benjaminarthurt’s picture

The user module operates at priority 300, so if your subscriber requires interaction with loaded user entities and core user functions like \Drupal::currentUser(), then your subscriber should be operating less than 300.

User Module:
$events[KernelEvents::TERMINATE][] = ['onKernelTerminate', 300];

In creating the Simple Access Log module I set my priority to 250 so it would operate with information about users but before the Dynamic Page Cache.

kitikonti’s picture

I cannot confirm this. Using 250 or 300 my code does not get triggered on cached pages. Also cannot use the Middleware approach in my case because I want to check if the user is authenticated which does not work there. Any idea how to do this?