You are here

eva.module in EVA: Entity Views Attachment 7

Same filename and directory in other branches
  1. 8.2 eva.module
  2. 8 eva.module

File

eva.module
View source
<?php

// Load theme functions
module_load_include('inc', 'eva', 'eva.theme');

/**
 * Implements hook_views_api().
 */
function eva_views_api() {
  return array(
    'api' => 3,
  );
}

/**
 * Implements hook_field_extra_fields().
 */
function eva_field_extra_fields() {
  $extras = array();
  $views = eva_get_views();
  foreach ($views as $entity => $data) {
    foreach ($data as $view) {
      if (!empty($view['bundles'])) {
        $bundles = $view['bundles'];
      }
      else {
        $entity_info = entity_get_info($entity);
        $bundles = array_keys($entity_info['bundles']);
      }
      foreach ($bundles as $bundle) {
        $context = $view['show_on'];
        $extras[$entity][$bundle][$context][$view['name'] . '_' . $view['display']] = array(
          'label' => empty($view['title']) ? $view['name'] : $view['title'],
          'description' => $view['title'],
          'weight' => 10,
        );

        // Provide a separate extra field for the exposed form if there is any.
        if ($context == 'display' && !empty($view['exposed form']) && !empty($view['exposed form split'])) {
          $extras[$entity][$bundle][$context][$view['name'] . '_' . $view[$context] . '_' . 'form'] = array(
            'label' => (empty($view['title']) ? $view['name'] : $view['title']) . ' (' . t('Exposed form') . ')',
            'description' => t('The exposed filter form of the view.'),
            'weight' => 9,
          );
        }
      }
    }
  }
  return $extras;
}

/**
 * Implements hook_entity_view_alter().
 */
function eva_entity_view_alter(&$build, $entity_type) {

  // If we cannot find the entity, return.
  if (!($entity = _eva_extract_entity_from_build($build, $entity_type))) {
    return;
  }

  // If there are no extra fields for this view mode, return.
  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
  if (!($fields = field_extra_fields_get_display($entity_type, $bundle, $build['#view_mode']))) {
    return;
  }

  // If there are no views for this entity type, return.
  if (!($views = eva_get_views($entity_type))) {
    return;
  }
  foreach ($views as $info) {
    $longname = $info['name'] . '_' . $info['display'];
    if (isset($fields[$longname]) && $fields[$longname]['visible']) {
      _eva_build_extra_fields($build, $entity_type, $entity, $fields, $info['name'], $info['display'], 'display');
    }
  }
}

/**
 * Implements hook_field_attach_form().
 */
function eva_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {

  // Retrieve all EVA views for this entity type.
  if (!($views = eva_get_views($entity_type))) {
    return;
  }

  // If there are no extra fields for this entity, return.
  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
  if (!($fields = field_info_extra_fields($entity_type, $bundle, 'form'))) {
    return;
  }

  // Loop through each view to see if it is an extra field. Unlike fields on the
  // display, fields on the form have no concept of visibility, they are always
  // added to the form.
  foreach ($views as $info) {
    if (isset($fields[$info['name'] . '_' . $info['display']])) {
      _eva_build_extra_fields($form, $entity_type, $entity, $fields, $info['name'], $info['display'], 'form');
    }
  }
}

/**
 * Adds the EVA to the build, which is either the rendered entity or the form.
 *
 * @param array $build
 *   The rendered entity or the entity form.
 * @param string $entity_type
 *   The entity type.
 * @param object $entity
 *   The entity object. This is used by the display plugin for processing.
 * @param array $fields
 *   The array of extra fields.
 * @param string $name
 *   The name of the view.
 * @param string $display_id
 *   The display ID of the view.
 * @param string $context
 *   Where this EVA is being used, either 'form' or 'display'.
 */
function _eva_build_extra_fields(&$build, $entity_type, $entity, $fields, $name, $display_id, $context) {
  if ($view = views_get_view($name)) {
    $view
      ->set_display($display_id);
    if ($view
      ->access($display_id)) {
      $view->current_entity = $entity;
      $view->current_entity_type = $entity_type;
      $view->current_entity_view_mode = $context === 'form' ? 'form' : $build['#view_mode'];
      $longname = $name . '_' . $display_id;
      if ($context == 'display' && isset($fields[$longname . '_form'])) {
        $view
          ->init_handlers();
        $exposed_form = $view->display_handler
          ->get_plugin('exposed_form');
        $build[$longname . '_form'] = array(
          '#markup' => $exposed_form
            ->render_exposed_form(TRUE),
        );
      }
      $arg_mode = $view->display_handler
        ->get_option('argument_mode');
      if ($arg_mode == 'token') {
        $args = array();
        if ($token_string = $view->display_handler
          ->get_option('default_argument')) {

          // Now do the token replacement.
          $token_values = eva_get_arguments_from_token_string($token_string, $entity_type, $entity);

          // We have to be careful to only replace arguments that have tokens.
          foreach ($token_values as $key => $value) {
            $args[$key] = $value;
          }
        }
      }
      elseif ($arg_mode == 'id') {
        list($id, , ) = entity_extract_ids($entity_type, $entity);
        $args = array(
          $id,
        );
      }
      else {

        // We should not get here, but if we are, prevent notices.
        $args = array();
      }
      $result = $view
        ->execute_display($display_id, $args);
      if (!empty($result)) {
        $build[$longname] = array(
          '#markup' => $result,
          '#weight' => $fields[$longname]['weight'],
        );
      }
    }
  }
}

