Issue #2477899 by dawehner, kevin.dutra, borisson_, bojanz, catch, amateescu: Multiple valued Base fields won't work in Views
parent
3f52754e42
commit
445bc90175
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\entity_test\Entity;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
|
||||
/**
|
||||
* Defines an entity type with a multivalue base field.
|
||||
*
|
||||
* @ContentEntityType(
|
||||
* id = "entity_test_multivalue_basefield",
|
||||
* label = @Translation("Entity Test with a multivalue base field"),
|
||||
* base_table = "entity_test_multivalue_basefield",
|
||||
* data_table = "entity_test_multivalue_basefield_field_data",
|
||||
* handlers = {
|
||||
* "views_data" = "Drupal\views\EntityViewsData",
|
||||
* },
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
* "uuid" = "uuid",
|
||||
* "bundle" = "type",
|
||||
* "label" = "name",
|
||||
* "langcode" = "langcode",
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class EntityTestMultiValueBasefield extends EntityTest {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
|
||||
$fields = parent::baseFieldDefinitions($entity_type);
|
||||
$fields['name']->setCardinality(2);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
}
|
|
@ -57,6 +57,13 @@ class EntityViewsData implements EntityHandlerInterface, EntityViewsDataInterfac
|
|||
*/
|
||||
protected $fieldStorageDefinitions;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Constructs an EntityViewsData object.
|
||||
*
|
||||
|
@ -112,6 +119,7 @@ class EntityViewsData implements EntityHandlerInterface, EntityViewsDataInterfac
|
|||
$data = [];
|
||||
|
||||
$base_table = $this->entityType->getBaseTable() ?: $this->entityType->id();
|
||||
$views_revision_base_table = NULL;
|
||||
$revisionable = $this->entityType->isRevisionable();
|
||||
$base_field = $this->entityType->getKey('id');
|
||||
|
||||
|
@ -235,6 +243,7 @@ class EntityViewsData implements EntityHandlerInterface, EntityViewsDataInterfac
|
|||
// Load all typed data definitions of all fields. This should cover each of
|
||||
// the entity base, revision, data tables.
|
||||
$field_definitions = $this->entityManager->getBaseFieldDefinitions($this->entityType->id());
|
||||
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
|
||||
if ($table_mapping = $this->storage->getTableMapping($field_definitions)) {
|
||||
// Fetch all fields that can appear in both the base table and the data
|
||||
// table.
|
||||
|
@ -257,6 +266,36 @@ class EntityViewsData implements EntityHandlerInterface, EntityViewsDataInterfac
|
|||
$this->mapFieldDefinition($table, $field_name, $field_definitions[$field_name], $table_mapping, $data[$table]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($field_definitions as $field_definition) {
|
||||
if ($table_mapping->requiresDedicatedTableStorage($field_definition->getFieldStorageDefinition())) {
|
||||
$table = $table_mapping->getDedicatedDataTableName($field_definition->getFieldStorageDefinition());
|
||||
|
||||
$data[$table]['table']['group'] = $this->entityType->getLabel();
|
||||
$data[$table]['table']['provider'] = $this->entityType->getProvider();
|
||||
$data[$table]['table']['join'][$views_base_table] = [
|
||||
'left_field' => $base_field,
|
||||
'field' => 'entity_id',
|
||||
'extra' => [
|
||||
['field' => 'deleted', 'value' => 0, 'numeric' => TRUE],
|
||||
],
|
||||
];
|
||||
|
||||
if ($revisionable) {
|
||||
$revision_table = $table_mapping->getDedicatedRevisionTableName($field_definition->getFieldStorageDefinition());
|
||||
|
||||
$data[$revision_table]['table']['group'] = $this->t('@entity_type revision', ['@entity_type' => $this->entityType->getLabel()]);
|
||||
$data[$revision_table]['table']['provider'] = $this->entityType->getProvider();
|
||||
$data[$revision_table]['table']['join'][$views_revision_base_table] = [
|
||||
'left_field' => $revision_field,
|
||||
'field' => 'entity_id',
|
||||
'extra' => [
|
||||
['field' => 'deleted', 'value' => 0, 'numeric' => TRUE],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the entity type key to each table generated.
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- entity_test
|
||||
id: test_entity_multivalue_basefield
|
||||
label: ''
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: entity_test_multivalue_basefield
|
||||
base_field: id
|
||||
core: '8'
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
fields:
|
||||
id:
|
||||
id: id
|
||||
table: entity_test_multivalue_basefield
|
||||
field: nid
|
||||
relationship: none
|
||||
plugin_id: field
|
||||
entity_type: entity_test_multivalue_basefield
|
||||
entity_field: id
|
||||
name:
|
||||
id: name
|
||||
table: entity_test_multivalue_basefield__name
|
||||
field: name
|
||||
plugin_id: field
|
||||
entity_type: entity_test_multivalue_basefield
|
||||
entity_field: name
|
||||
defaults:
|
||||
fields: false
|
||||
filters: false
|
||||
sorts:
|
||||
id:
|
||||
id: id
|
||||
table: entity_test_multivalue_basefield
|
||||
field: id
|
||||
order: asc
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\views\Kernel\Entity;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTestMultiValueBasefield;
|
||||
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests entity views with multivalue base fields.
|
||||
*
|
||||
* @group views
|
||||
*/
|
||||
class EntityViewsWithMultivalueBasefieldTest extends ViewsKernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['entity_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $testViews = ['test_entity_multivalue_basefield'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$this->installEntitySchema('entity_test_multivalue_basefield');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests entity views with multivalue base fields.
|
||||
*/
|
||||
public function testView() {
|
||||
EntityTestMultiValueBasefield::create([
|
||||
'name' => 'test',
|
||||
])->save();
|
||||
EntityTestMultiValueBasefield::create([
|
||||
'name' => ['test2', 'test3'],
|
||||
])->save();
|
||||
|
||||
$view = Views::getView('test_entity_multivalue_basefield');
|
||||
$view->execute();
|
||||
$this->assertIdenticalResultset($view, [
|
||||
['name' => ['test']],
|
||||
['name' => ['test2', 'test3']],
|
||||
], ['name' => 'name']);
|
||||
}
|
||||
|
||||
}
|
|
@ -11,6 +11,7 @@ use Drupal\Core\Config\Entity\ConfigEntityType;
|
|||
use Drupal\Core\Entity\ContentEntityType;
|
||||
use Drupal\Core\Entity\EntityType;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\Sql\DefaultTableMapping;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\IntegerItem;
|
||||
|
@ -160,6 +161,12 @@ class EntityViewsDataTest extends UnitTestCase {
|
|||
->setTranslatable(TRUE)
|
||||
->setSetting('max_length', 255);
|
||||
|
||||
// A base field with cardinality > 1
|
||||
$base_fields['string'] = BaseFieldDefinition::create('string')
|
||||
->setLabel('Strong')
|
||||
->setTranslatable(TRUE)
|
||||
->setCardinality(2);
|
||||
|
||||
foreach ($base_fields as $name => $base_field) {
|
||||
$base_field->setName($name);
|
||||
}
|
||||
|
@ -376,6 +383,10 @@ class EntityViewsDataTest extends UnitTestCase {
|
|||
$homepage_field_storage_definition->expects($this->any())
|
||||
->method('getSchema')
|
||||
->willReturn(UriItem::schema($homepage_field_storage_definition));
|
||||
$string_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
|
||||
$string_field_storage_definition->expects($this->any())
|
||||
->method('getSchema')
|
||||
->willReturn(StringItem::schema($string_field_storage_definition));
|
||||
|
||||
// Setup the user_id entity reference field.
|
||||
$this->entityManager->expects($this->any())
|
||||
|
@ -411,6 +422,7 @@ class EntityViewsDataTest extends UnitTestCase {
|
|||
'name' => $name_field_storage_definition,
|
||||
'description' => $description_field_storage_definition,
|
||||
'homepage' => $homepage_field_storage_definition,
|
||||
'string' => $string_field_storage_definition,
|
||||
'user_id' => $user_id_field_storage_definition,
|
||||
'revision_id' => $revision_id_field_storage_definition,
|
||||
]);
|
||||
|
@ -435,10 +447,12 @@ class EntityViewsDataTest extends UnitTestCase {
|
|||
['entity_test', $base_field_definitions],
|
||||
]));
|
||||
// Setup the table mapping.
|
||||
$table_mapping = $this->getMock('Drupal\Core\Entity\Sql\TableMappingInterface');
|
||||
$table_mapping = $this->getMockBuilder(DefaultTableMapping::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getTableNames')
|
||||
->willReturn(['entity_test']);
|
||||
->willReturn(['entity_test', 'entity_test__string']);
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getColumnNames')
|
||||
->willReturnMap([
|
||||
|
@ -450,12 +464,26 @@ class EntityViewsDataTest extends UnitTestCase {
|
|||
['description', ['value' => 'description__value', 'format' => 'description__format']],
|
||||
['homepage', ['value' => 'homepage']],
|
||||
['user_id', ['target_id' => 'user_id']],
|
||||
['string', ['value' => 'value']],
|
||||
]);
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getFieldNames')
|
||||
->willReturnMap([
|
||||
['entity_test', ['id', 'uuid', 'type', 'langcode', 'name', 'description', 'homepage', 'user_id']]
|
||||
['entity_test', ['id', 'uuid', 'type', 'langcode', 'name', 'description', 'homepage', 'user_id']],
|
||||
['entity_test__string', ['string']],
|
||||
]);
|
||||
$table_mapping->expects($this->any())
|
||||
->method('requiresDedicatedTableStorage')
|
||||
->willReturnCallback(function (BaseFieldDefinition $base_field) {
|
||||
return $base_field->getName() === 'string';
|
||||
});
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getDedicatedDataTableName')
|
||||
->willReturnCallback(function (BaseFieldDefinition $base_field) {
|
||||
if ($base_field->getName() === 'string') {
|
||||
return 'entity_test__string';
|
||||
}
|
||||
});
|
||||
|
||||
$this->entityStorage->expects($this->once())
|
||||
->method('getTableMapping')
|
||||
|
@ -492,6 +520,18 @@ class EntityViewsDataTest extends UnitTestCase {
|
|||
$relationship = $data['entity_test']['user_id']['relationship'];
|
||||
$this->assertEquals('users_field_data', $relationship['base']);
|
||||
$this->assertEquals('uid', $relationship['base field']);
|
||||
|
||||
$this->assertStringField($data['entity_test__string']['string']);
|
||||
$this->assertField($data['entity_test__string']['string'], 'string');
|
||||
$this->assertEquals([
|
||||
'left_field' => 'id',
|
||||
'field' => 'entity_id',
|
||||
'extra' => [[
|
||||
'field' => 'deleted',
|
||||
'value' => 0,
|
||||
'numeric' => TRUE,
|
||||
]],
|
||||
], $data['entity_test__string']['table']['join']['entity_test']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -529,10 +569,12 @@ class EntityViewsDataTest extends UnitTestCase {
|
|||
$this->viewsData->setEntityType($entity_type);
|
||||
|
||||
// Setup the table mapping.
|
||||
$table_mapping = $this->getMock('Drupal\Core\Entity\Sql\TableMappingInterface');
|
||||
$table_mapping = $this->getMockBuilder(DefaultTableMapping::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getTableNames')
|
||||
->willReturn(['entity_test_mul', 'entity_test_mul_property_data']);
|
||||
->willReturn(['entity_test_mul', 'entity_test_mul_property_data', 'entity_test_mul__string']);
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getColumnNames')
|
||||
->willReturnMap([
|
||||
|
@ -544,12 +586,14 @@ class EntityViewsDataTest extends UnitTestCase {
|
|||
['description', ['value' => 'description__value', 'format' => 'description__format']],
|
||||
['homepage', ['value' => 'homepage']],
|
||||
['user_id', ['target_id' => 'user_id']],
|
||||
['string', ['value' => 'value']],
|
||||
]);
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getFieldNames')
|
||||
->willReturnMap([
|
||||
['entity_test_mul', ['uuid']],
|
||||
['entity_test_mul_property_data', ['id', 'type', 'langcode', 'name', 'description', 'homepage', 'user_id']],
|
||||
['entity_test_mul__string', ['string']],
|
||||
]);
|
||||
|
||||
$table_mapping->expects($this->any())
|
||||
|
@ -560,6 +604,18 @@ class EntityViewsDataTest extends UnitTestCase {
|
|||
}
|
||||
return 'entity_test_mul_property_data';
|
||||
});
|
||||
$table_mapping->expects($this->any())
|
||||
->method('requiresDedicatedTableStorage')
|
||||
->willReturnCallback(function (BaseFieldDefinition $base_field) {
|
||||
return $base_field->getName() === 'string';
|
||||
});
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getDedicatedDataTableName')
|
||||
->willReturnCallback(function (BaseFieldDefinition $base_field) {
|
||||
if ($base_field->getName() === 'string') {
|
||||
return 'entity_test_mul__string';
|
||||
}
|
||||
});
|
||||
|
||||
$this->entityStorage->expects($this->once())
|
||||
->method('getTableMapping')
|
||||
|
@ -619,6 +675,18 @@ class EntityViewsDataTest extends UnitTestCase {
|
|||
$relationship = $data['entity_test_mul_property_data']['user_id']['relationship'];
|
||||
$this->assertEquals('users_field_data', $relationship['base']);
|
||||
$this->assertEquals('uid', $relationship['base field']);
|
||||
|
||||
$this->assertStringField($data['entity_test_mul__string']['string']);
|
||||
$this->assertField($data['entity_test_mul__string']['string'], 'string');
|
||||
$this->assertEquals([
|
||||
'left_field' => 'id',
|
||||
'field' => 'entity_id',
|
||||
'extra' => [[
|
||||
'field' => 'deleted',
|
||||
'value' => 0,
|
||||
'numeric' => TRUE,
|
||||
]],
|
||||
], $data['entity_test_mul__string']['table']['join']['entity_test_mul']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -650,10 +718,12 @@ class EntityViewsDataTest extends UnitTestCase {
|
|||
$this->viewsData->setEntityType($entity_type);
|
||||
|
||||
// Setup the table mapping.
|
||||
$table_mapping = $this->getMock('Drupal\Core\Entity\Sql\TableMappingInterface');
|
||||
$table_mapping = $this->getMockBuilder(DefaultTableMapping::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getTableNames')
|
||||
->willReturn(['entity_test_mulrev', 'entity_test_mulrev_revision', 'entity_test_mulrev_property_data', 'entity_test_mulrev_property_revision']);
|
||||
->willReturn(['entity_test_mulrev', 'entity_test_mulrev_revision', 'entity_test_mulrev_property_data', 'entity_test_mulrev_property_revision', 'entity_test_mulrev__string', 'entity_test_mulrev_revision__string']);
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getColumnNames')
|
||||
->willReturnMap([
|
||||
|
@ -666,6 +736,7 @@ class EntityViewsDataTest extends UnitTestCase {
|
|||
['homepage', ['value' => 'homepage']],
|
||||
['user_id', ['target_id' => 'user_id']],
|
||||
['revision_id', ['value' => 'id']],
|
||||
['string', ['value' => 'value']],
|
||||
]);
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getFieldNames')
|
||||
|
@ -674,7 +745,29 @@ class EntityViewsDataTest extends UnitTestCase {
|
|||
['entity_test_mulrev_revision', ['id', 'revision_id', 'langcode']],
|
||||
['entity_test_mulrev_property_data', ['id', 'revision_id', 'langcode', 'name', 'description', 'homepage', 'user_id']],
|
||||
['entity_test_mulrev_property_revision', ['id', 'revision_id', 'langcode', 'name', 'description', 'homepage', 'user_id']],
|
||||
['entity_test_mulrev__string', ['string']],
|
||||
['entity_test_mulrev_revision__string', ['string']],
|
||||
]);
|
||||
$table_mapping->expects($this->any())
|
||||
->method('requiresDedicatedTableStorage')
|
||||
->willReturnCallback(function (BaseFieldDefinition $base_field) {
|
||||
return $base_field->getName() === 'string';
|
||||
});
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getDedicatedDataTableName')
|
||||
->willReturnCallback(function (BaseFieldDefinition $base_field) {
|
||||
if ($base_field->getName() === 'string') {
|
||||
return 'entity_test_mulrev__string';
|
||||
}
|
||||
});
|
||||
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getDedicatedRevisionTableName')
|
||||
->willReturnCallback(function (BaseFieldDefinition $base_field) {
|
||||
if ($base_field->getName() === 'string') {
|
||||
return 'entity_test_mulrev_revision__string';
|
||||
}
|
||||
});
|
||||
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getFieldTableName')
|
||||
|
@ -767,6 +860,30 @@ class EntityViewsDataTest extends UnitTestCase {
|
|||
$relationship = $data['entity_test_mulrev_property_revision']['user_id']['relationship'];
|
||||
$this->assertEquals('users_field_data', $relationship['base']);
|
||||
$this->assertEquals('uid', $relationship['base field']);
|
||||
|
||||
$this->assertStringField($data['entity_test_mulrev__string']['string']);
|
||||
$this->assertField($data['entity_test_mulrev__string']['string'], 'string');
|
||||
$this->assertEquals([
|
||||
'left_field' => 'id',
|
||||
'field' => 'entity_id',
|
||||
'extra' => [[
|
||||
'field' => 'deleted',
|
||||
'value' => 0,
|
||||
'numeric' => TRUE,
|
||||
]],
|
||||
], $data['entity_test_mulrev__string']['table']['join']['entity_test_mulrev_property_data']);
|
||||
|
||||
$this->assertStringField($data['entity_test_mulrev_revision__string']['string']);
|
||||
$this->assertField($data['entity_test_mulrev_revision__string']['string'], 'string');
|
||||
$this->assertEquals([
|
||||
'left_field' => 'revision_id',
|
||||
'field' => 'entity_id',
|
||||
'extra' => [[
|
||||
'field' => 'deleted',
|
||||
'value' => 0,
|
||||
'numeric' => TRUE,
|
||||
]],
|
||||
], $data['entity_test_mulrev_revision__string']['table']['join']['entity_test_mulrev_property_revision']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -360,6 +360,13 @@ 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.
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup updates-8.1.0".
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue