Skip to content
views.module 54.8 KiB
Newer Older
Earl Miles's avatar
Earl Miles committed
<?php

/**
 * @file
 * Primarily Drupal hooks and global API functions to manipulate views.
 *
 * This is the main module file for Views. The main entry points into
 * this module are views_page() and views_block(), where it handles
 * incoming page and block requests.
 */

use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Language\Language;
use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\views\Plugin\Core\Entity\View;
use Drupal\field\FieldInstanceInterface;
Earl Miles's avatar
Earl Miles committed
/**
 * Implements hook_forms().
 *
 * To provide distinct form IDs for Views forms, the View name and
 * specific display name are appended to the base ID,
 * views_form_views_form. When such a form is built or submitted, this
 * function will return the proper callback function to use for the given form.
 */
function views_forms($form_id, $args) {
  if (strpos($form_id, 'views_form_') === 0) {
    return array(
      $form_id => array(
        'callback' => 'views_form',
      ),
    );
  }
}

/**
 * Returns a form ID for a Views form using the name and display of the View.
 */
function views_form_id($view) {
  $parts = array(
    'views_form',
Earl Miles's avatar
Earl Miles committed
    $view->current_display,
  );

  return implode('_', $parts);
}

/**
 * Implements hook_element_info().
 */
function views_element_info() {
  $types['view'] = array(
    '#theme_wrappers' => array('container'),
    '#pre_render' => array('views_pre_render_view_element'),
    '#name' => NULL,
    '#display_id' => 'default',
    '#arguments' => array(),
  );
  return $types;
}

/**
 * View element pre render callback.
 */
