diff --git a/core/modules/views/tests/fixtures/update/fix-revision-id-update.php b/core/modules/views/tests/fixtures/update/fix-revision-id-update.php new file mode 100644 index 0000000000..228ace239a --- /dev/null +++ b/core/modules/views/tests/fixtures/update/fix-revision-id-update.php @@ -0,0 +1,19 @@ +insert('config') + ->fields([ + 'collection' => '', + 'name' => 'views.view.test_fix_revision_id_update', + 'data' => serialize(Yaml::decode(file_get_contents('core/modules/views/tests/fixtures/update/views.view.test_fix_revision_id_update.yml'))), + ]) + ->execute(); diff --git a/core/modules/views/tests/fixtures/update/views.view.test_fix_revision_id_update.yml b/core/modules/views/tests/fixtures/update/views.view.test_fix_revision_id_update.yml new file mode 100644 index 0000000000..f443883b8a --- /dev/null +++ b/core/modules/views/tests/fixtures/update/views.view.test_fix_revision_id_update.yml @@ -0,0 +1,188 @@ +langcode: und +status: true +dependencies: { } +id: test_fix_revision_id_update +module: views +description: '' +tag: '' +base_table: entity_test_rev_revision +base_field: revision_id +core: '8' +display: + default: + display_options: + access: + type: none + cache: + type: tag + fields: + id: + id: id + table: entity_test_rev_revision + field: id + plugin_id: field + entity_type: entity_test_rev + entity_field: id + revision_id: + id: revision_id + table: entity_test_rev_revision + field: revision_id + plugin_id: field + entity_type: entity_test_rev + entity_field: revision_id + field_test: + id: field_test + table: entity_test_rev__field_test + field: field_test + plugin_id: field + entity_type: entity_test_rev + entity_field: field_test + field_test-revision_id_1: + id: field_test-revision_id_1 + table: entity_test_rev_revision__field_test + field: field_test-revision_id + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: false + alter: + alter_text: true + text: 'Replace: {{ field_test-revision_id_1 }}' + 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: value + type: number_integer + settings: + thousand_separator: '' + prefix_suffix: true + 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 + plugin_id: field + field_test-revision_id_2: + id: field_test-revision_id_2 + table: entity_test_rev_revision__field_test + field: field_test-revision_id + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: false + alter: + alter_text: true + text: 'field_test-revision_id_2: {{ field_test-revision_id_2 }}' + 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: value + type: number_integer + settings: + thousand_separator: '' + prefix_suffix: true + 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 + plugin_id: field + name: + id: name + table: entity_test_rev_revision + field: name + plugin_id: field + entity_type: entity_test_rev + entity_field: name + sorts: + revision_id: + id: revision_id + table: entity_test_rev_revision + field: revision_id + entity_type: entity_test_rev + entity_field: revision_id + order: ASC + style: + type: html_list + display_plugin: default + display_title: Master + id: default + position: 0 diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_field_field_revision_test.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_field_field_revision_test.yml index 817553fc68..8f3a1f8764 100644 --- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_field_field_revision_test.yml +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_field_field_revision_test.yml @@ -6,7 +6,7 @@ module: views description: '' tag: '' base_table: entity_test_rev_revision -base_field: id +base_field: revision_id display: default: display_options: @@ -36,6 +36,70 @@ display: plugin_id: field entity_type: entity_test_rev entity_field: field_test + field_test__revision_id_1: + id: field_test__revision_id_1 + table: entity_test_rev_revision__field_test + field: field_test__revision_id + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: false + alter: + alter_text: true + text: 'Replace: {{ field_test__revision_id_1 }}' + 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: value + type: number_integer + settings: + thousand_separator: '' + prefix_suffix: true + 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 + plugin_id: field name: id: name table: entity_test_rev_revision diff --git a/core/modules/views/tests/src/Functional/Update/ViewsFixRevisionIdUpdateTest.php b/core/modules/views/tests/src/Functional/Update/ViewsFixRevisionIdUpdateTest.php new file mode 100644 index 0000000000..0de26aa796 --- /dev/null +++ b/core/modules/views/tests/src/Functional/Update/ViewsFixRevisionIdUpdateTest.php @@ -0,0 +1,78 @@ +databaseDumpFiles = [ + __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.4.0.bare.standard.php.gz', + __DIR__ . '/../../../fixtures/update/fix-revision-id-update.php', + ]; + } + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->installModulesFromClassProperty($this->container); + } + + /** + * Tests the upgrade path for revision ids in field aliases. + */ + public function testViewsPostUpdateFixRevisionId() { + $view = View::load('test_fix_revision_id_update'); + $data = $view->toArray(); + $fields = $data['display']['default']['display_options']['fields']; + + $this->assertArrayHasKey('field_test-revision_id_1', $fields); + $this->assertEquals('field_test-revision_id_1', $fields['field_test-revision_id_1']['id']); + $this->assertEquals('field_test-revision_id', $fields['field_test-revision_id_1']['field']); + $this->assertEquals('Replace: {{ field_test-revision_id_1 }}', $fields['field_test-revision_id_1']['alter']['text']); + + $this->assertArrayHasKey('field_test-revision_id_2', $fields); + $this->assertEquals('field_test-revision_id_2', $fields['field_test-revision_id_2']['id']); + $this->assertEquals('field_test-revision_id', $fields['field_test-revision_id_2']['field']); + $this->assertEquals('field_test-revision_id_2: {{ field_test-revision_id_2 }}', $fields['field_test-revision_id_2']['alter']['text']); + + $this->runUpdates(); + + $view = View::load('test_fix_revision_id_update'); + $data = $view->toArray(); + $fields = $data['display']['default']['display_options']['fields']; + + $this->assertArrayHasKey('field_test__revision_id_1', $fields); + $this->assertEquals('field_test__revision_id_1', $fields['field_test__revision_id_1']['id']); + $this->assertEquals('field_test__revision_id', $fields['field_test__revision_id_1']['field']); + $this->assertEquals('Replace: {{ field_test__revision_id_1 }}', $fields['field_test__revision_id_1']['alter']['text']); + + $this->assertArrayHasKey('field_test__revision_id_2', $fields); + $this->assertEquals('field_test__revision_id_2', $fields['field_test__revision_id_2']['id']); + $this->assertEquals('field_test__revision_id', $fields['field_test__revision_id_2']['field']); + $this->assertEquals('field_test-revision_id_2: {{ field_test__revision_id_2 }}', $fields['field_test__revision_id_2']['alter']['text']); + + } + +} diff --git a/core/modules/views/tests/src/Kernel/Handler/FieldFieldTest.php b/core/modules/views/tests/src/Kernel/Handler/FieldFieldTest.php index 03ad765c46..90f585876d 100644 --- a/core/modules/views/tests/src/Kernel/Handler/FieldFieldTest.php +++ b/core/modules/views/tests/src/Kernel/Handler/FieldFieldTest.php @@ -463,6 +463,19 @@ public function testRevisionRender() { $this->assertEqual('next entity value', $executable->getStyle()->getField(3, 'name')); } + /** + * Tests the token replacement for revision fields. + */ + public function testRevisionTokenRender() { + $view = Views::getView('test_field_field_revision_test'); + $this->executeView($view); + + $this->assertEqual('Replace: 1', $view->getStyle()->getField(0, 'field_test__revision_id_1')); + $this->assertEqual('Replace: 2', $view->getStyle()->getField(1, 'field_test__revision_id_1')); + $this->assertEqual('Replace: 3', $view->getStyle()->getField(2, 'field_test__revision_id_1')); + $this->assertEqual('Replace: 4', $view->getStyle()->getField(3, 'field_test__revision_id_1')); + } + /** * Tests the result set of a complex revision view. */ diff --git a/core/modules/views/views.post_update.php b/core/modules/views/views.post_update.php index c949f81885..4531e43df6 100644 --- a/core/modules/views/views.post_update.php +++ b/core/modules/views/views.post_update.php @@ -436,3 +436,64 @@ function views_post_update_remove_core_key(&$sandbox = NULL) { return TRUE; }); } + +/** + * Fix '-revision_id' replacement token syntax. + */ +function views_post_update_fix_revision_id_part(&$sandbox = NULL) { + $message = ''; + // Regex to search only for token with machine name '-revision_id' + $old_part = '/{{([^}]+)(-revision_id)/'; + $new_part = '{{$1__revision_id'; + $old_field = '-revision_id'; + $new_field = '__revision_id'; + \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function ($view) use ($message, $old_part, $new_part, $old_field, $new_field) { + /** @var \Drupal\views\ViewEntityInterface $view */ + $is_update = FALSE; + $displays = $view->get('display'); + foreach ($displays as $display_name => &$display) { + if (isset($display['display_options']['fields'])) { + foreach ($display['display_options']['fields'] as $field_name => $field) { + if (!empty($field['alter']['text'])) { + // Fixes replacement token references in rewritten fields. + $alter_text = $field['alter']['text']; + if (preg_match($old_part, $alter_text) === 1) { + $is_update = TRUE; + $field['alter']['text'] = preg_replace($old_part, $new_part, $alter_text); + } + } + + if (!empty($field['alter']['path'])) { + // Fixes replacement token references in link paths. + $alter_path = $field['alter']['path']; + if (preg_match($old_part, $alter_path) === 1) { + $is_update = TRUE; + $field['alter']['path'] = preg_replace($old_part, $new_part, $alter_path); + } + } + + if (strpos($field_name, $old_field) !== FALSE) { + // Replaces the field name and the view id. + $is_update = TRUE; + $field['id'] = str_replace($old_field, $new_field, $field['id']); + $field['field'] = str_replace($old_field, $new_field, $field['field']); + + // Replace key with save order. + $field_name_update = str_replace($old_field, $new_field, $field_name); + $fields = $display['display_options']['fields']; + $keys = array_keys($fields); + $keys[array_search($field_name, $keys)] = $field_name_update; + $display['display_options']['fields'] = array_combine($keys, $fields); + unset($display['display_options']['fields'][$field_name]); + $display['display_options']['fields'][$field_name_update] = $field; + } + } + } + } + if ($is_update) { + $view->set('display', $displays); + } + + return $is_update; + }); +} diff --git a/core/modules/views/views.views.inc b/core/modules/views/views.views.inc index 40af91805c..e67af4a8fb 100644 --- a/core/modules/views/views.views.inc +++ b/core/modules/views/views.views.inc @@ -517,8 +517,8 @@ function views_field_default_views_data(FieldStorageConfigInterface $field_stora $field_alias = $field_name; } else { - $group = t('@group (historical data)', ['@group' => $group_name]); - $field_alias = $field_name . '-revision_id'; + $group = t('@group (historical data)', array('@group' => $group_name)); + $field_alias = $field_name . '__revision_id'; } $data[$table_alias][$field_alias] = [ @@ -576,7 +576,7 @@ function views_field_default_views_data(FieldStorageConfigInterface $field_stora 'field_name' => $field_name, 'entity_type' => $entity_type_id, // Provide a real field for group by. - 'real field' => $field_alias . '_' . $real_field, + 'real field' => $field_name . '_' . $real_field, 'additional fields' => $add_fields, // Default the element type to div, let the UI change it if necessary. 'element type' => 'div',