You are here

render_cache_page.module in Render cache 7.2

Hook implementations and frequently used functions for render cache page module.

File

modules/controller/render_cache_page/render_cache_page.module
View source
<?php

/**
 * @file
 * Hook implementations and frequently used functions for render cache page module.
 */
use Drupal\render_cache_page\RenderCache\Controller\PageControllerInterface;

// -----------------------------------------------------------------------
// Core Hooks

/**
 * Implements hook_init().
 *
 * As menu_execute_active_handler() runs before the page delivery, we fake the recursion
 * level to prevent #post_render_cache functions to be called before.
 */
function render_cache_page_init() {
  $rcc = render_cache_get_controller('page');
  if (!$rcc instanceof PageControllerInterface) {
    return;
  }

  // Delegate hook_init() to the render cache controller.
  $rcc
    ->hook_init();
}

/**
 * Implements hook_page_delivery_callback_alter().
 *
 * We hijack the page delivery callback to provide full page caching.
 *
 * This also allows to call the #post_render_cache callbacks at the
 * latest possible point.
 *
 * @param callback $callback
 */
function render_cache_page_page_delivery_callback_alter(&$callback) {
  if ($callback != 'drupal_deliver_html_page') {
    return;
  }

  // Store the original callback.
  $original_callback =& drupal_static(__FUNCTION__, '');
  $original_callback = $callback;

  // Use our own page deliver callback.
  $callback = 'render_cache_page_deliver_html_page';
}

/**
 * Implements hook_module_implements_alter().
 *
 * Moves our hook_page_page_delivery_callback_alter() implementation to occur
 * last so that we can consistently hijack the delivery callback.
 *
 * @param array $implementations
 *   Format: $[$module] = string|false
 * @param string $hook
 */
function render_cache_page_module_implements_alter(&$implementations, $hook) {
  if ($hook === 'page_delivery_callback_alter') {

    // Move our hook implementation to the bottom.
    $group = $implementations['render_cache_page'];
    unset($implementations['render_cache_page']);
    $implementations['render_cache_page'] = $group;
  }
}

// -----------------------------------------------------------------------
// Contrib Hooks

/**
 * Implements hook_ctools_plugin_directory().
 *
 * @param string $owner
 * @param string $plugin_type
 *
 * @return null|string
 */
function render_cache_page_ctools_plugin_directory($owner, $plugin_type) {
  if ($owner == 'render_cache') {
    return 'src/RenderCache/' . $plugin_type;
  }
  return NULL;
}

// -----------------------------------------------------------------------
// Public API

/**
 * Overrides drupal_deliver_html_page().
 *
 * @param mixed $page_callback_result
 */
function render_cache_page_deliver_html_page($page_callback_result) {

  // Menu status constants are integers; page content is a string or array.
  if (is_int($page_callback_result)) {

    // Never cache 403 or 404 pages.
    render_cache_call_is_cacheable(FALSE);

    // Early return for status codes.
    drupal_deliver_html_page($page_callback_result);
    return;
  }

  // Copied code from drupal_deliver_html_page:
  // Emit the correct charset HTTP header, but not if the page callback
  // result is NULL, since that likely indicates that it printed something
  // in which case, no further headers may be sent, and not if code running
  // for this page request has already set the content type header.
  if (isset($page_callback_result) && is_null(drupal_get_http_header('Content-Type'))) {
    drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
  }

  // Send appropriate HTTP-Header for browsers and search engines.
  global $language;
  drupal_add_http_header('Content-Language', $language->language);
  if (isset($page_callback_result)) {

    // Print anything besides a menu constant, assuming it's not NULL or
    // undefined.
    // The function does the printing.
    render_cache_page_drupal_render_page($page_callback_result);
  }

  // Perform end-of-request tasks.
  drupal_page_footer();
}

/**
 * Called instead of drupal_render_page().
 *
 * @param array $page
 */
