diff --git a/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php b/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php index 6f246f7..ec96d47 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php @@ -321,7 +321,7 @@ public function getTableMapping() { // the language code of the default revision. ->setExtraColumns($this->dataTable, array('default_langcode')); - $revision_base_fields = array_merge(array($this->idKey, $this->revisionKey, $this->langcodeKey), $revision_metadata_fields); + $revision_base_fields = array_merge(array($this->idKey, $this->revisionKey, $this->langcodeKey), $revisin_metadata_fields); $this->tableMapping->setFieldNames($this->revisionTable, $revision_base_fields); $revision_data_key_fields = array($this->idKey, $this->revisionKey, $this->langcodeKey); diff --git a/core/lib/Drupal/Core/Entity/EntityType.php b/core/lib/Drupal/Core/Entity/EntityType.php index 728b3ec..9eabb98 100644 --- a/core/lib/Drupal/Core/Entity/EntityType.php +++ b/core/lib/Drupal/Core/Entity/EntityType.php @@ -290,6 +290,14 @@ public function hasKey($key) { /** * {@inheritdoc} */ + public function setKey($key, $value) { + $this->entity_keys[$key] = $value; + return $this; + } + + /** + * {@inheritdoc} + */ public function id() { return $this->id; } diff --git a/core/lib/Drupal/Core/Entity/EntityTypeInterface.php b/core/lib/Drupal/Core/Entity/EntityTypeInterface.php index a6e39aa..ebc7a9a 100644 --- a/core/lib/Drupal/Core/Entity/EntityTypeInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityTypeInterface.php @@ -128,6 +128,8 @@ public function getKey($key); */ public function hasKey($key); + public function setKey($key, $value); + /** * Indicates whether entities should be statically cached. * diff --git a/core/lib/Drupal/Core/Entity/Schema/ContentEntitySchemaHandler.php b/core/lib/Drupal/Core/Entity/Schema/ContentEntitySchemaHandler.php index 4f30d47..ba8ab66 100644 --- a/core/lib/Drupal/Core/Entity/Schema/ContentEntitySchemaHandler.php +++ b/core/lib/Drupal/Core/Entity/Schema/ContentEntitySchemaHandler.php @@ -26,7 +26,7 @@ class ContentEntitySchemaHandler implements EntitySchemaHandlerInterface { /** * The storage field definitions for this entity type. * - * @var \Drupal\Core\Field\FieldDefinitionInterface[] + * @var \Drupal\Core\Field\FieldStorageDefinitionInterface[] */ protected $fieldStorageDefinitions; diff --git a/core/modules/file/src/Entity/File.php b/core/modules/file/src/Entity/File.php index cf8848b..a656707 100644 --- a/core/modules/file/src/Entity/File.php +++ b/core/modules/file/src/Entity/File.php @@ -23,7 +23,8 @@ * label = @Translation("File"), * controllers = { * "storage" = "Drupal\file\FileStorage", - * "view_builder" = "Drupal\Core\Entity\EntityViewBuilder" + * "view_builder" = "Drupal\Core\Entity\EntityViewBuilder", + * "views_data" = "Drupal\views\EntityViewsController" * }, * base_table = "file_managed", * entity_keys = { diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php index 01e6872..2548995 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php @@ -28,7 +28,8 @@ * "default" = "Drupal\entity_test\EntityTestForm", * "delete" = "Drupal\entity_test\EntityTestDeleteForm" * }, - * "translation" = "Drupal\content_translation\ContentTranslationHandler" + * "translation" = "Drupal\content_translation\ContentTranslationHandler", + * "views_data" = "Drupal\views\EntityViewsController" * }, * base_table = "entity_test", * fieldable = TRUE, diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php index a8abda5..6def2a8 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php @@ -24,7 +24,8 @@ * "default" = "Drupal\entity_test\EntityTestForm", * "delete" = "Drupal\entity_test\EntityTestDeleteForm" * }, - * "translation" = "Drupal\content_translation\ContentTranslationHandler" + * "translation" = "Drupal\content_translation\ContentTranslationHandler", + * "views_data" = "Drupal\views\EntityViewsController" * }, * base_table = "entity_test_mul", * data_table = "entity_test_mul_property_data", diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php index b30cbb1..6bd53eb 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php @@ -23,7 +23,8 @@ * "default" = "Drupal\entity_test\EntityTestForm", * "delete" = "Drupal\entity_test\EntityTestDeleteForm" * }, - * "translation" = "Drupal\content_translation\ContentTranslationHandler" + * "translation" = "Drupal\content_translation\ContentTranslationHandler", + * "views_data" = "Drupal\views\EntityViewsController" * }, * base_table = "entity_test_mulrev", * data_table = "entity_test_mulrev_property_data", diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php index ea99ed0..ebb602d 100644 --- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php @@ -23,7 +23,8 @@ * "default" = "Drupal\entity_test\EntityTestForm", * "delete" = "Drupal\entity_test\EntityTestDeleteForm" * }, - * "translation" = "Drupal\content_translation\ContentTranslationHandler" + * "translation" = "Drupal\content_translation\ContentTranslationHandler", + * "views_data" = "Drupal\views\EntityViewsController" * }, * base_table = "entity_test_rev", * revision_table = "entity_test_rev_revision", diff --git a/core/modules/views/src/EntityViewsController.php b/core/modules/views/src/EntityViewsController.php new file mode 100644 index 0000000..7e8eed7 --- /dev/null +++ b/core/modules/views/src/EntityViewsController.php @@ -0,0 +1,299 @@ +entityType = $entity_type; + $this->entityManager = $entity_manager; + $this->storageController = $storage_controller; + $this->moduleHandler = $module_handler; + $this->translationManager = $translation_manager; + $this->typedDataManager = $typed_data_manager; + $this->fieldStorageDefinitions = $entity_manager->getFieldStorageDefinitions($entity_type->id()); + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { + return new static( + $entity_type, + $container->get('entity.manager')->getController($entity_type->id(), 'storage'), + $container->get('entity.manager'), + $container->get('module_handler'), + $container->get('string_translation'), + $container->get('typed_data_manager') + ); + } + + /** + * {@inheritdoc} + */ + public function viewsData() { + $data = array(); + + // @todo In theory we should use the data table as base table, as this would + // save one pointless join (and one more for every relationship). + $base_table = $this->entityType->getBaseTable(); + $base_field = $this->entityType->getKey('id'); + $data_table = $this->entityType->getDataTable(); + $revision_table = $this->entityType->getRevisionTable(); + $revision_data_table = $this->entityType->getRevisionDataTable(); + $revision_field = $this->entityType->getKey('revision'); + + // Setup base information of the views data. + $data[$base_table]['table']['entity_type_id'] = $this->entityType->id(); + $data[$base_table]['table']['group'] = $this->entityType->getLabel(); + $data[$base_table]['table']['base'] = array( + 'field' => $base_field, + 'title' => $this->entityType->getLabel(), + ); + + // Setup relations to the revisions/property data. + if ($data_table) { + $data[$data_table]['table']['join'][$base_table] = array( + 'left_field' => $base_field, + 'field' => $base_field + ); + + } + if ($revision_table) { + $data[$revision_table]['table']['entity_type_id'] = $this->entityType->id(); + $data[$revision_table]['table']['group'] = $this->entityType->getLabel(); + $data[$revision_table]['table']['base'] = array( + 'field' => $revision_field, + 'title' => $this->t('@entity_type revisions', array('@entity_type' => $this->entityType->getLabel())), + ); + // Join the revision table to the base table. + $data[$revision_table]['table']['join'][$base_table] = array( + 'left_field' => $base_field, + 'field' => $base_field, + ); + + if ($revision_data_table) { + $data[$revision_data_table]['table']['join'][$revision_table] = array( + 'left_field' => $revision_field, + 'field' => $revision_field, + ); + } + } + + // Load all typed data definitions of all fields. This should cover each of + // the entity base, revision, data tables. + $field_definitions = $this->entityManager->getFieldDefinitions($this->entityType->id(), 'muuuh'); + $table_mapping = $this->storageController->getTableMapping(); + + // 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. + // @todo We should better just rely on information coming from the entity + // storage controller. + foreach ($table_mapping->getTableNames() as $table) { + foreach ($table_mapping->getFieldNames($table) as $field_name) { + // @todo: may one field be in multiple tables, eg. revision + base? + $this->mapFieldDefinition($field_name, $field_definitions[$field_name], $data[$table]); + } + } + return $data; + } + + protected function mapFieldDefinition($field_name, FieldDefinitionInterface $field_definition, &$views_table_data) { + // Create a dummy instance to retrieve property definitions. + $table_mapping = $this->storageController->getTableMapping(); + $field_column_mapping = $table_mapping->getColumnNames($field_name); + $field_schema = $this->fieldStorageDefinitions[$field_name]->getSchema(); + + switch ($field_definition->getType()) { +// case 'field_item:entity_reference': +// $id_definition = array_slice($property_definitions, 0, 1); +// $id_name = key($id_definition); +// $reference_definition = array_slice($property_definitions, 1, 1); +// $views_table_data[$field_name]['relationship'] = $this->generateRelationship($id_name, $id_definition, $reference_definition, $field_definition); +// break; + default: + $a = 123; + // Add all properties to views table data. + foreach ($field_column_mapping as $field_column_name => $schema_field_name) { + // @TODO: For now, we only support single property fields. + if (!isset($views_table_data[$field_name])) { + } +// if (!isset($views_table_data[$field_name])) { +// $views_table_data[$field_name] = $this->mapFieldStorageDefinition($name, $definition, $field_definition); +// } +// break; + } + } + // @todo Allow field types to customize this. + } + + /** + * Provides a mapping from typed data plugin types to view plugin types. + * + * + * @return array + * The modified views data field definition. + */ + protected function mapFieldStorageDefinition($column_name, $property_definition, $field_definition) { +// $views_field = array(); +// +// $views_field['title'] = $field_definition['label'] . ' (' . $property_definition['label'] . ')'; +// if (!empty($field_definition['description'])) { +// $views_field['help'] = $field_definition['description']; +// } +// +// $definition = $this->typedDataManager->getDefinition($property_definition['type']); +// +// $data_type = $property_definition['type']; +// +// // Map data types to their primitives if possible, for example the email type +// // will be mapped to its primitive type string. +// // @todo: Typed data api should provide an api to retrieve primitive types. +// if (is_subclass_of($definition['class'], 'Drupal\Core\TypedData\Type\FloatInterface')) { +// $data_type = 'float'; +// } +// else if (is_subclass_of($definition['class'], 'Drupal\Core\TypedData\Type\IntegerInterface')) { +// $data_type = 'integer'; +// } +// +// switch ($data_type) { +// case 'float': +// case 'integer': +// $views_field['field']['id'] = 'numeric'; +// $views_field['argument']['id'] = 'numeric'; +// $views_field['filter']['id'] = 'numeric'; +// $views_field['sort']['id'] = 'standard'; +// break; +// case 'string': +// $views_field['field']['id'] = 'standard'; +// $views_field['argument']['id'] = 'string'; +// $views_field['filter']['id'] = 'string'; +// $views_field['sort']['id'] = 'standard'; +// break; +// case 'boolean': +// $views_field['field']['id'] = 'boolean'; +// $views_field['argument']['id'] = 'numeric'; +// $views_field['filter']['id'] = 'boolean'; +// $views_field['sort']['id'] = 'standard'; +// break; +// // @todo: Should be mapped. +// case 'uuid': +// $views_field['field']['id'] = 'standard'; +// $views_field['argument']['id'] = 'string'; +// $views_field['filter']['id'] = 'string'; +// $views_field['sort']['id'] = 'standard'; +// break; +// // @todo: Move this to language field? +// case 'language': +// $views_field['field']['id'] = 'language'; +// $views_field['argument']['id'] = 'language'; +// $views_field['filter']['id'] = 'language'; +// $views_field['sort']['id'] = 'standard'; +// break; +// case 'entity_reference': +// // @todo No idea to determine how to find out whether the field is a number/string ID. +// // @todo Should the actual field handler respect that this is just renders a number +// // @todo Create an optional entity field handler, that can render the +// // entity. +// $views_field['field']['id'] = 'numeric'; +// $views_field['argument']['id'] = 'numeric'; +// $views_field['filter']['id'] = 'numeric'; +// $views_field['sort']['id'] = 'standard'; +// } +// +// return $views_field; + } + + /** + * Generates a relationship for the given ID property. + * + * @param $property_name + * @param $property_definition + * @param $field_definition + */ + protected function generateRelationship($id_name, $id_definition, $reference_definition, $field_definition) { + // @todo: implement mapping. + return array(); + + $views_relationship = array( + 'base' => $entity_info['base_table'], + 'base field' => $entity_info['entity_keys']['id'], + 'label' => $typed_data['label'], + 'id' => 'standard', + ); + + return $views_relationship; + } + +} diff --git a/core/modules/views/src/EntityViewsControllerInterface.php b/core/modules/views/src/EntityViewsControllerInterface.php new file mode 100644 index 0000000..47c3d71 --- /dev/null +++ b/core/modules/views/src/EntityViewsControllerInterface.php @@ -0,0 +1,23 @@ +entityStorage = $this->getMockBuilder('Drupal\Core\Entity\ContentEntityDatabaseStorage') + ->disableOriginalConstructor() + ->getMock(); + $this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface'); + + $this->entityManager->expects($this->any()) + ->method('getDefinition') + ->will($this->returnValueMap(array( + array('user', static::userEntityInfo()), + ))); + + $this->baseEntityType = new EntityType(array( + 'base_table' => 'entity_test', + 'id' => 'entity_test', + 'label' => 'Entity test', + 'entity_keys' => array( + 'id' => 'id', + ), + )); + + $this->translationManager = $this->getStringTranslationStub(); + $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface'); + $this->typedDataManager = $this->getMockBuilder('Drupal\Core\TypedData\TypedDataManager') + ->disableOriginalConstructor() + ->getMock(); + + $this->viewsController = new TestEntityViewsController($this->baseEntityType, $this->entityStorage, $this->entityManager, $this->moduleHandler, $this->translationManager, $this->typedDataManager); + + $field_type_manager = $this->getMockBuilder('Drupal\Core\Field\FieldTypePluginManager') + ->disableOriginalConstructor() + ->getMock(); + $field_type_manager->expects($this->any()) + ->method('getDefaultSettings') + ->willReturn(array()); + $field_type_manager->expects($this->any()) + ->method('getDefaultInstanceSettings') + ->willReturn(array()); + + $container = new ContainerBuilder(); + $container->set('plugin.manager.field.field_type', $field_type_manager); + \Drupal::setContainer($container); + } + + /** + * Tests base tables. + */ + public function testBaseTables() { + $data = $this->viewsController->viewsData(); + + $this->assertEquals('id', $data['entity_test']['table']['base']['field']); + $this->assertEquals('Entity test', $data['entity_test']['table']['base']['title']); + $this->assertFalse(isset($data['entity_test_mul_property_data'])); + $this->assertFalse(isset($data['revision_table'])); + $this->assertFalse(isset($data['revision_data_table'])); + } + + + /** + * Tests data_table support. + */ + public function testDataTable() { + $entity_type = $this->baseEntityType->set('data_table', 'entity_test_mul_property_data') + ->set('id', 'entity_test_mul'); + + $this->viewsController->setEntityType($entity_type); + + // Tests the join definition between the base and the data table. + $data = $this->viewsController->viewsData(); + $field_views_data = $data['entity_test_mul_property_data']; + $this->assertEquals(array('entity_test' => array('left_field' => 'id', 'field' => 'id')), $field_views_data['table']['join']); + $this->assertFalse(isset($data['revision_table'])); + $this->assertFalse(isset($data['revision_data_table'])); + } + + /** + * Tests revision table support. + */ + public function testRevisionTable() { + $entity_type = $this->baseEntityType + ->set('revision_table', 'entity_test_mulrev_revision') + ->set('revision_data_table', 'entity_test_mulrev_property_revision') + ->set('id', 'entity_test_mulrev') + ->setKey('revision', 'revision_id') + ; + $this->viewsController->setEntityType($entity_type); + + $data = $this->viewsController->viewsData(); + + // Tests the join definition between the base and the revision table. + $revision_data = $data['entity_test_mulrev_revision']; + $this->assertEquals(array('entity_test' => array('left_field' => 'id', 'field' => 'id')), $revision_data['table']['join']); + $revision_data = $data['entity_test_mulrev_property_revision']; + $this->assertEquals(array('entity_test_mulrev_revision' => array('left_field' => 'revision_id', 'field' => 'revision_id')), $revision_data['table']['join']); + $this->assertFalse(isset($data['data_table'])); + } + + /** + * Tests fields on the base table. + */ + public function testBaseTableFields() { + $this->entityManager->expects($this->any()) + ->method('getFieldDefinitions') + ->with('entity_test', 'muuuh') + ->will($this->returnCallback(function() { + return EntityTest::baseFieldDefinitions($this->baseEntityType); + })); + $this->viewsController->setSchemaFields(array('entity_test' => array('id', 'uuid', 'type', 'langcode', 'name', 'user_id'))); + $data = $this->viewsController->viewsData(); + +// $this->assertNumericField($data['entity_test']['id']); +// $this->assertUuidField($data['entity_test']['uuid']); +// $this->assertStringField($data['entity_test']['type']); +// $this->assertLanguageField($data['entity_test']['langcode']); +// $this->assertStringField($data['entity_test']['name']); +// +// $this->assertEntityReferenceField($data['entity_test']['user_id']); +// $relationship = $data['entity_test']['user_id']['relationship']; +// $this->assertEquals('users', $relationship['base']); +// $this->assertEquals('uid', $relationship['base field']); + } + + /** + * Tests fields on the data table. + */ + public function testDataTableFields() { + $this->entityManager->expects($this->any()) + ->method('getFieldDefinitions') + ->with('entity_test_mul') + ->will($this->returnCallback(function() { + return EntityTestMul::baseFieldDefinitions('entity_test_mul'); + })); + $this->viewsController->setSchemaFields(array( + 'entity_test_mul' => array('id', 'uuid', 'type', 'langcode'), + 'entity_test_mul_property_data' => array('id', 'langcode', 'default_langcode', 'name', 'user_id'), + )); + + $entity_type = $this->baseEntityType + ->set('data_table', 'entity_test_mul_property_data') + ->set('base_table', 'entity_test_mul') + ->set('id', 'entity_test_mul') + ; + $this->viewsController->setEntityType($entity_type); + + $data = $this->viewsController->viewsData(); + + // Check the base fields. +// $this->assertNumericField($data['entity_test_mul']['id']); +// $this->assertUuidField($data['entity_test_mul']['uuid']); +// $this->assertStringField($data['entity_test_mul']['type']); +// $this->assertLanguageField($data['entity_test_mul']['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']['user_id'])); +// +// // Check the data fields. +// $this->assertNumericField($data['entity_test_mul_property_data']['id']); +// $this->assertLanguageField($data['entity_test_mul_property_data']['langcode']); +// // @todo Plach said the default language should not be exposed. +// $this->assertStringField($data['entity_test_mul_property_data']['name']); +// +// $this->assertEntityReferenceField($data['entity_test_mul_property_data']['user_id']); +// $relationship = $data['entity_test_mul_property_data']['user_id']['relationship']; +// $this->assertEquals('users', $relationship['base']); +// $this->assertEquals('uid', $relationship['base field']); + } + + /** + * Tests fields on the revision table. + */ + public function testRevisionTableFields() { + $this->entityManager->expects($this->any()) + ->method('getFieldDefinitions') + ->with('entity_test_mulrev') + ->will($this->returnCallback(function() { + return EntityTestMulRev::baseFieldDefinitions('entity_test_mul'); + })); + $this->viewsController->setSchemaFields(array( + 'entity_test_mulrev' => array('id', 'revision_id', 'uuid', 'type'), + 'entity_test_mulrev_revision' => array('id', 'revision_id', 'langcode'), + 'entity_test_mulrev_property_data' => array('id', 'revision_id', 'langcode', 'default_langcode', 'name', 'user_id'), + 'entity_test_mulrev_property_revision' => array('id', 'revision_id', 'langcode', 'default_langcode', 'name', 'user_id'), + )); + + $entity_type = $this->baseEntityType + ->set('data_table', 'entity_test_mul_property_data') + ->set('revision_table', 'entity_test_mulrev_revision') + ->set('revision_data_table', 'entity_test_mulrev_property_revision') + ->set('base_table', 'entity_test_mulrev') + ->set('id', 'entity_test_mulrev'); + $this->viewsController->setEntityType($entity_type); + + $data = $this->viewsController->viewsData(); + + // Check the base fields. +// $this->assertNumericField($data['entity_test_mulrev']['id']); +// $this->assertNumericField($data['entity_test_mulrev']['revision_id']); +// $this->assertUuidField($data['entity_test_mulrev']['uuid']); +// $this->assertStringField($data['entity_test_mulrev']['type']); +// +// // Also ensure that field_data only fields don't appear on the base table. +// $this->assertFalse(isset($data['entity_test_mulrev']['name'])); +// $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->assertNumericField($data['entity_test_mulrev_revision']['revision_id']); +// $this->assertLanguageField($data['entity_test_mulrev_revision']['langcode']); +// // Also ensure that field_data only fields don't appear on the revision table. +// $this->assertFalse(isset($data['entity_test_mulrev_revision']['name'])); +// $this->assertFalse(isset($data['entity_test_mulrev_revision']['langcode'])); +// $this->assertFalse(isset($data['entity_test_mulrev_revision']['user_id'])); + + // @todo check property and revision property data. + } + + /** + * Tests views data for a string field. + * + * @param array $data + * The views data to check. + */ + public function assertStringField($data) { + $this->assertEquals('standard', $data['field']['id']); + $this->assertEquals('string', $data['filter']['id']); + $this->assertEquals('string', $data['argument']['id']); + $this->assertEquals('standard', $data['sort']['id']); + } + + /** + * Tests views data for a UUID field. + * + * @param array $data + * The views data to check. + */ + public function assertUuidField($data) { + // @todo Can we provide additional support for UUIDs in views? + $this->assertEquals('standard', $data['field']['id']); + $this->assertEquals('string', $data['filter']['id']); + $this->assertEquals('string', $data['argument']['id']); + $this->assertEquals('standard', $data['sort']['id']); + } + + /** + * Tests views data for a numeric field. + * + * @param array $data + * The views data to check. + */ + public function assertNumericField($data) { + $this->assertEquals('numeric', $data['field']['id']); + $this->assertEquals('numeric', $data['filter']['id']); + $this->assertEquals('numeric', $data['argument']['id']); + $this->assertEquals('standard', $data['sort']['id']); + } + + /** + * Tests views data for a language field. + * + * @param array $data + * The views data to check. + */ + public function assertLanguageField($data) { + $this->assertEquals('language', $data['field']['id']); + $this->assertEquals('language', $data['filter']['id']); + $this->assertEquals('language', $data['argument']['id']); + $this->assertEquals('standard', $data['sort']['id']); + } + + public function assertEntityReferenceField($data) { + $this->assertEquals('numeric', $data['field']['id']); + $this->assertEquals('numeric', $data['filter']['id']); + $this->assertEquals('numeric', $data['argument']['id']); + $this->assertEquals('standard', $data['sort']['id']); + } + + /** + * Returns entity info for the user entity. + * + * @return array + */ + public static function userEntityInfo() { + return array( + 'id' => 'user', + 'label' => 'User', + 'base_table' => 'users', + 'entity_keys' => array( + 'id' => 'uid', + 'uuid' => 'uuid', + ), + ); + } + +} + +class TestEntityViewsController extends EntityViewsController { + + protected $schemaFields = array(); + + public function setSchemaFields($fields) { + $this->schemaFields = $fields; + } + + /** + * {@inheritdoc} + */ + protected function drupalSchemaFieldsSql($table) { + return isset($this->schemaFields[$table]) ? $this->schemaFields[$table] : array(); + } + + public function setEntityType(EntityTypeInterface $entity_type) { + $this->entityType = $entity_type; + } + +} + +} + +namespace { + use Drupal\Component\Utility\String; + + if (!function_exists('t')) { + function t($string, array $args = array()) { + return String::format($string, $args); + } + } +} diff --git a/core/modules/views/views.views.inc b/core/modules/views/views.views.inc index 489da54..cb4b812 100644 --- a/core/modules/views/views.views.inc +++ b/core/modules/views/views.views.inc @@ -154,5 +154,14 @@ function views_views_data() { ), ); } + + // Registers views data for the entity itself. + foreach (\Drupal::entityManager()->getDefinitions() as $entity_type_id => $entity_type) { + if ($entity_type->hasControllerClass('views_data')) { + $views_controller = \Drupal::entityManager()->getController($entity_type_id, 'views_data'); + $data += $views_controller->viewsData(); + } + } + return $data; }