1<?php 2 3namespace Drupal\Tests\field\Kernel\EntityReference\Views; 4 5use Drupal\entity_test\Entity\EntityTestMulChanged; 6use Drupal\field\Entity\FieldStorageConfig; 7use Drupal\entity_test\Entity\EntityTest; 8use Drupal\entity_test\Entity\EntityTestMul; 9use Drupal\Tests\field\Traits\EntityReferenceTestTrait; 10use Drupal\Tests\views\Kernel\ViewsKernelTestBase; 11use Drupal\views\Tests\ViewTestData; 12use Drupal\views\Views; 13 14/** 15 * Tests entity reference relationship data. 16 * 17 * @group entity_reference 18 * 19 * @see core_field_views_data() 20 */ 21class EntityReferenceRelationshipTest extends ViewsKernelTestBase { 22 23 use EntityReferenceTestTrait; 24 25 /** 26 * Views used by this test. 27 * 28 * @var array 29 */ 30 public static $testViews = [ 31 'test_entity_reference_entity_test_view', 32 'test_entity_reference_entity_test_view_long', 33 'test_entity_reference_reverse_entity_test_view', 34 'test_entity_reference_entity_test_mul_view', 35 'test_entity_reference_reverse_entity_test_mul_view', 36 'test_entity_reference_group_by_empty_relationships', 37 ]; 38 39 /** 40 * Modules to install. 41 * 42 * @var array 43 */ 44 protected static $modules = [ 45 'user', 46 'field', 47 'entity_test', 48 'views', 49 'entity_reference_test_views', 50 ]; 51 52 /** 53 * The entity_test entities used by the test. 54 * 55 * @var array 56 */ 57 protected $entities = []; 58 59 /** 60 * {@inheritdoc} 61 */ 62 protected function setUp($import_test_views = TRUE): void { 63 parent::setUp(); 64 65 $this->installEntitySchema('user'); 66 $this->installEntitySchema('user_role'); 67 $this->installEntitySchema('entity_test'); 68 $this->installEntitySchema('entity_test_mul'); 69 $this->installEntitySchema('entity_test_mul_changed'); 70 71 // Create reference from entity_test to entity_test_mul. 72 $this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_data', 'field_test_data', 'entity_test_mul'); 73 74 // Create reference from entity_test_mul to entity_test. 75 $this->createEntityReferenceField('entity_test_mul', 'entity_test_mul', 'field_data_test', 'field_data_test', 'entity_test'); 76 77 // Create another field for testing with a long name. So its storage name 78 // will become hashed. Use entity_test_mul_changed, so the resulting field 79 // tables created will be greater than 48 chars long. 80 // @see \Drupal\Core\Entity\Sql\DefaultTableMapping::generateFieldTableName() 81 $this->createEntityReferenceField('entity_test_mul_changed', 'entity_test_mul_changed', 'field_test_data_with_a_long_name', 'field_test_data_with_a_long_name', 'entity_test'); 82 83 // Create reference from entity_test_mul to entity_test cardinality: infinite. 84 $this->createEntityReferenceField('entity_test_mul', 'entity_test_mul', 'field_data_test_unlimited', 'field_data_test_unlimited', 'entity_test', 'default', [], FieldStorageConfig::CARDINALITY_UNLIMITED); 85 86 ViewTestData::createTestViews(static::class, ['entity_reference_test_views']); 87 } 88 89 /** 90 * Tests using the views relationship. 91 */ 92 public function testNoDataTableRelationship() { 93 94 // Create some test entities which link each other. 95 $referenced_entity = EntityTestMul::create(); 96 $referenced_entity->save(); 97 98 $entity = EntityTest::create(); 99 $entity->field_test_data->target_id = $referenced_entity->id(); 100 $entity->save(); 101 $this->assertEquals($referenced_entity->id(), $entity->field_test_data[0]->entity->id()); 102 $this->entities[] = $entity; 103 104 $entity = EntityTest::create(); 105 $entity->field_test_data->target_id = $referenced_entity->id(); 106 $entity->save(); 107 $this->assertEquals($referenced_entity->id(), $entity->field_test_data[0]->entity->id()); 108 $this->entities[] = $entity; 109 110 Views::viewsData()->clear(); 111 112 // Check the generated views data. 113 $views_data = Views::viewsData()->get('entity_test__field_test_data'); 114 $this->assertEquals('standard', $views_data['field_test_data']['relationship']['id']); 115 $this->assertEquals('entity_test_mul_property_data', $views_data['field_test_data']['relationship']['base']); 116 $this->assertEquals('id', $views_data['field_test_data']['relationship']['base field']); 117 $this->assertEquals('field_test_data_target_id', $views_data['field_test_data']['relationship']['relationship field']); 118 $this->assertEquals('entity_test_mul', $views_data['field_test_data']['relationship']['entity type']); 119 120 // Check the backwards reference. 121 $views_data = Views::viewsData()->get('entity_test_mul_property_data'); 122 $this->assertEquals('entity_reverse', $views_data['reverse__entity_test__field_test_data']['relationship']['id']); 123 $this->assertEquals('entity_test', $views_data['reverse__entity_test__field_test_data']['relationship']['base']); 124 $this->assertEquals('id', $views_data['reverse__entity_test__field_test_data']['relationship']['base field']); 125 $this->assertEquals('entity_test__field_test_data', $views_data['reverse__entity_test__field_test_data']['relationship']['field table']); 126 $this->assertEquals('field_test_data_target_id', $views_data['reverse__entity_test__field_test_data']['relationship']['field field']); 127 $this->assertEquals('field_test_data', $views_data['reverse__entity_test__field_test_data']['relationship']['field_name']); 128 $this->assertEquals('entity_test', $views_data['reverse__entity_test__field_test_data']['relationship']['entity_type']); 129 $this->assertEquals(['field' => 'deleted', 'value' => 0, 'numeric' => TRUE], $views_data['reverse__entity_test__field_test_data']['relationship']['join_extra'][0]); 130 131 // Check an actual test view. 132 $view = Views::getView('test_entity_reference_entity_test_view'); 133 $this->executeView($view); 134 /** @var \Drupal\views\ResultRow $row */ 135 foreach ($view->result as $index => $row) { 136 // Check that the actual ID of the entity is the expected one. 137 $this->assertEquals($this->entities[$index]->id(), $row->id); 138 139 // Also check that we have the correct result entity. 140 $this->assertEquals($this->entities[$index]->id(), $row->_entity->id()); 141 142 // Test the forward relationship. 143 $this->assertEquals(1, $row->entity_test_mul_property_data_entity_test__field_test_data_i); 144 145 // Test that the correct relationship entity is on the row. 146 $this->assertEquals(1, $row->_relationship_entities['field_test_data']->id()); 147 $this->assertEquals('entity_test_mul', $row->_relationship_entities['field_test_data']->bundle()); 148 } 149 150 // Check the backwards reference view. 151 $view = Views::getView('test_entity_reference_reverse_entity_test_view'); 152 $this->executeView($view); 153 /** @var \Drupal\views\ResultRow $row */ 154 foreach ($view->result as $index => $row) { 155 $this->assertEquals(1, $row->id); 156 $this->assertEquals(1, $row->_entity->id()); 157 158 // Test the backwards relationship. 159 $this->assertEquals($this->entities[$index]->id(), $row->field_test_data_entity_test_mul_property_data_id); 160 161 // Test that the correct relationship entity is on the row. 162 $this->assertEquals($this->entities[$index]->id(), $row->_relationship_entities['reverse__entity_test__field_test_data']->id()); 163 $this->assertEquals('entity_test', $row->_relationship_entities['reverse__entity_test__field_test_data']->bundle()); 164 } 165 } 166 167 /** 168 * Tests views data generated for relationship. 169 * 170 * @see entity_reference_field_views_data() 171 */ 172 public function testDataTableRelationship() { 173 174 // Create some test entities which link each other. 175 $referenced_entity = EntityTest::create(); 176 $referenced_entity->save(); 177 178 $entity = EntityTestMul::create(); 179 $entity->field_data_test->target_id = $referenced_entity->id(); 180 $entity->save(); 181 $this->assertEquals($referenced_entity->id(), $entity->field_data_test[0]->entity->id()); 182 $this->entities[] = $entity; 183 184 $entity = EntityTestMul::create(); 185 $entity->field_data_test->target_id = $referenced_entity->id(); 186 $entity->save(); 187 $this->assertEquals($referenced_entity->id(), $entity->field_data_test[0]->entity->id()); 188 $this->entities[] = $entity; 189 190 Views::viewsData()->clear(); 191 192 // Check the generated views data. 193 $views_data = Views::viewsData()->get('entity_test_mul__field_data_test'); 194 $this->assertEquals('standard', $views_data['field_data_test']['relationship']['id']); 195 $this->assertEquals('entity_test', $views_data['field_data_test']['relationship']['base']); 196 $this->assertEquals('id', $views_data['field_data_test']['relationship']['base field']); 197 $this->assertEquals('field_data_test_target_id', $views_data['field_data_test']['relationship']['relationship field']); 198 $this->assertEquals('entity_test', $views_data['field_data_test']['relationship']['entity type']); 199 200 // Check the backwards reference. 201 $views_data = Views::viewsData()->get('entity_test'); 202 $this->assertEquals('entity_reverse', $views_data['reverse__entity_test_mul__field_data_test']['relationship']['id']); 203 $this->assertEquals('entity_test_mul_property_data', $views_data['reverse__entity_test_mul__field_data_test']['relationship']['base']); 204 $this->assertEquals('id', $views_data['reverse__entity_test_mul__field_data_test']['relationship']['base field']); 205 $this->assertEquals('entity_test_mul__field_data_test', $views_data['reverse__entity_test_mul__field_data_test']['relationship']['field table']); 206 $this->assertEquals('field_data_test_target_id', $views_data['reverse__entity_test_mul__field_data_test']['relationship']['field field']); 207 $this->assertEquals('field_data_test', $views_data['reverse__entity_test_mul__field_data_test']['relationship']['field_name']); 208 $this->assertEquals('entity_test_mul', $views_data['reverse__entity_test_mul__field_data_test']['relationship']['entity_type']); 209 $this->assertEquals(['field' => 'deleted', 'value' => 0, 'numeric' => TRUE], $views_data['reverse__entity_test_mul__field_data_test']['relationship']['join_extra'][0]); 210 211 // Check an actual test view. 212 $view = Views::getView('test_entity_reference_entity_test_mul_view'); 213 $this->executeView($view); 214 /** @var \Drupal\views\ResultRow $row */ 215 foreach ($view->result as $index => $row) { 216 // Check that the actual ID of the entity is the expected one. 217 $this->assertEquals($this->entities[$index]->id(), $row->id); 218 219 // Also check that we have the correct result entity. 220 $this->assertEquals($this->entities[$index]->id(), $row->_entity->id()); 221 222 // Test the forward relationship. 223 $this->assertEquals(1, $row->entity_test_entity_test_mul__field_data_test_id); 224 225 // Test that the correct relationship entity is on the row. 226 $this->assertEquals(1, $row->_relationship_entities['field_data_test']->id()); 227 $this->assertEquals('entity_test', $row->_relationship_entities['field_data_test']->bundle()); 228 229 } 230 231 // Check the backwards reference view. 232 $view = Views::getView('test_entity_reference_reverse_entity_test_mul_view'); 233 $this->executeView($view); 234 /** @var \Drupal\views\ResultRow $row */ 235 foreach ($view->result as $index => $row) { 236 $this->assertEquals(1, $row->id); 237 $this->assertEquals(1, $row->_entity->id()); 238 239 // Test the backwards relationship. 240 $this->assertEquals($this->entities[$index]->id(), $row->field_data_test_entity_test_id); 241 242 // Test that the correct relationship entity is on the row. 243 $this->assertEquals($this->entities[$index]->id(), $row->_relationship_entities['reverse__entity_test_mul__field_data_test']->id()); 244 $this->assertEquals('entity_test_mul', $row->_relationship_entities['reverse__entity_test_mul__field_data_test']->bundle()); 245 } 246 } 247 248 /** 249 * Tests views data generated for relationship. 250 * 251 * @see entity_reference_field_views_data() 252 */ 253 public function testDataTableRelationshipWithLongFieldName() { 254 // Create some test entities which link each other. 255 $referenced_entity = EntityTest::create(); 256 $referenced_entity->save(); 257 258 $entity = EntityTestMulChanged::create(); 259 $entity->field_test_data_with_a_long_name->target_id = $referenced_entity->id(); 260 $entity->save(); 261 $this->entities[] = $entity; 262 263 $entity = EntityTestMulChanged::create(); 264 $entity->field_test_data_with_a_long_name->target_id = $referenced_entity->id(); 265 $entity->save(); 266 $this->entities[] = $entity; 267 268 Views::viewsData()->clear(); 269 270 // Check an actual test view. 271 $view = Views::getView('test_entity_reference_entity_test_view_long'); 272 $this->executeView($view); 273 /** @var \Drupal\views\ResultRow $row */ 274 foreach ($view->result as $index => $row) { 275 // Check that the actual ID of the entity is the expected one. 276 $this->assertEquals($this->entities[$index]->id(), $row->id); 277 278 // Also check that we have the correct result entity. 279 $this->assertEquals($this->entities[$index]->id(), $row->_entity->id()); 280 281 // Test the forward relationship. 282 // $this->assertEquals(1, $row->entity_test_entity_test_mul__field_data_test_id); 283 284 // Test that the correct relationship entity is on the row. 285 $this->assertEquals(1, $row->_relationship_entities['field_test_data_with_a_long_name']->id()); 286 $this->assertEquals('entity_test', $row->_relationship_entities['field_test_data_with_a_long_name']->bundle()); 287 288 } 289 } 290 291 /** 292 * Tests group by with optional and empty relationship. 293 */ 294 public function testGroupByWithEmptyRelationships() { 295 $entities = []; 296 // Create 4 entities with name1 and 3 entities with name2. 297 for ($i = 1; $i <= 4; $i++) { 298 $entity = [ 299 'name' => 'name' . $i, 300 ]; 301 $entity = EntityTest::create($entity); 302 $entities[] = $entity; 303 $entity->save(); 304 } 305 306 $entity = EntityTestMul::create([ 307 'name' => 'name1', 308 ]); 309 $entity->field_data_test_unlimited = [ 310 ['target_id' => $entities[0]->id()], 311 ['target_id' => $entities[1]->id()], 312 ['target_id' => $entities[2]->id()], 313 ]; 314 $entity->save(); 315 316 $entity = EntityTestMul::create([ 317 'name' => 'name2', 318 ]); 319 $entity->field_data_test_unlimited = [ 320 ['target_id' => $entities[0]->id()], 321 ['target_id' => $entities[1]->id()], 322 ]; 323 $entity->save(); 324 325 $entity = EntityTestMul::create([ 326 'name' => 'name3', 327 ]); 328 $entity->field_data_test_unlimited->target_id = $entities[0]->id(); 329 $entity->save(); 330 331 $view = Views::getView('test_entity_reference_group_by_empty_relationships'); 332 $this->executeView($view); 333 $this->assertCount(4, $view->result); 334 // First three results should contain a reference from EntityTestMul. 335 $this->assertNotEmpty($view->getStyle()->getField(0, 'name_2')); 336 $this->assertNotEmpty($view->getStyle()->getField(1, 'name_2')); 337 $this->assertNotEmpty($view->getStyle()->getField(2, 'name_2')); 338 // Fourth result has no reference from EntityTestMul hence the output for 339 // should be empty. 340 $this->assertEquals('', $view->getStyle()->getField(3, 'name_2')); 341 342 $fields = $view->field; 343 // Check getValue for reference with a value. The first 3 rows reference 344 // EntityTestMul, so have value 'name1'. 345 $this->assertEquals('name1', $fields['name_2']->getValue($view->result[0])); 346 $this->assertEquals('name1', $fields['name_2']->getValue($view->result[1])); 347 $this->assertEquals('name1', $fields['name_2']->getValue($view->result[2])); 348 // Ensure getValue works on empty references. 349 $this->assertNull($fields['name_2']->getValue($view->result[3])); 350 } 351 352 /** 353 * Test that config entities don't get relationships added. 354 */ 355 public function testEntityReferenceConfigEntity() { 356 // Create reference from entity_test to a config entity. 357 $this->createEntityReferenceField('entity_test', 'entity_test', 'field_test_config_entity', 'field_test_config_entity', 'user_role'); 358 Views::viewsData()->clear(); 359 $views_data = Views::viewsData()->getAll(); 360 // Test that a relationship got added for content entities but not config 361 // entities. 362 $this->assertTrue(isset($views_data['entity_test__field_test_data']['field_test_data']['relationship'])); 363 $this->assertFalse(isset($views_data['entity_test__field_test_config_entity']['field_test_config_entity']['relationship'])); 364 } 365 366} 367