function render_cache_page_drupal_render_page($page) {

  // We could retrieve this also from $_REQUEST, but this is cleaner as it
  // matches the Drupal 8 request object closer.
  $page_callback =& drupal_static('render_cache_page_page_delivery_callback_alter', '');
  $context = array(
    'page_callback' => $page_callback,
    'request' => $_REQUEST,
  );

  // The view() method always takes multiple objects.
  $pages = array(
    'page' => (object) array(
      'content' => $page,
    ),
  );

  // Delegate to render cache controller.
  $rcc = render_cache_get_controller('page');
  $rcc
    ->setContext($context);
  $build = $rcc
    ->view($pages);

  // Now that we have build the page succesfully and ran post_render functions,
  // lets add the HTML back to it.
  if (!empty($build['page']['#render_cache_page_theme_wrappers'])) {
    $build['page']['#theme_wrappers'] = $build['page']['#render_cache_page_theme_wrappers'];
    unset($build['page']['#render_cache_page_theme_wrappers']);
  }

  // If the #theme_wrappers is still empty, then just put back the default from
  // element_info('page').
  if (empty($build['page']['#theme_wrappers'])) {
    $element_info = element_info('page');
    $build['page']['#theme_wrappers'] = $element_info['#theme_wrappers'];
  }

  // Process the assets.
  drupal_process_attached($build['page']);

  // And restore properties.
  $build['page'] += $build['page']['#render_cache_original'];
  unset($build['page']['#render_cache_original']);
  unset($build['page']['#attached']);
  unset($build['page']['#printed']);
  unset($build['page']['#children']);

  // We need to unset #type and #theme to only render the #markup.
  unset($build['page']['#type']);
  unset($build['page']['#theme']);

  // Call drupal_render() like the original function, but allow other modules
  // to alter the output before and after rendering.
  drupal_alter('render_cache_page_pre_render', $build);
  $output = drupal_render($build);
  drupal_alter('render_cache_page_post_render', $output, $build);

  // Allow other modules to alter the output before and after sending, to
  // enable them to e.g. replace placeholders via Javascript.
  drupal_alter('render_cache_page_pre_send', $output, $build);
  print $output;
  drupal_alter('render_cache_page_post_send', $output, $build);
}

/**
 * Overrides drupal_render_page().
 *
 * This function is identical to drupal_render_page(), but does not drupal_render()
 * at the end to allow render caching.
 *
 * @param array $page
 *
 * @return array
 */
function render_cache_page_drupal_render_page_helper($page) {
  $main_content_display =& drupal_static('system_main_content_added', FALSE);

  // Allow menu callbacks to return strings or arbitrary arrays to render.
  // If the array returned is not of #type page directly, we need to fill
  // in the page with defaults.
  if (is_string($page) || is_array($page) && (!isset($page['#type']) || $page['#type'] != 'page')) {
    drupal_set_page_content($page);
    $page = element_info('page');
  }

  // Modules can add elements to $page as needed in hook_page_build().
  foreach (module_implements('page_build') as $module) {
    $function = $module . '_page_build';
    $function($page);
  }

  // Modules alter the $page as needed. Blocks are populated into regions like
  // 'sidebar_first', 'footer', etc.
  drupal_alter('page', $page);

  // If no module has taken care of the main content, add it to the page now.
  // This allows the site to still be usable even if no modules that
  // control page regions (for example, the Block module) are enabled.
  if (!$main_content_display) {
    $page['content']['system_main'] = drupal_set_page_content();
  }

  // --- These lines were changed.
  // Remove the #theme_wrappers to remove the chicken-egg-situation of page and html
  // for #post_render_cache and script adding. Store it in another var, in
  // case some module tries to alter it in hook_page_alter().
  if (!empty($page['#theme_wrappers'])) {
    $page['#render_cache_page_theme_wrappers'] = $page['#theme_wrappers'];
  }
  $page['#theme_wrappers'] = array();
  return $page;
}