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): void { 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(): void { // 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|null|false * The current view object, NULL if no view is set yet, * or FALSE if the view was removed. */ 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|null|false * The current view object, NULL if no view is set yet, * or FALSE if the view was removed. */ 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): void { $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): void { $view->disable()->save(); } /** * Replaces the substitutions recursive foreach condition. */ function _views_query_tag_alter_condition(AlterableInterface $query, &$conditions, $substitutions): void { 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): void { $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); }