You are here

function render_cache_entity_view_callback in Render cache 7

Same name and namespace in other branches
  1. 7.2 modules/controller/render_cache_entity/render_cache_entity.module \render_cache_entity_view_callback()

Override entity API rendering callback to add a caching layer.

This callback is registered as $entity_info[$type]['view callback'] with hook_entity_info_alter()

Parameters

object[] $entities:

string $view_mode:

string|null $langcode:

string $entity_type:

Return value

array

Throws

\EntityMalformedException

See also

entity_view()

render_cache_entity_info_alter()

1 string reference to 'render_cache_entity_view_callback'
render_cache_entity_info_alter in ./render_cache.module
Implements hook_entity_info_alter().

File

./render_cache.module, line 25
Hook implementations and frequently used functions for render cache module.

Code

function render_cache_entity_view_callback($entities, $view_mode, $langcode = NULL, $entity_type) {

  // Remove any passed values that are not an object, this can happen with out
  // of date Apache Solr search when entities are deleted and probably other
  // situations.
  foreach ($entities as $key => $entity) {
    if (!is_object($entity)) {
      unset($entities[$key]);
    }
  }
  $entity_info = entity_get_info($entity_type);
  $entity_order = array_keys($entities);

  // Prepare context
  $context = array(
    'entity_type' => $entity_type,
    'view_mode' => $view_mode,
    'langcode' => $langcode,
  );

  // Setup drupal_render style cache array.
  $cache_info = render_cache_cache_info_defaults();
  $cache_info['keys'] = array(
    'entity',
    $entity_type,
    $view_mode,
  );

  /* @see hook_render_cache_block_default_cache_info_alter() */
  drupal_alter('render_cache_entity_default_cache_info', $cache_info, $context);

  // Retrieve a list of cache_ids
  $cid_map = array();
  foreach ($entities as $id => $entity) {
    list($entity_id, $entity_revision_id, $bundle) = entity_extract_ids($entity_type, $entity);
    $entity_context = $context + array(
      'entity_id' => $entity_id,
      'entity_revision_id' => $entity_revision_id,
      'bundle' => $bundle,
    );
    $cid_map[$id] = render_cache_get_entity_cid($entity, $cache_info, $entity_context);
  }
  $cids = array_values($cid_map);
  $cached_entities = array();
  if (isset($cache_info['granularity']) && $cache_info['granularity'] != DRUPAL_NO_CACHE) {
    $cached_entities = cache_get_multiple($cids, 'cache_render');
  }

  // Calculate remaining entities
  $cid_remaining = array_intersect($cid_map, $cids);
  $entities = array_intersect_key($entities, $cid_remaining);

  // Render non-cached entities.
  if (!empty($entities)) {

    // If this is a view callback.
    if (isset($entity_info['render cache']['callback'])) {
      $rendered = $entity_info['render cache']['callback']($entities, $view_mode, $langcode, $entity_type);
    }
    else {

      // We need the $page variable from entity_view() that it does not pass us.
      if (version_compare(PHP_VERSION, '5.4.0', '>=')) {

        // Get only the stack frames we need (PHP 5.4 only).
        $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
      }
      elseif (version_compare(PHP_VERSION, '5.3.6', '>=')) {
        $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT);
      }
      else {

        // @see http://php.net/manual/en/function.debug-backtrace.php#refsect1-function.debug-backtrace-parameters
        $backtrace = debug_backtrace(TRUE);
      }
      $page = NULL;

      // As a safety, do not grab an unexpected arg for $page, check that this
      // was called from entity_view().
      if (isset($backtrace[1]['function']) && $backtrace[1]['function'] === 'entity_view' && isset($backtrace[1]['args'][4])) {
        $page = $backtrace[1]['args'][4];
      }
      $rendered = entity_get_controller($entity_type)
        ->view($entities, $view_mode, $langcode, $page);
    }
    $rendered = reset($rendered);

    // Store rendered entities in cache for future views.
    foreach (element_children($rendered) as $id) {

      // Remove #weight as it will not be accurate, we weight in the cached and
      // rendered merge below.
      unset($rendered[$id]['#weight']);

      // Cache the entity.
      $cid = $cid_map[$id];
      $render = $rendered[$id];
      _render_cache_pre_render($render, $cid, $cache_info);
      $cached_entities[$cid] = (object) array(
        'data' => $render,
      );
    }
  }

  // Not needed in rest of function.
  unset($entities, $rendered);

  // Return false if no entities are available, matches entity_view()'s
  // functionality.
  if (empty($cached_entities)) {
    return FALSE;
  }

  // Put entities back in their request order and output.
  $return = array();

  // Render entities cached as render arrays.
  foreach ($entity_order as $weight => $id) {
    $cid = $cid_map[$id];
    if (!empty($cached_entities[$cid]->data)) {
      $render = $cached_entities[$cid]->data;
      _render_cache_post_render($render, $id);
      $return[$id] = $render;
      $return[$id]['#weight'] = $weight;
    }
  }

  // Return $return, wrap with entity type key in array to match
  // entity_view()'s functionality.
  return array(
    $entity_type => $return,
  );
}