diff --git a/dynamic_entity_reference.views.inc b/dynamic_entity_reference.views.inc new file mode 100644 index 0000000..7cb6de8 --- /dev/null +++ b/dynamic_entity_reference.views.inc @@ -0,0 +1,100 @@ +getEntityTypeLabels(TRUE); + $options = array_keys($labels['Content']); + $settings = $field_storage->getSettings(); + // Identify all the target entity type ids that can be referenced. + if ($settings['exclude_entity_types']) { + $target_entity_type_ids = array_diff($options, $settings['entity_type_ids'] ?: array()); + } + else { + $target_entity_type_ids = array_intersect($options, $settings['entity_type_ids'] ?: array()); + } + foreach ($data as $table_name => $table_data) { + // Add a relationship to all the target entity types. + foreach ($target_entity_type_ids as $target_entity_type_id) { + $target_entity_type = $entity_manager->getDefinition($target_entity_type_id); + $entity_type_id = $field_storage->getTargetEntityTypeId(); + $entity_type = $entity_manager->getDefinition($entity_type_id); + $target_base_table = $target_entity_type->getDataTable() ?: $target_entity_type->getBaseTable(); + $field_name = $field_storage->getName(); + + // Provide a relationship for the entity type with the dynamic entity + // reference field. + $args = array( + '@label' => $target_entity_type->getLabel(), + '@field_name' => $field_name, + ); + $data[$table_name][$target_entity_type_id . '__' . $field_name]['relationship'] = array( + 'title' => t('@label referenced from @field_name', $args), + 'label' => t('@field_name: @label', $args), + 'group' => $entity_type->getLabel(), + 'help' => t('Appears in: @bundles.', array('@bundles' => implode(', ', $field_storage->getBundles()))), + 'id' => 'standard', + 'base' => $target_base_table, + 'entity type' => $target_entity_type_id, + 'base field' => $target_entity_type->getKey('id'), + 'relationship field' => $field_name . '_target_id', + // Entity reference field only has one target type whereas dynamic + // entity reference field can have multiple target types that is why we + // need extra join condition on target types. + 'extra' => array( + array( + 'left_field' => $field_name . '_target_type', + 'value' => $target_entity_type_id, + ), + ), + ); + + // Provide a reverse relationship for the entity type that is referenced + // by the field. + $pseudo_field_name = 'reverse__' . $entity_type_id . '__' . $field_name; + /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */ + $table_mapping = $entity_manager->getStorage($entity_type_id)->getTableMapping(); + $args['@entity'] = $entity_type->getLabel(); + $args['@label'] = $target_entity_type->getLowercaseLabel(); + $data[$target_base_table][$pseudo_field_name]['relationship'] = array( + 'title' => t('@entity using @field_name', $args), + 'label' => t('@field_name', array('@field_name' => $field_name)), + 'group' => $target_entity_type->getLabel(), + 'help' => t('Relate each @entity with a @field_name set to the @label.', $args), + 'id' => 'entity_reverse', + 'base' => $entity_type->getDataTable() ?: $entity_type->getBaseTable(), + 'entity_type' => $entity_type_id, + 'base field' => $entity_type->getKey('id'), + 'field_name' => $field_name, + 'field table' => $table_mapping->getDedicatedDataTableName($field_storage), + 'field field' => $field_name . '_target_id', + // Entity reference field only has one target type whereas dynamic + // entity reference field can have multiple target types that is why we + // need extra join condition on target types. + 'join_extra' => array( + array( + 'field' => $field_name . '_target_type', + 'value' => $target_entity_type_id, + ), + array( + 'field' => 'deleted', + 'value' => 0, + 'numeric' => TRUE, + ), + ), + ); + } + } + + return $data; +} diff --git a/src/Tests/Views/DynamicEntityReferenceRelationshipTest.php b/src/Tests/Views/DynamicEntityReferenceRelationshipTest.php new file mode 100644 index 0000000..8e3bc78 --- /dev/null +++ b/src/Tests/Views/DynamicEntityReferenceRelationshipTest.php @@ -0,0 +1,318 @@ +installEntitySchema('user'); + $this->installEntitySchema('entity_test'); + $this->installEntitySchema('entity_test_mul'); + + $field_storage = FieldStorageConfig::create(array( + 'entity_type' => 'entity_test', + 'field_name' => 'field_test', + 'type' => 'dynamic_entity_reference', + 'settings' => array( + 'exclude_entity_types' => FALSE, + 'entity_type_ids' => array( + 'entity_test', + 'entity_test_mul', + ), + ), + 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, + )); + $field_storage->save(); + + $field = FieldConfig::create(array( + 'entity_type' => 'entity_test', + 'field_name' => 'field_test', + 'bundle' => 'entity_test', + 'settings' => array(), + )); + $field->save(); + + $field_storage = FieldStorageConfig::create(array( + 'entity_type' => 'entity_test_mul', + 'field_name' => 'field_test_mul', + 'type' => 'dynamic_entity_reference', + 'settings' => array( + 'exclude_entity_types' => FALSE, + 'entity_type_ids' => array( + 'entity_test', + 'entity_test_mul', + ), + ), + 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, + )); + $field_storage->save(); + + $field = FieldConfig::create(array( + 'entity_type' => 'entity_test_mul', + 'field_name' => 'field_test_mul', + 'bundle' => 'entity_test_mul', + 'settings' => array(), + )); + $field->save(); + + ViewTestData::createTestViews(get_class($this), array('dynamic_entity_reference_test_views')); + } + + /** + * Tests using the views relationship. + */ + public function testNoDataTableRelationship() { + // Create some test entities which link each other. + $referenced_entity = EntityTest::create(); + $referenced_entity->save(); + $referenced_entity_mul = EntityTestMul::create(); + $referenced_entity_mul->save(); + + $entity = EntityTest::create(); + $entity->field_test[] = $referenced_entity; + $entity->field_test[] = $referenced_entity_mul; + $entity->save(); + $this->assertEqual($entity->field_test[0]->entity->id(), $referenced_entity->id()); + $this->assertEqual($entity->field_test[1]->entity->id(), $referenced_entity_mul->id()); + $this->entities[] = $entity; + + $entity = EntityTest::create(); + $entity->field_test[] = $referenced_entity; + $entity->field_test[] = $referenced_entity_mul; + $entity->save(); + $this->assertEqual($entity->field_test[0]->entity->id(), $referenced_entity->id()); + $this->assertEqual($entity->field_test[1]->entity->id(), $referenced_entity_mul->id()); + $this->entities[] = $entity; + + Views::viewsData()->clear(); + + // Check just the generated views data. + $views_data_field_test = Views::viewsData()->get('entity_test__field_test'); + + // Check views data for test entity referenced from field_test. + $this->assertEqual($views_data_field_test['entity_test__field_test']['relationship']['id'], 'standard'); + $this->assertEqual($views_data_field_test['entity_test__field_test']['relationship']['base'], 'entity_test'); + $this->assertEqual($views_data_field_test['entity_test__field_test']['relationship']['entity type'], 'entity_test'); + $this->assertEqual($views_data_field_test['entity_test__field_test']['relationship']['base field'], 'id'); + $this->assertEqual($views_data_field_test['entity_test__field_test']['relationship']['relationship field'], 'field_test_target_id'); + $this->assertEqual($views_data_field_test['entity_test__field_test']['relationship']['extra'][0]['left_field'], 'field_test_target_type'); + $this->assertEqual($views_data_field_test['entity_test__field_test']['relationship']['extra'][0]['value'], 'entity_test'); + + // Check views data for test entity - data table referenced from field_test. + $this->assertEqual($views_data_field_test['entity_test_mul__field_test']['relationship']['id'], 'standard'); + $this->assertEqual($views_data_field_test['entity_test_mul__field_test']['relationship']['base'], 'entity_test_mul_property_data'); + $this->assertEqual($views_data_field_test['entity_test_mul__field_test']['relationship']['entity type'], 'entity_test_mul'); + $this->assertEqual($views_data_field_test['entity_test_mul__field_test']['relationship']['base field'], 'id'); + $this->assertEqual($views_data_field_test['entity_test_mul__field_test']['relationship']['relationship field'], 'field_test_target_id'); + $this->assertEqual($views_data_field_test['entity_test_mul__field_test']['relationship']['extra'][0]['left_field'], 'field_test_target_type'); + $this->assertEqual($views_data_field_test['entity_test_mul__field_test']['relationship']['extra'][0]['value'], 'entity_test_mul'); + + // Check the backwards reference for test entity using field_test. + $views_data_entity_test = Views::viewsData()->get('entity_test'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['id'], 'entity_reverse'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['base'], 'entity_test'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['base field'], 'id'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['field table'], 'entity_test__field_test'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['field field'], 'field_test_target_id'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['join_extra'][0]['field'], 'field_test_target_type'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['join_extra'][0]['value'], 'entity_test'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['join_extra'][1]['field'], 'deleted'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['join_extra'][1]['value'], 0); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['join_extra'][1]['numeric'], TRUE); + + // Check the backwards reference for test entity - data table using + // field_test. + $views_data_entity_test = Views::viewsData()->get('entity_test_mul_property_data'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['id'], 'entity_reverse'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['base'], 'entity_test'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['base field'], 'id'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['field table'], 'entity_test__field_test'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['field field'], 'field_test_target_id'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['join_extra'][0]['field'], 'field_test_target_type'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['join_extra'][0]['value'], 'entity_test_mul'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['join_extra'][1]['field'], 'deleted'); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['join_extra'][1]['value'], 0); + $this->assertEqual($views_data_entity_test['reverse__entity_test__field_test']['relationship']['join_extra'][1]['numeric'], TRUE); + +// // Check an actual test view. +// $view = Views::getView('test_dynamic_entity_reference_view'); +// $this->executeView($view); +// +// foreach (array_keys($view->result) as $index) { +// // Just check that the actual ID of the entity is the expected one. +// $this->assertEqual($view->result[$index]->id, $this->entities[$index + 1]->id()); +// // Test the forward relationship. +// // The second and third entity refer to the first one. +// // The value key on the result will be in the format +// // BASE_TABLE_FIELD_NAME. +// $this->assertEqual($view->result[$index]->entity_test_entity_test__field_test_id, $index == 0 ? NULL : 1); +// +// if ($index > 0) { +// // Test that the correct relationship entity is on the row. +// $this->assertEqual($view->result[$index]->_relationship_entities['test_relationship']->id(), 1); +// } +// } +// +// $view->destroy(); +// $this->executeView($view, 'embed_1'); +// +// foreach (array_keys($view->result) as $index) { +// $this->assertEqual($view->result[$index]->id, $this->entities[$index + 1]->id()); +// // The second and third entity refer to the first one. +// $this->assertEqual($view->result[$index]->entity_test_entity_test__field_test_id, $index == 0 ? NULL : 1); +// } + } + + /** + * Tests using the views relationship. + */ + public function testDataTableRelationship() { + // Create some test entities which link each other. + $referenced_entity = EntityTest::create(); + $referenced_entity->save(); + $referenced_entity_mul = EntityTestMul::create(); + $referenced_entity_mul->save(); + + $entity = EntityTestMul::create(); + $entity->field_test_mul[] = $referenced_entity; + $entity->field_test_mul[] = $referenced_entity_mul; + $entity->save(); + $this->assertEqual($entity->field_test_mul[0]->entity->id(), $referenced_entity->id()); + $this->assertEqual($entity->field_test_mul[1]->entity->id(), $referenced_entity_mul->id()); + $this->entities[] = $entity; + + $entity = EntityTestMul::create(); + $entity->field_test_mul[] = $referenced_entity; + $entity->field_test_mul[] = $referenced_entity_mul; + $entity->save(); + $this->assertEqual($entity->field_test_mul[0]->entity->id(), $referenced_entity->id()); + $this->assertEqual($entity->field_test_mul[1]->entity->id(), $referenced_entity_mul->id()); + $this->entities[] = $entity; + + Views::viewsData()->clear(); + + // Check just the generated views data. + $views_data_field_test = Views::viewsData()->get('entity_test_mul__field_test_mul'); + + // Check views data for test entity referenced from field_test_mul. + $this->assertEqual($views_data_field_test['entity_test__field_test_mul']['relationship']['id'], 'standard'); + $this->assertEqual($views_data_field_test['entity_test__field_test_mul']['relationship']['base'], 'entity_test'); + $this->assertEqual($views_data_field_test['entity_test__field_test_mul']['relationship']['entity type'], 'entity_test'); + $this->assertEqual($views_data_field_test['entity_test__field_test_mul']['relationship']['base field'], 'id'); + $this->assertEqual($views_data_field_test['entity_test__field_test_mul']['relationship']['relationship field'], 'field_test_mul_target_id'); + $this->assertEqual($views_data_field_test['entity_test__field_test_mul']['relationship']['extra'][0]['left_field'], 'field_test_mul_target_type'); + $this->assertEqual($views_data_field_test['entity_test__field_test_mul']['relationship']['extra'][0]['value'], 'entity_test'); + + // Check views data for test entity - data table referenced from + // field_test_mul. + $this->assertEqual($views_data_field_test['entity_test_mul__field_test_mul']['relationship']['id'], 'standard'); + $this->assertEqual($views_data_field_test['entity_test_mul__field_test_mul']['relationship']['base'], 'entity_test_mul_property_data'); + $this->assertEqual($views_data_field_test['entity_test_mul__field_test_mul']['relationship']['entity type'], 'entity_test_mul'); + $this->assertEqual($views_data_field_test['entity_test_mul__field_test_mul']['relationship']['base field'], 'id'); + $this->assertEqual($views_data_field_test['entity_test_mul__field_test_mul']['relationship']['relationship field'], 'field_test_mul_target_id'); + $this->assertEqual($views_data_field_test['entity_test_mul__field_test_mul']['relationship']['extra'][0]['left_field'], 'field_test_mul_target_type'); + $this->assertEqual($views_data_field_test['entity_test_mul__field_test_mul']['relationship']['extra'][0]['value'], 'entity_test_mul'); + + // Check the backwards reference for test entity using field_test. + $views_data_entity_test = Views::viewsData()->get('entity_test'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['id'], 'entity_reverse'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['base'], 'entity_test_mul_property_data'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['base field'], 'id'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['field table'], 'entity_test_mul__field_test_mul'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['field field'], 'field_test_mul_target_id'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['join_extra'][0]['field'], 'field_test_mul_target_type'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['join_extra'][0]['value'], 'entity_test'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['join_extra'][1]['field'], 'deleted'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['join_extra'][1]['value'], 0); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['join_extra'][1]['numeric'], TRUE); + + // Check the backwards reference for test entity - data table using + // field_test. + $views_data_entity_test = Views::viewsData()->get('entity_test_mul_property_data'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['id'], 'entity_reverse'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['base'], 'entity_test_mul_property_data'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['base field'], 'id'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['field table'], 'entity_test_mul__field_test_mul'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['field field'], 'field_test_mul_target_id'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['join_extra'][0]['field'], 'field_test_mul_target_type'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['join_extra'][0]['value'], 'entity_test_mul'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['join_extra'][1]['field'], 'deleted'); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['join_extra'][1]['value'], 0); + $this->assertEqual($views_data_entity_test['reverse__entity_test_mul__field_test_mul']['relationship']['join_extra'][1]['numeric'], TRUE); + +// // Check an actual test view. +// $view = Views::getView('test_dynamic_entity_reference_view'); +// $this->executeView($view); +// +// foreach (array_keys($view->result) as $index) { +// // Just check that the actual ID of the entity is the expected one. +// $this->assertEqual($view->result[$index]->id, $this->entities[$index + 1]->id()); +// // Test the forward relationship. +// // The second and third entity refer to the first one. +// // The value key on the result will be in the format +// // BASE_TABLE_FIELD_NAME. +// $this->assertEqual($view->result[$index]->entity_test_entity_test__field_test_id, $index == 0 ? NULL : 1); +// +// if ($index > 0) { +// // Test that the correct relationship entity is on the row. +// $this->assertEqual($view->result[$index]->_relationship_entities['test_relationship']->id(), 1); +// } +// } +// +// $view->destroy(); +// $this->executeView($view, 'embed_1'); +// +// foreach (array_keys($view->result) as $index) { +// $this->assertEqual($view->result[$index]->id, $this->entities[$index + 1]->id()); +// // The second and third entity refer to the first one. +// $this->assertEqual($view->result[$index]->entity_test_entity_test__field_test_id, $index == 0 ? NULL : 1); +// } + } + +} diff --git a/tests/modules/dynamic_entity_reference_test_views/dynamic_entity_reference_test_views.info.yml b/tests/modules/dynamic_entity_reference_test_views/dynamic_entity_reference_test_views.info.yml new file mode 100644 index 0000000..f9eb684 --- /dev/null +++ b/tests/modules/dynamic_entity_reference_test_views/dynamic_entity_reference_test_views.info.yml @@ -0,0 +1,8 @@ +name: 'Dynamic entity reference test views' +type: module +description: 'Provides default views for views dynamic entity reference tests.' +package: Testing +core: 8.x +dependencies: + - dynamic_entity_reference + - views diff --git a/tests/modules/dynamic_entity_reference_test_views/test_views/views.view.test_dynamic_entity_reference_view.yml b/tests/modules/dynamic_entity_reference_test_views/test_views/views.view.test_dynamic_entity_reference_view.yml new file mode 100644 index 0000000..a24f96b --- /dev/null +++ b/tests/modules/dynamic_entity_reference_test_views/test_views/views.view.test_dynamic_entity_reference_view.yml @@ -0,0 +1,76 @@ +langcode: und +status: true +dependencies: + module: + - entity_test + - field +id: test_dynamic_entity_reference_view +label: null +module: views +description: '' +tag: '' +base_table: entity_test +base_field: id +core: '8' +display: + default: + display_options: + defaults: + fields: false + relationships: false + pager: false + sorts: false + fields: + id: + field: id + id: id + relationship: none + table: entity_test + plugin_id: numeric + id_1: + field: id + id: id_1 + relationship: test_relationship + table: entity_test + plugin_id: numeric + pager: + options: + offset: 0 + type: none + sorts: + id: + field: id + id: id + order: ASC + relationship: none + table: entity_test + plugin_id: standard + relationships: + test_relationship: + id: field_test + table: entity_test__field_test + field: entity_test__field_test + relationship: none + plugin_id: standard + display_plugin: default + display_title: Master + id: default + position: 0 + embed_1: + display_options: + defaults: + relationships: false + relationships: + test_relationship: + id: field_test + table: entity_test + field: reverse__entity_test__field_test + relationship: none + group_type: group + admin_label: field_test + required: false + plugin_id: entity_reverse + display_plugin: embed + display_title: Embed + id: embed_1 + position: null