Update to Drupal 8.0.0. For more information, see https://www.drupal.org/node/2619030

This commit is contained in:
Pantheon Automation 2015-11-19 07:04:44 -08:00 committed by Greg Anderson
parent 7784f4c23d
commit 25a6735fb3
49 changed files with 1394 additions and 281 deletions

View file

@ -116,11 +116,29 @@ class EntityViewsData implements EntityHandlerInterface, EntityViewsDataInterfac
public function getViewsData() {
$data = [];
$base_table = $this->entityType->getBaseTable();
$base_table = $this->entityType->getBaseTable() ?: $this->entityType->id();
$revisionable = $this->entityType->isRevisionable();
$base_field = $this->entityType->getKey('id');
$data_table = $this->entityType->getDataTable();
$revision_table = $this->entityType->getRevisionTable();
$revision_data_table = $this->entityType->getRevisionDataTable();
$revision_table = '';
if ($revisionable) {
$revision_table = $this->entityType->getRevisionTable() ?: $this->entityType->id() . '_revision';
}
$translatable = $this->entityType->isTranslatable();
$data_table = '';
if ($translatable) {
$data_table = $this->entityType->getDataTable() ?: $this->entityType->id() . '_field_data';
}
// Some entity types do not have a revision data table defined, but still
// have a revision table name set in
// \Drupal\Core\Entity\Sql\SqlContentEntityStorage::initTableLayout() so we
// apply the same kind of logic.
$revision_data_table = '';
if ($revisionable && $translatable) {
$revision_data_table = $this->entityType->getRevisionDataTable() ?: $this->entityType->id() . '_field_revision';
}
$revision_field = $this->entityType->getKey('revision');
// Setup base information of the views data.
@ -213,6 +231,10 @@ class EntityViewsData implements EntityHandlerInterface, EntityViewsDataInterfac
// the entity base, revision, data tables.
$field_definitions = $this->entityManager->getBaseFieldDefinitions($this->entityType->id());
if ($table_mapping = $this->storage->getTableMapping()) {
// Fetch all fields that can appear in both the base table and the data
// table.
$entity_keys = $this->entityType->getKeys();
$duplicate_fields = array_intersect_key($entity_keys, array_flip(['id', 'revision', 'bundle']));
// Iterate over each table we have so far and collect field data for each.
// Based on whether the field is in the field_definitions provided by the
// entity manager.
@ -221,6 +243,12 @@ class EntityViewsData implements EntityHandlerInterface, EntityViewsDataInterfac
// @todo https://www.drupal.org/node/2337511
foreach ($table_mapping->getTableNames() as $table) {
foreach ($table_mapping->getFieldNames($table) as $field_name) {
// To avoid confusing duplication in the user interface, for fields
// that are on both base and data tables, only add them on the data
// table (same for revision vs. revision data).
if ($data_table && ($table === $base_table || $table === $revision_table) && in_array($field_name, $duplicate_fields)) {
continue;
}
$this->mapFieldDefinition($table, $field_name, $field_definitions[$field_name], $table_mapping, $data[$table]);
}
}

View file

@ -0,0 +1,48 @@
<?php
/**
* @file
* Contains \Drupal\views\Tests\Update\FieldHandlersUpdateTest.
*/
namespace Drupal\views\Tests\Update;
use Drupal\system\Tests\Update\UpdatePathTestBase;
use Drupal\views\Entity\View;
/**
* Tests the upgrade path for views field handlers.
*
* @see views_post_update_cleanup_duplicate_views_data()
*
* @group Update
*/
class FieldHandlersUpdateTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
__DIR__ . '/../../../tests/fixtures/update/duplicate-field-handler.php',
];
}
/**
* Tests that field handlers are updated properly.
*/
public function testViewsUpdate8004() {
$this->runUpdates();
// Load and initialize our test view.
$view = View::load('test_duplicate_field_handlers');
$data = $view->toArray();
// Check that the field is using the expected base table.
$this->assertEqual('node_field_data', $data['display']['default']['display_options']['fields']['nid']['table']);
$this->assertEqual('node_field_data', $data['display']['default']['display_options']['filters']['type']['table']);
$this->assertEqual('node_field_data', $data['display']['default']['display_options']['sorts']['vid']['table']);
$this->assertEqual('node_field_data', $data['display']['default']['display_options']['arguments']['nid']['table']);
}
}

View file

@ -0,0 +1,11 @@
<?php
$connection = Drupal\Core\Database\Database::getConnection();
$connection->insert('config')
->fields(array(
'collection' => '',
'name' => 'views.view.test_duplicate_field_handlers',
'data' => serialize(\Drupal\Component\Serialization\Yaml::decode(file_get_contents('core/modules/views/tests/modules/views_test_config/test_views/views.view.test_duplicate_field_handlers.yml'))),
))
->execute();

View file

@ -0,0 +1,246 @@
langcode: en
status: true
dependencies:
config:
- node.type.article
module:
- node
- user
id: test_duplicate_field_handlers
label: 'Test Duplicate Field Handlers'
module: views
description: ''
tag: ''
base_table: node_field_data
base_field: nid
core: 8.x
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: none
options:
items_per_page: null
offset: 0
style:
type: default
row:
type: fields
fields:
nid:
id: nid
table: node
field: nid
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: 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
entity_type: node
entity_field: nid
plugin_id: field
filters:
type:
id: type
table: node
field: type
relationship: none
group_type: group
admin_label: ''
operator: in
value:
article: article
group: 1
exposed: false
expose:
operator_id: ''
label: ''
description: ''
use_operator: false
operator: ''
identifier: ''
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
reduce: false
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: type
plugin_id: bundle
sorts:
vid:
id: vid
table: node
field: vid
relationship: none
group_type: group
admin_label: ''
order: ASC
exposed: false
expose:
label: ''
entity_type: node
entity_field: vid
plugin_id: standard
title: 'Test Duplicate Field Handlers'
header: { }
footer: { }
empty: { }
relationships: { }
arguments:
nid:
id: nid
table: node
field: nid
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: { }
break_phrase: false
not: false
entity_type: node
entity_field: nid
plugin_id: numeric
display_extenders: { }
cache_metadata:
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- 'user.node_grants:view'
- user.permissions
cacheable: false
page_1:
display_plugin: page
id: page_1
display_title: Page
position: 1
display_options:
display_extenders: { }
path: test-duplicate-field-handlers
cache_metadata:
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- 'user.node_grants:view'
- user.permissions
cacheable: false

View file

@ -130,7 +130,7 @@ display:
fields:
nid:
id: nid
table: node
table: node_field_data
field: nid
relationship: none
group_type: group

View file

