Upgraded drupal core with security updates
[yaffs-website] / web / core / modules / views / tests / src / Unit / EntityViewsDataTest.php
1 <?php
2
3 /**
4  * @file
5  * Contains \Drupal\Tests\views\Unit\EntityViewsDataTest.
6  */
7
8 namespace Drupal\Tests\views\Unit;
9
10 use Drupal\Core\Config\Entity\ConfigEntityType;
11 use Drupal\Core\Entity\ContentEntityType;
12 use Drupal\Core\Entity\EntityType;
13 use Drupal\Core\Entity\EntityTypeInterface;
14 use Drupal\Core\Entity\Sql\DefaultTableMapping;
15 use Drupal\Core\Field\BaseFieldDefinition;
16 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
17 use Drupal\Core\Field\Plugin\Field\FieldType\IntegerItem;
18 use Drupal\Core\Field\Plugin\Field\FieldType\LanguageItem;
19 use Drupal\Core\Field\Plugin\Field\FieldType\StringItem;
20 use Drupal\Core\Field\Plugin\Field\FieldType\UriItem;
21 use Drupal\Core\Field\Plugin\Field\FieldType\UuidItem;
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 Symfony\Component\DependencyInjection\ContainerBuilder;
30
31 /**
32  * @coversDefaultClass \Drupal\views\EntityViewsData
33  * @group Views
34  */
35 class EntityViewsDataTest extends UnitTestCase {
36
37   /**
38    * Entity info to use in this test.
39    *
40    * @var \Drupal\Core\Entity\EntityTypeInterface|\Drupal\Tests\views\Unit\TestEntityType
41    */
42   protected $baseEntityType;
43
44   /**
45    * The mocked entity storage.
46    *
47    * @var \Drupal\Core\Entity\Sql\SqlContentEntityStorage|\PHPUnit_Framework_MockObject_MockObject
48    */
49   protected $entityStorage;
50
51   /**
52    * The mocked entity manager.
53    *
54    * @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
55    */
56   protected $entityManager;
57
58   /**
59    * The mocked module handler.
60    *
61    * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
62    */
63   protected $moduleHandler;
64
65   /**
66    * The mocked translation manager.
67    *
68    * @var \Drupal\Core\StringTranslation\TranslationInterface|\PHPUnit_Framework_MockObject_MockObject
69    */
70   protected $translationManager;
71
72   /**
73    * The tested entity views controller.
74    *
75    * @var \Drupal\Tests\views\Unit\TestEntityViewsData
76    */
77   protected $viewsData;
78
79   /**
80    * {@inheritdoc}
81    */
82   protected function setUp() {
83     $this->entityStorage = $this->getMockBuilder('Drupal\Core\Entity\Sql\SqlContentEntityStorage')
84       ->disableOriginalConstructor()
85       ->getMock();
86     $this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
87
88     $typed_data_manager = $this->getMock(TypedDataManagerInterface::class);
89     $typed_data_manager->expects($this->any())
90       ->method('createDataDefinition')
91       ->willReturn($this->getMock('Drupal\Core\TypedData\DataDefinitionInterface'));
92
93     $typed_data_manager->expects($this->any())
94       ->method('getDefinition')
95       ->with($this->equalTo('field_item:string_long'))
96       ->willReturn(['class' => '\Drupal\Core\Field\Plugin\Field\FieldType\StringLongItem']);
97
98     $this->baseEntityType = new TestEntityType([
99       'base_table' => 'entity_test',
100       'id' => 'entity_test',
101       'label' => 'Entity test',
102       'entity_keys' => [
103         'uuid' => 'uuid',
104         'id' => 'id',
105         'langcode' => 'langcode',
106         'bundle' => 'type',
107         'revision' => 'revision_id',
108       ],
109       'provider' => 'entity_test',
110       'list_cache_contexts' => ['entity_test_list_cache_context'],
111     ]);
112
113     $this->translationManager = $this->getStringTranslationStub();
114     $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
115
116     $this->viewsData = new TestEntityViewsData($this->baseEntityType, $this->entityStorage, $this->entityManager, $this->moduleHandler, $this->translationManager);
117
118     $field_type_manager = $this->getMockBuilder('Drupal\Core\Field\FieldTypePluginManager')
119       ->disableOriginalConstructor()
120       ->getMock();
121     $field_type_manager->expects($this->any())
122       ->method('getDefaultStorageSettings')
123       ->willReturn([]);
124     $field_type_manager->expects($this->any())
125       ->method('getDefaultFieldSettings')
126       ->willReturn([]);
127
128     $container = new ContainerBuilder();
129     $container->set('plugin.manager.field.field_type', $field_type_manager);
130     $container->set('entity.manager', $this->entityManager);
131     $container->set('typed_data_manager', $typed_data_manager);
132     \Drupal::setContainer($container);
133   }
134
135   /**
136    * Helper method to setup base fields.
137    *
138    * @param \Drupal\Core\Field\BaseFieldDefinition[] $base_fields
139    *   The base fields which are adapted.
140    *
141    * @return \Drupal\Core\Field\BaseFieldDefinition[]
142    *   The setup base fields.
143    */
144   protected function setupBaseFields(array $base_fields) {
145     // Add a description field to the fields supplied by the EntityTest
146     // classes. This example comes from the taxonomy Term entity.
147     $base_fields['description'] = BaseFieldDefinition::create('text_long')
148       ->setLabel('Description')
149       ->setDescription('A description of the term.')
150       ->setTranslatable(TRUE)
151       ->setDisplayOptions('view', [
152           'label' => 'hidden',
153           'type' => 'text_default',
154           'weight' => 0,
155         ])
156       ->setDisplayConfigurable('view', TRUE)
157       ->setDisplayOptions('form', [
158           'type' => 'text_textfield',
159           'weight' => 0,
160         ])
161       ->setDisplayConfigurable('form', TRUE);
162
163     // Add a URL field; this example is from the Comment entity.
164     $base_fields['homepage'] = BaseFieldDefinition::create('uri')
165       ->setLabel('Homepage')
166       ->setDescription("The comment author's home page address.")
167       ->setTranslatable(TRUE)
168       ->setSetting('max_length', 255);
169
170     // A base field with cardinality > 1
171     $base_fields['string']  = BaseFieldDefinition::create('string')
172       ->setLabel('Strong')
173       ->setTranslatable(TRUE)
174       ->setCardinality(2);
175
176     foreach ($base_fields as $name => $base_field) {
177       $base_field->setName($name);
178     }
179     return $base_fields;
180   }
181
182   /**
183    * Tests base tables.
184    */
185   public function testBaseTables() {
186     $data = $this->viewsData->getViewsData();
187
188     $this->assertEquals('entity_test', $data['entity_test']['table']['entity type']);
189     $this->assertEquals(FALSE, $data['entity_test']['table']['entity revision']);
190     $this->assertEquals('Entity test', $data['entity_test']['table']['group']);
191     $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
192
193     $this->assertEquals('id', $data['entity_test']['table']['base']['field']);
194     $this->assertEquals(['entity_test_list_cache_context'], $data['entity_test']['table']['base']['cache_contexts']);
195     $this->assertEquals('Entity test', $data['entity_test']['table']['base']['title']);
196
197     $this->assertFalse(isset($data['entity_test']['table']['defaults']));
198
199     $this->assertFalse(isset($data['entity_test_mul_property_data']));
200     $this->assertFalse(isset($data['revision_table']));
201     $this->assertFalse(isset($data['revision_data_table']));
202   }
203
204   /**
205    * Tests data_table support.
206    */
207   public function testDataTable() {
208     $entity_type = $this->baseEntityType
209       ->set('data_table', 'entity_test_mul_property_data')
210       ->set('id', 'entity_test_mul')
211       ->set('translatable', TRUE)
212       ->setKey('label', 'label');
213
214     $this->viewsData->setEntityType($entity_type);
215
216     // Tests the join definition between the base and the data table.
217     $data = $this->viewsData->getViewsData();
218     $base_views_data = $data['entity_test'];
219
220     // Ensure that the base table is set to the data table.
221     $this->assertEquals('id', $data['entity_test_mul_property_data']['table']['base']['field']);
222     $this->assertEquals('Entity test', $data['entity_test_mul_property_data']['table']['base']['title']);
223     $this->assertFalse(isset($data['entity_test']['table']['base']));
224
225     $this->assertEquals('entity_test_mul', $data['entity_test_mul_property_data']['table']['entity type']);
226     $this->assertEquals(FALSE, $data['entity_test_mul_property_data']['table']['entity revision']);
227     $this->assertEquals('Entity test', $data['entity_test_mul_property_data']['table']['group']);
228     $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
229     $this->assertEquals(['field' => 'label', 'table' => 'entity_test_mul_property_data'], $data['entity_test_mul_property_data']['table']['base']['defaults']);
230
231     // Ensure the join information is set up properly.
232     $this->assertCount(1, $base_views_data['table']['join']);
233     $this->assertEquals(['entity_test_mul_property_data' => ['left_field' => 'id', 'field' => 'id', 'type' => 'INNER']], $base_views_data['table']['join']);
234     $this->assertFalse(isset($data['revision_table']));
235     $this->assertFalse(isset($data['revision_data_table']));
236   }
237
238   /**
239    * Tests revision table without data table support.
240    */
241   public function testRevisionTableWithoutDataTable() {
242     $entity_type = $this->baseEntityType
243       ->set('revision_table', 'entity_test_mulrev_revision')
244       ->set('revision_data_table', NULL)
245       ->set('id', 'entity_test_mulrev')
246       ->setKey('revision', 'revision_id')
247     ;
248     $this->viewsData->setEntityType($entity_type);
249
250     $data = $this->viewsData->getViewsData();
251
252     $this->assertEquals('Entity test revisions', $data['entity_test_mulrev_revision']['table']['base']['title']);
253     $this->assertEquals('revision_id', $data['entity_test_mulrev_revision']['table']['base']['field']);
254
255     $this->assertEquals(FALSE, $data['entity_test']['table']['entity revision']);
256     $this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_revision']['table']['entity type']);
257     $this->assertEquals(TRUE, $data['entity_test_mulrev_revision']['table']['entity revision']);
258     $this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_revision']['table']['entity type']);
259     $this->assertEquals(TRUE, $data['entity_test_mulrev_revision']['table']['entity revision']);
260
261     $this->assertEquals('Entity test revision', $data['entity_test_mulrev_revision']['table']['group']);
262     $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
263
264     // Ensure the join information is set up properly.
265     // Tests the join definition between the base and the revision table.
266     $revision_data = $data['entity_test_mulrev_revision'];
267     $this->assertCount(1, $revision_data['table']['join']);
268     $this->assertEquals(['entity_test' => ['left_field' => 'revision_id', 'field' => 'revision_id', 'type' => 'INNER']], $revision_data['table']['join']);
269     $this->assertFalse(isset($data['data_table']));
270   }
271
272   /**
273    * Tests revision table with data table support.
274    */
275   public function testRevisionTableWithRevisionDataTableAndDataTable() {
276     $entity_type = $this->baseEntityType
277       ->set('data_table', 'entity_test_mul_property_data')
278       ->set('revision_table', 'entity_test_mulrev_revision')
279       ->set('revision_data_table', 'entity_test_mulrev_property_revision')
280       ->set('id', 'entity_test_mulrev')
281       ->set('translatable', TRUE)
282       ->setKey('revision', 'revision_id')
283     ;
284     $this->viewsData->setEntityType($entity_type);
285
286     $data = $this->viewsData->getViewsData();
287
288     $this->assertEquals('Entity test revisions', $data['entity_test_mulrev_property_revision']['table']['base']['title']);
289     $this->assertEquals('revision_id', $data['entity_test_mulrev_property_revision']['table']['base']['field']);
290     $this->assertFalse(isset($data['entity_test_mulrev_revision']['table']['base']));
291
292     $this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_property_revision']['table']['entity type']);
293     $this->assertEquals('Entity test revision', $data['entity_test_mulrev_revision']['table']['group']);
294     $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
295
296     // Ensure the join information is set up properly.
297     // Tests the join definition between the base and the revision table.
298     $revision_field_data = $data['entity_test_mulrev_property_revision'];
299     $this->assertCount(1, $revision_field_data['table']['join']);
300     $this->assertEquals([
301       'entity_test_mul_property_data' => [
302         'left_field' => 'revision_id', 'field' => 'revision_id', 'type' => 'INNER'
303       ],
304     ], $revision_field_data['table']['join']);
305
306     $revision_base_data = $data['entity_test_mulrev_revision'];
307     $this->assertCount(1, $revision_base_data['table']['join']);
308     $this->assertEquals([
309       'entity_test_mulrev_property_revision' => [
310         'left_field' => 'revision_id', 'field' => 'revision_id', 'type' => 'INNER'
311       ],
312     ], $revision_base_data['table']['join']);
313
314     $this->assertFalse(isset($data['data_table']));
315   }
316
317   /**
318    * Tests revision table with data table support.
319    */
320   public function testRevisionTableWithRevisionDataTable() {
321     $entity_type = $this->baseEntityType
322       ->set('revision_table', 'entity_test_mulrev_revision')
323       ->set('revision_data_table', 'entity_test_mulrev_property_revision')
324       ->set('id', 'entity_test_mulrev')
325       ->set('translatable', TRUE)
326       ->setKey('revision', 'revision_id')
327     ;
328     $this->viewsData->setEntityType($entity_type);
329
330     $data = $this->viewsData->getViewsData();
331
332     $this->assertEquals('Entity test revisions', $data['entity_test_mulrev_property_revision']['table']['base']['title']);
333     $this->assertEquals('revision_id', $data['entity_test_mulrev_property_revision']['table']['base']['field']);
334     $this->assertFalse(isset($data['entity_test_mulrev_revision']['table']['base']));
335
336     $this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_property_revision']['table']['entity type']);
337     $this->assertEquals('Entity test revision', $data['entity_test_mulrev_revision']['table']['group']);
338     $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
339
340     // Ensure the join information is set up properly.
341     // Tests the join definition between the base and the revision table.
342     $revision_field_data = $data['entity_test_mulrev_property_revision'];
343     $this->assertCount(1, $revision_field_data['table']['join']);
344     $this->assertEquals([
345       'entity_test_mulrev_field_data' => [
346         'left_field' => 'revision_id', 'field' => 'revision_id', 'type' => 'INNER'
347       ],
348     ], $revision_field_data['table']['join']);
349
350     $revision_base_data = $data['entity_test_mulrev_revision'];
351     $this->assertCount(1, $revision_base_data['table']['join']);
352     $this->assertEquals([
353       'entity_test_mulrev_property_revision' => [
354         'left_field' => 'revision_id', 'field' => 'revision_id', 'type' => 'INNER'
355       ],
356     ], $revision_base_data['table']['join']);
357     $this->assertFalse(isset($data['data_table']));
358   }
359
360   /**
361    * Helper method to mock all store definitions.
362    */
363   protected function setupFieldStorageDefinition() {
364     $id_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
365     $id_field_storage_definition->expects($this->any())
366       ->method('getSchema')
367       ->willReturn(IntegerItem::schema($id_field_storage_definition));
368     $uuid_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
369     $uuid_field_storage_definition->expects($this->any())
370       ->method('getSchema')
371       ->willReturn(UuidItem::schema($uuid_field_storage_definition));
372     $type_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
373     $type_field_storage_definition->expects($this->any())
374       ->method('getSchema')
375       ->willReturn(StringItem::schema($type_field_storage_definition));
376     $langcode_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
377     $langcode_field_storage_definition->expects($this->any())
378       ->method('getSchema')
379       ->willReturn(LanguageItem::schema($langcode_field_storage_definition));
380     $name_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
381     $name_field_storage_definition->expects($this->any())
382       ->method('getSchema')
383       ->willReturn(StringItem::schema($name_field_storage_definition));
384     $description_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
385     $description_field_storage_definition->expects($this->any())
386       ->method('getSchema')
387       ->willReturn(TextLongItem::schema($description_field_storage_definition));
388     $homepage_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
389     $homepage_field_storage_definition->expects($this->any())
390       ->method('getSchema')
391       ->willReturn(UriItem::schema($homepage_field_storage_definition));
392     $string_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
393     $string_field_storage_definition->expects($this->any())
394       ->method('getSchema')
395       ->willReturn(StringItem::schema($string_field_storage_definition));
396
397     // Setup the user_id entity reference field.
398     $this->entityManager->expects($this->any())
399       ->method('getDefinition')
400       ->willReturnMap([
401           ['user', TRUE, static::userEntityInfo()],
402         ]
403       );
404     $user_id_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
405     $user_id_field_storage_definition->expects($this->any())
406       ->method('getSetting')
407       ->with('target_type')
408       ->willReturn('user');
409     $user_id_field_storage_definition->expects($this->any())
410       ->method('getSettings')
411       ->willReturn(['target_type' => 'user']);
412     $user_id_field_storage_definition->expects($this->any())
413       ->method('getSchema')
414       ->willReturn(EntityReferenceItem::schema($user_id_field_storage_definition));
415
416     $revision_id_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
417     $revision_id_field_storage_definition->expects($this->any())
418       ->method('getSchema')
419       ->willReturn(IntegerItem::schema($revision_id_field_storage_definition));
420
421     $this->entityManager->expects($this->any())
422       ->method('getFieldStorageDefinitions')
423       ->willReturn([
424         'id' => $id_field_storage_definition,
425         'uuid' => $uuid_field_storage_definition,
426         'type' => $type_field_storage_definition,
427         'langcode' => $langcode_field_storage_definition,
428         'name' => $name_field_storage_definition,
429         'description' => $description_field_storage_definition,
430         'homepage' => $homepage_field_storage_definition,
431         'string' => $string_field_storage_definition,
432         'user_id' => $user_id_field_storage_definition,
433         'revision_id' => $revision_id_field_storage_definition,
434       ]);
435   }
436
437   /**
438    * Tests fields on the base table.
439    */
440   public function testBaseTableFields() {
441     $base_field_definitions = $this->setupBaseFields(EntityTest::baseFieldDefinitions($this->baseEntityType));
442     $user_base_field_definitions = [
443       'uid' => BaseFieldDefinition::create('integer')
444         ->setLabel('ID')
445         ->setDescription('The ID of the user entity.')
446         ->setReadOnly(TRUE)
447         ->setSetting('unsigned', TRUE)
448     ];
449     $this->entityManager->expects($this->any())
450       ->method('getBaseFieldDefinitions')
451       ->will($this->returnValueMap([
452         ['user', $user_base_field_definitions],
453         ['entity_test', $base_field_definitions],
454       ]));
455     // Setup the table mapping.
456     $table_mapping = $this->getMockBuilder(DefaultTableMapping::class)
457       ->disableOriginalConstructor()
458       ->getMock();
459     $table_mapping->expects($this->any())
460       ->method('getTableNames')
461       ->willReturn(['entity_test', 'entity_test__string']);
462     $table_mapping->expects($this->any())
463       ->method('getColumnNames')
464       ->willReturnMap([
465         ['id', ['value' => 'id']],
466         ['uuid', ['value' => 'uuid']],
467         ['type', ['value' => 'type']],
468         ['langcode', ['value' => 'langcode']],
469         ['name', ['value' => 'name']],
470         ['description', ['value' => 'description__value', 'format' => 'description__format']],
471         ['homepage', ['value' => 'homepage']],
472         ['user_id', ['target_id' => 'user_id']],
473         ['string', ['value' => 'value']],
474       ]);
475     $table_mapping->expects($this->any())
476       ->method('getFieldNames')
477       ->willReturnMap([
478         ['entity_test', ['id', 'uuid', 'type', 'langcode', 'name', 'description', 'homepage', 'user_id']],
479         ['entity_test__string', ['string']],
480       ]);
481     $table_mapping->expects($this->any())
482       ->method('requiresDedicatedTableStorage')
483       ->willReturnCallback(function (BaseFieldDefinition $base_field) {
484         return $base_field->getName() === 'string';
485       });
486     $table_mapping->expects($this->any())
487       ->method('getDedicatedDataTableName')
488       ->willReturnCallback(function (BaseFieldDefinition $base_field) {
489         if ($base_field->getName() === 'string') {
490           return 'entity_test__string';
491         }
492       });
493
494     $this->entityStorage->expects($this->once())
495       ->method('getTableMapping')
496       ->willReturn($table_mapping);
497
498     $this->setupFieldStorageDefinition();
499
500     $data = $this->viewsData->getViewsData();
501
502     $this->assertNumericField($data['entity_test']['id']);
503     $this->assertField($data['entity_test']['id'], 'id');
504     $this->assertUuidField($data['entity_test']['uuid']);
505     $this->assertField($data['entity_test']['uuid'], 'uuid');
506     $this->assertStringField($data['entity_test']['type']);
507     $this->assertEquals('type', $data['entity_test']['type']['entity field']);
508
509     $this->assertLanguageField($data['entity_test']['langcode']);
510     $this->assertField($data['entity_test']['langcode'], 'langcode');
511     $this->assertEquals('Original language', $data['entity_test']['langcode']['title']);
512
513     $this->assertStringField($data['entity_test']['name']);
514     $this->assertField($data['entity_test']['name'], 'name');
515
516     $this->assertLongTextField($data['entity_test'], 'description');
517     $this->assertField($data['entity_test']['description__value'], 'description');
518     $this->assertField($data['entity_test']['description__format'], 'description');
519
520     $this->assertUriField($data['entity_test']['homepage']);
521     $this->assertField($data['entity_test']['homepage'], 'homepage');
522
523     $this->assertEntityReferenceField($data['entity_test']['user_id']);
524     $this->assertField($data['entity_test']['user_id'], 'user_id');
525
526     $relationship = $data['entity_test']['user_id']['relationship'];
527     $this->assertEquals('users_field_data', $relationship['base']);
528     $this->assertEquals('uid', $relationship['base field']);
529
530     $this->assertStringField($data['entity_test__string']['string']);
531     $this->assertField($data['entity_test__string']['string'], 'string');
532     $this->assertEquals([
533       'left_field' => 'id',
534       'field' => 'entity_id',
535       'extra' => [[
536         'field' => 'deleted',
537         'value' => 0,
538         'numeric' => TRUE,
539       ]],
540     ], $data['entity_test__string']['table']['join']['entity_test']);
541   }
542
543   /**
544    * Tests fields on the data table.
545    */
546   public function testDataTableFields() {
547     $entity_type = $this->baseEntityType
548       ->set('data_table', 'entity_test_mul_property_data')
549       ->set('base_table', 'entity_test_mul')
550       ->set('id', 'entity_test_mul')
551       ->setKey('bundle', 'type')
552     ;
553     $base_field_definitions = $this->setupBaseFields(EntityTestMul::baseFieldDefinitions($this->baseEntityType));
554     $base_field_definitions['type'] = BaseFieldDefinition::create('entity_reference')
555       ->setLabel('entity test type')
556       ->setSetting('target_type', 'entity_test_bundle')
557       ->setTranslatable(TRUE);
558     $base_field_definitions = $this->setupBaseFields($base_field_definitions);
559     $user_base_field_definitions = [
560       'uid' => BaseFieldDefinition::create('integer')
561         ->setLabel('ID')
562         ->setDescription('The ID of the user entity.')
563         ->setReadOnly(TRUE)
564         ->setSetting('unsigned', TRUE)
565     ];
566     $entity_test_type = new ConfigEntityType(['id' => 'entity_test_bundle']);
567
568     $this->entityManager->expects($this->any())
569       ->method('getBaseFieldDefinitions')
570       ->will($this->returnValueMap([
571         ['user', $user_base_field_definitions],
572         ['entity_test_mul', $base_field_definitions],
573       ]));
574
575     $this->viewsData->setEntityType($entity_type);
576
577     // Setup the table mapping.
578     $table_mapping = $this->getMockBuilder(DefaultTableMapping::class)
579       ->disableOriginalConstructor()
580       ->getMock();
581     $table_mapping->expects($this->any())
582       ->method('getTableNames')
583       ->willReturn(['entity_test_mul', 'entity_test_mul_property_data', 'entity_test_mul__string']);
584     $table_mapping->expects($this->any())
585       ->method('getColumnNames')
586       ->willReturnMap([
587         ['id', ['value' => 'id']],
588         ['uuid', ['value' => 'uuid']],
589         ['type', ['value' => 'type']],
590         ['langcode', ['value' => 'langcode']],
591         ['name', ['value' => 'name']],
592         ['description', ['value' => 'description__value', 'format' => 'description__format']],
593         ['homepage', ['value' => 'homepage']],
594         ['user_id', ['target_id' => 'user_id']],
595         ['string', ['value' => 'value']],
596       ]);
597     $table_mapping->expects($this->any())
598       ->method('getFieldNames')
599       ->willReturnMap([
600         ['entity_test_mul', ['uuid']],
601         ['entity_test_mul_property_data', ['id', 'type', 'langcode', 'name', 'description', 'homepage', 'user_id']],
602         ['entity_test_mul__string', ['string']],
603       ]);
604
605     $table_mapping->expects($this->any())
606       ->method('getFieldTableName')
607       ->willReturnCallback(function($field) {
608         if ($field == 'uuid') {
609           return 'entity_test_mul';
610         }
611         return 'entity_test_mul_property_data';
612       });
613     $table_mapping->expects($this->any())
614       ->method('requiresDedicatedTableStorage')
615       ->willReturnCallback(function (BaseFieldDefinition $base_field) {
616         return $base_field->getName() === 'string';
617       });
618     $table_mapping->expects($this->any())
619       ->method('getDedicatedDataTableName')
620       ->willReturnCallback(function (BaseFieldDefinition $base_field) {
621         if ($base_field->getName() === 'string') {
622           return 'entity_test_mul__string';
623         }
624       });
625
626     $this->entityStorage->expects($this->once())
627       ->method('getTableMapping')
628       ->willReturn($table_mapping);
629
630     $this->setupFieldStorageDefinition();
631
632     $user_entity_type = static::userEntityInfo();
633     $this->entityManager->expects($this->any())
634       ->method('getDefinition')
635       ->will($this->returnValueMap([
636         ['user', TRUE, $user_entity_type],
637         ['entity_test_bundle', TRUE, $entity_test_type],
638       ]));
639
640     $data = $this->viewsData->getViewsData();
641
642     // Check the base fields.
643     $this->assertFalse(isset($data['entity_test_mul']['id']));
644     $this->assertFalse(isset($data['entity_test_mul']['type']));
645     $this->assertUuidField($data['entity_test_mul']['uuid']);
646     $this->assertField($data['entity_test_mul']['uuid'], 'uuid');
647
648     $this->assertFalse(isset($data['entity_test_mul']['type']['relationship']));
649
650     // Also ensure that field_data only fields don't appear on the base table.
651     $this->assertFalse(isset($data['entity_test_mul']['name']));
652     $this->assertFalse(isset($data['entity_test_mul']['description']));
653     $this->assertFalse(isset($data['entity_test_mul']['description__value']));
654     $this->assertFalse(isset($data['entity_test_mul']['description__format']));
655     $this->assertFalse(isset($data['entity_test_mul']['user_id']));
656     $this->assertFalse(isset($data['entity_test_mul']['homepage']));
657
658     // Check the data fields.
659     $this->assertNumericField($data['entity_test_mul_property_data']['id']);
660     $this->assertField($data['entity_test_mul_property_data']['id'], 'id');
661
662     $this->assertBundleField($data['entity_test_mul_property_data']['type']);
663     $this->assertField($data['entity_test_mul_property_data']['type'], 'type');
664
665     $this->assertLanguageField($data['entity_test_mul_property_data']['langcode']);
666     $this->assertField($data['entity_test_mul_property_data']['langcode'], 'langcode');
667     $this->assertEquals('Translation language', $data['entity_test_mul_property_data']['langcode']['title']);
668
669     $this->assertStringField($data['entity_test_mul_property_data']['name']);
670     $this->assertField($data['entity_test_mul_property_data']['name'], 'name');
671
672     $this->assertLongTextField($data['entity_test_mul_property_data'], 'description');
673     $this->assertField($data['entity_test_mul_property_data']['description__value'], 'description');
674     $this->assertField($data['entity_test_mul_property_data']['description__format'], 'description');
675
676     $this->assertUriField($data['entity_test_mul_property_data']['homepage']);
677     $this->assertField($data['entity_test_mul_property_data']['homepage'], 'homepage');
678
679     $this->assertEntityReferenceField($data['entity_test_mul_property_data']['user_id']);
680     $this->assertField($data['entity_test_mul_property_data']['user_id'], 'user_id');
681     $relationship = $data['entity_test_mul_property_data']['user_id']['relationship'];
682     $this->assertEquals('users_field_data', $relationship['base']);
683     $this->assertEquals('uid', $relationship['base field']);
684
685     $this->assertStringField($data['entity_test_mul__string']['string']);
686     $this->assertField($data['entity_test_mul__string']['string'], 'string');
687     $this->assertEquals([
688       'left_field' => 'id',
689       'field' => 'entity_id',
690       'extra' => [[
691         'field' => 'deleted',
692         'value' => 0,
693         'numeric' => TRUE,
694       ]],
695     ], $data['entity_test_mul__string']['table']['join']['entity_test_mul']);
696   }
697
698   /**
699    * Tests fields on the revision table.
700    */
701   public function testRevisionTableFields() {
702     $entity_type = $this->baseEntityType
703       ->set('base_table', 'entity_test_mulrev')
704       ->set('revision_table', 'entity_test_mulrev_revision')
705       ->set('data_table', 'entity_test_mulrev_property_data')
706       ->set('revision_data_table', 'entity_test_mulrev_property_revision')
707       ->set('id', 'entity_test_mulrev')
708       ->set('translatable', TRUE);
709     $base_field_definitions = $this->setupBaseFields(EntityTestMulRev::baseFieldDefinitions($this->baseEntityType));
710     $user_base_field_definitions = [
711       'uid' => BaseFieldDefinition::create('integer')
712         ->setLabel('ID')
713         ->setDescription('The ID of the user entity.')
714         ->setReadOnly(TRUE)
715         ->setSetting('unsigned', TRUE)
716     ];
717     $this->entityManager->expects($this->any())
718       ->method('getBaseFieldDefinitions')
719       ->will($this->returnValueMap([
720         ['user', $user_base_field_definitions],
721         ['entity_test_mulrev', $base_field_definitions],
722       ]));
723
724     $this->viewsData->setEntityType($entity_type);
725
726     // Setup the table mapping.
727     $table_mapping = $this->getMockBuilder(DefaultTableMapping::class)
728       ->disableOriginalConstructor()
729       ->getMock();
730     $table_mapping->expects($this->any())
731       ->method('getTableNames')
732       ->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']);
733     $table_mapping->expects($this->any())
734       ->method('getColumnNames')
735       ->willReturnMap([
736         ['id', ['value' => 'id']],
737         ['uuid', ['value' => 'uuid']],
738         ['type', ['value' => 'type']],
739         ['langcode', ['value' => 'langcode']],
740         ['name', ['value' => 'name']],
741         ['description', ['value' => 'description__value', 'format' => 'description__format']],
742         ['homepage', ['value' => 'homepage']],
743         ['user_id', ['target_id' => 'user_id']],
744         ['revision_id', ['value' => 'id']],
745         ['string', ['value' => 'value']],
746       ]);
747     $table_mapping->expects($this->any())
748       ->method('getFieldNames')
749       ->willReturnMap([
750         ['entity_test_mulrev', ['id', 'revision_id', 'uuid', 'type']],
751         ['entity_test_mulrev_revision', ['id', 'revision_id', 'langcode']],
752         ['entity_test_mulrev_property_data', ['id', 'revision_id', 'langcode', 'name', 'description', 'homepage', 'user_id']],
753         ['entity_test_mulrev_property_revision', ['id', 'revision_id', 'langcode', 'name', 'description', 'homepage', 'user_id']],
754         ['entity_test_mulrev__string', ['string']],
755         ['entity_test_mulrev_revision__string', ['string']],
756       ]);
757     $table_mapping->expects($this->any())
758       ->method('requiresDedicatedTableStorage')
759       ->willReturnCallback(function (BaseFieldDefinition $base_field) {
760         return $base_field->getName() === 'string';
761       });
762     $table_mapping->expects($this->any())
763       ->method('getDedicatedDataTableName')
764       ->willReturnCallback(function (BaseFieldDefinition $base_field) {
765         if ($base_field->getName() === 'string') {
766           return 'entity_test_mulrev__string';
767         }
768       });
769
770     $table_mapping->expects($this->any())
771       ->method('getDedicatedRevisionTableName')
772       ->willReturnCallback(function (BaseFieldDefinition $base_field) {
773         if ($base_field->getName() === 'string') {
774           return 'entity_test_mulrev_revision__string';
775         }
776       });
777
778     $table_mapping->expects($this->any())
779       ->method('getFieldTableName')
780       ->willReturnCallback(function($field) {
781         if ($field == 'uuid') {
782           return 'entity_test_mulrev';
783         }
784         return 'entity_test_mulrev_property_data';
785       });
786
787     $this->entityStorage->expects($this->once())
788       ->method('getTableMapping')
789       ->willReturn($table_mapping);
790
791     $this->setupFieldStorageDefinition();
792
793     $data = $this->viewsData->getViewsData();
794
795     // Check the base fields.
796     $this->assertFalse(isset($data['entity_test_mulrev']['id']));
797     $this->assertFalse(isset($data['entity_test_mulrev']['type']));
798     $this->assertFalse(isset($data['entity_test_mulrev']['revision_id']));
799     $this->assertUuidField($data['entity_test_mulrev']['uuid']);
800     $this->assertField($data['entity_test_mulrev']['uuid'], 'uuid');
801
802     // Also ensure that field_data only fields don't appear on the base table.
803     $this->assertFalse(isset($data['entity_test_mulrev']['name']));
804     $this->assertFalse(isset($data['entity_test_mul']['description']));
805     $this->assertFalse(isset($data['entity_test_mul']['description__value']));
806     $this->assertFalse(isset($data['entity_test_mul']['description__format']));
807     $this->assertFalse(isset($data['entity_test_mul']['homepage']));
808     $this->assertFalse(isset($data['entity_test_mulrev']['langcode']));
809     $this->assertFalse(isset($data['entity_test_mulrev']['user_id']));
810
811     // Check the revision fields. The revision ID should only appear in the data
812     // table.
813     $this->assertFalse(isset($data['entity_test_mulrev_revision']['revision_id']));
814
815     // Also ensure that field_data only fields don't appear on the revision table.
816     $this->assertFalse(isset($data['entity_test_mulrev_revision']['id']));
817     $this->assertFalse(isset($data['entity_test_mulrev_revision']['name']));
818     $this->assertFalse(isset($data['entity_test_mulrev_revision']['description']));
819     $this->assertFalse(isset($data['entity_test_mulrev_revision']['description__value']));
820     $this->assertFalse(isset($data['entity_test_mulrev_revision']['description__format']));
821     $this->assertFalse(isset($data['entity_test_mulrev_revision']['homepage']));
822     $this->assertFalse(isset($data['entity_test_mulrev_revision']['user_id']));
823
824     // Check the data fields.
825     $this->assertNumericField($data['entity_test_mulrev_property_data']['id']);
826     $this->assertField($data['entity_test_mulrev_property_data']['id'], 'id');
827     $this->assertNumericField($data['entity_test_mulrev_property_data']['revision_id']);
828     $this->assertField($data['entity_test_mulrev_property_data']['revision_id'], 'revision_id');
829     $this->assertLanguageField($data['entity_test_mulrev_property_data']['langcode']);
830     $this->assertField($data['entity_test_mulrev_property_data']['langcode'], 'langcode');
831     $this->assertStringField($data['entity_test_mulrev_property_data']['name']);
832     $this->assertField($data['entity_test_mulrev_property_data']['name'], 'name');
833
834     $this->assertLongTextField($data['entity_test_mulrev_property_data'], 'description');
835     $this->assertField($data['entity_test_mulrev_property_data']['description__value'], 'description');
836     $this->assertField($data['entity_test_mulrev_property_data']['description__format'], 'description');
837     $this->assertUriField($data['entity_test_mulrev_property_data']['homepage']);
838     $this->assertField($data['entity_test_mulrev_property_data']['homepage'], 'homepage');
839
840     $this->assertEntityReferenceField($data['entity_test_mulrev_property_data']['user_id']);
841     $this->assertField($data['entity_test_mulrev_property_data']['user_id'], 'user_id');
842     $relationship = $data['entity_test_mulrev_property_data']['user_id']['relationship'];
843     $this->assertEquals('users_field_data', $relationship['base']);
844     $this->assertEquals('uid', $relationship['base field']);
845
846     // Check the property data fields.
847     $this->assertNumericField($data['entity_test_mulrev_property_revision']['id']);
848     $this->assertField($data['entity_test_mulrev_property_revision']['id'], 'id');
849
850     $this->assertLanguageField($data['entity_test_mulrev_property_revision']['langcode']);
851     $this->assertField($data['entity_test_mulrev_property_revision']['langcode'], 'langcode');
852     $this->assertEquals('Translation language', $data['entity_test_mulrev_property_revision']['langcode']['title']);
853
854     $this->assertStringField($data['entity_test_mulrev_property_revision']['name']);
855     $this->assertField($data['entity_test_mulrev_property_revision']['name'], 'name');
856
857     $this->assertLongTextField($data['entity_test_mulrev_property_revision'], 'description');
858     $this->assertField($data['entity_test_mulrev_property_revision']['description__value'], 'description');
859     $this->assertField($data['entity_test_mulrev_property_revision']['description__format'], 'description');
860
861     $this->assertUriField($data['entity_test_mulrev_property_revision']['homepage']);
862     $this->assertField($data['entity_test_mulrev_property_revision']['homepage'], 'homepage');
863
864     $this->assertEntityReferenceField($data['entity_test_mulrev_property_revision']['user_id']);
865     $this->assertField($data['entity_test_mulrev_property_revision']['user_id'], 'user_id');
866     $relationship = $data['entity_test_mulrev_property_revision']['user_id']['relationship'];
867     $this->assertEquals('users_field_data', $relationship['base']);
868     $this->assertEquals('uid', $relationship['base field']);
869
870     $this->assertStringField($data['entity_test_mulrev__string']['string']);
871     $this->assertField($data['entity_test_mulrev__string']['string'], 'string');
872     $this->assertEquals([
873       'left_field' => 'id',
874       'field' => 'entity_id',
875       'extra' => [[
876         'field' => 'deleted',
877         'value' => 0,
878         'numeric' => TRUE,
879       ]],
880     ], $data['entity_test_mulrev__string']['table']['join']['entity_test_mulrev_property_data']);
881
882     $this->assertStringField($data['entity_test_mulrev_revision__string']['string']);
883     $this->assertField($data['entity_test_mulrev_revision__string']['string'], 'string');
884     $this->assertEquals([
885       'left_field' => 'revision_id',
886       'field' => 'entity_id',
887       'extra' => [[
888         'field' => 'deleted',
889         'value' => 0,
890         'numeric' => TRUE,
891       ]],
892     ], $data['entity_test_mulrev_revision__string']['table']['join']['entity_test_mulrev_property_revision']);
893   }
894
895   /**
896    * Tests generic stuff per field.
897    *
898    * @param array $data
899    *   The views data to check.
900    * @param string $field_name
901    *   The entity field name.
902    */
903   protected function assertField($data, $field_name) {
904     $this->assertEquals($field_name, $data['entity field']);
905   }
906
907   /**
908    * Tests add link types.
909    */
910   public function testEntityLinks() {
911     $this->baseEntityType->setLinkTemplate('canonical', '/entity_test/{entity_test}');
912     $this->baseEntityType->setLinkTemplate('edit-form', '/entity_test/{entity_test}/edit');
913     $this->baseEntityType->setLinkTemplate('delete-form', '/entity_test/{entity_test}/delete');
914
915     $data = $this->viewsData->getViewsData();
916     $this->assertEquals('entity_link', $data['entity_test']['view_entity_test']['field']['id']);
917     $this->assertEquals('entity_link_edit', $data['entity_test']['edit_entity_test']['field']['id']);
918     $this->assertEquals('entity_link_delete', $data['entity_test']['delete_entity_test']['field']['id']);
919   }
920
921   /**
922    * Tests additional edit links.
923    */
924   public function testEntityLinksJustEditForm() {
925     $this->baseEntityType->setLinkTemplate('edit-form', '/entity_test/{entity_test}/edit');
926
927     $data = $this->viewsData->getViewsData();
928     $this->assertFalse(isset($data['entity_test']['view_entity_test']));
929     $this->assertFalse(isset($data['entity_test']['delete_entity_test']));
930
931     $this->assertEquals('entity_link_edit', $data['entity_test']['edit_entity_test']['field']['id']);
932   }
933
934   /**
935    * @covers ::getViewsData
936    */
937   public function testGetViewsDataWithoutEntityOperations() {
938     // Make sure there is no list builder. The API does not document is
939     // supports resetting entity handlers, so this might break in the future.
940     $this->baseEntityType->setListBuilderClass(NULL);
941     $data = $this->viewsData->getViewsData();
942     $this->assertArrayNotHasKey('operations', $data[$this->baseEntityType->getBaseTable()]);
943   }
944
945   /**
946    * @covers ::getViewsData
947    */
948   public function testGetViewsDataWithEntityOperations() {
949     $this->baseEntityType->setListBuilderClass('\Drupal\Core\Entity\EntityListBuilder');
950     $data = $this->viewsData->getViewsData();
951     $this->assertSame('entity_operations', $data[$this->baseEntityType->getBaseTable()]['operations']['field']['id']);
952   }
953
954   /**
955    * Tests views data for a string field.
956    *
957    * @param $data
958    *   The views data to check.
959    */
960   protected function assertStringField($data) {
961     $this->assertEquals('field', $data['field']['id']);
962     $this->assertEquals('string', $data['filter']['id']);
963     $this->assertEquals('string', $data['argument']['id']);
964     $this->assertEquals('standard', $data['sort']['id']);
965   }
966
967   /**
968    * Tests views data for a URI field.
969    *
970    * @param $data
971    *   The views data to check.
972    */
973   protected function assertUriField($data) {
974     $this->assertEquals('field', $data['field']['id']);
975     $this->assertEquals('string', $data['field']['default_formatter']);
976     $this->assertEquals('string', $data['filter']['id']);
977     $this->assertEquals('string', $data['argument']['id']);
978     $this->assertEquals('standard', $data['sort']['id']);
979   }
980
981   /**
982    * Tests views data for a long text field.
983    *
984    * @param $data
985    *   The views data for the table this field is in.
986    * @param $field_name
987    *   The name of the field being checked.
988    */
989   protected function assertLongTextField($data, $field_name) {
990     $value_field = $data[$field_name . '__value'];
991     $this->assertEquals('field', $value_field['field']['id']);
992     $this->assertEquals($field_name . '__format', $value_field['field']['format']);
993     $this->assertEquals('string', $value_field['filter']['id']);
994     $this->assertEquals('string', $value_field['argument']['id']);
995     $this->assertEquals('standard', $value_field['sort']['id']);
996
997     $this->assertStringField($data[$field_name . '__format']);
998   }
999
1000   /**
1001    * Tests views data for a UUID field.
1002    *
1003    * @param array $data
1004    *   The views data to check.
1005    */
1006   protected function assertUuidField($data) {
1007     // @todo Can we provide additional support for UUIDs in views?
1008     $this->assertEquals('field', $data['field']['id']);
1009     $this->assertFalse($data['field']['click sortable']);
1010     $this->assertEquals('string', $data['filter']['id']);
1011     $this->assertEquals('string', $data['argument']['id']);
1012     $this->assertEquals('standard', $data['sort']['id']);
1013   }
1014
1015   /**
1016    * Tests views data for a numeric field.
1017    *
1018    * @param array $data
1019    *   The views data to check.
1020    */
1021   protected function assertNumericField($data) {
1022     $this->assertEquals('field', $data['field']['id']);
1023     $this->assertEquals('numeric', $data['filter']['id']);
1024     $this->assertEquals('numeric', $data['argument']['id']);
1025     $this->assertEquals('standard', $data['sort']['id']);
1026   }
1027
1028   /**
1029    * Tests views data for a language field.
1030    *
1031    * @param array $data
1032    *   The views data to check.
1033    */
1034   protected function assertLanguageField($data) {
1035     $this->assertEquals('field', $data['field']['id']);
1036     $this->assertEquals('language', $data['filter']['id']);
1037     $this->assertEquals('language', $data['argument']['id']);
1038     $this->assertEquals('standard', $data['sort']['id']);
1039   }
1040
1041   /**
1042    * Tests views data for a entity reference field.
1043    */
1044   protected function assertEntityReferenceField($data) {
1045     $this->assertEquals('field', $data['field']['id']);
1046     $this->assertEquals('numeric', $data['filter']['id']);
1047     $this->assertEquals('numeric', $data['argument']['id']);
1048     $this->assertEquals('standard', $data['sort']['id']);
1049   }
1050
1051   /**
1052    * Tests views data for a bundle field.
1053    */
1054   protected function assertBundleField($data) {
1055     $this->assertEquals('field', $data['field']['id']);
1056     $this->assertEquals('bundle', $data['filter']['id']);
1057     $this->assertEquals('string', $data['argument']['id']);
1058     $this->assertEquals('standard', $data['sort']['id']);
1059   }
1060
1061   /**
1062    * Returns entity info for the user entity.
1063    *
1064    * @return array
1065    */
1066   protected static function userEntityInfo() {
1067     return new ContentEntityType([
1068       'id' => 'user',
1069       'class' => 'Drupal\user\Entity\User',
1070       'label' => 'User',
1071       'base_table' => 'users',
1072       'data_table' => 'users_field_data',
1073       'entity_keys' => [
1074         'id' => 'uid',
1075         'uuid' => 'uuid',
1076       ],
1077     ]);
1078   }
1079
1080 }
1081
1082 class TestEntityViewsData extends EntityViewsData {
1083
1084   public function setEntityType(EntityTypeInterface $entity_type) {
1085     $this->entityType = $entity_type;
1086   }
1087
1088 }
1089
1090 class TestEntityType extends EntityType {
1091
1092   /**
1093    * Sets a specific entity key.
1094    *
1095    * @param string $key
1096    *   The name of the entity key.
1097    * @param string $value
1098    *   The new value of the key.
1099    *
1100    * @return $this
1101    */
1102   public function setKey($key, $value) {
1103     $this->entity_keys[$key] = $value;
1104     return $this;
1105   }
1106
1107 }
1108
1109 namespace Drupal\entity_test\Entity;
1110
1111 if (!function_exists('t')) {
1112   function t($string, array $args = []) {
1113     return strtr($string, $args);
1114   }
1115 }
1116
1117
1118 namespace Drupal\Core\Entity;
1119
1120 if (!function_exists('t')) {
1121   function t($string, array $args = []) {
1122     return strtr($string, $args);
1123   }
1124 }