Mercurial > hg > cmmr2012-drupal-site
diff core/modules/views/views.install @ 0:c75dbcec494b
Initial commit from drush-created site
author | Chris Cannam |
---|---|
date | Thu, 05 Jul 2018 14:24:15 +0000 |
parents | |
children | a9cd425dd02b |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/modules/views/views.install Thu Jul 05 14:24:15 2018 +0000 @@ -0,0 +1,510 @@ +<?php + +/** + * @file + * Contains install and update functions for Views. + */ + +use Drupal\Core\Config\Schema\ArrayElement; +use Drupal\views\Views; + +/** + * Implements hook_install(). + */ +function views_install() { + module_set_weight('views', 10); +} + +/** + * Update views field plugins. + */ +function views_update_8001(&$sandbox) { + $config_factory = \Drupal::configFactory(); + $ids = []; + $message = NULL; + $ago_formats = [ + 'time ago', + 'time hence', + 'time span', + 'raw time ago', + 'raw time hence', + 'raw time span', + 'inverse time span', + ]; + + foreach ($config_factory->listAll('views.view.') as $view_config_name) { + $view = $config_factory->getEditable($view_config_name); + + $displays = $view->get('display'); + + foreach ($displays as $display_name => $display) { + if (!empty($display['display_options']['fields'])) { + foreach ($display['display_options']['fields'] as $field_name => $field) { + if (isset($field['entity_type']) && $field['plugin_id'] === 'date') { + $ids[] = $view->get('id'); + + // Grab the settings we need to move to a different place in the + // config schema. + $date_format = !empty($field['date_format']) ? $field['date_format'] : 'medium'; + $custom_date_format = !empty($field['custom_date_format']) ? $field['custom_date_format'] : ''; + $timezone = !empty($field['timezone']) ? $field['timezone'] : ''; + + // Save off the base part of the config path we are updating. + $base = "display.$display_name.display_options.fields.$field_name"; + + if (in_array($date_format, $ago_formats)) { + // Update the field to use the Field API formatter. + $view->set($base . '.plugin_id', 'field'); + $view->set($base . '.type', 'timestamp_ago'); + + // Ensure the granularity is an integer, which is defined in the + // field.formatter.settings.timestamp_ago schema. + $granularity = is_numeric($custom_date_format) ? (int) $custom_date_format : 2; + + // Add the new settings. + if ($date_format === 'time ago' || $date_format === 'time hence' || $date_format === 'time span') { + $view->set($base . '.settings.future_format', '@interval hence'); + $view->set($base . '.settings.past_format', '@interval ago'); + $view->set($base . '.settings.granularity', $granularity); + } + elseif ($date_format === 'raw time ago' || $date_format === 'raw time hence') { + $view->set($base . '.settings.future_format', '@interval'); + $view->set($base . '.settings.past_format', '@interval'); + $view->set($base . '.settings.granularity', $granularity); + } + elseif ($date_format === 'raw time span') { + $view->set($base . '.settings.future_format', '@interval'); + $view->set($base . '.settings.past_format', '-@interval'); + $view->set($base . '.settings.granularity', $granularity); + } + elseif ($date_format === 'inverse time span') { + $view->set($base . '.settings.future_format', '-@interval'); + $view->set($base . '.settings.past_format', '@interval'); + $view->set($base . '.settings.granularity', $granularity); + } + } + else { + // Update the field to use the Field API formatter. + $view->set($base . '.plugin_id', 'field'); + $view->set($base . '.type', 'timestamp'); + + // Add the new settings, and make sure everything is a string + // to conform with the field.formatter.settings.timestamp schema. + $view->set($base . '.settings.date_format', (string) $date_format); + $view->set($base . '.settings.custom_date_format', (string) $custom_date_format); + $view->set($base . '.settings.timezone', (string) $timezone); + } + + // Remove the old settings. + $view->clear($base . '.date_format'); + $view->clear($base . '.custom_date_format'); + $view->clear($base . '.timezone'); + } + } + } + } + + $view->save(TRUE); + } + + if (!empty($ids)) { + $message = \Drupal::translation()->translate('Updated field plugins for views: @ids', ['@ids' => implode(', ', array_unique($ids))]); + } + + return $message; +} + +/** + * Updates %1 and !1 tokens to argument tokens. + */ +function views_update_8002() { + $config_factory = \Drupal::configFactory(); + foreach ($config_factory->listAll('views.view.') as $view_config_name) { + $view = $config_factory->getEditable($view_config_name); + + $displays = $view->get('display'); + $argument_map_per_display = _views_update_argument_map($displays); + + $changed = FALSE; + + // Update all the field settings, which support tokens. + foreach ($displays as $display_name => &$display) { + if (!empty($display['display_options']['fields'])) { + $token_values = [ + 'path', + 'alt', + 'link_class', + 'rel', + 'target', + 'query', + 'fragment', + 'prefix', + 'suffix', + 'more_link_text', + 'more_link_path', + 'link_attributes', + 'text', + ]; + + foreach ($display['display_options']['fields'] as $field_name => &$field) { + foreach ($token_values as $token_name) { + if (!empty($field['alter'][$token_name])) { + if (is_array($field['alter'][$token_name])) { + foreach (array_keys($field['alter'][$token_name]) as $key) { + $field['alter'][$token_name][$key] = _views_update_8002_token_update($field['alter'][$token_name][$key], $argument_map_per_display[$display_name]); + $changed = TRUE; + } + } + else { + $field['alter'][$token_name] = _views_update_8002_token_update($field['alter'][$token_name], $argument_map_per_display[$display_name]); + $changed = TRUE; + } + } + } + } + } + } + + // Update the area handlers with tokens. + foreach ($displays as $display_name => &$display) { + $area_types = ['header', 'footer', 'empty']; + foreach ($area_types as $area_type) { + if (!empty($display['display_options'][$area_type])) { + foreach ($display['display_options'][$area_type] as &$area) { + switch ($area['plugin_id']) { + case 'title': + $area['title'] = _views_update_8002_token_update($area['title'], $argument_map_per_display[$display_name]); + $changed = TRUE; + break; + case 'result': + $area['content'] = _views_update_8002_token_update($area['content'], $argument_map_per_display[$display_name]); + $changed = TRUE; + break; + case 'text': + $area['content']['value'] = _views_update_8002_token_update($area['content']['value'], $argument_map_per_display[$display_name]); + $changed = TRUE; + break; + case 'text_custom': + $area['content'] = _views_update_8002_token_update($area['content'], $argument_map_per_display[$display_name]); + $changed = TRUE; + break; + case 'entity': + $area['target'] = _views_update_8002_token_update($area['target'], $argument_map_per_display[$display_name]); + $changed = TRUE; + break; + } + } + } + } + } + + // Update the argument title settings. + foreach ($displays as $display_name => &$display) { + if (!empty($display['display_options']['arguments'])) { + foreach ($display['display_options']['arguments'] as &$argument) { + if (isset($argument['exception']['title'])) { + $argument['exception']['title'] = _views_update_8002_token_update($argument['exception']['title'], $argument_map_per_display[$display_name]); + $changed = TRUE; + } + if (isset($argument['title'])) { + $argument['title'] = _views_update_8002_token_update($argument['title'], $argument_map_per_display[$display_name]); + $changed = TRUE; + } + } + } + } + + // Update the display title settings. + // Update the more link text and more link URL. + foreach ($displays as $display_name => &$display) { + if (!empty($display['display_options']['title'])) { + $display['display_options']['title'] = _views_update_8002_token_update($display['display_options']['title'], $argument_map_per_display[$display_name]); + $changed = TRUE; + } + if (!empty($display['display_options']['use_more_text'])) { + $display['display_options']['use_more_text'] = _views_update_8002_token_update($display['display_options']['use_more_text'], $argument_map_per_display[$display_name]); + $changed = TRUE; + } + if (!empty($display['display_options']['link_url'])) { + $display['display_options']['link_url'] = _views_update_8002_token_update($display['display_options']['link_url'], $argument_map_per_display[$display_name]); + $changed = TRUE; + } + } + + // Update custom classes for row class + grid classes. + // Update RSS description field. + foreach ($displays as $display_name => &$display) { + if (!empty($display['display_options']['style'])) { + if (!empty($display['display_options']['style']['options']['row_class_custom'])) { + $display['display_options']['style']['options']['row_class_custom'] = _views_update_8002_token_update($display['display_options']['style']['options']['row_class_custom'], $argument_map_per_display[$display_name]); + $changed = TRUE; + } + if (!empty($display['display_options']['style']['options']['col_class_custom'])) { + $display['display_options']['style']['options']['col_class_custom'] = _views_update_8002_token_update($display['display_options']['style']['options']['col_class_custom'], $argument_map_per_display[$display_name]); + $changed = TRUE; + } + if (!empty($display['display_options']['style']['options']['description'])) { + $display['display_options']['style']['options']['description'] = _views_update_8002_token_update($display['display_options']['style']['options']['description'], $argument_map_per_display[$display_name]); + $changed = TRUE; + } + } + } + + if ($changed) { + $view->set('display', $displays); + $view->save(TRUE); + } + } +} + +/** + * Updates a views configuration string from using %/! to twig tokens. + * + * @param string $text + * Text in which to search for argument tokens and replace them with their + * twig representation. + * @param array $argument_map + * A map of argument machine names keyed by their previous index. + * + * @return string + * The updated token. + */ +function _views_update_8002_token_update($text, array $argument_map) { + $text = preg_replace_callback('/%(\d)/', function ($match) use ($argument_map) { + return "{{ arguments.{$argument_map[$match[1]]} }}"; + }, $text); + $text = preg_replace_callback('/!(\d)/', function ($match) use ($argument_map) { + return "{{ raw_arguments.{$argument_map[$match[1]]} }}"; + }, $text); + + return $text; +} + +/** + * Builds an argument map for each Views display. + * + * @param array $displays + * A list of Views displays. + * + * @return array + * The argument map keyed by display id. + */ +function _views_update_argument_map($displays) { + $argument_map = []; + foreach ($displays as $display_id => $display) { + $argument_map[$display_id] = []; + if (isset($display['display_options']['arguments'])) { + foreach (array_keys($display['display_options']['arguments']) as $number => $name) { + $argument_map[$display_id][$number + 1] = $name; + } + } + elseif (isset($displays['default']['display_options']['arguments'])) { + foreach (array_keys($displays['default']['display_options']['arguments']) as $number => $name) { + $argument_map[$display_id][$number + 1] = $name; + } + } + } + + return $argument_map; +} + +/** + * Clear caches to fix entity operations field. + */ +function views_update_8003() { + // Empty update to cause a cache flush so that views data is rebuilt. Entity + // types that don't implement a list builder cannot have the entity operations + // field. +} + +/** + * Clear caches due to updated entity views data. + */ +function views_update_8004() { + // Empty update to cause a cache flush so that views data is rebuilt. +} + +/** + * Clear views data cache. + */ +function views_update_8005() { + // Empty update function to rebuild the views data. +} + +/** + * Clear caches due to updated entity views data. + */ +function views_update_8100() { + // Empty update to cause a cache flush so that views data is rebuilt. +} + +/** + * Set default values for enabled/expanded flag on page displays. + */ +function views_update_8101() { + $config_factory = \Drupal::configFactory(); + foreach ($config_factory->listAll('views.view.') as $view_config_name) { + $view = $config_factory->getEditable($view_config_name); + $save = FALSE; + foreach ($view->get('display') as $display_id => $display) { + if ($display['display_plugin'] == 'page') { + $display['display_options']['menu']['enabled'] = TRUE; + $display['display_options']['menu']['expanded'] = FALSE; + $view->set("display.$display_id", $display); + $save = TRUE; + } + } + if ($save) { + $view->save(); + } + } +} + +/** + * Rebuild the container to add a new container parameter. + */ +function views_update_8200() { + // Empty update to cause a cache rebuild so that the container is rebuilt. +} + +/** + * Rebuild cache to refresh the views config schema. + */ +function views_update_8201() { + // Empty update to cause a cache rebuild so that config schema get refreshed. +} + +/** + * Update field names for multi-value base fields. + */ +function views_update_8500() { + // Find all multi-value base fields for content entities. + $entity_type_manager = \Drupal::entityTypeManager(); + $entity_field_manager = \Drupal::service('entity_field.manager'); + $table_update_info = []; + + foreach ($entity_type_manager->getDefinitions() as $entity_type_id => $entity_type) { + if ($entity_type->hasHandlerClass('views_data')) { + $base_field_definitions = $entity_field_manager->getBaseFieldDefinitions($entity_type_id); + + $entity_storage = $entity_type_manager->getStorage($entity_type_id); + $table_mapping = $entity_storage->getTableMapping($base_field_definitions); + + foreach ($base_field_definitions as $field_name => $base_field_definition) { + $base_field_storage_definition = $base_field_definition->getFieldStorageDefinition(); + + // Skip single value and custom storage base fields. + if (!$base_field_storage_definition->isMultiple() || $base_field_storage_definition->hasCustomStorage()) { + continue; + } + + // Get the actual table, as well as the column for the main property + // name so we can perform an update later on the views. + $table_name = $table_mapping->getFieldTableName($field_name); + $main_property_name = $base_field_storage_definition->getMainPropertyName(); + + $table_update_info[$table_name][$field_name] = $table_mapping->getFieldColumnName($base_field_storage_definition, $main_property_name); + } + } + } + + if (empty($table_update_info)) { + return; + } + + $config_factory = \Drupal::configFactory(); + /** @var \Drupal\Core\Config\TypedConfigManagerInterface $typed_config_manager */ + $typed_config_manager = \Drupal::service('config.typed'); + $views_data = Views::viewsData(); + $handler_types = ['field', 'argument', 'sort', 'relationship', 'filter']; + + $required_cleanup_handlers = []; + foreach ($config_factory->listAll('views.view.') as $id) { + $view = $config_factory->getEditable($id); + $changed = FALSE; + + foreach ($view->get('display') as $display_id => &$display) { + foreach ($handler_types as $handler_type_singular) { + $handler_type_plural = $handler_type_singular . 's'; + $handler_data = $view->get("display.$display_id.display_options.$handler_type_plural"); + + if (empty($handler_data)) { + continue; + } + + foreach ($handler_data as $key => $data) { + // If this handler has a table we're interested in, update the field + // name. + $table = $data['table']; + if (isset($table_update_info[$table])) { + $path_to_handler = "display.$display_id.display_options.$handler_type_plural.$key"; + $path_field = "{$path_to_handler}.field"; + $path_plugin_id = "{$path_to_handler}.plugin_id"; + $original_field_name = $view->get($path_field); + + // Only if the wrong field name is set do we change the field. It + // could already be using the correct field. Like + // user__roles/roles_target_id. + if (isset($table_update_info[$table][$original_field_name])) { + $required_cleanup_handlers[$id][] = $path_to_handler; + + // Set both the new table field as well as new 'plugin_id' field. + $view->set($path_field, $table_update_info[$table][$original_field_name]); + $view->set($path_plugin_id, $views_data->get($table)[$table_update_info[$table][$original_field_name]][$handler_type_singular]['id']); + + $changed = TRUE; + } + } + } + } + } + + if ($changed) { + $view->save(TRUE); + } + } + + // Beside of updating the field and plugin ID we also need to truncate orphan + // keys so he configuration applies to the config schema. + // We cannot do that inline in the other code, due to caching issues with + // typed configuration. + foreach ($required_cleanup_handlers as $id => $paths_to_handlers) { + $changed = FALSE; + $typed_view = $typed_config_manager->get($id); + $view = $config_factory->getEditable($id); + foreach ($paths_to_handlers as $path_to_handler) { + /** @var \Drupal\Core\Config\Schema\TypedConfigInterface $typed_view */ + + /** @var \Drupal\Core\Config\Schema\ArrayElement $typed_config */ + $typed_config = $typed_view->get($path_to_handler); + $config = $typed_config->getValue(); + + // Filter values we want to convert from a string to an array. + if (strpos($path_to_handler, 'filters') !== FALSE && $typed_config->get('value') instanceof ArrayElement && is_string($config['value'])) { + // An empty string casted to an array is an array with one + // element. + if ($config['value'] === '') { + $config['value'] = []; + } + else { + $config['value'] = (array) $config['value']; + } + } + + // For all the other fields we try to determine the fields using + // config schema and remove everything which is not needed. + foreach (array_keys($config) as $config_key) { + if (!isset($typed_config->getDataDefinition()['mapping'][$config_key])) { + unset($config[$config_key]); + $changed = TRUE; + } + } + $typed_config->setValue($config); + $view->set($path_to_handler, $typed_config->getValue()); + } + + if ($changed) { + $view->save(); + } + } +}