@ -93,7 +93,12 @@ class EntityViewsDataTest extends UnitTestCase {
'base_table' => 'entity_test',
'id' => 'entity_test',
'label' => 'Entity test',
'entity_keys' => ['id' => 'id', 'langcode' => 'langcode'],
'entity_keys' => [
'id' => 'id',
'langcode' => 'langcode',
'bundle' => 'type',
'revision' => 'revision_id',
],
'provider' => 'entity_test',
'list_cache_contexts' => ['entity_test_list_cache_context'],
]);
@ -190,6 +195,7 @@ class EntityViewsDataTest extends UnitTestCase {
$entity_type = $this->baseEntityType
->set('data_table', 'entity_test_mul_property_data')
->set('id', 'entity_test_mul')
->set('translatable', TRUE)
->setKey('label', 'label');
$this->viewsData->setEntityType($entity_type);
@ -259,6 +265,7 @@ class EntityViewsDataTest extends UnitTestCase {
->set('revision_table', 'entity_test_mulrev_revision')
->set('revision_data_table', 'entity_test_mulrev_property_revision')
->set('id', 'entity_test_mulrev')
->set('translatable', TRUE)
->setKey('revision', 'revision_id')
;
$this->viewsData->setEntityType($entity_type);
@ -297,6 +304,7 @@ class EntityViewsDataTest extends UnitTestCase {
->set('revision_table', 'entity_test_mulrev_revision')
->set('revision_data_table', 'entity_test_mulrev_property_revision')
->set('id', 'entity_test_mulrev')
->set('translatable', TRUE)
->setKey('revision', 'revision_id')
;
$this->viewsData->setEntityType($entity_type);
@ -316,7 +324,7 @@ class EntityViewsDataTest extends UnitTestCase {
$revision_data = $data['entity_test_mulrev_property_revision'];
$this->assertCount(2, $revision_data['table']['join']);
$this->assertEquals([
'entity_test' => ['left_field' => 'revision_id', 'field' => 'revision_id', 'type' => 'INNER'],
'entity_test_mulrev_field_data' => ['left_field' => 'revision_id', 'field' => 'revision_id', 'type' => 'INNER'],
'entity_test_mulrev_revision' => ['left_field' => 'revision_id', 'field' => 'revision_id', 'type' => 'INNER'],
], $revision_data['table']['join']);
$this->assertFalse(isset($data['data_table']));
@ -526,10 +534,19 @@ class EntityViewsDataTest extends UnitTestCase {
$table_mapping->expects($this->any())
->method('getFieldNames')
->willReturnMap([
['entity_test_mul', ['id', 'uuid', 'type', 'langcode']],
['entity_test_mul_property_data', ['id', 'langcode', 'name', 'description', 'homepage', 'user_id']],
['entity_test_mul', ['uuid']],
['entity_test_mul_property_data', ['id', 'type', 'langcode', 'name', 'description', 'homepage', 'user_id']],
]);
$table_mapping->expects($this->any())
->method('getFieldTableName')
->willReturnCallback(function($field) {
if ($field == 'uuid') {
return 'entity_test_mul';
}
return 'entity_test_mul_property_data';
});
$this->entityStorage->expects($this->once())
->method('getTableMapping')
->willReturn($table_mapping);
@ -547,17 +564,13 @@ class EntityViewsDataTest extends UnitTestCase {
$data = $this->viewsData->getViewsData();
// Check the base fields.
$this->assertNumericField($data['entity_test_mul']['id']);
$this->assertField($data['entity_test_mul']['id'], 'id');
$this->assertFalse(isset($data['entity_test_mul']['id']));
$this->assertFalse(isset($data['entity_test_mul']['type']));
$this->assertUuidField($data['entity_test_mul']['uuid']);
$this->assertField($data['entity_test_mul']['uuid'], 'uuid');
$this->assertBundleField($data['entity_test_mul']['type']);
$this->assertField($data['entity_test_mul']['type'], 'type');
$this->assertFalse(isset($data['entity_test_mul']['type']['relationship']));
$this->assertLanguageField($data['entity_test_mul']['langcode']);
$this->assertField($data['entity_test_mul']['langcode'], 'langcode');
// Also ensure that field_data only fields don't appear on the base table.
$this->assertFalse(isset($data['entity_test_mul']['name']));
$this->assertFalse(isset($data['entity_test_mul']['description']));
@ -570,6 +583,9 @@ class EntityViewsDataTest extends UnitTestCase {
$this->assertNumericField($data['entity_test_mul_property_data']['id']);
$this->assertField($data['entity_test_mul_property_data']['id'], 'id');
$this->assertBundleField($data['entity_test_mul_property_data']['type']);
$this->assertField($data['entity_test_mul_property_data']['type'], 'type');
$this->assertLanguageField($data['entity_test_mul_property_data']['langcode']);
$this->assertField($data['entity_test_mul_property_data']['langcode'], 'langcode');
$this->assertEquals('Translation language', $data['entity_test_mul_property_data']['langcode']['title']);
@ -600,7 +616,8 @@ class EntityViewsDataTest extends UnitTestCase {
->set('revision_table', 'entity_test_mulrev_revision')
->set('data_table', 'entity_test_mulrev_property_data')
->set('revision_data_table', 'entity_test_mulrev_property_revision')
->set('id', 'entity_test_mulrev');
->set('id', 'entity_test_mulrev')
->set('translatable', TRUE);
$base_field_definitions = $this->setupBaseFields(EntityTestMulRev::baseFieldDefinitions($this->baseEntityType));
$user_base_field_definitions = [
'uid' => BaseFieldDefinition::create('integer')
@ -645,6 +662,15 @@ class EntityViewsDataTest extends UnitTestCase {
['entity_test_mulrev_property_revision', ['id', 'revision_id', 'langcode', 'name', 'description', 'homepage', 'user_id']],
]);
$table_mapping->expects($this->any())
->method('getFieldTableName')
->willReturnCallback(function($field) {
if ($field == 'uuid') {
return 'entity_test_mulrev';
}
return 'entity_test_mulrev_property_data';
});
$this->entityStorage->expects($this->once())
->method('getTableMapping')
->willReturn($table_mapping);
@ -654,14 +680,11 @@ class EntityViewsDataTest extends UnitTestCase {
$data = $this->viewsData->getViewsData();
// Check the base fields.
$this->assertNumericField($data['entity_test_mulrev']['id']);
$this->assertField($data['entity_test_mulrev']['id'], 'id');
$this->assertNumericField($data['entity_test_mulrev']['revision_id']);
$this->assertField($data['entity_test_mulrev']['revision_id'], 'revision_id');
$this->assertFalse(isset($data['entity_test_mulrev']['id']));
$this->assertFalse(isset($data['entity_test_mulrev']['type']));
$this->assertFalse(isset($data['entity_test_mulrev']['revision_id']));
$this->assertUuidField($data['entity_test_mulrev']['uuid']);
$this->assertField($data['entity_test_mulrev']['uuid'], 'uuid');
$this->assertStringField($data['entity_test_mulrev']['type']);
$this->assertField($data['entity_test_mulrev']['type'], 'type');
// Also ensure that field_data only fields don't appear on the base table.
$this->assertFalse(isset($data['entity_test_mulrev']['name']));
@ -672,17 +695,12 @@ class EntityViewsDataTest extends UnitTestCase {
$this->assertFalse(isset($data['entity_test_mulrev']['langcode']));
$this->assertFalse(isset($data['entity_test_mulrev']['user_id']));
// Check the revision fields.
$this->assertNumericField($data['entity_test_mulrev_revision']['id']);
$this->assertField($data['entity_test_mulrev_revision']['id'], 'id');
$this->assertNumericField($data['entity_test_mulrev_revision']['revision_id']);
$this->assertField($data['entity_test_mulrev_revision']['revision_id'], 'revision_id');
$this->assertLanguageField($data['entity_test_mulrev_revision']['langcode']);
$this->assertField($data['entity_test_mulrev_revision']['langcode'], 'langcode');
$this->assertEquals('Original language', $data['entity_test_mulrev_revision']['langcode']['title']);
// Check the revision fields. The revision ID should only appear in the data
// table.
$this->assertFalse(isset($data['entity_test_mulrev_revision']['revision_id']));
// Also ensure that field_data only fields don't appear on the revision table.
$this->assertFalse(isset($data['entity_test_mulrev_revision']['id']));
$this->assertFalse(isset($data['entity_test_mulrev_revision']['name']));
$this->assertFalse(isset($data['entity_test_mulrev_revision']['description']));
$this->assertFalse(isset($data['entity_test_mulrev_revision']['description__value']));
@ -693,6 +711,8 @@ class EntityViewsDataTest extends UnitTestCase {
// Check the data fields.
$this->assertNumericField($data['entity_test_mulrev_property_data']['id']);
$this->assertField($data['entity_test_mulrev_property_data']['id'], 'id');
$this->assertNumericField($data['entity_test_mulrev_property_data']['revision_id']);
$this->assertField($data['entity_test_mulrev_property_data']['revision_id'], 'revision_id');
$this->assertLanguageField($data['entity_test_mulrev_property_data']['langcode']);
$this->assertField($data['entity_test_mulrev_property_data']['langcode'], 'langcode');
$this->assertStringField($data['entity_test_mulrev_property_data']['name']);

View file

@ -5,6 +5,9 @@
* Post update functions for Views.
*/
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\views\Views;
/**
* @addtogroup updates-8.0.0-beta
* @{
@ -31,6 +34,99 @@ function views_post_update_update_cacheability_metadata() {
}
/**
* Update some views fields that were previously duplicated.
*/
function views_post_update_cleanup_duplicate_views_data() {
$config_factory = \Drupal::configFactory();
$ids = [];
$message = NULL;
$data_tables = [];
$base_tables = [];
$revision_tables = [];
$entities_by_table = [];
$duplicate_fields = [];
$handler_types = Views::getHandlerTypes();
/** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
$entity_type_manager = \Drupal::service('entity_type.manager');
// This will allow us to create an index of all entity types of the site.
foreach ($entity_type_manager->getDefinitions() as $entity_type_id => $entity_type) {
// Store the entity keyed by base table. If it has a data table, use that as
// well.
if ($data_table = $entity_type->getDataTable()) {
$entities_by_table[$data_table] = $entity_type;
}
if ($base_table = $entity_type->getBaseTable()) {
$entities_by_table[$base_table] = $entity_type;
}
// The following code basically contains the same kind of logic as
// \Drupal\Core\Entity\Sql\SqlContentEntityStorage::initTableLayout() to
// prefetch all tables (base, data, revision, and revision data).
$base_tables[$entity_type_id] = $entity_type->getBaseTable() ?: $entity_type->id();
$revisionable = $entity_type->isRevisionable();
$revision_table = '';
if ($revisionable) {
$revision_table = $entity_type->getRevisionTable() ?: $entity_type->id() . '_revision';
}
$revision_tables[$entity_type_id] = $revision_table;
$translatable = $entity_type->isTranslatable();
$data_table = '';
// For example the data table just exists, when the entity type is
// translatable.
if ($translatable) {
$data_table = $entity_type->getDataTable() ?: $entity_type->id() . '_field_data';
}
$data_tables[$entity_type_id] = $data_table;
$duplicate_fields[$entity_type_id] = array_intersect_key($entity_type->getKeys(), array_flip(['id', 'revision', 'bundle']));
}
foreach ($config_factory->listAll('views.view.') as $view_config_name) {
$changed = FALSE;
$view = $config_factory->getEditable($view_config_name);
$displays = $view->get('display');
if (isset($entities_by_table[$view->get('base_table')])) {
$entity_type = $entities_by_table[$view->get('base_table')];
$entity_type_id = $entity_type->id();
$data_table = $data_tables[$entity_type_id];
$base_table = $base_tables[$entity_type_id];
$revision_table = $revision_tables[$entity_type_id];
if ($data_table) {
foreach ($displays as $display_name => &$display) {
foreach ($handler_types as $handler_type) {
if (!empty($display['display_options'][$handler_type['plural']])) {
foreach ($display['display_options'][$handler_type['plural']] as $field_name => &$field) {
$table = $field['table'];
if (($table === $base_table || $table === $revision_table) && in_array($field_name, $duplicate_fields[$entity_type_id])) {
$field['table'] = $data_table;
$changed = TRUE;
}
}
}
}
}
}
}
if ($changed) {
$view->set('display', $displays);
$view->save();
$ids[] = $view->get('id');
}
}
if (!empty($ids)) {
$message = new TranslatableMarkup('Updated tables for field handlers for views: @ids', ['@ids' => implode(', ', array_unique($ids))]);
}
return $message;
}
/**
* @} End of "addtogroup updates-8.0.0-beta".
*/