function views_pre_render_view_element($element) {
  $element['#attributes']['class'][] = 'views-element-container';

  $view = views_get_view($element['#name']);
  if ($view && $view->access($element['#display_id'])) {
    $element['view'] = $view->preview($element['#display_id'], $element['#arguments']);
Earl Miles's avatar
Earl Miles committed
/**
 * Implement hook_theme(). Register views theming functions.
 */
function views_theme($existing, $type, $theme, $path) {
  Drupal::moduleHandler()->loadInclude('views', 'inc', 'views.theme');
Earl Miles's avatar
Earl Miles committed

  // Some quasi clever array merging here.
  $base = array(
Earl Miles's avatar
Earl Miles committed
  );

  // Our extra version of pager from pager.inc
  $hooks['views_mini_pager'] = $base + array(
    'variables' => array('tags' => array(), 'quantity' => 10, 'element' => 0, 'parameters' => array()),
  );

  $variables = array(
    // For displays, we pass in a dummy array as the first parameter, since
    // $view is an object but the core contextual_preprocess() function only
    // attaches contextual links when the primary theme argument is an array.
    'display' => array('view_array' => array(), 'view' => NULL),
    'style' => array('view' => NULL, 'options' => NULL, 'rows' => NULL, 'title' => NULL),
    'row' => array('view' => NULL, 'options' => NULL, 'row' => NULL, 'field_alias' => NULL),
    'exposed_form' => array('view' => NULL, 'options' => NULL),
    'pager' => array(
      'view' => NULL, 'options' => NULL,
      'tags' => array(), 'quantity' => 10, 'element' => 0, 'parameters' => array()
    ),
  );

  // Default view themes
  $hooks['views_view_field'] = $base + array(
    'variables' => array('view' => NULL, 'field' => NULL, 'row' => NULL),
  );
  $hooks['views_view_grouping'] = $base + array(
    'variables' => array('view' => NULL, 'grouping' => NULL, 'grouping_level' => NULL, 'rows' => NULL, 'title' => NULL),
    'template' => 'views-view-grouping',
Earl Miles's avatar
Earl Miles committed

  // Register theme functions for all style plugins
  foreach ($plugins as $type => $info) {
      // Not all plugins have theme functions, and they can also explicitly
      // prevent a theme function from being registered automatically.
      if (!isset($def['theme']) || empty($def['register_theme'])) {
        continue;
      }
      $hooks[$def['theme']] = array(
        'variables' => $variables[$type],
      );
      if ($def['module'] == 'views') {
        $def['theme_file'] = 'views.theme.inc';
      }
      elseif (isset($def['theme_file'])) {
        $def['theme_path'] = drupal_get_path('module', $def['module']);
      if (isset($def['theme_path'])) {
        $hooks[$def['theme']]['path'] = $def['theme_path'];
      }
      if (isset($def['theme_file'])) {
        $hooks[$def['theme']]['file'] = $def['theme_file'];
      }
      if (isset($def['theme_path']) && isset($def['theme_file'])) {
        $include = DRUPAL_ROOT . '/' . $def['theme_path'] . '/' . $def['theme_file'];
        if (is_file($include)) {
          require_once $include;
      if (!function_exists('theme_' . $def['theme'])) {
        $hooks[$def['theme']]['template'] = drupal_clean_css_identifier($def['theme']);
      }
Earl Miles's avatar
Earl Miles committed
    }
  }

  $hooks['views_form_views_form'] = $base + array(
    'render element' => 'form',
  );

  $hooks['views_exposed_form'] = $base + array(
    'template' => 'views-exposed-form',
    'render element' => 'form',
  );

  $hooks['views_more'] = $base + array(
    'variables' => array('more_url' => NULL, 'link_text' => 'more', 'view' => NULL),
    'template' => 'views-more',
/**
 * Returns a list of plugins and metadata about them.
 *
 * @return array
 *   An array keyed by PLUGIN_TYPE:PLUGIN_NAME, like 'display:page' or
 *   'pager:full', containing an array with the following keys:
 *   - title: The plugin's title.
 *   - type: The plugin type.
 *   - module: The module providing the plugin.
 *   - views: An array of enabled Views that are currently using this plugin,
 *     keyed by machine name.
 */
function views_plugin_list() {
  $plugins = array();
  foreach (views_get_enabled_views() as $view) {
      foreach ($plugin_data as $type => $info) {
        if ($type == 'display' && isset($display['display_plugin'])) {
          $name = $display['display_plugin'];
        elseif (isset($display['display_options']["{$type}_plugin"])) {
          $name = $display['display_options']["{$type}_plugin"];
        elseif (isset($display['display_options'][$type]['type'])) {
          $name = $display['display_options'][$type]['type'];
        }
        else {
          continue;
        }

        // Key first by the plugin type, then the name.
        $key = $type . ':' . $name;
        // Add info for this plugin.
        if (!isset($plugins[$key])) {
          $plugins[$key] = array(
            'type' => $type,
            'title' => check_plain($info[$name]['title']),
            'module' => check_plain($info[$name]['module']),
            'views' => array(),
          );
        }

        // Add this view to the list for this plugin.
        $plugins[$key]['views'][$view->id()] = $view->id();
Earl Miles's avatar
Earl Miles committed
/**
 * A theme preprocess function to automatically allow view-based node
 * templates if called from a view.
 *
 * The 'modules/node.views.inc' file is a better place for this, but
 * we haven't got a chance to load that file before Drupal builds the
 * node portion of the theme registry.
 */
function views_preprocess_node(&$variables) {
  Drupal::moduleHandler()->loadInclude('node', 'views.inc');
  // The 'view' attribute of the node is added in
  // \Drupal\views\Plugin\views\row\EntityRow::preRender().
  if (!empty($variables['node']->view) && $variables['node']->view->storage->id()) {
    $variables['view'] = $variables['node']->view;
    $variables['theme_hook_suggestions'][] = 'node__view__' . $variables['node']->view->storage->id();
    if (!empty($variables['node']->view->current_display)) {
      $variables['theme_hook_suggestions'][] = 'node__view__' . $variables['node']->view->storage->id() . '__' . $variables['node']->view->current_display;
Earl Miles's avatar
Earl Miles committed

      // If a node is being rendered in a view, and the view does not have a path,
      // prevent drupal from accidentally setting the $page variable:
      if ($variables['page'] && $variables['view_mode'] == 'full' && !$variables['view']->display_handler->hasPath()) {
        $variables['page'] = FALSE;
Earl Miles's avatar
Earl Miles committed
      }
    }
  }

  // Allow to alter comments and links based on the settings in the row plugin.
  if (!empty($variables['view']->rowPlugin) && $variables['view']->rowPlugin->getPluginId() == 'entity:node') {
    node_row_node_view_preprocess_node($variables);
Earl Miles's avatar
Earl Miles committed
  }
}

/**
 * A theme preprocess function to automatically allow view-based node
 * templates if called from a view.
 */
function views_preprocess_comment(&$variables) {
  // The view data is added to the comment in
  // \Drupal\views\Plugin\views\row\EntityRow::preRender().
  if (!empty($variables['comment']->view) && $variables['comment']->view->storage->id()) {
    $variables['view'] = &$variables['comment']->view;
    $variables['theme_hook_suggestions'][] = 'comment__view__' . $variables['comment']->view->storage->id();
    if (!empty($variables['node']->view->current_display)) {
      $variables['theme_hook_suggestions'][] = 'comment__view__' . $variables['comment']->view->storage->id() . '__' . $variables['comment']->view->current_display;
Earl Miles's avatar
Earl Miles committed
 */
function views_permission() {
  return array(
    'access all views' => array(
      'title' => t('Bypass views access control'),
      'description' => t('Bypass access control when accessing views.'),
Earl Miles's avatar
Earl Miles committed
    ),
  );
}

/**
 * Implement hook_menu().
 */
function views_menu() {
  // Any event which causes a menu rebuild could potentially mean that the
Earl Miles's avatar
Earl Miles committed
  // Views data is updated -- module changes, profile changes, etc.
  views_invalidate_cache();
  $items = array();
  $items['views/ajax'] = array(
    'title' => 'Views',
    'theme callback' => 'ajax_base_page_theme',
    'route_name' => 'views_ajax',
Earl Miles's avatar
Earl Miles committed
    'type' => MENU_CALLBACK,
  );
  // Define another taxonomy autocomplete because the default one of drupal
  // does not support a vid a argument anymore
  $items['admin/views/ajax/autocomplete/taxonomy/%'] = array(
Earl Miles's avatar
Earl Miles committed
    'page callback' => 'views_ajax_autocomplete_taxonomy',
Earl Miles's avatar
Earl Miles committed
    'theme callback' => 'ajax_base_page_theme',
    'access callback' => 'user_access',
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK,
    'file' => 'includes/ajax.inc',
  );
  return $items;
}

/**
 * Implement hook_menu_alter().
 */
function views_menu_alter(&$callbacks) {
  $our_paths = array();
  $views = views_get_applicable_views('uses_hook_menu');
Earl Miles's avatar
Earl Miles committed
  foreach ($views as $data) {
    list($view, $display_id) = $data;
    $result = $view->executeHookMenu($display_id, $callbacks);
Earl Miles's avatar
Earl Miles committed
    if (is_array($result)) {
      // The menu system doesn't support having two otherwise
      // identical paths with different placeholders.  So we
      // want to remove the existing items from the menu whose
      // paths would conflict with ours.

      // First, we must find any existing menu items that may
      // conflict.  We use a regular expression because we don't
      // know what placeholders they might use.  Note that we
      // first construct the regex itself by replacing %views_arg
      // in the display path, then we use this constructed regex
      // (which will be something like '#^(foo/%[^/]*/bar)$#') to
      // search through the existing paths.
      $regex = '#^(' . preg_replace('#%views_arg#', '%[^/]*', implode('|', array_keys($result))) . ')$#';
      $matches = preg_grep($regex, array_keys($callbacks));

      // Remove any conflicting items that were found.
      foreach ($matches as $path) {
        // Don't remove the paths we just added!
        if (!isset($our_paths[$path])) {
          unset($callbacks[$path]);
        }
      }
      foreach ($result as $path => $item) {
        if (!isset($callbacks[$path])) {
          // Add a new item, possibly replacing (and thus effectively
          // overriding) one that we removed above.
          $callbacks[$path] = $item;
        }
        $our_paths[$path] = TRUE;
      }
    }
    $view->destroy();
  }
}

/**
 * Helper function for menu loading. This will automatically be
 * called in order to 'load' a views argument; primarily it
 * will be used to perform validation.
 *
 * @param $value
 *   The actual value passed.
 * @param $name
 *   The name of the view. This needs to be specified in the 'load function'
 *   of the menu entry.
 * @param $display_id
 *   The display id that will be loaded for this menu item.
 * @param $index
 *   The menu argument index. This counts from 1.
 */
function views_arg_load($value, $name, $display_id, $index) {
  static $views = array();

  // Make sure we haven't already loaded this views argument for a similar menu
  // item elsewhere.
  $key = $name . ':' . $display_id . ':' . $value . ':' . $index;
  if (isset($views[$key])) {
    return $views[$key];
  }

  if ($view = views_get_view($name)) {
    $view->setDisplay($display_id);
    $view->initHandlers();
Earl Miles's avatar
Earl Miles committed

    $ids = array_keys($view->argument);

    $indexes = array();
Earl Miles's avatar
Earl Miles committed

    foreach ($path as $id => $piece) {
      if ($piece == '%' && !empty($ids)) {
        $indexes[$id] = array_shift($ids);
      }
    }

    if (isset($indexes[$index])) {
      if (isset($view->argument[$indexes[$index]])) {
        $arg = $view->argument[$indexes[$index]]->validateMenuArgument($value) ? $value : FALSE;
Earl Miles's avatar
Earl Miles committed
        $view->destroy();

        // Store the output in case we load this same menu item again.
        $views[$key] = $arg;
        return $arg;
      }
    }
    $view->destroy();
  }
}

/**
 * Page callback: Displays a page view, given a name and display id.
 *
 * @param $name
 *   The name of a view.
 * @param $display_id
 *   The display id of a view.
 *
 * @return
 *   Either the HTML of a fully-executed view, or MENU_NOT_FOUND.
 */
function views_page($name, $display_id) {
  $args = func_get_args();
  // Remove $name and $display_id from the arguments.
  array_shift($args);
  array_shift($args);

  // Load the view and render it.
  if ($view = views_get_view($name)) {
    if ($output = $view->executeDisplay($display_id, $args)) {
      return $output;
    }
    else {
      return array();
    }
  // Fallback if we get here no view was found.
Earl Miles's avatar
Earl Miles committed
  return MENU_NOT_FOUND;
}

/**
 * Implements hook_page_alter().
 */
function views_page_alter(&$page) {
  // If the main content of this page contains a view, attach its contextual
  // links to the overall page array. This allows them to be rendered directly
  // next to the page title.
Earl Miles's avatar
Earl Miles committed
    views_add_contextual_links($page, 'page', $view, $view->current_display);
  }
}

/**
 * Implements MODULE_preprocess_HOOK().
 */
function views_preprocess_html(&$variables) {
  // Early-return to prevent adding unnecessary JavaScript.
  if (!user_access('access contextual links')) {
    return;
  }

Earl Miles's avatar
Earl Miles committed
  // If the page contains a view as its main content, contextual links may have
  // been attached to the page as a whole; for example, by views_page_alter().
  // This allows them to be associated with the page and rendered by default
  // next to the page title (which we want). However, it also causes the
  // Contextual Links module to treat the wrapper for the entire page (i.e.,
  // the <body> tag) as the HTML element that these contextual links are
  // associated with. This we don't want; for better visual highlighting, we
  // prefer a smaller region to be chosen. The region we prefer differs from
  // theme to theme and depends on the details of the theme's markup in
  // page.tpl.php, so we can only find it using JavaScript. We therefore remove
  // the "contextual-region" class from the <body> tag here and add
Earl Miles's avatar
Earl Miles committed
  // JavaScript that will insert it back in the correct place.
  if (!empty($variables['page']['#views_contextual_links'])) {
    $key = array_search('contextual-region', $variables['attributes']['class']);
Earl Miles's avatar
Earl Miles committed
    if ($key !== FALSE) {
      unset($variables['attributes']['class'][$key]);
      $variables['attributes']['data-views-page-contextual-id'] = $variables['title_suffix']['contextual_links']['#id'];
      drupal_add_library('views', 'views.contextual-links');
Earl Miles's avatar
Earl Miles committed
    }
  }
}

/**
 * Adds contextual links associated with a view display to a renderable array.
 *
 * This function should be called when a view is being rendered in a particular
 * location and you want to attach the appropriate contextual links (e.g.,
 * links for editing the view) to it.
 *
 * The function operates by checking the view's display plugin to see if it has
 * defined any contextual links that are intended to be displayed in the
 * requested location; if so, it attaches them. The contextual links intended
 * for a particular location are defined by the 'contextual links' and
 * 'contextual_links_locations' properties in the plugin annotation; as a
 * result, these hook implementations have full control over where and how
 * contextual links are rendered for each display.
Earl Miles's avatar
Earl Miles committed
 *
 * In addition to attaching the contextual links to the passed-in array (via
 * the standard #contextual_links property), this function also attaches
 * additional information via the #views_contextual_links_info property. This
 * stores an array whose keys are the names of each module that provided
 * views-related contextual links (same as the keys of the #contextual_links
 * array itself) and whose values are themselves arrays whose keys ('location',
 * 'view_name', and 'view_display_id') store the location, name of the view,
 * and display ID that were passed in to this function. This allows you to
 * access information about the contextual links and how they were generated in
 * a variety of contexts where you might be manipulating the renderable array
 * later on (for example, alter hooks which run later during the same page
 * request).
 *
 * @param $render_element
 *   The renderable array to which contextual links will be added. This array
 *   should be suitable for passing in to drupal_render() and will normally
 *   contain a representation of the view display whose contextual links are
 *   being requested.
 * @param $location
 *   The location in which the calling function intends to render the view and
 *   its contextual links. The core system supports three options for this
 *   parameter:
 *   - 'block': Used when rendering a block which contains a view. This
 *     retrieves any contextual links intended to be attached to the block
 *     itself.
 *   - 'page': Used when rendering the main content of a page which contains a
 *     view. This retrieves any contextual links intended to be attached to the
 *     page itself (for example, links which are displayed directly next to the
 *     page title).
 *   - 'view': Used when rendering the view itself, in any context. This
 *     retrieves any contextual links intended to be attached directly to the
 *     view.
 *   If you are rendering a view and its contextual links in another location,
 *   you can pass in a different value for this parameter. However, you will
 *   also need to set 'contextual_links_locations' in your plugin annotation to
 *   indicate which view displays support having their contextual links
 *   rendered in the location you have defined.
Earl Miles's avatar
Earl Miles committed
 * @param $view
 *   The view whose contextual links will be added.
 * @param $display_id
 *   The ID of the display within $view whose contextual links will be added.
 *
 * @see \Drupal\views\Plugin\block\block\ViewsBlock::addContextualLinks()
Earl Miles's avatar
Earl Miles committed
 * @see views_page_alter()
 * @see template_preprocess_views_view()
 */
function views_add_contextual_links(&$render_element, $location, ViewExecutable $view, $display_id) {
Earl Miles's avatar
Earl Miles committed
  // Do not do anything if the view is configured to hide its administrative
  // links.
Earl Miles's avatar
Earl Miles committed
    // Also do not do anything if the display plugin has not defined any
    // contextual links that are intended to be displayed in the requested
    // location.
    $plugin_id = $view->displayHandlers->get($display_id)->getPluginId();
    $plugin = Views::pluginManager('display')->getDefinition($plugin_id);
    // If contextual_links_locations are not set, provide a sane default. (To
Earl Miles's avatar
Earl Miles committed
    // avoid displaying any contextual links at all, a display plugin can still
    // set 'contextual_links_locations' to, e.g., {""}.)

    if (!isset($plugin['contextual_links_locations'])) {
      $plugin['contextual_links_locations'] = array('view');
    elseif ($plugin['contextual_links_locations'] == array() || $plugin['contextual_links_locations'] == array('')) {
      $plugin['contextual_links_locations'] = array();
    }
    else {
      $plugin += array('contextual_links_locations' => array('view'));
    }

Earl Miles's avatar
Earl Miles committed
    // On exposed_forms blocks contextual links should always be visible.
    $plugin['contextual_links_locations'][] = 'exposed_filter';
    $has_links = !empty($plugin['contextual links']) && !empty($plugin['contextual_links_locations']);
    if ($has_links && in_array($location, $plugin['contextual_links_locations'])) {
Earl Miles's avatar
Earl Miles committed
      foreach ($plugin['contextual links'] as $module => $link) {
        $args = array();
        $valid = TRUE;
        if (!empty($link['argument properties'])) {
          foreach ($link['argument properties'] as $property) {
            // If the plugin is trying to create an invalid contextual link
            // (for example, "path/to/{$view->storage->property}", where
            // $view->storage->{property} does not exist), we cannot construct
            // the link, so we skip it.
            if (!property_exists($view->storage, $property)) {
Earl Miles's avatar
Earl Miles committed
              $valid = FALSE;
              break;
            }
            else {
              $args[] = $view->storage->{$property};
Earl Miles's avatar
Earl Miles committed
            }
          }
        }
        // If the link was valid, attach information about it to the renderable
        // array.
        if ($valid) {
          $render_element['#views_contextual_links'] = TRUE;
          $render_element['#contextual_links'][$module] = array(
            $link['parent path'],
            $args,
            array(
              'location' => $location,
              'name' => $view->storage->id(),
              'display_id' => $display_id,
            )
 * This is a wrapper around language_list to return a plain key value array.
 * @param string $field
 *   The field of the language object which should be used as the value of the
 *   array.
 * @param int $flags
 *   (optional) Specifies the state of the languages that have to be returned.
 *   It can be: Language::STATE_CONFIGURABLE, Language::STATE_LOCKED,
 *   Language::STATE_ALL.
 *
 * @return array
 *   An array of language names (or $field) keyed by the langcode.
Earl Miles's avatar
Earl Miles committed
 *
 * @see locale_language_list()
 */
function views_language_list($field = 'name', $flags = Language::STATE_ALL) {
Earl Miles's avatar
Earl Miles committed
  $list = array();
  foreach ($languages as $language) {
    $list[$language->id] = ($field == 'name') ? t($language->name) : $language->$field;
Earl Miles's avatar
Earl Miles committed
  }
  return $list;
}

/**
 * Implements hook_ENTITY_TYPE_create() for 'field_instance'.
function views_field_instance_create(FieldInstanceInterface $field_instance) {
  cache('views_info')->deleteAll();
  cache('views_results')->deleteAll();
 * Implements hook_ENTITY_TYPE_update() for 'field_instance'.
function views_field_instance_update(FieldInstanceInterface $field_instance) {
  cache('views_info')->deleteAll();
  cache('views_results')->deleteAll();
 * Implements hook_ENTITY_TYPE_delete() for 'field_instance'.
function views_field_instance_delete(FieldInstanceInterface $field_instance) {
  cache('views_info')->deleteAll();
  cache('views_results')->deleteAll();
Earl Miles's avatar
Earl Miles committed
}

/**
 * Invalidate the views cache, forcing a rebuild on the next grab of table data.
 */
function views_invalidate_cache() {
  cache('views_info')->deleteAll();
  Cache::deleteTags(array('content' => TRUE));
  Drupal::state()->set('menu_rebuild_needed', TRUE);
  $module_handler = Drupal::moduleHandler();

  // Set the router to be rebuild.
  // @todo Figure out why the cache rebuild is trigged but the route table
  //   does not exist yet.
  if (db_table_exists('router')) {
    Drupal::service('router.builder')->rebuild();
  }

  // Invalidate the block cache to update views block derivatives.
  if ($module_handler->moduleExists('block')) {
    Drupal::service('plugin.manager.block')->clearCachedDefinitions();
  // Allow modules to respond to the Views cache being cleared.
  $module_handler->invokeAll('views_invalidate_cache');
Earl Miles's avatar
Earl Miles committed
}

/**
 * Set the current 'page view' that is being displayed so that it is easy
 * for other modules or the theme to identify.
 */
function &views_set_page_view($view = NULL) {
  static $cache = NULL;
  if (isset($view)) {
    $cache = $view;
  }

  return $cache;
}

/**
 * Find out what, if any, page view is currently in use.
 * Note that this returns a reference, so be careful! You can unintentionally
 * modify the $view object.
 *
 * @return \Drupal\views\ViewExecutable
Earl Miles's avatar
Earl Miles committed
 *   A fully formed, empty $view object.
 */
function &views_get_page_view() {
  return views_set_page_view();
}

/**
 * Set the current 'current view' that is being built/rendered so that it is
 * easy for other modules or items in drupal_eval to identify
 *
Earl Miles's avatar
Earl Miles committed
 */
function &views_set_current_view($view = NULL) {
  static $cache = NULL;
  if (isset($view)) {
    $cache = $view;
  }

  return $cache;
}

/**
 * Find out what, if any, current view is currently in use.
 * Note that this returns a reference, so be careful! You can unintentionally
 * modify the $view object.
 *
 * @return \Drupal\views\ViewExecutable
 *   The current view object.
Earl Miles's avatar
Earl Miles committed
 */
function &views_get_current_view() {
  return views_set_current_view();
}

/**
 * Implements hook_hook_info().
 */
function views_hook_info() {
  $hooks = array();

  $hooks += array_fill_keys(array(
    'views_data',
    'views_data_alter',
    'views_analyze',
    'views_invalidate_cache',
  ), array('group' => 'views'));

  // Register a views_plugins alter hook for all plugin types.
  foreach (ViewExecutable::getPluginTypes() as $type) {
    $hooks['views_plugins_' . $type . '_alter'] = array(
      'group' => 'views',
    );
  }

  $hooks += array_fill_keys(array(
    'views_query_substitutions',
    'views_form_substitutions',
    'views_pre_view',
    'views_pre_build',
    'views_post_build',
    'views_pre_execute',
    'views_post_execute',
    'views_pre_render',
    'views_post_render',
    'views_query_alter',
  ), array('group' => 'views_execution'));
 * Implements hook_library_info().
 */
function views_library_info() {
  $path = drupal_get_path('module', 'views');
  $libraries['views.module'] = array(
    'title' => 'Views base',
    'version' => VERSION,
    'css' => array(
      "$path/css/views.module.css"
    ),
  );
  $libraries['views.ajax'] = array(
    'title' => 'Views AJAX',
    'version' => VERSION,
    'js' => array(
      "$path/js/base.js" => array('group' => JS_DEFAULT),
      "$path/js/ajax_view.js" => array('group' => JS_DEFAULT),
    ),
    'dependencies' => array(
      array('system', 'jquery'),
      array('system', 'drupal'),
      array('system', 'drupalSettings'),
      array('system', 'jquery.once'),
      array('system', 'jquery.form'),
      array('system', 'drupal.ajax'),
    ),
  );
  $libraries['views.contextual-links'] = array(
    'title' => 'Views Contextual links',
    'version' => VERSION,
    'js' => array(
      // Set to -10 to move it before the contextual links javascript file.
      "$path/js/views-contextual.js" => array('group' => JS_LIBRARY, 'weight' => -10),
    ),
    'dependencies' => array(
      array('system', 'jquery'),
      array('system', 'drupal'),
    ),
  );
  $libraries['views.exposed-form'] = array(
    'title' => 'Views exposed form',
    'version' => VERSION,
    'css' => array(
      "$path/css/views.exposed_form.css",
    ),
  );
Earl Miles's avatar
Earl Miles committed
}

/**
 * Fetch a list of all base tables available
 *
 * @param $type
 *   Either 'display', 'style' or 'row'
 * @param $key
 *   For style plugins, this is an optional type to restrict to. May be 'normal',
 *   'summary', 'feed' or others based on the neds of the display.
 * @param $base
 *   An array of possible base tables.
 *
 * @return
 *   A keyed array of in the form of 'base_table' => 'Description'.
 */
function views_fetch_plugin_names($type, $key = NULL, $base = array()) {
  $definitions = Views::pluginManager($type)->getDefinitions();
Bram Goffings's avatar
Bram Goffings committed
  foreach ($definitions as $id => $plugin) {
    // Skip plugins that don't conform to our key, if they have one.
    if ($key && isset($plugin['display_types']) && !in_array($key, $plugin['display_types'])) {
    if (empty($plugin['no_ui']) && (empty($base) || empty($plugin['base']) || array_intersect($base, $plugin['base']))) {
Bram Goffings's avatar
Bram Goffings committed
      $plugins[$id] = $plugin['title'];
  if (!empty($plugins)) {
    asort($plugins);
    return $plugins;
 * Gets all the views plugin definitions.
 *
 * @return array
 *   An array of plugin definitions for all types.
function views_get_plugin_definitions() {
  $plugins = array();
  foreach (ViewExecutable::getPluginTypes() as $plugin_type) {
    $plugins[$plugin_type] = Views::pluginManager($plugin_type)->getDefinitions();
/**
 * Get enabled display extenders.
 */
function views_get_enabled_display_extenders() {
  $enabled = array_filter((array) config('views.settings')->get('display_extenders'));
Earl Miles's avatar
Earl Miles committed
/**
 * Return a list of all views and display IDs that have a particular
 * setting in their display's plugin settings.
 *
 * @param string $type
 *   A flag from the display plugin definitions (e.g, 'uses_hook_menu').
 *
 * @return array
 *   A list of arrays containing the $view and $display_id.
Earl Miles's avatar
Earl Miles committed
 * @code
 * array(
 *   array($view, $display_id),
 *   array($view, $display_id),
 * );
 * @endcode
 */
function views_get_applicable_views($type) {
  // Get all display plugins which provides the type.
  $display_plugins = Views::pluginManager('display')->getDefinitions();
  $ids = array();
  foreach ($display_plugins as $id => $definition) {
    if (!empty($definition[$type])) {
      $ids[$id] = $id;
  $entity_ids = Drupal::service('entity.query')->get('view')
    ->condition("display.*.display_plugin", $ids, 'IN')
    ->execute();
  foreach (Drupal::entityManager()->getStorageController('view')->loadMultiple($entity_ids) as $view) {
    // Check each display to see if it meets the criteria and is enabled.
    foreach ($executable->displayHandlers as $id => $handler) {
      if (!empty($handler->definition[$type]) && $handler->isEnabled()) {
        $result[] = array($executable, $id);
Earl Miles's avatar
Earl Miles committed
  return $result;
}

/**
 * Returns an array of all views as fully loaded $view objects.
  return Drupal::entityManager()->getStorageController('view')->loadMultiple();
Earl Miles's avatar
Earl Miles committed
/**
 * Returns an array of all enabled views, as fully loaded $view objects.
 */
function views_get_enabled_views() {
    ->condition('status', TRUE)
    ->execute();

  return entity_load_multiple('view', $query);
Earl Miles's avatar
Earl Miles committed
}

/**
 * Returns an array of all disabled views, as fully loaded $view objects.
 */
function views_get_disabled_views() {
    ->condition('status', FALSE)
    ->execute();

  return entity_load_multiple('view', $query);
Earl Miles's avatar
Earl Miles committed
}

/**
 * Return an array of view as options array, that can be used by select,
 * checkboxes and radios as #options.
 *
 * @param bool $views_only
 *  If TRUE, only return views, not displays.
 * @param string $filter
 *  Filters the views on status. Can either be 'all' (default), 'enabled' or
 *  'disabled'
 * @param  mixed $exclude_view
 *  view or current display to exclude
 *  either a
 *  - views object (containing $exclude_view->storage->name and $exclude_view->current_display)
Earl Miles's avatar
Earl Miles committed
 *  - views name as string:  e.g. my_view
 *  - views name and display id (separated by ':'): e.g. my_view:default
 * @param bool $optgroup
 *  If TRUE, returns an array with optgroups for each view (will be ignored for
 *  $views_only = TRUE). Can be used by select
 * @param bool $sort
 *  If TRUE, the list of views is sorted ascending.
Earl Miles's avatar
Earl Miles committed
 *
 * @return array
 *  an associative array for use in select.
 *  - key: view name and display id separated by ':', or the view name only
 */
function views_get_views_as_options($views_only = FALSE, $filter = 'all', $exclude_view = NULL, $optgroup = FALSE, $sort = FALSE) {
Earl Miles's avatar
Earl Miles committed

  // Filter the big views array.