5 * Contains \Drupal\Tests\views\Unit\EntityViewsDataTest.
8 namespace Drupal\Tests\views\Unit;
10 use Drupal\Core\Config\Entity\ConfigEntityType;
11 use Drupal\Core\Entity\ContentEntityType;
12 use Drupal\Core\Entity\EntityTypeInterface;
13 use Drupal\Core\Entity\Sql\DefaultTableMapping;
14 use Drupal\Core\Field\BaseFieldDefinition;
15 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
16 use Drupal\Core\Field\Plugin\Field\FieldType\IntegerItem;
17 use Drupal\Core\Field\Plugin\Field\FieldType\LanguageItem;
18 use Drupal\Core\Field\Plugin\Field\FieldType\StringItem;
19 use Drupal\Core\Field\Plugin\Field\FieldType\UriItem;
20 use Drupal\Core\Field\Plugin\Field\FieldType\UuidItem;
21 use Drupal\Core\State\StateInterface;
22 use Drupal\Core\TypedData\TypedDataManagerInterface;
23 use Drupal\text\Plugin\Field\FieldType\TextLongItem;
24 use Drupal\entity_test\Entity\EntityTest;
25 use Drupal\entity_test\Entity\EntityTestMul;
26 use Drupal\entity_test\Entity\EntityTestMulRev;
27 use Drupal\Tests\UnitTestCase;
28 use Drupal\views\EntityViewsData;
29 use Prophecy\Argument;
30 use Symfony\Component\DependencyInjection\ContainerBuilder;
33 * @coversDefaultClass \Drupal\views\EntityViewsData
36 class EntityViewsDataTest extends UnitTestCase {
39 * Entity info to use in this test.
41 * @var \Drupal\Core\Entity\EntityTypeInterface|\Drupal\Tests\views\Unit\TestEntityType
43 protected $baseEntityType;
46 * The mocked entity storage.
48 * @var \Drupal\Core\Entity\Sql\SqlContentEntityStorage|\PHPUnit_Framework_MockObject_MockObject
50 protected $entityStorage;
53 * The mocked entity manager.
55 * @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
57 protected $entityManager;
60 * The mocked module handler.
62 * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
64 protected $moduleHandler;
67 * The mocked translation manager.
69 * @var \Drupal\Core\StringTranslation\TranslationInterface|\PHPUnit_Framework_MockObject_MockObject
71 protected $translationManager;
74 * The tested entity views controller.
76 * @var \Drupal\Tests\views\Unit\TestEntityViewsData
83 protected function setUp() {
84 $this->entityStorage = $this->getMockBuilder('Drupal\Core\Entity\Sql\SqlContentEntityStorage')
85 ->disableOriginalConstructor()
87 $this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
89 $typed_data_manager = $this->getMock(TypedDataManagerInterface::class);
90 $typed_data_manager->expects($this->any())
91 ->method('createDataDefinition')
92 ->willReturn($this->getMock('Drupal\Core\TypedData\DataDefinitionInterface'));
94 $typed_data_manager->expects($this->any())
95 ->method('getDefinition')
96 ->will($this->returnValueMap([
97 'entity:user' => ['class' => '\Drupal\Core\TypedData\DataDefinitionInterface'],
98 'field_item:string_long' => ['class' => '\Drupal\Core\Field\Plugin\Field\FieldType\StringLongItem'],
101 $this->baseEntityType = new TestEntityType([
102 'base_table' => 'entity_test',
103 'id' => 'entity_test',
104 'label' => 'Entity test',
108 'langcode' => 'langcode',
110 'revision' => 'revision_id',
112 'provider' => 'entity_test',
113 'list_cache_contexts' => ['entity_test_list_cache_context'],
116 $this->translationManager = $this->getStringTranslationStub();
117 $this->baseEntityType->setStringTranslation($this->translationManager);
118 $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
120 $this->viewsData = new TestEntityViewsData($this->baseEntityType, $this->entityStorage, $this->entityManager, $this->moduleHandler, $this->translationManager);
122 $field_type_manager = $this->getMockBuilder('Drupal\Core\Field\FieldTypePluginManager')
123 ->disableOriginalConstructor()
125 $field_type_manager->expects($this->any())
126 ->method('getDefaultStorageSettings')
128 $field_type_manager->expects($this->any())
129 ->method('getDefaultFieldSettings')
132 $state = $this->prophesize(StateInterface::class);
133 $state->get(Argument::any(), [])->willReturn([]);
135 $container = new ContainerBuilder();
136 $container->set('plugin.manager.field.field_type', $field_type_manager);
137 $container->set('entity.manager', $this->entityManager);
138 $container->set('typed_data_manager', $typed_data_manager);
139 $container->set('state', $state->reveal());
140 \Drupal::setContainer($container);
144 * Helper method to setup base fields.
146 * @param \Drupal\Core\Field\BaseFieldDefinition[] $base_fields
147 * The base fields which are adapted.
149 * @return \Drupal\Core\Field\BaseFieldDefinition[]
150 * The setup base fields.
152 protected function setupBaseFields(array $base_fields) {
153 // Add a description field to the fields supplied by the EntityTest
154 // classes. This example comes from the taxonomy Term entity.
155 $base_fields['description'] = BaseFieldDefinition::create('text_long')
156 ->setLabel('Description')
157 ->setDescription('A description of the term.')
158 ->setTranslatable(TRUE)
159 ->setDisplayOptions('view', [
161 'type' => 'text_default',
164 ->setDisplayConfigurable('view', TRUE)
165 ->setDisplayOptions('form', [
166 'type' => 'text_textfield',
169 ->setDisplayConfigurable('form', TRUE);
171 // Add a URL field; this example is from the Comment entity.
172 $base_fields['homepage'] = BaseFieldDefinition::create('uri')
173 ->setLabel('Homepage')
174 ->setDescription("The comment author's home page address.")
175 ->setTranslatable(TRUE)
176 ->setSetting('max_length', 255);
178 // A base field with cardinality > 1
179 $base_fields['string'] = BaseFieldDefinition::create('string')
181 ->setTranslatable(TRUE)
184 foreach ($base_fields as $name => $base_field) {
185 $base_field->setName($name);
193 public function testBaseTables() {
194 $data = $this->viewsData->getViewsData();
196 $this->assertEquals('entity_test', $data['entity_test']['table']['entity type']);
197 $this->assertEquals(FALSE, $data['entity_test']['table']['entity revision']);
198 $this->assertEquals('Entity test', $data['entity_test']['table']['group']);
199 $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
201 $this->assertEquals('id', $data['entity_test']['table']['base']['field']);
202 $this->assertEquals(['entity_test_list_cache_context'], $data['entity_test']['table']['base']['cache_contexts']);
203 $this->assertEquals('Entity test', $data['entity_test']['table']['base']['title']);
205 $this->assertFalse(isset($data['entity_test']['table']['defaults']));
207 $this->assertFalse(isset($data['entity_test_mul_property_data']));
208 $this->assertFalse(isset($data['revision_table']));
209 $this->assertFalse(isset($data['revision_data_table']));
213 * Tests data_table support.
215 public function testDataTable() {
216 $entity_type = $this->baseEntityType
217 ->set('data_table', 'entity_test_mul_property_data')
218 ->set('id', 'entity_test_mul')
219 ->set('translatable', TRUE)
220 ->setKey('label', 'label');
222 $this->viewsData->setEntityType($entity_type);
224 // Tests the join definition between the base and the data table.
225 $data = $this->viewsData->getViewsData();
226 $base_views_data = $data['entity_test'];
228 // Ensure that the base table is set to the data table.
229 $this->assertEquals('id', $data['entity_test_mul_property_data']['table']['base']['field']);
230 $this->assertEquals('Entity test', $data['entity_test_mul_property_data']['table']['base']['title']);
231 $this->assertFalse(isset($data['entity_test']['table']['base']));
233 $this->assertEquals('entity_test_mul', $data['entity_test_mul_property_data']['table']['entity type']);
234 $this->assertEquals(FALSE, $data['entity_test_mul_property_data']['table']['entity revision']);
235 $this->assertEquals('Entity test', $data['entity_test_mul_property_data']['table']['group']);
236 $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
237 $this->assertEquals(['field' => 'label', 'table' => 'entity_test_mul_property_data'], $data['entity_test_mul_property_data']['table']['base']['defaults']);
239 // Ensure the join information is set up properly.
240 $this->assertCount(1, $base_views_data['table']['join']);
241 $this->assertEquals(['entity_test_mul_property_data' => ['left_field' => 'id', 'field' => 'id', 'type' => 'INNER']], $base_views_data['table']['join']);
242 $this->assertFalse(isset($data['revision_table']));
243 $this->assertFalse(isset($data['revision_data_table']));
247 * Tests revision table without data table support.
249 public function testRevisionTableWithoutDataTable() {
250 $entity_type = $this->baseEntityType
251 ->set('revision_table', 'entity_test_mulrev_revision')
252 ->set('revision_data_table', NULL)
253 ->set('id', 'entity_test_mulrev')
254 ->setKey('revision', 'revision_id');
255 $this->viewsData->setEntityType($entity_type);
257 $data = $this->viewsData->getViewsData();
259 $this->assertEquals('Entity test revisions', $data['entity_test_mulrev_revision']['table']['base']['title']);
260 $this->assertEquals('revision_id', $data['entity_test_mulrev_revision']['table']['base']['field']);
262 $this->assertEquals(FALSE, $data['entity_test']['table']['entity revision']);
263 $this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_revision']['table']['entity type']);
264 $this->assertEquals(TRUE, $data['entity_test_mulrev_revision']['table']['entity revision']);
265 $this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_revision']['table']['entity type']);
266 $this->assertEquals(TRUE, $data['entity_test_mulrev_revision']['table']['entity revision']);
268 $this->assertEquals('Entity test revision', $data['entity_test_mulrev_revision']['table']['group']);
269 $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
271 // Ensure the join information is set up properly.
272 // Tests the join definition between the base and the revision table.
273 $revision_data = $data['entity_test_mulrev_revision'];
274 $this->assertCount(1, $revision_data['table']['join']);
275 $this->assertEquals(['entity_test' => ['left_field' => 'revision_id', 'field' => 'revision_id', 'type' => 'INNER']], $revision_data['table']['join']);
276 $this->assertFalse(isset($data['data_table']));
280 * Tests revision table with data table support.
282 public function testRevisionTableWithRevisionDataTableAndDataTable() {
283 $entity_type = $this->baseEntityType
284 ->set('data_table', 'entity_test_mul_property_data')
285 ->set('revision_table', 'entity_test_mulrev_revision')
286 ->set('revision_data_table', 'entity_test_mulrev_property_revision')
287 ->set('id', 'entity_test_mulrev')
288 ->set('translatable', TRUE)
289 ->setKey('revision', 'revision_id');
290 $this->viewsData->setEntityType($entity_type);
292 $data = $this->viewsData->getViewsData();
294 $this->assertEquals('Entity test revisions', $data['entity_test_mulrev_property_revision']['table']['base']['title']);
295 $this->assertEquals('revision_id', $data['entity_test_mulrev_property_revision']['table']['base']['field']);
296 $this->assertFalse(isset($data['entity_test_mulrev_revision']['table']['base']));
298 $this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_property_revision']['table']['entity type']);
299 $this->assertEquals('Entity test revision', $data['entity_test_mulrev_revision']['table']['group']);
300 $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
302 // Ensure the join information is set up properly.
303 // Tests the join definition between the base and the revision table.
304 $revision_field_data = $data['entity_test_mulrev_property_revision'];
305 $this->assertCount(1, $revision_field_data['table']['join']);
306 $this->assertEquals([
307 'entity_test_mul_property_data' => [
308 'left_field' => 'revision_id',
309 'field' => 'revision_id',
312 ], $revision_field_data['table']['join']);
314 $revision_base_data = $data['entity_test_mulrev_revision'];
315 $this->assertCount(1, $revision_base_data['table']['join']);
316 $this->assertEquals([
317 'entity_test_mulrev_property_revision' => [
318 'left_field' => 'revision_id',
319 'field' => 'revision_id',
322 ], $revision_base_data['table']['join']);
324 $this->assertFalse(isset($data['data_table']));
328 * Tests revision table with data table support.
330 public function testRevisionTableWithRevisionDataTable() {
331 $entity_type = $this->baseEntityType
332 ->set('revision_table', 'entity_test_mulrev_revision')
333 ->set('revision_data_table', 'entity_test_mulrev_property_revision')
334 ->set('id', 'entity_test_mulrev')
335 ->set('translatable', TRUE)
336 ->setKey('revision', 'revision_id');
337 $this->viewsData->setEntityType($entity_type);
339 $data = $this->viewsData->getViewsData();
341 $this->assertEquals('Entity test revisions', $data['entity_test_mulrev_property_revision']['table']['base']['title']);
342 $this->assertEquals('revision_id', $data['entity_test_mulrev_property_revision']['table']['base']['field']);
343 $this->assertFalse(isset($data['entity_test_mulrev_revision']['table']['base']));
345 $this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_property_revision']['table']['entity type']);
346 $this->assertEquals('Entity test revision', $data['entity_test_mulrev_revision']['table']['group']);
347 $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
349 // Ensure the join information is set up properly.
350 // Tests the join definition between the base and the revision table.
351 $revision_field_data = $data['entity_test_mulrev_property_revision'];
352 $this->assertCount(1, $revision_field_data['table']['join']);
353 $this->assertEquals([
354 'entity_test_mulrev_field_data' => [
355 'left_field' => 'revision_id',
356 'field' => 'revision_id',
359 ], $revision_field_data['table']['join']);
361 $revision_base_data = $data['entity_test_mulrev_revision'];
362 $this->assertCount(1, $revision_base_data['table']['join']);
363 $this->assertEquals([
364 'entity_test_mulrev_property_revision' => [
365 'left_field' => 'revision_id',
366 'field' => 'revision_id',
369 ], $revision_base_data['table']['join']);
370 $this->assertFalse(isset($data['data_table']));
374 * Helper method to mock all store definitions.
376 protected function setupFieldStorageDefinition() {
377 $id_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
378 $id_field_storage_definition->expects($this->any())
379 ->method('getSchema')
380 ->willReturn(IntegerItem::schema($id_field_storage_definition));
381 $uuid_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
382 $uuid_field_storage_definition->expects($this->any())
383 ->method('getSchema')
384 ->willReturn(UuidItem::schema($uuid_field_storage_definition));
385 $type_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
386 $type_field_storage_definition->expects($this->any())
387 ->method('getSchema')
388 ->willReturn(StringItem::schema($type_field_storage_definition));
389 $langcode_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
390 $langcode_field_storage_definition->expects($this->any())
391 ->method('getSchema')
392 ->willReturn(LanguageItem::schema($langcode_field_storage_definition));
393 $name_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
394 $name_field_storage_definition->expects($this->any())
395 ->method('getSchema')
396 ->willReturn(StringItem::schema($name_field_storage_definition));
397 $description_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
398 $description_field_storage_definition->expects($this->any())
399 ->method('getSchema')
400 ->willReturn(TextLongItem::schema($description_field_storage_definition));
401 $homepage_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
402 $homepage_field_storage_definition->expects($this->any())
403 ->method('getSchema')
404 ->willReturn(UriItem::schema($homepage_field_storage_definition));
405 $string_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
406 $string_field_storage_definition->expects($this->any())
407 ->method('getSchema')
408 ->willReturn(StringItem::schema($string_field_storage_definition));
410 // Setup the user_id entity reference field.
411 $this->entityManager->expects($this->any())
412 ->method('getDefinition')
414 ['user', TRUE, static::userEntityInfo()],
417 $user_id_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
418 $user_id_field_storage_definition->expects($this->any())
419 ->method('getSetting')
420 ->with('target_type')
421 ->willReturn('user');
422 $user_id_field_storage_definition->expects($this->any())
423 ->method('getSettings')
424 ->willReturn(['target_type' => 'user']);
425 $user_id_field_storage_definition->expects($this->any())
426 ->method('getSchema')
427 ->willReturn(EntityReferenceItem::schema($user_id_field_storage_definition));
429 $revision_id_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
430 $revision_id_field_storage_definition->expects($this->any())
431 ->method('getSchema')
432 ->willReturn(IntegerItem::schema($revision_id_field_storage_definition));
434 $this->entityManager->expects($this->any())
435 ->method('getFieldStorageDefinitions')
437 'id' => $id_field_storage_definition,
438 'uuid' => $uuid_field_storage_definition,
439 'type' => $type_field_storage_definition,
440 'langcode' => $langcode_field_storage_definition,
441 'name' => $name_field_storage_definition,
442 'description' => $description_field_storage_definition,
443 'homepage' => $homepage_field_storage_definition,
444 'string' => $string_field_storage_definition,
445 'user_id' => $user_id_field_storage_definition,
446 'revision_id' => $revision_id_field_storage_definition,
451 * Tests fields on the base table.
453 public function testBaseTableFields() {
454 $base_field_definitions = $this->setupBaseFields(EntityTest::baseFieldDefinitions($this->baseEntityType));
455 $user_base_field_definitions = [
456 'uid' => BaseFieldDefinition::create('integer')
458 ->setDescription('The ID of the user entity.')
460 ->setSetting('unsigned', TRUE)
462 $this->entityManager->expects($this->any())
463 ->method('getBaseFieldDefinitions')
464 ->will($this->returnValueMap([
465 ['user', $user_base_field_definitions],
466 ['entity_test', $base_field_definitions],
468 // Setup the table mapping.
469 $table_mapping = $this->getMockBuilder(DefaultTableMapping::class)
470 ->disableOriginalConstructor()
472 $table_mapping->expects($this->any())
473 ->method('getTableNames')
474 ->willReturn(['entity_test', 'entity_test__string']);
475 $table_mapping->expects($this->any())
476 ->method('getColumnNames')
478 ['id', ['value' => 'id']],
479 ['uuid', ['value' => 'uuid']],
480 ['type', ['value' => 'type']],
481 ['langcode', ['value' => 'langcode']],
482 ['name', ['value' => 'name']],
483 ['description', ['value' => 'description__value', 'format' => 'description__format']],
484 ['homepage', ['value' => 'homepage']],
485 ['user_id', ['target_id' => 'user_id']],
486 ['string', ['value' => 'string_value']],
488 $table_mapping->expects($this->any())
489 ->method('getFieldNames')
491 ['entity_test', ['id', 'uuid', 'type', 'langcode', 'name', 'description', 'homepage', 'user_id']],
492 ['entity_test__string', ['string']],
494 $table_mapping->expects($this->any())
495 ->method('requiresDedicatedTableStorage')
496 ->willReturnCallback(function (BaseFieldDefinition $base_field) {
497 return $base_field->getName() === 'string';
499 $table_mapping->expects($this->any())
500 ->method('getDedicatedDataTableName')
501 ->willReturnCallback(function (BaseFieldDefinition $base_field) {
502 if ($base_field->getName() === 'string') {
503 return 'entity_test__string';
507 $this->entityStorage->expects($this->once())
508 ->method('getTableMapping')
509 ->willReturn($table_mapping);
511 $this->setupFieldStorageDefinition();
513 $data = $this->viewsData->getViewsData();
515 $this->assertNumericField($data['entity_test']['id']);
516 $this->assertField($data['entity_test']['id'], 'id');
517 $this->assertUuidField($data['entity_test']['uuid']);
518 $this->assertField($data['entity_test']['uuid'], 'uuid');
519 $this->assertStringField($data['entity_test']['type']);
520 $this->assertEquals('type', $data['entity_test']['type']['entity field']);
522 $this->assertLanguageField($data['entity_test']['langcode']);
523 $this->assertField($data['entity_test']['langcode'], 'langcode');
524 $this->assertEquals('Original language', $data['entity_test']['langcode']['title']);
526 $this->assertStringField($data['entity_test']['name']);
527 $this->assertField($data['entity_test']['name'], 'name');
529 $this->assertLongTextField($data['entity_test'], 'description');
530 $this->assertField($data['entity_test']['description__value'], 'description');
531 $this->assertField($data['entity_test']['description__format'], 'description');
533 $this->assertUriField($data['entity_test']['homepage']);
534 $this->assertField($data['entity_test']['homepage'], 'homepage');
536 $this->assertEntityReferenceField($data['entity_test']['user_id']);
537 $this->assertField($data['entity_test']['user_id'], 'user_id');
539 $relationship = $data['entity_test']['user_id']['relationship'];
540 $this->assertEquals('users_field_data', $relationship['base']);
541 $this->assertEquals('uid', $relationship['base field']);
543 // The string field name should be used as the 'entity field' but the actual
544 // field should reflect what the column mapping is using for multi-value
545 // base fields NOT just the field name. The actual column name returned from
546 // mappings in the test mocks is 'value'.
547 $this->assertStringField($data['entity_test__string']['string_value']);
548 $this->assertField($data['entity_test__string']['string_value'], 'string');
549 $this->assertEquals([
550 'left_field' => 'id',
551 'field' => 'entity_id',
553 'field' => 'deleted',
558 ], $data['entity_test__string']['table']['join']['entity_test']);
562 * Tests fields on the data table.
564 public function testDataTableFields() {
565 $entity_type = $this->baseEntityType
566 ->set('data_table', 'entity_test_mul_property_data')
567 ->set('base_table', 'entity_test_mul')
568 ->set('id', 'entity_test_mul')
569 ->setKey('bundle', 'type');
570 $base_field_definitions = $this->setupBaseFields(EntityTestMul::baseFieldDefinitions($this->baseEntityType));
571 $base_field_definitions['type'] = BaseFieldDefinition::create('entity_reference')
572 ->setLabel('entity test type')
573 ->setSetting('target_type', 'entity_test_bundle')
574 ->setTranslatable(TRUE);
575 $base_field_definitions = $this->setupBaseFields($base_field_definitions);
576 $user_base_field_definitions = [
577 'uid' => BaseFieldDefinition::create('integer')
579 ->setDescription('The ID of the user entity.')
581 ->setSetting('unsigned', TRUE)
583 $entity_test_type = new ConfigEntityType(['id' => 'entity_test_bundle']);
585 $this->entityManager->expects($this->any())
586 ->method('getBaseFieldDefinitions')
587 ->will($this->returnValueMap([
588 ['user', $user_base_field_definitions],
589 ['entity_test_mul', $base_field_definitions],
592 $this->viewsData->setEntityType($entity_type);
594 // Setup the table mapping.
595 $table_mapping = $this->getMockBuilder(DefaultTableMapping::class)
596 ->disableOriginalConstructor()
598 $table_mapping->expects($this->any())
599 ->method('getTableNames')
600 ->willReturn(['entity_test_mul', 'entity_test_mul_property_data', 'entity_test_mul__string']);
601 $table_mapping->expects($this->any())
602 ->method('getColumnNames')
604 ['id', ['value' => 'id']],
605 ['uuid', ['value' => 'uuid']],
606 ['type', ['value' => 'type']],
607 ['langcode', ['value' => 'langcode']],
608 ['name', ['value' => 'name']],
609 ['description', ['value' => 'description__value', 'format' => 'description__format']],
610 ['homepage', ['value' => 'homepage']],
611 ['user_id', ['target_id' => 'user_id']],
612 ['string', ['value' => 'string_value']],
614 $table_mapping->expects($this->any())
615 ->method('getFieldNames')
617 ['entity_test_mul', ['uuid']],
618 ['entity_test_mul_property_data', ['id', 'type', 'langcode', 'name', 'description', 'homepage', 'user_id']],
619 ['entity_test_mul__string', ['string']],
622 $table_mapping->expects($this->any())
623 ->method('getFieldTableName')
624 ->willReturnCallback(function ($field) {
625 if ($field == 'uuid') {
626 return 'entity_test_mul';
628 return 'entity_test_mul_property_data';
630 $table_mapping->expects($this->any())
631 ->method('requiresDedicatedTableStorage')
632 ->willReturnCallback(function (BaseFieldDefinition $base_field) {
633 return $base_field->getName() === 'string';
635 $table_mapping->expects($this->any())
636 ->method('getDedicatedDataTableName')
637 ->willReturnCallback(function (BaseFieldDefinition $base_field) {
638 if ($base_field->getName() === 'string') {
639 return 'entity_test_mul__string';
643 $this->entityStorage->expects($this->once())
644 ->method('getTableMapping')
645 ->willReturn($table_mapping);
647 $this->setupFieldStorageDefinition();
649 $user_entity_type = static::userEntityInfo();
650 $this->entityManager->expects($this->any())
651 ->method('getDefinition')
652 ->will($this->returnValueMap([
653 ['user', TRUE, $user_entity_type],
654 ['entity_test_bundle', TRUE, $entity_test_type],
657 $data = $this->viewsData->getViewsData();
659 // Check the base fields.
660 $this->assertFalse(isset($data['entity_test_mul']['id']));
661 $this->assertFalse(isset($data['entity_test_mul']['type']));
662 $this->assertUuidField($data['entity_test_mul']['uuid']);
663 $this->assertField($data['entity_test_mul']['uuid'], 'uuid');
665 $this->assertFalse(isset($data['entity_test_mul']['type']['relationship']));
667 // Also ensure that field_data only fields don't appear on the base table.
668 $this->assertFalse(isset($data['entity_test_mul']['name']));
669 $this->assertFalse(isset($data['entity_test_mul']['description']));
670 $this->assertFalse(isset($data['entity_test_mul']['description__value']));
671 $this->assertFalse(isset($data['entity_test_mul']['description__format']));
672 $this->assertFalse(isset($data['entity_test_mul']['user_id']));
673 $this->assertFalse(isset($data['entity_test_mul']['homepage']));
675 // Check the data fields.
676 $this->assertNumericField($data['entity_test_mul_property_data']['id']);
677 $this->assertField($data['entity_test_mul_property_data']['id'], 'id');
679 $this->assertBundleField($data['entity_test_mul_property_data']['type']);
680 $this->assertField($data['entity_test_mul_property_data']['type'], 'type');
682 $this->assertLanguageField($data['entity_test_mul_property_data']['langcode']);
683 $this->assertField($data['entity_test_mul_property_data']['langcode'], 'langcode');
684 $this->assertEquals('Translation language', $data['entity_test_mul_property_data']['langcode']['title']);
686 $this->assertStringField($data['entity_test_mul_property_data']['name']);
687 $this->assertField($data['entity_test_mul_property_data']['name'], 'name');
689 $this->assertLongTextField($data['entity_test_mul_property_data'], 'description');
690 $this->assertField($data['entity_test_mul_property_data']['description__value'], 'description');
691 $this->assertField($data['entity_test_mul_property_data']['description__format'], 'description');
693 $this->assertUriField($data['entity_test_mul_property_data']['homepage']);
694 $this->assertField($data['entity_test_mul_property_data']['homepage'], 'homepage');
696 $this->assertEntityReferenceField($data['entity_test_mul_property_data']['user_id']);
697 $this->assertField($data['entity_test_mul_property_data']['user_id'], 'user_id');
698 $relationship = $data['entity_test_mul_property_data']['user_id']['relationship'];
699 $this->assertEquals('users_field_data', $relationship['base']);
700 $this->assertEquals('uid', $relationship['base field']);
702 $this->assertStringField($data['entity_test_mul__string']['string_value']);
703 $this->assertField($data['entity_test_mul__string']['string_value'], 'string');
704 $this->assertEquals([
705 'left_field' => 'id',
706 'field' => 'entity_id',
708 'field' => 'deleted',
713 ], $data['entity_test_mul__string']['table']['join']['entity_test_mul']);
717 * Tests fields on the revision table.
719 public function testRevisionTableFields() {
720 $entity_type = $this->baseEntityType
721 ->set('base_table', 'entity_test_mulrev')
722 ->set('revision_table', 'entity_test_mulrev_revision')
723 ->set('data_table', 'entity_test_mulrev_property_data')
724 ->set('revision_data_table', 'entity_test_mulrev_property_revision')
725 ->set('id', 'entity_test_mulrev')
726 ->set('translatable', TRUE);
727 $base_field_definitions = $this->setupBaseFields(EntityTestMulRev::baseFieldDefinitions($this->baseEntityType));
728 $user_base_field_definitions = [
729 'uid' => BaseFieldDefinition::create('integer')
731 ->setDescription('The ID of the user entity.')
733 ->setSetting('unsigned', TRUE)
735 $this->entityManager->expects($this->any())
736 ->method('getBaseFieldDefinitions')
737 ->will($this->returnValueMap([
738 ['user', $user_base_field_definitions],
739 ['entity_test_mulrev', $base_field_definitions],
742 $this->viewsData->setEntityType($entity_type);
744 // Setup the table mapping.
745 $table_mapping = $this->getMockBuilder(DefaultTableMapping::class)
746 ->disableOriginalConstructor()
748 $table_mapping->expects($this->any())
749 ->method('getTableNames')
750 ->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']);
751 $table_mapping->expects($this->any())
752 ->method('getColumnNames')
754 ['id', ['value' => 'id']],
755 ['uuid', ['value' => 'uuid']],
756 ['type', ['value' => 'type']],
757 ['langcode', ['value' => 'langcode']],
758 ['name', ['value' => 'name']],
759 ['description', ['value' => 'description__value', 'format' => 'description__format']],
760 ['homepage', ['value' => 'homepage']],
761 ['user_id', ['target_id' => 'user_id']],
762 ['revision_id', ['value' => 'revision_id']],
763 ['string', ['value' => 'string_value']],
765 $table_mapping->expects($this->any())
766 ->method('getFieldNames')
768 ['entity_test_mulrev', ['id', 'revision_id', 'uuid', 'type']],
769 ['entity_test_mulrev_revision', ['id', 'revision_id', 'langcode']],
770 ['entity_test_mulrev_property_data', ['id', 'revision_id', 'langcode', 'name', 'description', 'homepage', 'user_id']],
771 ['entity_test_mulrev_property_revision', ['id', 'revision_id', 'langcode', 'name', 'description', 'homepage', 'user_id']],
772 ['entity_test_mulrev__string', ['string']],
773 ['entity_test_mulrev_revision__string', ['string']],
775 $table_mapping->expects($this->any())
776 ->method('requiresDedicatedTableStorage')
777 ->willReturnCallback(function (BaseFieldDefinition $base_field) {
778 return $base_field->getName() === 'string';
780 $table_mapping->expects($this->any())
781 ->method('getDedicatedDataTableName')
782 ->willReturnCallback(function (BaseFieldDefinition $base_field) {
783 if ($base_field->getName() === 'string') {
784 return 'entity_test_mulrev__string';
788 $table_mapping->expects($this->any())
789 ->method('getDedicatedRevisionTableName')
790 ->willReturnCallback(function (BaseFieldDefinition $base_field) {
791 if ($base_field->getName() === 'string') {
792 return 'entity_test_mulrev_revision__string';
796 $table_mapping->expects($this->any())
797 ->method('getFieldTableName')
798 ->willReturnCallback(function ($field) {
799 if ($field == 'uuid') {
800 return 'entity_test_mulrev';
802 return 'entity_test_mulrev_property_data';
805 $this->entityStorage->expects($this->once())
806 ->method('getTableMapping')
807 ->willReturn($table_mapping);
809 $this->setupFieldStorageDefinition();
811 $data = $this->viewsData->getViewsData();
813 // Check the base fields.
814 $this->assertFalse(isset($data['entity_test_mulrev']['id']));
815 $this->assertFalse(isset($data['entity_test_mulrev']['type']));
816 $this->assertFalse(isset($data['entity_test_mulrev']['revision_id']));
817 $this->assertUuidField($data['entity_test_mulrev']['uuid']);
818 $this->assertField($data['entity_test_mulrev']['uuid'], 'uuid');
820 // Also ensure that field_data only fields don't appear on the base table.
821 $this->assertFalse(isset($data['entity_test_mulrev']['name']));
822 $this->assertFalse(isset($data['entity_test_mul']['description']));
823 $this->assertFalse(isset($data['entity_test_mul']['description__value']));
824 $this->assertFalse(isset($data['entity_test_mul']['description__format']));
825 $this->assertFalse(isset($data['entity_test_mul']['homepage']));
826 $this->assertFalse(isset($data['entity_test_mulrev']['langcode']));
827 $this->assertFalse(isset($data['entity_test_mulrev']['user_id']));
829 // Check the revision fields. The revision ID should only appear in the data
831 $this->assertFalse(isset($data['entity_test_mulrev_revision']['revision_id']));
833 // Also ensure that field_data only fields don't appear on the revision table.
834 $this->assertFalse(isset($data['entity_test_mulrev_revision']['id']));
835 $this->assertFalse(isset($data['entity_test_mulrev_revision']['name']));
836 $this->assertFalse(isset($data['entity_test_mulrev_revision']['description']));
837 $this->assertFalse(isset($data['entity_test_mulrev_revision']['description__value']));
838 $this->assertFalse(isset($data['entity_test_mulrev_revision']['description__format']));
839 $this->assertFalse(isset($data['entity_test_mulrev_revision']['homepage']));
840 $this->assertFalse(isset($data['entity_test_mulrev_revision']['user_id']));
842 // Check the data fields.
843 $this->assertNumericField($data['entity_test_mulrev_property_data']['id']);
844 $this->assertField($data['entity_test_mulrev_property_data']['id'], 'id');
845 $this->assertNumericField($data['entity_test_mulrev_property_data']['revision_id']);
846 $this->assertField($data['entity_test_mulrev_property_data']['revision_id'], 'revision_id');
847 $this->assertLanguageField($data['entity_test_mulrev_property_data']['langcode']);
848 $this->assertField($data['entity_test_mulrev_property_data']['langcode'], 'langcode');
849 $this->assertStringField($data['entity_test_mulrev_property_data']['name']);
850 $this->assertField($data['entity_test_mulrev_property_data']['name'], 'name');
852 $this->assertLongTextField($data['entity_test_mulrev_property_data'], 'description');
853 $this->assertField($data['entity_test_mulrev_property_data']['description__value'], 'description');
854 $this->assertField($data['entity_test_mulrev_property_data']['description__format'], 'description');
855 $this->assertUriField($data['entity_test_mulrev_property_data']['homepage']);
856 $this->assertField($data['entity_test_mulrev_property_data']['homepage'], 'homepage');
858 $this->assertEntityReferenceField($data['entity_test_mulrev_property_data']['user_id']);
859 $this->assertField($data['entity_test_mulrev_property_data']['user_id'], 'user_id');
860 $relationship = $data['entity_test_mulrev_property_data']['user_id']['relationship'];
861 $this->assertEquals('users_field_data', $relationship['base']);
862 $this->assertEquals('uid', $relationship['base field']);
864 // Check the property data fields.
865 $this->assertNumericField($data['entity_test_mulrev_property_revision']['id']);
866 $this->assertField($data['entity_test_mulrev_property_revision']['id'], 'id');
868 $this->assertLanguageField($data['entity_test_mulrev_property_revision']['langcode']);
869 $this->assertField($data['entity_test_mulrev_property_revision']['langcode'], 'langcode');
870 $this->assertEquals('Translation language', $data['entity_test_mulrev_property_revision']['langcode']['title']);
872 $this->assertStringField($data['entity_test_mulrev_property_revision']['name']);
873 $this->assertField($data['entity_test_mulrev_property_revision']['name'], 'name');
875 $this->assertLongTextField($data['entity_test_mulrev_property_revision'], 'description');
876 $this->assertField($data['entity_test_mulrev_property_revision']['description__value'], 'description');
877 $this->assertField($data['entity_test_mulrev_property_revision']['description__format'], 'description');
879 $this->assertUriField($data['entity_test_mulrev_property_revision']['homepage']);
880 $this->assertField($data['entity_test_mulrev_property_revision']['homepage'], 'homepage');
882 $this->assertEntityReferenceField($data['entity_test_mulrev_property_revision']['user_id']);
883 $this->assertField($data['entity_test_mulrev_property_revision']['user_id'], 'user_id');
884 $relationship = $data['entity_test_mulrev_property_revision']['user_id']['relationship'];
885 $this->assertEquals('users_field_data', $relationship['base']);
886 $this->assertEquals('uid', $relationship['base field']);
888 $this->assertStringField($data['entity_test_mulrev__string']['string_value']);
889 $this->assertField($data['entity_test_mulrev__string']['string_value'], 'string');
890 $this->assertEquals([
891 'left_field' => 'id',
892 'field' => 'entity_id',
894 'field' => 'deleted',
899 ], $data['entity_test_mulrev__string']['table']['join']['entity_test_mulrev_property_data']);
901 $this->assertStringField($data['entity_test_mulrev_revision__string']['string_value']);
902 $this->assertField($data['entity_test_mulrev_revision__string']['string_value'], 'string');
903 $this->assertEquals([
904 'left_field' => 'revision_id',
905 'field' => 'entity_id',
907 'field' => 'deleted',
912 ], $data['entity_test_mulrev_revision__string']['table']['join']['entity_test_mulrev_property_revision']);
916 * Tests generic stuff per field.
919 * The views data to check.
920 * @param string $field_name
921 * The entity field name.
923 protected function assertField($data, $field_name) {
924 $this->assertEquals($field_name, $data['entity field']);
928 * Tests add link types.
930 public function testEntityLinks() {
931 $this->baseEntityType->setLinkTemplate('canonical', '/entity_test/{entity_test}');
932 $this->baseEntityType->setLinkTemplate('edit-form', '/entity_test/{entity_test}/edit');
933 $this->baseEntityType->setLinkTemplate('delete-form', '/entity_test/{entity_test}/delete');
935 $data = $this->viewsData->getViewsData();
936 $this->assertEquals('entity_link', $data['entity_test']['view_entity_test']['field']['id']);
937 $this->assertEquals('entity_link_edit', $data['entity_test']['edit_entity_test']['field']['id']);
938 $this->assertEquals('entity_link_delete', $data['entity_test']['delete_entity_test']['field']['id']);
942 * Tests additional edit links.
944 public function testEntityLinksJustEditForm() {
945 $this->baseEntityType->setLinkTemplate('edit-form', '/entity_test/{entity_test}/edit');
947 $data = $this->viewsData->getViewsData();
948 $this->assertFalse(isset($data['entity_test']['view_entity_test']));
949 $this->assertFalse(isset($data['entity_test']['delete_entity_test']));
951 $this->assertEquals('entity_link_edit', $data['entity_test']['edit_entity_test']['field']['id']);
955 * @covers ::getViewsData
957 public function testGetViewsDataWithoutEntityOperations() {
958 // Make sure there is no list builder. The API does not document is
959 // supports resetting entity handlers, so this might break in the future.
960 $this->baseEntityType->setListBuilderClass(NULL);
961 $data = $this->viewsData->getViewsData();
962 $this->assertArrayNotHasKey('operations', $data[$this->baseEntityType->getBaseTable()]);
966 * @covers ::getViewsData
968 public function testGetViewsDataWithEntityOperations() {
969 $this->baseEntityType->setListBuilderClass('\Drupal\Core\Entity\EntityListBuilder');
970 $data = $this->viewsData->getViewsData();
971 $this->assertSame('entity_operations', $data[$this->baseEntityType->getBaseTable()]['operations']['field']['id']);
975 * Tests views data for a string field.
978 * The views data to check.
980 protected function assertStringField($data) {
981 $this->assertEquals('field', $data['field']['id']);
982 $this->assertEquals('string', $data['filter']['id']);
983 $this->assertEquals('string', $data['argument']['id']);
984 $this->assertEquals('standard', $data['sort']['id']);
988 * Tests views data for a URI field.
991 * The views data to check.
993 protected function assertUriField($data) {
994 $this->assertEquals('field', $data['field']['id']);
995 $this->assertEquals('string', $data['field']['default_formatter']);
996 $this->assertEquals('string', $data['filter']['id']);
997 $this->assertEquals('string', $data['argument']['id']);
998 $this->assertEquals('standard', $data['sort']['id']);
1002 * Tests views data for a long text field.
1005 * The views data for the table this field is in.
1006 * @param $field_name
1007 * The name of the field being checked.
1009 protected function assertLongTextField($data, $field_name) {
1010 $value_field = $data[$field_name . '__value'];
1011 $this->assertEquals('field', $value_field['field']['id']);
1012 $this->assertEquals($field_name . '__format', $value_field['field']['format']);
1013 $this->assertEquals('string', $value_field['filter']['id']);
1014 $this->assertEquals('string', $value_field['argument']['id']);
1015 $this->assertEquals('standard', $value_field['sort']['id']);
1017 $this->assertStringField($data[$field_name . '__format']);
1021 * Tests views data for a UUID field.
1023 * @param array $data
1024 * The views data to check.
1026 protected function assertUuidField($data) {
1027 // @todo Can we provide additional support for UUIDs in views?
1028 $this->assertEquals('field', $data['field']['id']);
1029 $this->assertFalse($data['field']['click sortable']);
1030 $this->assertEquals('string', $data['filter']['id']);
1031 $this->assertEquals('string', $data['argument']['id']);
1032 $this->assertEquals('standard', $data['sort']['id']);
1036 * Tests views data for a numeric field.
1038 * @param array $data
1039 * The views data to check.
1041 protected function assertNumericField($data) {
1042 $this->assertEquals('field', $data['field']['id']);
1043 $this->assertEquals('numeric', $data['filter']['id']);
1044 $this->assertEquals('numeric', $data['argument']['id']);
1045 $this->assertEquals('standard', $data['sort']['id']);
1049 * Tests views data for a language field.
1051 * @param array $data
1052 * The views data to check.
1054 protected function assertLanguageField($data) {
1055 $this->assertEquals('field', $data['field']['id']);
1056 $this->assertEquals('language', $data['filter']['id']);
1057 $this->assertEquals('language', $data['argument']['id']);
1058 $this->assertEquals('standard', $data['sort']['id']);
1062 * Tests views data for a entity reference field.
1064 protected function assertEntityReferenceField($data) {
1065 $this->assertEquals('field', $data['field']['id']);
1066 $this->assertEquals('numeric', $data['filter']['id']);
1067 $this->assertEquals('numeric', $data['argument']['id']);
1068 $this->assertEquals('standard', $data['sort']['id']);
1072 * Tests views data for a bundle field.
1074 protected function assertBundleField($data) {
1075 $this->assertEquals('field', $data['field']['id']);
1076 $this->assertEquals('bundle', $data['filter']['id']);
1077 $this->assertEquals('string', $data['argument']['id']);
1078 $this->assertEquals('standard', $data['sort']['id']);
1082 * Returns entity info for the user entity.
1086 protected static function userEntityInfo() {
1087 return new ContentEntityType([
1089 'class' => 'Drupal\user\Entity\User',
1091 'base_table' => 'users',
1092 'data_table' => 'users_field_data',
1102 class TestEntityViewsData extends EntityViewsData {
1104 public function setEntityType(EntityTypeInterface $entity_type) {
1105 $this->entityType = $entity_type;
1110 class TestEntityType extends ContentEntityType {
1113 * Sets a specific entity key.
1115 * @param string $key
1116 * The name of the entity key.
1117 * @param string $value
1118 * The new value of the key.
1122 public function setKey($key, $value) {
1123 $this->entity_keys[$key] = $value;
1129 namespace Drupal\entity_test\Entity;
1131 if (!function_exists('t')) {
1132 function t($string, array $args = []) {
1133 return strtr($string, $args);
1138 namespace Drupal\Core\Entity;
1140 if (!function_exists('t')) {
1141 function t($string, array $args = []) {
1142 return strtr($string, $args);