/**
 * Gets a list of views and displays attached to specific entities.
 *
 * This function will cache its results into the views cache, so it gets
 * cleared by Views appropriately.
 *
 * @param string|null $type
 *   (optional) The entity type we want to retrieve views for. If NULL is
 *   specified, views for all entity types will be returned. Defaults to NULL.
 * @param bool $reset
 *   (optional) Force a rebuild of the data. Defaults to FALSE.
 *
 * @return array
 *   An array of view name/display name values, or an empty array().
 */
function eva_get_views($type = NULL, $reset = FALSE) {
  $used_views =& drupal_static(__FUNCTION__);
  if (!isset($used_views) || $reset) {
    views_include('cache');

    // If we're not resetting, check the Views cache.
    if (!$reset) {
      $cache = views_cache_get("eva");
      if (isset($cache->data)) {
        $used_views = $cache->data;
      }
    }

    // If it's still empty rebuild it.
    if (!isset($used_views)) {
      $used_views = array();

      // Trigger a rebuild of the views object cache, which may not be fully loaded.
      ctools_include('export');
      ctools_export_load_object_reset('views_view');

      // Build and cache the data, both in the DB and statically.
      $views = views_get_applicable_views('uses hook entity view');
      foreach ($views as $data) {
        list($view, $display_id) = $data;
        $view_entity = $view->display_handler
          ->get_option('entity_type');

        // Initialize handlers, to determine if the view uses exposed filters.
        $view
          ->init_handlers();
        $used_views[$view_entity][] = array(
          'name' => $view->name,
          'title' => 'EVA: ' . $view
            ->get_human_name() . ' - ' . $view->display[$display_id]->display_title,
          'display' => $display_id,
          'show_on' => $view->display_handler
            ->get_option('show_on'),
          'bundles' => $view->display_handler
            ->get_option('bundles'),
          'exposed form' => $view->display_handler
            ->uses_exposed(),
          'exposed form split' => $view->display_handler
            ->get_option('exposed_form_as_field'),
        );
        $view
          ->destroy();
      }
      views_cache_set("eva", $used_views);
    }
  }

  // Now spit back the data.
  if (isset($type) & isset($used_views)) {
    return isset($used_views[$type]) ? $used_views[$type] : array();
  }
  else {
    return isset($used_views) ? $used_views : array();
  }
}

/**
 * Extract an actual entity object from its $build array.
 *
 * This is a bit more complicated than it should be, since core entities, contrib
 * entities, and contrib entities based on EntityAPI all store their junk in
 * different slots of the build array. See http://drupal.org/node/1170198.
 *
 * @param array $build
 *   The build array as passed to hook_entity_view_alter().
 * @param string $entity_type
 *   (optional) The entity type. Defaults to NULL.
 *
 * @return object|bool
 *   Either the entity object, or FALSE if it cannot be found.
 */
function _eva_extract_entity_from_build($build, $entity_type = NULL) {

  // EntityAPI often sticks stuff in here.
  if (!empty($build['#entity'])) {
    return $build['#entity'];
  }
  elseif (!empty($build['#entity_type']) && !empty($build['#' . $build['#entity_type']])) {
    return $build['#' . $build['#entity_type']];
  }
  elseif ($entity_type && !empty($build['#' . $entity_type])) {
    return $build['#' . $entity_type];
  }
  elseif ($build['#entity_type'] == 'user') {
    return $build['#account'];
  }
  elseif ($build['#entity_type'] == 'taxonomy_term') {
    return $build['#term'];
  }
  return FALSE;
}

/**
 * Get view arguments array from string that contains tokens
 *
 * @param string $string
 *   The token string defined by the view.
 * @param string $type
 *   The token type.
 * @param object $object
 *   The object being used for replacement data (typically a node).
 *
 * @return array
 *   An array of argument values.
 *
 * @todo: security?
 */
function eva_get_arguments_from_token_string($string, $type, $object) {
  $args = trim($string);
  if (empty($args)) {
    return array();
  }
  $args = token_replace($args, array(
    $type => $object,
  ), array(
    'sanitize' => FALSE,
    'clear' => TRUE,
  ));
  return explode('/', $args);
}

/**
 * Implements hook_modules_enabled().
 */
function eva_modules_enabled($modules) {

  // Reset the static cache in case any of the enabled modules
  // implement an eva view
  drupal_static_reset('eva_get_views');
  cache_clear_all('*', 'cache_views', TRUE);
}

/**
 * Implements hook_modules_disabled().
 */
function eva_modules_disabled($modules) {

  // Reset the static cache in case any of the disabled modules
  // implemented an eva view
  drupal_static_reset('eva_get_views');
  cache_clear_all('*', 'cache_views', TRUE);
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function eva_form_views_ui_edit_form_alter(&$form, &$form_state, $form_id) {

  // Clear the field cache when views are saved. This will make sure newly
  // created EVA views and/or exposed filters will appear.
  $form['actions']['save']["#submit"][] = 'field_cache_clear';
}

Functions

Namesort descending Description
eva_entity_view_alter Implements hook_entity_view_alter().
eva_field_attach_form Implements hook_field_attach_form().
eva_field_extra_fields Implements hook_field_extra_fields().
eva_form_views_ui_edit_form_alter Implements hook_form_FORM_ID_alter().
eva_get_arguments_from_token_string Get view arguments array from string that contains tokens
eva_get_views Gets a list of views and displays attached to specific entities.
eva_modules_disabled Implements hook_modules_disabled().
eva_modules_enabled Implements hook_modules_enabled().
eva_views_api Implements hook_views_api().
_eva_build_extra_fields Adds the EVA to the build, which is either the rendered entity or the form.
_eva_extract_entity_from_build Extract an actual entity object from its $build array.