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

Note

Note there are two approaches for alternate delivery in Drupal 8, a route subscriber and a route enhancer. This change notice covers route subscribers (kernel events). For detail on route enhancers see Controller derivation moved from RouteSubscriber to RouteEnhancers. The preferred approach is to use route enhancers (see Controller derivation moved from RouteSubscriber to RouteEnhancers) rather than kernel events (route subscribers).

Detail

The "delivery callback" system introduced in Drupal 7 has been removed. That includes drupal_deliver_page(), ajax_deliver(), and drupal_deliver_html_page().

With the new mime-type-sensitive routing system in Drupal 8, this system became redundant (see New Symfony-based routing system). Instead, for returning an Ajax response see the Ajax change notice. Otherwise, this functionality has been subsumed into the kernel.view event, which handles turning controller responses into the appropriate response object based on, among other things, the mime type of the request.

hook_page_delivery_callback_alter()
Drupal 7 provided hook_page_delivery_callback_alter to enable modules to change the delivery callback mid-request "based on information unrelated to the path of the page accessed. For example, it can be used to set the delivery callback based on a HTTP request header…".

Request handling based on a limited set of HTTP headers is now supported by the routing system.

To change request handling mid-request for other types of conditions, modules can create event listeners to override the default controller for the response.
In Drupal 7

/**
 * Implements hook_page_delivery_callback_alter().
 */
function overlay_page_delivery_callback_alter(&$callback) {
  if (overlay_display_empty_page()) {
    $callback = 'overlay_deliver_empty_page';
  }
}

/**
 * Prints an empty page.
 *
 * This function is used to print out a bare minimum empty page which still has
 * the scripts and styles necessary in order to trigger the overlay to close.
 */
function overlay_deliver_empty_page() {
  $empty_page = '<html><head><title></title>' . drupal_get_css() . drupal_get_js() . '</head><body class="overlay"></body></html>';
  print $empty_page;
  drupal_exit();
}

In Drupal 8, create a services.yml file in your module to register your subscriber.

services:
  overlay.subscriber:
    class: Drupal\overlay\EventSubscriber\OverlaySubscriber
    tags:
      - { name: event_subscriber }

Then create the event listener in src/EventSubscriber/OverlaySubscriber.php:


namespace Drupal\overlay\EventSubscriber;

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

/**
 * Listener to process request controller information.
 */
class OverlaySubscriber implements EventSubscriberInterface {

  /**
   * Sets the controller to OverlayController:close() if overlay_display_empty_page()
   * returns TRUE;
   *
   * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event
   *   Event that is created to create a response for a request.
   */
  public function onRequestSetController(GetResponseEvent $event) {
    $request = $event->getRequest();
    if (overlay_display_empty_page()) {
      $request->attributes->set('_controller', '\Drupal\overlay\OverlayController::close');
    }
  }

  /**
   * Registers the methods in this class that should be listeners.
   *
   * @return array
   *   An array of event listener definitions.
   */
  static function getSubscribedEvents() {
    // The RouterListener has priority 32, and we need to run after that.
    $events[KernelEvents::REQUEST][] = array('onRequestSetController', 30);

    return $events;
  }
}

Lastly add a controller class to handle the alternate response:


namespace Drupal\overlay;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\HttpFoundation\Response;

class OverlayController implements ContainerAwareInterface {

  use ContainerAwareTrait;

  public function close() {
    return new Response('<html><head><title></title>' . drupal_get_css() . drupal_get_js() . '</head><body class="overlay"></body></html>');
  }

}
Impacts: 
Module developers