Skip to content
Snippets Groups Projects
Commit 663762f3 authored by catch's avatar catch
Browse files

Issue #2989745 by plach, jungle, alexpott, Lendude, catch, tim.plunkett:...

Issue #2989745 by plach, jungle, alexpott, Lendude, catch, tim.plunkett: views_update_8500() inlines configuration changes instead of this being done on config save for bc

(cherry picked from commit 6964f09b)
parent 4679a0d3
Branches
No related tags found
No related merge requests found
<?php
namespace Drupal\views;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Config\Schema\ArrayElement;
use Drupal\Core\Config\TypedConfigManagerInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\Sql\DefaultTableMapping;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a BC layer for modules providing old configurations.
*
* @internal
* This class is only meant to fix outdated views configuration and its
* methods should not be invoked directly. It will be removed once all the
* deprecated methods have been removed.
*/
class ViewsConfigUpdater implements ContainerInjectionInterface {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The entity field manager.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $entityFieldManager;
/**
* The typed config manager.
*
* @var \Drupal\Core\Config\TypedConfigManagerInterface
*/
protected $typedConfigManager;
/**
* The views data service.
*
* @var \Drupal\views\ViewsData
*/
protected $viewsData;
/**
* An array of helper data for the multivalue base field update.
*
* @var array
*/
protected $multivalueBaseFieldsUpdateTableInfo;
/**
* Flag determining whether deprecations should be triggered.
*
* @var bool
*/
protected $deprecationsEnabled = TRUE;
/**
* Stores which deprecations were triggered.
*
* @var bool
*/
protected $triggeredDeprecations = [];
/**
* ViewsConfigUpdater constructor.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
* The entity field manager.
* @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config_manager
* The typed config manager.
* @param \Drupal\views\ViewsData $views_data
* The views data service.
*/
public function __construct(
EntityTypeManagerInterface $entity_type_manager,
EntityFieldManagerInterface $entity_field_manager,
TypedConfigManagerInterface $typed_config_manager,
ViewsData $views_data
) {
$this->entityTypeManager = $entity_type_manager;
$this->entityFieldManager = $entity_field_manager;
$this->typedConfigManager = $typed_config_manager;
$this->viewsData = $views_data;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity_type.manager'),
$container->get('entity_field.manager'),
$container->get('config.typed'),
$container->get('views.views_data')
);
}
/**
* Sets the deprecations enabling status.
*
* @param bool $enabled
* Whether deprecations should be enabled.
*/
public function setDeprecationsEnabled($enabled) {
$this->deprecationsEnabled = $enabled;
}
/**
* Performs all required updates.
*
* @param \Drupal\views\ViewEntityInterface $view
* The View to update.
*
* @return bool
* Whether the view was updated.
*/
public function updateAll(ViewEntityInterface $view) {
return $this->processDisplayHandlers($view, FALSE, function (&$handler, $handler_type, $key, $display_id) use ($view) {
$changed = FALSE;
if ($this->processEntityLinkUrlHandler($handler, $handler_type, $view)) {
$changed = TRUE;
}
if ($this->processOperatorDefaultsHandler($handler, $handler_type, $view)) {
$changed = TRUE;
}
if ($this->processMultivalueBaseFieldHandler($handler, $handler_type, $key, $display_id, $view)) {
$changed = TRUE;
}
return $changed;
});
}
/**
* Processes all display handlers.
*
* @param \Drupal\views\ViewEntityInterface $view
* The View to update.
* @param bool $return_on_changed
* Whether processing should stop after a change is detected.
* @param callable $handler_processor
* A callback performing the actual update.
*
* @return bool
* Whether the view was updated.
*/
protected function processDisplayHandlers(ViewEntityInterface $view, $return_on_changed, callable $handler_processor) {
$changed = FALSE;
$displays = $view->get('display');
$handler_types = ['field', 'argument', 'sort', 'relationship', 'filter'];
foreach ($displays as $display_id => &$display) {
foreach ($handler_types as $handler_type) {
$handler_type_plural = $handler_type . 's';
if (!empty($display['display_options'][$handler_type_plural])) {
foreach ($display['display_options'][$handler_type_plural] as $key => &$handler) {
if ($handler_processor($handler, $handler_type, $key, $display_id)) {
$changed = TRUE;
if ($return_on_changed) {
return $changed;
}
}
}
}
}
}
if ($changed) {
$view->set('display', $displays);
}
return $changed;
}
/**
* Add additional settings to the entity link field.
*
* @param \Drupal\views\ViewEntityInterface $view
* The View to update.
*
* @return bool
* Whether the view was updated.
*
* @deprecated in drupal:9.0.0 and is removed from drupal:10.0.0.
* Module-provided Views configuration should be updated to accommodate the
* changes described below.
*
* @see https://www.drupal.org/node/2857891
*/
public function needsEntityLinkUrlUpdate(ViewEntityInterface $view) {
return $this->processDisplayHandlers($view, TRUE, function (&$handler, $handler_type) use ($view) {
return $this->processEntityLinkUrlHandler($handler, $handler_type, $view);
});
}
/**
* Processes entity link URL fields.
*
* @param array $handler
* A display handler.
* @param string $handler_type
* The handler type.
* @param \Drupal\views\ViewEntityInterface $view
* The View being updated.
*
* @return bool
* Whether the handler was updated.
*/
protected function processEntityLinkUrlHandler(array &$handler, $handler_type, ViewEntityInterface $view) {
$changed = FALSE;
if ($handler_type === 'field') {
if (isset($handler['plugin_id']) && $handler['plugin_id'] === 'entity_link') {
// Add any missing settings for entity_link.
if (!isset($handler['output_url_as_text'])) {
$handler['output_url_as_text'] = FALSE;
$changed = TRUE;
}
if (!isset($handler['absolute'])) {
$handler['absolute'] = FALSE;
$changed = TRUE;
}
}
elseif (isset($handler['plugin_id']) && $handler['plugin_id'] === 'node_path') {
// Convert the use of node_path to entity_link.
$handler['plugin_id'] = 'entity_link';
$handler['field'] = 'view_node';
$handler['output_url_as_text'] = TRUE;
$changed = TRUE;
}
}
$deprecations_triggered = &$this->triggeredDeprecations['2857891'][$view->id()];
if ($this->deprecationsEnabled && $changed && !$deprecations_triggered) {
$deprecations_triggered = TRUE;
@trigger_error(sprintf('The entity link url update for the "%s" view is deprecated in drupal:9.0.0 and is removed from drupal:10.0.0. Module-provided Views configuration should be updated to accommodate the changes described at https://www.drupal.org/node/2857891.', $view->id()), E_USER_DEPRECATED);
}
return $changed;
}
/**
* Add additional settings to the entity link field.
*
* @param \Drupal\views\ViewEntityInterface $view
* The View to update.
*
* @return bool
* Whether the view was updated.
*
* @deprecated in drupal:9.0.0 and is removed from drupal:10.0.0.
* Module-provided Views configuration should be updated to accommodate the
* changes described below.
*
* @see https://www.drupal.org/node/2869168
*/
public function needsOperatorDefaultsUpdate(ViewEntityInterface $view) {
return $this->processDisplayHandlers($view, TRUE, function (&$handler, $handler_type) use ($view) {
return $this->processOperatorDefaultsHandler($handler, $handler_type, $view);
});
}
/**
* Processes operator defaults.
*
* @param array $handler
* A display handler.
* @param string $handler_type
* The handler type.
* @param \Drupal\views\ViewEntityInterface $view
* The View being updated.
*
* @return bool
* Whether the handler was updated.
*/
protected function processOperatorDefaultsHandler(array &$handler, $handler_type, ViewEntityInterface $view) {
$changed = FALSE;
if ($handler_type === 'filter') {
if (!isset($handler['expose']['operator_limit_selection'])) {
$handler['expose']['operator_limit_selection'] = FALSE;
$changed = TRUE;
}
if (!isset($handler['expose']['operator_list'])) {
$handler['expose']['operator_list'] = [];
$changed = TRUE;
}
}
$deprecations_triggered = &$this->triggeredDeprecations['2869168'][$view->id()];
if ($this->deprecationsEnabled && $changed && !$deprecations_triggered) {
$deprecations_triggered = TRUE;
@trigger_error(sprintf('The operator defaults update for the "%s" view is deprecated in drupal:9.0.0 and is removed from drupal:10.0.0. Module-provided Views configuration should be updated to accommodate the changes described at https://www.drupal.org/node/2869168.', $view->id()), E_USER_DEPRECATED);
}
return $changed;
}
/**
* Update field names for multi-value base fields.
*
* @param \Drupal\views\ViewEntityInterface $view
* The View to update.
*
* @return bool
* Whether the view was updated.
*
* @deprecated in drupal:9.0.0 and is removed from drupal:10.0.0.
* Module-provided Views configuration should be updated to accommodate the
* changes described below.
*
* @see https://www.drupal.org/node/2900684
*/
public function needsMultivalueBaseFieldUpdate(ViewEntityInterface $view) {
if ($this->getMultivalueBaseFieldUpdateTableInfo()) {
return $this->processDisplayHandlers($view, TRUE, function (&$handler, $handler_type, $key, $display_id) use ($view) {
return $this->processMultivalueBaseFieldHandler($handler, $handler_type, $key, $display_id, $view);
});
}
return FALSE;
}
/**
* Returns the multivalue base fields update table info.
*
* @return array
* An array of multivalue base field info.
*/
protected function getMultivalueBaseFieldUpdateTableInfo() {
$table_info = &$this->multivalueBaseFieldsUpdateTableInfo;
if (!isset($table_info)) {
$table_info = [];
foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) {
if ($entity_type->hasHandlerClass('views_data')) {
$base_field_definitions = $this->entityFieldManager->getBaseFieldDefinitions($entity_type_id);
$entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
$table_mapping = $entity_storage->getTableMapping($base_field_definitions);
if (!$table_mapping instanceof DefaultTableMapping) {
continue;
}
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 on the views in
// ::updateFieldNamesForMultivalueBaseFields().
$table_name = $table_mapping->getFieldTableName($field_name);
$main_property_name = $base_field_storage_definition->getMainPropertyName();
$table_info[$table_name][$field_name] = $table_mapping->getFieldColumnName($base_field_storage_definition, $main_property_name);
}
}
}
}
return $table_info;
}
/**
* Processes handlers affected by the multivalue base field update.
*
* @param array $handler
* A display handler.
* @param string $handler_type
* The handler type.
* @param string $key
* The handler key.
* @param string $display_id
* The handler display ID.
* @param \Drupal\views\ViewEntityInterface $view
* The view being updated.
*
* @return bool
* Whether the handler was updated.
*/
protected function processMultivalueBaseFieldHandler(array &$handler, $handler_type, $key, $display_id, ViewEntityInterface $view) {
$changed = FALSE;
// If there are no multivalue base fields we have nothing to do.
$table_info = $this->getMultivalueBaseFieldUpdateTableInfo();
if (!$table_info) {
return $changed;
}
// Only if the wrong field name is set do we process the field. It
// could already be using the correct field. Like "user__roles" vs
// "roles_target_id".
if (isset($handler['table']) && isset($table_info[$handler['table']]) && isset($table_info[$handler['table']][$handler['field']])) {
$changed = TRUE;
$original_field_name = $handler['field'];
$handler['field'] = $table_info[$handler['table']][$original_field_name];
$handler['plugin_id'] = $this->viewsData->get($handler['table'])[$table_info[$handler['table']][$original_field_name]][$handler_type]['id'];
// Retrieve type data information about the handler to clean it up
// reliably. We need to manually create a typed view rather than
// instantiating the current one, as the schema will be affected by the
// updated values.
$id = 'views.view.' . $view->id();
$path_to_handler = "display.$display_id.display_options.{$handler_type}s.$key";
$view_config = $view->toArray();
$keys = explode('.', $path_to_handler);
NestedArray::setValue($view_config, $keys, $handler);
/** @var \Drupal\Core\Config\Schema\TypedConfigInterface $typed_view */
$typed_view = $this->typedConfigManager->createFromNameAndData($id, $view_config);
/** @var \Drupal\Core\Config\Schema\ArrayElement $typed_handler */
$typed_handler = $typed_view->get($path_to_handler);
// Filter values we want to convert from a string to an array.
if ($handler_type === 'filter' && $typed_handler->get('value') instanceof ArrayElement && is_string($handler['value'])) {
// An empty string cast to an array is an array with one element.
if ($handler['value'] === '') {
$handler['value'] = [];
}
else {
$handler['value'] = (array) $handler['value'];
}
$handler['operator'] = $this->mapOperatorFromSingleToMultiple($handler['operator']);
}
// For all the other fields we try to determine the fields using config
// schema and remove everything not being defined in the new handler.
foreach (array_keys($handler) as $handler_key) {
if (!isset($typed_handler->getDataDefinition()['mapping'][$handler_key])) {
unset($handler[$handler_key]);
}
}
}
$deprecations_triggered = &$this->triggeredDeprecations['2900684'][$view->id()];
if ($this->deprecationsEnabled && $changed && !$deprecations_triggered) {
$deprecations_triggered = TRUE;
@trigger_error(sprintf('The multivalue base field update for the "%s" view is deprecated in drupal:9.0.0 and is removed from drupal:10.0.0. Module-provided Views configuration should be updated to accommodate the changes described at https://www.drupal.org/node/2900684.', $view->id()), E_USER_DEPRECATED);
}
return $changed;
}
/**
* Maps a single operator to a multiple one, if possible.
*
* @param string $single_operator
* A single operator.
*
* @return string
* A multiple operator or the original one if no mapping was available.
*/
protected function mapOperatorFromSingleToMultiple($single_operator) {
switch ($single_operator) {
case '=':
return 'or';
case '!=':
return 'not';
default:
return $single_operator;
}
}
}
langcode: en
status: true
dependencies:
module:
- node
- user
id: node_link_update_test
label: 'node link update test'
module: views
description: ''
tag: ''
base_table: node_field_data
base_field: nid
display:
default:
display_plugin: default
id: default
display_title: Master
position: 0
display_options:
access:
type: perm
options:
perm: 'access content'
cache:
type: tag
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: mini
options:
items_per_page: 10
offset: 0
id: 0
total_pages: null
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
tags:
previous: ‹‹
next: ››
style:
type: default
options:
grouping: { }
row_class: ''
default_row_class: true
uses_fields: false
row:
type: fields
options:
inline: { }
separator: ''
hide_empty: false
default_field_elements: true
fields:
title:
id: title
table: node_field_data
field: title
entity_type: node
entity_field: title
label: ''
alter:
alter_text: false
make_link: false
absolute: false
trim: false
word_boundary: false
ellipsis: false
strip_tags: false
html: false
hide_empty: false
empty_zero: false
settings:
link_to_entity: true
plugin_id: field
relationship: none
group_type: group
admin_label: ''
exclude: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_alter_empty: true
click_sort_column: value
type: string
group_column: value
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
path:
id: path
table: node
field: path
entity_type: node
plugin_id: node_path
view_node:
id: view_node
table: node
field: view_node
relationship: none
group_type: group
admin_label: ''
label: ''
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: false
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
text: view
entity_type: node
plugin_id: entity_link
filters:
status:
value: '1'
table: node_field_data
field: status
plugin_id: boolean
entity_type: node
entity_field: status
id: status
expose:
operator: ''
group: 1
sorts:
created:
id: created
table: node_field_data
field: created
order: DESC
entity_type: node
entity_field: created
plugin_id: date
relationship: none
group_type: group
admin_label: ''
exposed: false
expose:
label: ''
granularity: second
header: { }
footer: { }
empty: { }
relationships: { }
arguments: { }
display_extenders: { }
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url.query_args
- 'user.node_grants:view'
- user.permissions
tags: { }
langcode: en
status: true
dependencies:
module:
- node
- user
id: test_exposed_filters
label: 'Test Exposed filters'
module: views
description: ''
tag: ''
base_table: node_field_data
base_field: nid
display:
default:
display_plugin: default
id: default
display_title: Master
position: 0
display_options:
access:
type: perm
options:
perm: 'access content'
cache:
type: tag
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: mini
options:
items_per_page: 10
offset: 0
id: 0
total_pages: null
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
tags:
previous: ‹‹
next: ››
style:
type: default
row:
type: fields
options:
default_field_elements: true
inline: { }
separator: ''
hide_empty: false
fields:
title:
id: title
table: node_field_data
field: title
entity_type: node
entity_field: title
label: ''
alter:
alter_text: false
make_link: false
absolute: false
trim: false
word_boundary: false
ellipsis: false
strip_tags: false
html: false
hide_empty: false
empty_zero: false
settings:
link_to_entity: true
plugin_id: field
relationship: none
group_type: group
admin_label: ''
exclude: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_alter_empty: true
click_sort_column: value
type: string
group_column: value
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
filters:
status:
value: '1'
table: node_field_data
field: status
plugin_id: boolean
entity_type: node
entity_field: status
id: status
expose:
operator: ''
group: 1
title:
id: title
table: node_field_data
field: title
relationship: none
group_type: group
admin_label: ''
operator: '='
value: ''
group: 1
exposed: true
expose:
operator_id: title_op
label: Title
description: ''
use_operator: true
operator: title_op
identifier: title
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
placeholder: ''
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
entity_type: node
entity_field: title
plugin_id: string
created:
id: created
table: node_field_data
field: created
relationship: none
group_type: group
admin_label: ''
operator: '='
value:
min: ''
max: ''
value: ''
type: date
group: 1
exposed: true
expose:
operator_id: created_op
label: 'Authored on'
description: ''
use_operator: true
operator: created_op
identifier: created
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
placeholder: ''
min_placeholder: ''
max_placeholder: ''
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
entity_type: node
entity_field: created
plugin_id: date
sorts:
created:
id: created
table: node_field_data
field: created
order: DESC
entity_type: node
entity_field: created
plugin_id: date
relationship: none
group_type: group
admin_label: ''
exposed: false
expose:
label: ''
granularity: second
title: 'Test Exposed filters'
header: { }
footer: { }
empty: { }
relationships: { }
arguments: { }
display_extenders: { }
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- 'user.node_grants:view'
- user.permissions
tags: { }
page_1:
display_plugin: page
id: page_1
display_title: Page
position: 1
display_options:
display_extenders: { }
path: test-exposed-filters
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- 'user.node_grants:view'
- user.permissions
tags: { }
uuid: 001475a0-daec-4e8a-8ca7-97b0d24100a6
langcode: en
status: true
dependencies:
module:
- user
id: test_user_multi_value
label: test_user_multi_value
module: views
description: ''
tag: ''
base_table: users_field_data
base_field: uid
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: 0
display_options:
access:
type: perm
options:
perm: 'access user profiles'
cache:
type: tag
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
exposed_form:
type: basic
options:
submit_button: Filter
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: mini
options:
items_per_page: 10
offset: 0
id: 0
total_pages: null
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
tags:
previous: ‹‹
next: ››
style:
type: default
options:
grouping: { }
row_class: ''
default_row_class: true
uses_fields: false
row:
type: fields
options:
inline: { }
separator: ''
hide_empty: false
default_field_elements: true
fields:
roles:
id: roles
table: user__roles
field: roles
relationship: none
group_type: group
admin_label: ''
label: ''
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: false
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
click_sort_column: target_id
type: entity_reference_label
settings:
link: true
group_column: target_id
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
entity_type: user
entity_field: roles
plugin_id: field
filters:
roles:
id: roles
table: user__roles
field: roles
relationship: none
group_type: group
admin_label: ''
operator: '='
value: ''
group: 1
exposed: false
expose:
operator_id: ''
label: ''
description: ''
use_operator: false
operator: ''
identifier: ''
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
entity_type: user
entity_field: roles
plugin_id: string
sorts: { }
header: { }
footer: { }
empty: { }
relationships: { }
arguments:
roles:
id: roles
table: user__roles
field: roles
relationship: none
group_type: group
admin_label: ''
default_action: ignore
exception:
value: all
title_enable: false
title: All
title_enable: false
title: ''
default_argument_type: fixed
default_argument_options:
argument: ''
default_argument_skip_url: false
summary_options:
base_path: ''
count: true
items_per_page: 25
override: false
summary:
sort_order: asc
number_of_records: 0
format: default_summary
specify_validation: false
validate:
type: none
fail: 'not found'
validate_options: { }
glossary: false
limit: 0
case: none
path_case: none
transform_dash: false
break_phrase: false
entity_type: user
entity_field: roles
plugin_id: string
display_extenders: { }
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- user.permissions
tags: { }
<?php
namespace Drupal\Tests\views\Kernel;
use Drupal\Core\Config\FileStorage;
use Drupal\views\ViewsConfigUpdater;
/**
* @coversDefaultClass \Drupal\views\ViewsConfigUpdater
*
* @group Views
* @group legacy
*/
class ViewsConfigUpdaterTest extends ViewsKernelTestBase {
/**
* The views config updater.
*
* @var \Drupal\views\ViewsConfigUpdater
*/
protected $configUpdater;
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp();
$this->configUpdater = $this->container
->get('class_resolver')
->getInstanceFromDefinition(ViewsConfigUpdater::class);
}
/**
* Loads a test view.
*
* @param string $view_id
* The view config ID.
*
* @return \Drupal\views\ViewEntityInterface
* A view entity object.
*/
protected function loadTestView($view_id) {
// We just instantiate the test view from the raw configuration, as it may
// not be possible to save it, due to its faulty schema.
$config_dir = drupal_get_path('module', 'views') . '/tests/fixtures/update';
$file_storage = new FileStorage($config_dir);
$values = $file_storage->read($view_id);
/** @var \Drupal\views\ViewEntityInterface $test_view */
$test_view = $this->container
->get('entity_type.manager')
->getStorage('view')
->create($values);
return $test_view;
}
/**
* @covers ::needsEntityLinkUrlUpdate
*/
public function testNeedsEntityLinkUrlUpdate() {
$test_view = $this->loadTestView('views.view.node_link_update_test');
$this->configUpdater->setDeprecationsEnabled(FALSE);
$needs_update = $this->configUpdater->needsEntityLinkUrlUpdate($test_view);
$this->assertTrue($needs_update);
}
/**
* @covers ::needsEntityLinkUrlUpdate
*
* @expectedDeprecation The entity link url update for the "node_link_update_test" view is deprecated in drupal:9.0.0 and is removed from drupal:10.0.0. Module-provided Views configuration should be updated to accommodate the changes described at https://www.drupal.org/node/2857891.
*/
public function testNeedsEntityLinkUrlUpdateDeprecation() {
$test_view = $this->loadTestView('views.view.node_link_update_test');
$needs_update = $this->configUpdater->needsEntityLinkUrlUpdate($test_view);
$this->assertTrue($needs_update);
}
/**
* @covers ::needsOperatorDefaultsUpdate
*/
public function testNeedsOperatorUpdateDefaults() {
$test_view = $this->loadTestView('views.view.test_exposed_filters');
$this->configUpdater->setDeprecationsEnabled(FALSE);
$needs_update = $this->configUpdater->needsOperatorDefaultsUpdate($test_view);
$this->assertTrue($needs_update);
}
/**
* @covers ::needsOperatorDefaultsUpdate
*
* @expectedDeprecation The operator defaults update for the "test_exposed_filters" view is deprecated in drupal:9.0.0 and is removed from drupal:10.0.0. Module-provided Views configuration should be updated to accommodate the changes described at https://www.drupal.org/node/2869168.
*/
public function testNeedsOperatorDefaultsUpdateDeprecation() {
$test_view = $this->loadTestView('views.view.test_exposed_filters');
$needs_update = $this->configUpdater->needsOperatorDefaultsUpdate($test_view);
$this->assertTrue($needs_update);
}
/**
* @covers ::needsMultivalueBaseFieldUpdate
*/
public function testNeedsFieldNamesForMultivalueBaseFieldsUpdate() {
$test_view = $this->loadTestView('views.view.test_user_multi_value');
$this->configUpdater->setDeprecationsEnabled(FALSE);
$needs_update = $this->configUpdater->needsMultivalueBaseFieldUpdate($test_view);
$this->assertTrue($needs_update);
}
/**
* @covers ::needsMultivalueBaseFieldUpdate
*
* @expectedDeprecation The multivalue base field update for the "test_user_multi_value" view is deprecated in drupal:9.0.0 and is removed from drupal:10.0.0. Module-provided Views configuration should be updated to accommodate the changes described at https://www.drupal.org/node/2900684.
*/
public function testNeedsFieldNamesForMultivalueBaseUpdateFieldsDeprecation() {
$test_view = $this->loadTestView('views.view.test_user_multi_value');
$needs_update = $this->configUpdater->needsMultivalueBaseFieldUpdate($test_view);
$this->assertTrue($needs_update);
}
/**
* @covers ::updateAll
*
* @expectedDeprecation The entity link url update for the "node_link_update_test" view is deprecated in drupal:9.0.0 and is removed from drupal:10.0.0. Module-provided Views configuration should be updated to accommodate the changes described at https://www.drupal.org/node/2857891.
* @expectedDeprecation The operator defaults update for the "test_exposed_filters" view is deprecated in drupal:9.0.0 and is removed from drupal:10.0.0. Module-provided Views configuration should be updated to accommodate the changes described at https://www.drupal.org/node/2869168.
* @expectedDeprecation The multivalue base field update for the "test_user_multi_value" view is deprecated in drupal:9.0.0 and is removed from drupal:10.0.0. Module-provided Views configuration should be updated to accommodate the changes described at https://www.drupal.org/node/2900684.
*/
public function testUpdateAll() {
$view_ids = [
'views.view.node_link_update_test',
'views.view.test_exposed_filters',
'views.view.test_user_multi_value',
];
foreach ($view_ids as $view_id) {
$test_view = $this->loadTestView($view_id);
$this->configUpdater->updateAll($test_view);
}
// @todo Improve this in https://www.drupal.org/node/3121008.
$this->pass('Views processed');
}
}
......@@ -16,6 +16,7 @@
use Drupal\views\ViewExecutable;
use Drupal\views\Entity\View;
use Drupal\views\Views;
use Drupal\views\ViewsConfigUpdater;
/**
* Implements hook_help().
......@@ -822,49 +823,9 @@ function views_view_delete(EntityInterface $entity) {
/**
* Implements hook_ENTITY_TYPE_presave().
*
* Provides a BC layer for modules providing old configurations.
*/
function views_view_presave(ViewEntityInterface $view) {
$displays = $view->get('display');
$changed = FALSE;
foreach ($displays as $display_name => &$display) {
if (isset($display['display_options']['fields'])) {
foreach ($display['display_options']['fields'] as $field_name => &$field) {
if (isset($field['plugin_id']) && $field['plugin_id'] === 'entity_link') {
// Add any missing settings for entity_link.
if (!isset($field['output_url_as_text'])) {
$field['output_url_as_text'] = FALSE;
$changed = TRUE;
}
if (!isset($field['absolute'])) {
$field['absolute'] = FALSE;
$changed = TRUE;
}
}
elseif (isset($field['plugin_id']) && $field['plugin_id'] === 'node_path') {
// Convert the use of node_path to entity_link.
$field['plugin_id'] = 'entity_link';
$field['field'] = 'view_node';
$field['output_url_as_text'] = TRUE;
$changed = TRUE;
}
}
}
if (isset($display['display_options']['filters'])) {
foreach ($display['display_options']['filters'] as $filter_name => &$filter) {
if (!isset($filter['expose']['operator_limit_selection'])) {
$filter['expose']['operator_limit_selection'] = FALSE;
$changed = TRUE;
}
if (!isset($filter['expose']['operator_list'])) {
$filter['expose']['operator_list'] = [];
$changed = TRUE;
}
}
}
}
if ($changed) {
$view->set('display', $displays);
}
/** @var \Drupal\views\ViewsConfigUpdater $config_updater */
$config_updater = \Drupal::classResolver(ViewsConfigUpdater::class);
$config_updater->updateAll($view);
}
......@@ -5,6 +5,9 @@
* Post update functions for Views.
*/
use Drupal\Core\Config\Entity\ConfigEntityUpdater;
use Drupal\views\ViewsConfigUpdater;
/**
* Implements hook_removed_post_updates().
*/
......@@ -29,3 +32,15 @@ function views_removed_post_updates() {
'views_post_update_remove_core_key' => '9.0.0',
];
}
/**
* Update field names for multi-value base fields.
*/
function views_post_update_field_names_for_multivalue_fields(&$sandbox = NULL) {
/** @var \Drupal\views\ViewsConfigUpdater $view_config_updater */
$view_config_updater = \Drupal::classResolver(ViewsConfigUpdater::class);
$view_config_updater->setDeprecationsEnabled(FALSE);
\Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function ($view) use ($view_config_updater) {
return $view_config_updater->needsMultivalueBaseFieldUpdate($view);
});
}
......@@ -115,6 +115,10 @@ public static function isDeprecationSkipped($message) {
'%The "Symfony\\\\Component\\\\Validator\\\\Context\\\\ExecutionContextInterface::.*\(\)" method is considered internal Used by the validator engine. Should not be called by user\s\*\s*code\. It may change without further notice\. You should not extend it from "[^"]+".%',
'%The ".*" service relies on the deprecated "Symfony\\\\Component\\\\Debug\\\\BufferingLogger" class\. It should either be deprecated or its implementation upgraded\.%',
'%The "PHPUnit\\\\Framework\\\\TestCase::addWarning\(\)" method is considered internal%',
// The following deprecations were not added as part of the original
// issues and thus were not addressed in time for the 9.0.0 release.
'%The entity link url update for the "\w+" view is deprecated in drupal:9.0.0 and is removed from drupal:10.0.0. Module-provided Views configuration should be updated to accommodate the changes described at https://www.drupal.org/node/2857891.%',
'%The operator defaults update for the "\w+" view is deprecated in drupal:9.0.0 and is removed from drupal:10.0.0. Module-provided Views configuration should be updated to accommodate the changes described at https://www.drupal.org/node/2869168.%',
];
return (bool) preg_filter($dynamic_skipped_deprecations, '$0', $message);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment