views.module
Same filename in other branches
File
-
core/
modules/ views/ views.module
View source
<?php
/**
* @file
*/
use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\field\FieldStorageConfigInterface;
use Drupal\views\ViewExecutable;
use Drupal\views\Entity\View;
use Drupal\views\Views;
/**
* Allows 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) : void {
// 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;
// The view variable is deprecated.
$variables['deprecations']['view'] = "'view' is deprecated in drupal:11.1.0 and is removed in drupal:12.0.0. There is no replacement. See https://www.drupal.org/node/3459903";
// 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 (!empty($variables['view']->current_display) && $variables['page'] && $variables['view_mode'] == 'full' && !$variables['view']->display_handler
->hasPath()) {
$variables['page'] = FALSE;
}
}
}
/**
* Allows view-based comment templates if called from a view.
*/
function views_preprocess_comment(&$variables) : void {
// 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;
}
}
/**
* 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.
*
* 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 array $render_element
* The renderable array to which contextual links will be added. This array
* should be suitable for passing in to
* \Drupal\Core\Render\RendererInterface::render() and will normally contain a
* representation of the view display whose contextual links are being
* requested.
* @param string $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.
* @param string $display_id
* The ID of the display within $view whose contextual links will be added.
* @param array $view_element
* The render array of the view. It should contain the following properties:
* - #view_id: The ID of the view.
* - #view_display_show_admin_links: A boolean whether the admin links
* should be shown.
* - #view_display_plugin_id: The plugin ID of the display.
*
* @see \Drupal\views\Plugin\Block\ViewsBlock::addContextualLinks()
* @see template_preprocess_views_view()
*/
function views_add_contextual_links(&$render_element, $location, $display_id, ?array $view_element = NULL) {
if (!isset($view_element)) {
$view_element = $render_element;
}
$view_element['#cache_properties'] = [
'view_id',
'view_display_show_admin_links',
'view_display_plugin_id',
];
$view_id = $view_element['#view_id'];
$show_admin_links = $view_element['#view_display_show_admin_links'];
$display_plugin_id = $view_element['#view_display_plugin_id'];
// Do not do anything if the view is configured to hide its administrative
// links or if the Contextual Links module is not enabled.
if (\Drupal::moduleHandler()->moduleExists('contextual') && $show_admin_links) {
// 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 = Views::pluginManager('display')->getDefinition($display_plugin_id);
// If contextual_links_locations are not set, provide a sane default. (To
// 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'] = [
'view',
];
}
elseif ($plugin['contextual_links_locations'] == [] || $plugin['contextual_links_locations'] == [
'',
]) {
$plugin['contextual_links_locations'] = [];
}
else {
$plugin += [
'contextual_links_locations' => [
'view',
],
];
}
// 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'])) {
foreach ($plugin['contextual links'] as $group => $link) {
$args = [];
$valid = TRUE;
if (!empty($link['route_parameters_names'])) {
$view_storage = \Drupal::entityTypeManager()->getStorage('view')
->load($view_id);
foreach ($link['route_parameters_names'] as $parameter_name => $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)) {
$valid = FALSE;
break;
}
else {
$args[$parameter_name] = $view_storage->get($property);
}
}
}
// 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'][$group] = [
'route_parameters' => $args,
'metadata' => [
'location' => $location,
'name' => $view_id,
'display_id' => $display_id,
],
];
// If we're setting contextual links on a page, for a page view, for a
// user that may use contextual links, attach Views' contextual links
// JavaScript.
$render_element['#cache']['contexts'][] = 'user.permissions';
}
}
}
}
}
/**
* Invalidate the views cache, forcing a rebuild on the next grab of table data.
*/
function views_invalidate_cache() {
// Set the menu as needed to be rebuilt.
\Drupal::service('router.builder')->setRebuildNeeded();
$module_handler = \Drupal::moduleHandler();
// Reset the RouteSubscriber from views.
\Drupal::getContainer()->get('views.route_subscriber')
->reset();
// 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');
}
/**
* Set the current view.
*
* Set the current view that is being built/rendered so that it is
* easy for other modules or items in drupal_eval to identify
*
* @return \Drupal\views\ViewExecutable
* The current view object, or NULL if no view is set.
*/
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.
*/
function &views_get_current_view() {
return views_set_current_view();
}
/**
* Implements hook_hook_info().
*/
function views_hook_info() : array {
$hooks = [];
$hooks += array_fill_keys([
'views_data',
'views_data_alter',
'views_analyze',
'views_invalidate_cache',
], [
'group' => 'views',
]);
// Register a views_plugins alter hook for all plugin types.
foreach (ViewExecutable::getPluginTypes() as $type) {
$hooks['views_plugins_' . $type . '_alter'] = [
'group' => 'views',
];
}
$hooks += array_fill_keys([
'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',
], [
'group' => 'views_execution',
]);
$hooks['field_views_data'] = [
'group' => 'views',
];
$hooks['field_views_data_alter'] = [
'group' => 'views',
];
return $hooks;
}
/**
* Returns whether the view is enabled.
*
* @param \Drupal\views\Entity\View $view
* The view object to check.
*
* @return bool
* Returns TRUE if a view is enabled, FALSE otherwise.
*/
function views_view_is_enabled(View $view) {
return $view->status();
}
/**
* Returns whether the view is disabled.
*
* @param \Drupal\views\Entity\View $view
* The view object to check.
*
* @return bool
* Returns TRUE if a view is disabled, FALSE otherwise.
*/
function views_view_is_disabled(View $view) {
return !$view->status();
}
/**
* Enables and saves a view.
*
* @param \Drupal\views\Entity\View $view
* The View object to disable.
*/
function views_enable_view(View $view) {
$view->enable()
->save();
}
/**
* Disables and saves a view.
*
* @param \Drupal\views\Entity\View $view
* The View object to disable.
*/
function views_disable_view(View $view) {
$view->disable()
->save();
}
/**
* Replaces the substitutions recursive foreach condition.
*/
function _views_query_tag_alter_condition(AlterableInterface $query, &$conditions, $substitutions) {
foreach ($conditions as $condition_id => &$condition) {
if (is_numeric($condition_id)) {
if (is_string($condition['field'])) {
$condition['field'] = str_replace(array_keys($substitutions), array_values($substitutions), $condition['field']);
}
elseif (is_object($condition['field'])) {
$sub_conditions =& $condition['field']->conditions();
_views_query_tag_alter_condition($query, $sub_conditions, $substitutions);
}
// $condition['value'] is a subquery so alter the subquery recursive.
// Therefore make sure to get the metadata of the main query.
if (is_object($condition['value'])) {
$subquery = $condition['value'];
$subquery->addMetaData('views_substitutions', $query->getMetaData('views_substitutions'));
\Drupal::moduleHandler()->invoke('views', 'query_views_alter', [
$condition['value'],
]);
}
elseif (isset($condition['value'])) {
// We can not use a simple str_replace() here because it always returns
// a string and we have to keep the type of the condition value intact.
if (is_array($condition['value'])) {
foreach ($condition['value'] as &$value) {
if (is_string($value)) {
$value = str_replace(array_keys($substitutions), array_values($substitutions), $value);
}
}
}
elseif (is_string($condition['value'])) {
$condition['value'] = str_replace(array_keys($substitutions), array_values($substitutions), $condition['value']);
}
}
}
}
}
/**
* Embed a view using a PHP snippet.
*
* This function is meant to be called from PHP snippets, should one wish to
* embed a view in a node or something. It's meant to provide the simplest
* solution and doesn't really offer a lot of options, but breaking the function
* apart is pretty easy, and this provides a worthwhile guide to doing so.
*
* Note that this function does NOT display the title of the view. If you want
* to do that, you will need to do what this function does manually, by
* loading the view, getting the preview and then getting $view->getTitle().
*
* @param string $name
* The name of the view to embed.
* @param string $display_id
* The display id to embed. If unsure, use 'default', as it will always be
* valid. But things like 'page' or 'block' should work here.
* @param mixed ...$args
* Any additional parameters will be passed as arguments.
*
* @return array|null
* A renderable array containing the view output or NULL if the display ID
* of the view to be executed doesn't exist.
*/
function views_embed_view($name, $display_id = 'default', ...$args) {
$view = Views::getView($name);
if (!$view || !$view->access($display_id)) {
return;
}
return [
'#type' => 'view',
'#name' => $name,
'#display_id' => $display_id,
'#arguments' => $args,
];
}
/**
* Get the result of a view.
*
* @param string $name
* The name of the view to retrieve the data from.
* @param string $display_id
* The display ID. On the edit page for the view in question, you'll find a
* list of displays at the left side of the control area. "Default" will be at
* the top of that list. Hover your cursor over the name of the display you
* want to use. A URL will appear in the status bar of your browser. This is
* usually at the bottom of the window, in the chrome. Everything after
* #views-tab- is the display ID, e.g. page_1.
* @param mixed ...$args
* Any additional parameters will be passed as arguments.
*
* @return array
* An array containing an object for each view item.
*/
function views_get_view_result($name, $display_id = NULL, ...$args) {
$view = Views::getView($name);
if (is_object($view)) {
if (is_array($args)) {
$view->setArguments($args);
}
if (is_string($display_id)) {
$view->setDisplay($display_id);
}
else {
$view->initDisplay();
}
$view->preExecute();
$view->execute();
return $view->result;
}
else {
return [];
}
}
/**
* Validation callback for query tags.
*/
function views_element_validate_tags($element, FormStateInterface $form_state) {
$values = array_map('trim', explode(',', $element['#value']));
foreach ($values as $value) {
if (preg_match("/[^a-z_]/", $value)) {
$form_state->setError($element, t('The query tags may only contain lower-case alphabetical characters and underscores.'));
return;
}
}
}
/**
* Determines whether the entity type the field appears in is SQL based.
*
* @param \Drupal\field\FieldStorageConfigInterface $field_storage
* The field storage definition.
*
* @return \Drupal\Core\Entity\Sql\SqlContentEntityStorage
* Returns the entity type storage if supported.
*
* @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use
* \Drupal::service('views.field_data_provider')
* ->getSqlStorageForField($field_storage); instead.
* @see https://www.drupal.org/node/3489502
*/
function _views_field_get_entity_type_storage(FieldStorageConfigInterface $field_storage) {
@trigger_error('_views_field_get_entity_type_storage() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use \\Drupal::service(\'views.field_data_provider\')->getSqlStorageForField($field_storage). See https://www.drupal.org/node/3489502', E_USER_DEPRECATED);
return \Drupal::service('views.field_data_provider')->getSqlStorageForField($field_storage);
}
/**
* Default views data implementation for a field.
*
* @param \Drupal\field\FieldStorageConfigInterface $field_storage
* The field definition.
*
* @return array
* The default views data for the field.
*
* @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use
* \Drupal::service('views.field_data_provider')
* ->defaultFieldImplementation($field_storage); instead.
* @see https://www.drupal.org/node/3489502
*/
function views_field_default_views_data(FieldStorageConfigInterface $field_storage) {
@trigger_error('views_field_default_views_data() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use \\Drupal::service(\'views.field_data_provider\')->defaultFieldImplementation($field_storage). See https://www.drupal.org/node/3489502', E_USER_DEPRECATED);
return \Drupal::service('views.field_data_provider')->defaultFieldImplementation($field_storage);
}
/**
* Returns the label of a certain field.
*
* Therefore it looks up in all bundles to find the most used field.
*
* @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use
* \Drupal::service('entity_field.manager')->getFieldLabels() instead.
*
* @see https://www.drupal.org/node/3489411
*/
function views_entity_field_label($entity_type, $field_name) {
@trigger_error("views_entity_field_label() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use \\Drupal::service('entity_field.manager')->getFieldLabels(). See https://www.drupal.org/node/3489411", E_USER_DEPRECATED);
return \Drupal::service('entity_field.manager')->getFieldLabels($entity_type, $field_name);
}
Functions
Title | Deprecated | Summary |
---|---|---|
views_add_contextual_links | Adds contextual links associated with a view display to a renderable array. | |
views_disable_view | Disables and saves a view. | |
views_element_validate_tags | Validation callback for query tags. | |
views_embed_view | Embed a view using a PHP snippet. | |
views_enable_view | Enables and saves a view. | |
views_entity_field_label | in drupal:11.2.0 and is removed from drupal:12.0.0. Use \Drupal::service('entity_field.manager')->getFieldLabels() instead. |
Returns the label of a certain field. |
views_field_default_views_data | in drupal:11.2.0 and is removed from drupal:12.0.0. Use \Drupal::service('views.field_data_provider') ->defaultFieldImplementation($field_storage); instead. |
Default views data implementation for a field. |
views_get_current_view | Find out what, if any, current view is currently in use. | |
views_get_view_result | Get the result of a view. | |
views_hook_info | Implements hook_hook_info(). | |
views_invalidate_cache | Invalidate the views cache, forcing a rebuild on the next grab of table data. | |
views_preprocess_comment | Allows view-based comment templates if called from a view. | |
views_preprocess_node | Allows view-based node templates if called from a view. | |
views_set_current_view | Set the current view. | |
views_view_is_disabled | Returns whether the view is disabled. | |
views_view_is_enabled | Returns whether the view is enabled. | |
_views_field_get_entity_type_storage | in drupal:11.2.0 and is removed from drupal:12.0.0. Use \Drupal::service('views.field_data_provider') ->getSqlStorageForField($field_storage); instead. |
Determines whether the entity type the field appears in is SQL based. |
_views_query_tag_alter_condition | Replaces the substitutions recursive foreach condition. |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.