Commit 841e4a9a authored by webchick's avatar webchick

Issue #1847596 by amateescu, amitaibu, YesCT, Berdir, David_Rothstein, xjm,...

Issue #1847596 by amateescu, amitaibu, YesCT, Berdir, David_Rothstein, xjm, rteijeiro, ParisLiakos, webchick, Wim Leers, yched, jhodgdon, Bojhan: Remove Taxonomy term reference field in favor of Entity reference
parent f7324499
......@@ -33,7 +33,15 @@ function entity_reference_help($route_name, RouteMatchInterface $route_match) {
$output .= '<dt>' . t('Filtering and sorting reference fields') . '</dt>';
$output .= '<dd>' . t('Depending on the chosen entity type, additional filtering and sorting options are available for the list of entities that can be referred to, in the field settings. For example, the list of users can be filtered by role and sorted by name or ID.') . '</dd>';
$output .= '<dt>' . t('Displaying a reference') . '</dt>';
$output .= '<dd>' . t('An entity reference can be displayed as a simple label with or without a link to the entity. Alternatively, the referenced entity can be displayed as a teaser (or any other available view mode) inside the referencing entity.') . '</dd>';
$output .= '<dd>' . t('An entity reference can be displayed as a simple label with or without a link to the entity. Alternatively, the referenced entity can be displayed as a teaser (or any other available view mode) inside the referencing entity. Certain entity types may provide additional display options. You can configure how the entity reference is displayed on the <em>Manage display</em> page for the entity.') . '</dd>';
$output .= '<dt>' . t('Configuring form displays') . '</dt>';
$output .= '<dd>' . t('Reference fields have several widgets available on the <em>Manage form display</em> page:');
$output .= '<ul>';
$output .= '<li>' . t('The <em>Check boxes/radio buttons</em> widget displays the existing entities for the entity type as check boxes or radio buttons based on the <em>Allowed number of values</em> set for the field.') . '</li>';
$output .= '<li>' . t('The <em>Select list</em> widget displays the existing entities in a drop-down list or scrolling list box based on the <em>Allowed number of values</em> setting for the field.') . '</li>';
$output .= '<li>' . t('The <em>Autocomplete</em> widget displays text fields in which users can type entity labels based on the <em>Allowed number of values</em>. The widget can be configured to display all entities that contain the typed characters or restricted to those starting with those characters.') . '</li>';
$output .= '<li>' . t('The <em>Autocomplete (Tags style)</em> widget displays a multi-text field in which users can type in a comma-separated list of entity labels.') . '</li>';
$output .= '</ul>';
$output .= '</dl>';
return $output;
}
......
......@@ -10,6 +10,7 @@
use Drupal\Component\Utility\String;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\entity_reference\Tests\EntityReferenceTestTrait;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\simpletest\WebTestBase;
......@@ -22,6 +23,7 @@
class ManageFieldsTest extends WebTestBase {
use FieldUiTestTrait;
use EntityReferenceTestTrait;
/**
* Modules to install.
......@@ -91,18 +93,12 @@ protected function setUp() {
));
$vocabulary->save();
entity_create('field_storage_config', array(
'field_name' => 'field_' . $vocabulary->id(),
'entity_type' => 'node',
'type' => 'taxonomy_term_reference',
))->save();
entity_create('field_config', array(
'field_name' => 'field_' . $vocabulary->id(),
'entity_type' => 'node',
'label' => 'Tags',
'bundle' => 'article',
))->save();
$handler_settings = array(
'target_bundles' => array(
$vocabulary->id() => $vocabulary->id(),
),
);
$this->createEntityReferenceField('node', 'article', 'field_' . $vocabulary->id(), 'Tags', 'taxonomy_term', 'default', $handler_settings);
entity_get_form_display('node', 'article', 'default')
->setComponent('field_' . $vocabulary->id())
......@@ -606,7 +602,7 @@ function testDuplicateFieldName() {
$edit = array(
'field_name' => 'tags',
'label' => $this->randomMachineName(),
'new_storage_type' => 'taxonomy_term_reference',
'new_storage_type' => 'entity_reference',
);
$url = 'admin/structure/types/manage/' . $this->contentType . '/fields/add-field';
$this->drupalPostForm($url, $edit, t('Save and continue'));
......
......@@ -17,10 +17,11 @@ bundle: forum
mode: default
content:
taxonomy_forums:
type: taxonomy_term_reference_link
type: entity_reference_label
weight: -1
label: above
settings: { }
settings:
link: true
third_party_settings: { }
body:
label: hidden
......
......@@ -17,10 +17,11 @@ bundle: forum
mode: teaser
content:
taxonomy_forums:
type: taxonomy_term_reference_link
type: entity_reference_label
weight: 10
label: above
settings: { }
settings:
link: true
third_party_settings: { }
body:
label: hidden
......
......@@ -18,5 +18,11 @@ default_value: { }
default_value_callback: ''
settings:
handler: default
handler_settings:
target_bundles:
forums: forums
sort:
field: _none
auto_create: true
third_party_settings: { }
field_type: taxonomy_term_reference
field_type: entity_reference
......@@ -7,15 +7,9 @@ dependencies:
id: node.taxonomy_forums
field_name: taxonomy_forums
entity_type: node
type: taxonomy_term_reference
type: entity_reference
settings:
allowed_values:
-
vocabulary: forums
parent: 0
target_type: taxonomy_term
options_list_callback: null
target_bundle: null
module: taxonomy
locked: false
cardinality: 1
......
......@@ -9,7 +9,7 @@ source:
view_mode: default
options:
label: hidden
type: taxonomy_term_reference_link
type: entity_reference_label
weight: 20
process:
......
......@@ -6,8 +6,8 @@ source:
plugin: d6_taxonomy_vocabulary
constants:
entity_type: node
type: taxonomy_term_reference
parent: 0
type: entity_reference
target_entity_type: taxonomy_term
cardinality: -1
process:
entity_type: 'constants/entity_type'
......@@ -16,8 +16,7 @@ process:
plugin: migration
migration: d6_taxonomy_vocabulary
source: vid
'settings/allowed_values/0/vocabulary': @field_name
'settings/allowed_values/0/parent': 'constants/parent'
'settings/target_type': 'constants/target_entity_type'
cardinality: 'constants/cardinality'
destination:
plugin: entity:field_storage_config
......
......@@ -6,7 +6,8 @@ source:
plugin: d6_taxonomy_vocabulary_per_type
constants:
entity_type: node
parent: 0
auto_create: true
selection_handler: 'default:taxonomy_term'
process:
entity_type: 'constants/entity_type'
bundle: type
......@@ -14,6 +15,9 @@ process:
plugin: migration
migration: d6_taxonomy_vocabulary
source: vid
'settings/handler': 'constants/selection_handler'
'settings/handler_settings/target_bundles/0': @field_name
'settings/handler_settings/auto_create': 'constants/auto_create'
destination:
plugin: entity:field_config
migration_dependencies:
......
......@@ -290,6 +290,9 @@ migrate_entity_constant:
id:
type: string
label: 'ID'
target_entity_type:
type: string
label: 'Target entity type'
view_mode:
type: string
label: 'View mode'
......@@ -360,3 +363,9 @@ migrate_entity_constant:
sequence:
type: string
label: 'Settings'
selection_handler:
type: string
label: 'Entity reference selection handler'
auto_create:
type: boolean
label: 'Entity reference selection setting: Auto-create new entities'
......@@ -31,6 +31,7 @@ class MigrateDrupal6Test extends MigrateFullDrupalTestBase {
'block_content',
'datetime',
'dblog',
'entity_reference',
'file',
'forum',
'image',
......
......@@ -7,13 +7,16 @@
namespace Drupal\migrate_drupal\Tests\d6;
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\entity_reference\Tests\EntityReferenceTestTrait;
/**
* Base class for Taxonomy/Node migration tests.
*/
abstract class MigrateTermNodeTestBase extends MigrateDrupal6TestBase {
use EntityReferenceTestTrait;
/**
* {@inheritdoc}
*/
......@@ -31,26 +34,13 @@ protected function setUp() {
$node_type = entity_create('node_type', array('type' => 'story'));
$node_type->save();
foreach (array('vocabulary_1_i_0_', 'vocabulary_2_i_1_', 'vocabulary_3_i_2_') as $name) {
entity_create('field_storage_config', array(
'field_name' => $name,
'entity_type' => 'node',
'type' => 'taxonomy_term_reference',
'cardinality' => -1,
'settings' => array(
'allowed_values' => array(
array(
'vocabulary' => $vocabulary->id(),
'parent' => '0',
),
),
$handler_settings = array(
'target_bundles' => array(
$vocabulary->id() => $vocabulary->id(),
),
))->save();
entity_create('field_config', array(
'field_name' => $name,
'entity_type' => 'node',
'bundle' => 'story',
))->save();
'auto_create' => TRUE,
);
$this->createEntityReferenceField('node', 'story', $name, NULL, 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
}
$id_mappings = array(
'd6_vocabulary_field_instance' => array(
......
......@@ -33,7 +33,10 @@ protected function setUp() {
entity_create('field_storage_config', array(
'entity_type' => 'node',
'field_name' => 'tags',
'type' => 'taxonomy_term_reference',
'type' => 'entity_reference',
'settings' => array(
'target_type' => 'taxonomy_term',
),
))->save();
foreach (array('page', 'article', 'story') as $type) {
......@@ -45,6 +48,15 @@ protected function setUp() {
'entity_type' => 'node',
'bundle' => $type,
'required' => 1,
'settings' => array(
'handler' => 'default',
'handler_settings' => array(
'target_bundles' => array(
'tags' => 'tags',
),
'auto_create' => TRUE,
),
),
))->save();
}
......@@ -75,7 +87,7 @@ protected function setUp() {
public function testVocabularyEntityDisplay() {
// Test that the field exists.
$component = entity_get_display('node', 'page', 'default')->getComponent('tags');
$this->assertIdentical('taxonomy_term_reference_link', $component['type']);
$this->assertIdentical('entity_reference_label', $component['type']);
$this->assertIdentical(20, $component['weight']);
// Test the Id map.
$this->assertIdentical(array('node', 'article', 'default', 'tags'), entity_load('migration', 'd6_vocabulary_entity_display')->getIdMap()->lookupDestinationID(array(4, 'article')));
......
......@@ -33,7 +33,10 @@ protected function setUp() {
entity_create('field_storage_config', array(
'entity_type' => 'node',
'field_name' => 'tags',
'type' => 'taxonomy_term_reference',
'type' => 'entity_reference',
'settings' => array(
'target_type' => 'taxonomy_term',
),
))->save();
foreach (array('page', 'article', 'story') as $type) {
......@@ -45,6 +48,15 @@ protected function setUp() {
'entity_type' => 'node',
'bundle' => $type,
'required' => 1,
'settings' => array(
'handler' => 'default',
'handler_settings' => array(
'target_bundles' => array(
'tags' => 'tags',
),
'auto_create' => TRUE,
),
),
))->save();
}
......
......@@ -57,15 +57,10 @@ protected function setUp() {
entity_create('field_storage_config', array(
'entity_type' => 'node',
'field_name' => 'tags',
'type' => 'taxonomy_term_reference',
'type' => 'entity_reference',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
'settings' => array(
'allowed_values' => array(
array(
'vocabulary' => 'tags',
'parent' => 0,
),
),
'target_type' => 'taxonomy_term',
),
))->save();
......@@ -93,6 +88,11 @@ public function testVocabularyFieldInstance() {
$field = FieldConfig::load($field_id);
$this->assertIdentical($field_id, $field->id(), 'Field instance exists on page bundle.');
$settings = $field->getSettings();
$this->assertIdentical('default:taxonomy_term', $settings['handler'], 'The handler plugin ID is correct.');
$this->assertIdentical(['tags'], $settings['handler_settings']['target_bundles'], 'The target_bundle handler setting is correct.');
$this->assertIdentical(TRUE, $settings['handler_settings']['auto_create'], 'The "auto_create" setting is correct.');
$this->assertIdentical(array('node', 'article', 'tags'), entity_load('migration', 'd6_vocabulary_field_instance')->getIdMap()->lookupDestinationID(array(4, 'article')));
}
......
......@@ -63,8 +63,10 @@ public function testVocabularyField() {
$field_storage_id = 'node.tags';
$field_storage = FieldStorageConfig::load($field_storage_id);
$this->assertIdentical($field_storage_id, $field_storage->id());
$settings = $field_storage->getSettings();
$this->assertIdentical($settings['allowed_values'][0]['vocabulary'], 'tags', "Vocabulary has correct settings.");
$this->assertIdentical('taxonomy_term', $settings['target_type'], "Target type is correct.");
$this->assertIdentical(array('node', 'tags'), entity_load('migration', 'd6_vocabulary_field')->getIdMap()->lookupDestinationID(array(4)), "Test IdMap");
}
......
......@@ -8,7 +8,6 @@
namespace Drupal\node\Plugin\views\wizard;
use Drupal\Core\Form\FormStateInterface;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\views\Plugin\views\wizard\WizardPluginBase;
/**
......@@ -121,7 +120,7 @@ protected function defaultDisplayFiltersUser(array $form, FormStateInterface $fo
}
}
if (!empty($tids)) {
$vid = $form['displays']['show']['tagged_with']['#selection_settings']['target_bundles'][0];
$vid = reset($form['displays']['show']['tagged_with']['#selection_settings']['target_bundles']);
$filters['tid'] = array(
'id' => 'tid',
'table' => 'taxonomy_index',
......@@ -229,18 +228,17 @@ protected function buildFilters(&$form, FormStateInterface $form_state) {
foreach ($bundles as $bundle) {
$display = entity_get_form_display($this->entityTypeId, $bundle, 'default');
$taxonomy_fields = array_filter(\Drupal::entityManager()->getFieldDefinitions($this->entityTypeId, $bundle), function ($field_definition) {
return $field_definition->getType() == 'taxonomy_term_reference';
return $field_definition->getType() == 'entity_reference' && $field_definition->getSetting('target_type') == 'taxonomy_term';
});
foreach ($taxonomy_fields as $field_name => $field) {
$widget = $display->getComponent($field_name);
// We define "tag-like" taxonomy fields as ones that use the
// "Autocomplete term widget (tagging)" widget.
if ($widget['type'] == 'taxonomy_autocomplete') {
$tag_fields[] = $field_name;
// "Autocomplete (Tags style)" widget.
if ($widget['type'] == 'entity_reference_autocomplete_tags') {
$tag_fields[$field_name] = $field;
}
}
}
$tag_fields = array_unique($tag_fields);
if (!empty($tag_fields)) {
// If there is more than one "tag-like" taxonomy field available to
// the view, we can only make our filter apply to one of them (as
......@@ -248,14 +246,14 @@ protected function buildFilters(&$form, FormStateInterface $form_state) {
// that is created by the Standard install profile in core and also
// commonly used by contrib modules; thus, it is most likely to be
// associated with the "main" free-tagging vocabulary on the site.
if (in_array('field_tags', $tag_fields)) {
if (array_key_exists('field_tags', $tag_fields)) {
$tag_field_name = 'field_tags';
}
else {
$tag_field_name = reset($tag_fields);
$tag_field_name = key($tag_fields);
}
// Add the autocomplete textfield to the wizard.
$target_bundles = [FieldStorageConfig::loadByName('node', $tag_field_name)->getSetting('allowed_values')[0]['vocabulary']];
$target_bundles = $tag_fields[$tag_field_name]->getSetting('handler_settings')['target_bundles'];
$form['displays']['show']['tagged_with'] = array(
'#type' => 'entity_autocomplete',
'#title' => $this->t('tagged with'),
......
......@@ -75,11 +75,11 @@ function testNodeAccessBasic() {
if ($is_private) {
$edit['private[0][value]'] = TRUE;
$edit['body[0][value]'] = 'private node';
$edit['field_tags'] = 'private';
$edit['field_tags[target_id]'] = 'private';
}
else {
$edit['body[0][value]'] = 'public node';
$edit['field_tags'] = 'public';
$edit['field_tags[target_id]'] = 'public';
}
$this->drupalPostForm('node/add/article', $edit, t('Save'));
......
......@@ -7,8 +7,10 @@
namespace Drupal\node\Tests;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Language\LanguageInterface;
use Drupal\entity_reference\Tests\EntityReferenceTestTrait;
use Drupal\node\Entity\NodeType;
/**
......@@ -18,6 +20,8 @@
*/
class PagePreviewTest extends NodeTestBase {
use EntityReferenceTestTrait;
/**
* Enable the node and taxonomy modules to test both on the preview.
*
......@@ -63,41 +67,29 @@ protected function setUp() {
// Create a field.
$this->field_name = Unicode::strtolower($this->randomMachineName());
entity_create('field_storage_config', array(
'field_name' => $this->field_name,
'entity_type' => 'node',
'type' => 'taxonomy_term_reference',
'settings' => array(
'allowed_values' => array(
array(
'vocabulary' => $this->vocabulary->id(),
'parent' => '0',
),
),
$handler_settings = array(
'target_bundles' => array(
$this->vocabulary->id() => $this->vocabulary->id(),
),
'cardinality' => '-1',
))->save();
entity_create('field_config', array(
'field_name' => $this->field_name,
'entity_type' => 'node',
'bundle' => 'page',
))->save();
'auto_create' => TRUE,
);
$this->createEntityReferenceField('node', 'page', $this->field_name, 'Tags', 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
entity_get_form_display('node', 'page', 'default')
->setComponent($this->field_name, array(
'type' => 'taxonomy_autocomplete',
'type' => 'entity_reference_autocomplete_tags',
))
->save();
// Show on default display and teaser.
entity_get_display('node', 'page', 'default')
->setComponent($this->field_name, array(
'type' => 'taxonomy_term_reference_link',
'type' => 'entity_reference_label',
))
->save();
entity_get_display('node', 'page', 'teaser')
->setComponent($this->field_name, array(
'type' => 'taxonomy_term_reference_link',
'type' => 'entity_reference_label',
))
->save();
}
......@@ -108,7 +100,7 @@ protected function setUp() {
function testPagePreview() {
$title_key = 'title[0][value]';
$body_key = 'body[0][value]';
$term_key = $this->field_name;
$term_key = $this->field_name . '[target_id]';
// Fill in node creation form and preview node.
$edit = array();
......@@ -145,13 +137,13 @@ function testPagePreview() {
$this->clickLink(t('Back to content editing'));
$this->assertFieldByName($title_key, $edit[$title_key], 'Title field displayed.');
$this->assertFieldByName($body_key, $edit[$body_key], 'Body field displayed.');
$this->assertFieldByName($term_key, $edit[$term_key], 'Term field displayed.');
$this->assertFieldByName($term_key, $edit[$term_key] . ' (' . $this->term->id() . ')', 'Term field displayed.');
// Assert the content is kept when reloading the page.
$this->drupalGet('node/add/page', array('query' => array('uuid' => $uuid)));
$this->assertFieldByName($title_key, $edit[$title_key], 'Title field displayed.');
$this->assertFieldByName($body_key, $edit[$body_key], 'Body field displayed.');
$this->assertFieldByName($term_key, $edit[$term_key], 'Term field displayed.');
$this->assertFieldByName($term_key, $edit[$term_key] . ' (' . $this->term->id() . ')', 'Term field displayed.');
// Save the node.
$this->drupalPostForm('node/add/page', $edit, t('Save'));
......@@ -163,7 +155,7 @@ function testPagePreview() {
// Check the term appears again on the edit form.
$this->drupalGet('node/' . $node->id() . '/edit');
$this->assertFieldByName($term_key, $edit[$term_key], 'Term field displayed.');
$this->assertFieldByName($term_key, $edit[$term_key] . ' (' . $this->term->id() . ')', 'Term field displayed.');
// Check with two new terms on the edit form, additionally to the existing
// one.
......@@ -227,7 +219,7 @@ function testPagePreview() {
function testPagePreviewWithRevisions() {
$title_key = 'title[0][value]';
$body_key = 'body[0][value]';
$term_key = $this->field_name;
$term_key = $this->field_name . '[target_id]';
// Force revision on "Basic page" content.
$node_type = NodeType::load('page');
$node_type->setNewRevision(TRUE);
......
......@@ -10,6 +10,7 @@
use Drupal\Component\Serialization\Json;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\entity_reference\Tests\EntityReferenceTestTrait;
use Drupal\simpletest\WebTestBase;
/**
......@@ -19,6 +20,8 @@
*/
class QuickEditAutocompleteTermTest extends WebTestBase {
use EntityReferenceTestTrait;
/**
* Modules to enable.
*
......@@ -81,44 +84,31 @@ protected function setUp() {
]);
$this->vocabulary->save();
$this->fieldName = 'field_' . $this->vocabulary->id();
entity_create('field_storage_config', [
'field_name' => $this->fieldName,
'entity_type' => 'node',
'type' => 'taxonomy_term_reference',
// Set cardinality to unlimited for tagging.
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
'settings' => [
'allowed_values' => [
[
'vocabulary' => $this->vocabulary->id(),
'parent' => 0,
],
],
],
])->save();
entity_create('field_config', [
'field_name' => $this->fieldName,
'entity_type' => 'node',
'label' => 'Tags',
'bundle' => 'article',
])->save();
$handler_settings = array(
'target_bundles' => array(
$this->vocabulary->id() => $this->vocabulary->id(),
),
'auto_create' => TRUE,
);
$this->createEntityReferenceField('node', 'article', $this->fieldName, 'Tags', 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
entity_get_form_display('node', 'article', 'default')
->setComponent($this->fieldName, [
'type' => 'taxonomy_autocomplete',
'type' => 'entity_reference_autocomplete_tags',
'weight' => -4,
])
->save();
entity_get_display('node', 'article', 'default')
->setComponent($this->fieldName, [
'type' => 'taxonomy_term_reference_link',
'type' => 'entity_reference_label',
'weight' => 10,
])
->save();
entity_get_display('node', 'article', 'teaser')
->setComponent($this->fieldName, [
'type' => 'taxonomy_term_reference_link',
'type' => 'entity_reference_label',
'weight' => 10,
])
->save();
......@@ -156,7 +146,7 @@ public function testAutocompleteQuickEdit() {
'form_id' => 'quickedit_field_form',
'form_token' => $token_match[1],
'form_build_id' => $build_id_match[1],
$this->fieldName => implode(', ', array($this->term1->getName(), 'new term', $this->term2->getName())),
$this->fieldName . '[target_id]' => implode(', ', array($this->term1->getName(), 'new term', $this->term2->getName())),
'op' => t('Save'),
);
......@@ -182,7 +172,12 @@ public function testAutocompleteQuickEdit() {
// taxonomy terms, including the one that has just been newly created and
// which is not yet stored.
$this->setRawContent($ajax_commands[0]['data']);
$this->assertFieldByName($this->fieldName, implode(', ', array($this->term1->getName(), 'new term', $this->term2->label())));
$expected = array(
$this->term1->getName() . ' (' . $this->term1->id() . ')',
'new term',
$this->term2->getName() . ' (' . $this->term2->id() . ')',
);
$this->assertFieldByName($this->fieldName . '[target_id]', implode(', ', $expected));
// Save the entity.
$post = array('nocssjs' => 'true');
......
......@@ -2,7 +2,7 @@
/**
* @file
* Contains \Drupal\rdf\Tests\TaxonomyTermFieldAttributesTest.
* Contains \Drupal\rdf\Tests\EntityReferenceFieldAttributesTest.
*/
namespace Drupal\rdf\Tests;
......@@ -15,7 +15,7 @@