diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php index 8aec9d1..d592062 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php @@ -146,8 +146,8 @@ public function massageFormValues(array $values, array $form, FormStateInterface * The bundle name. * * @throws \InvalidArgumentException - * Thrown when there's no 'auto_create_bundle' set but the entity reference - * is configured to store new entities in multiple bundles. + * Thrown when the field allows references from multiple target bundles, + * 'auto_create' is enabled and 'auto_create_bundle' is not set. */ protected function getAutocreateBundle() { $bundle = NULL; @@ -160,7 +160,11 @@ protected function getAutocreateBundle() { elseif (!$bundle = $this->getSelectionHandlerSetting('auto_create_bundle')) { // If no bundle has been set as auto create target means that there is // an inconsistency in entity reference field settings. - throw new \InvalidArgumentException("Reference auto-create is enabled on multiple target bundles but 'auto_create_bundle' is not set."); + throw new \InvalidArgumentException(sprintf( + "Create referenced entities if they don't already exist option is enabled but a specific destination bundle is not set. You should re-visit and fix the settings of the '%s' (%s) field.", + $this->fieldDefinition->getLabel(), + $this->fieldDefinition->getName() + )); } } diff --git a/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php b/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php index 7d1f862..0a5ead8 100644 --- a/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php +++ b/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php @@ -238,12 +238,16 @@ public static function calculateDependencies(FieldDefinitionInterface $field_def $dependencies = parent::calculateDependencies($field_definition); $handler_settings = $field_definition->getSetting('handler_settings'); - if (!empty($handler_settings['auto_create_bundle'])) { + // Dependencies for 'target_bundles' covers also the 'auto_create_bundle' + // value, if any, because the latter is included in 'target_bundles' list. + if (!empty($handler_settings['target_bundles'])) { $target_type = \Drupal::entityManager()->getDefinition($field_definition->getFieldStorageDefinition()->getSetting('target_type')); if ($bundle_entity_type = $target_type->getBundleEntityType()) { $storage = \Drupal::entityManager()->getStorage($bundle_entity_type); - if ($bundle = $storage->load($handler_settings['auto_create_bundle'])) { - $dependencies[$bundle->getConfigDependencyKey()][] = $bundle->getConfigDependencyName(); + foreach ($handler_settings['target_bundles'] as $id) { + if ($bundle = $storage->load($id)) { + $dependencies[$bundle->getConfigDependencyKey()][] = $bundle->getConfigDependencyName(); + } } } } @@ -258,17 +262,35 @@ public static function onDependencyRemoval(FieldDefinitionInterface $field_defin $changed = parent::onDependencyRemoval($field_definition, $dependencies); $handler_settings = $field_definition->getSetting('handler_settings'); - if (!empty($handler_settings['auto_create_bundle'])) { + // Dependencies for 'target_bundles' covers also the 'auto_create_bundle' + // value, if any, because the latter is included in 'target_bundles' list. + if (!empty($handler_settings['target_bundles'])) { $target_type = \Drupal::entityManager()->getDefinition($field_definition->getFieldStorageDefinition()->getSetting('target_type')); if ($bundle_entity_type = $target_type->getBundleEntityType()) { $storage = \Drupal::entityManager()->getStorage($bundle_entity_type); - $bundle = $storage->load($handler_settings['auto_create_bundle']); - if ($bundle && isset($dependencies[$bundle->getConfigDependencyKey()][$bundle->getConfigDependencyName()])) { - unset($handler_settings['auto_create_bundle']); - $handler_settings['auto_create'] = FALSE; - $field_definition->setSetting('handler_settings', $handler_settings); - $changed = TRUE; + $auto_create_bundle = !empty($handler_settings['auto_create_bundle']) ? $handler_settings['auto_create_bundle'] : FALSE; + foreach ($handler_settings['target_bundles'] as $id) { + $bundle = $storage->load($id); + if ($bundle && !empty($dependencies[$bundle->getConfigDependencyKey()][$bundle->getConfigDependencyName()])) { + // Remove this bundle from target bundles. + unset($handler_settings['target_bundles'][$id]); + // If this bundle is set also as 'auto_create_bundle' make it NULL. + if ($auto_create_bundle && $auto_create_bundle == $id) { + $handler_settings['auto_create_bundle'] = NULL; + } + $changed = TRUE; + } } + + // If only one target bundle has left, set that as 'auto_create_bundle'. + if (!empty($handler_settings['auto_create']) && count($handler_settings['target_bundles']) === 1) { + $handler_settings['auto_create_bundle'] = key($handler_settings['target_bundles']); + } + + // If there's no 'auto_create_bundle' set, there's no auto creation. + $handler_settings['auto_create'] = !empty($handler_settings['auto_create_bundle']); + + $field_definition->setSetting('handler_settings', $handler_settings); } } diff --git a/core/modules/entity_reference/src/Tests/EntityReferenceAutoCreateTest.php b/core/modules/entity_reference/src/Tests/EntityReferenceAutoCreateTest.php index 4f3636e..e9489e5 100644 --- a/core/modules/entity_reference/src/Tests/EntityReferenceAutoCreateTest.php +++ b/core/modules/entity_reference/src/Tests/EntityReferenceAutoCreateTest.php @@ -229,7 +229,11 @@ public function testMultipleTargetBundles() { catch (\InvalidArgumentException $e) { $this->assertIdentical( $e->getMessage(), - "Reference auto-create is enabled on multiple target bundles but 'auto_create_bundle' is not set." + sprintf( + "Create referenced entities if they don't already exist option is enabled but a specific destination bundle is not set. You should re-visit and fix the settings of the '%s' (%s) field.", + $field_config->getLabel(), + $field_config->getName() + ) ); } } diff --git a/core/modules/entity_reference/src/Tests/EntityReferenceSettingsTest.php b/core/modules/entity_reference/src/Tests/EntityReferenceSettingsTest.php new file mode 100644 index 0000000..3a59b14 --- /dev/null +++ b/core/modules/entity_reference/src/Tests/EntityReferenceSettingsTest.php @@ -0,0 +1,127 @@ +installEntitySchema('node'); + $this->installEntitySchema('taxonomy_term'); + + $this->nodeType = Unicode::strtolower($this->randomMachineName()); + NodeType::create([ + 'type' => $this->nodeType, + 'name' => $this->randomString(), + ])->save(); + + // Create 3 taxonomy vocabularies. + $this->vids = ['vid1', 'vid2', 'vid3']; + $this->vids = array_combine($this->vids, $this->vids); + foreach ($this->vids as $vid) { + Vocabulary::create([ + 'vid' => $vid, + 'name' => $this->randomString(), + ])->save(); + } + } + + /** + * Tests dependencies. + */ + public function testDependency() { + /** @var \Drupal\Core\Config\ConfigFactoryInterface $factory */ + $factory = $this->container->get('config.factory'); + + $name = Unicode::strtolower($this->randomMachineName()); + $label = $this->randomString(); + $handler_settings = [ + 'target_bundles' => $this->vids, + 'auto_create' => TRUE, + 'auto_create_bundle' => 'vid1', + ]; + + // Create an entity reference field with auto creation, targeting 3 taxonomy + // vocabularies. Set the first vocabulary as 'auto_create_bundle'. + $this->createEntityReferenceField('node', $this->nodeType, $name, $label, 'taxonomy_term', 'default', $handler_settings); + $id = "field.field.node.{$this->nodeType}.$name"; + + // Test field creation. + $config = $factory->get($id); + $this->assertIdentical($config->get('settings.handler_settings.target_bundles'), $this->vids); + $this->assertTrue($config->get('settings.handler_settings.auto_create')); + $this->assertIdentical($config->get('settings.handler_settings.auto_create_bundle'), 'vid1'); + + // Delete the first vocabulary. + Vocabulary::load('vid1')->delete(); + + // Reload the field config and test again. + $config = $factory->getEditable($id); + + $this->assertIdentical($config->get('settings.handler_settings.target_bundles'), ['vid2' => 'vid2', 'vid3' => 'vid3']); + // 'auto_create' is FALSE. + $this->assertFalse($config->get('settings.handler_settings.auto_create')); + // 'auto_create_bundle' is NULL. + $this->assertNull($config->get('settings.handler_settings.auto_create_bundle')); + + // Set the 'auto_create_bundle' to 'vid2', 'auto_create' to TRUE. + $config + ->set('settings.handler_settings.auto_create', TRUE) + ->set('settings.handler_settings.auto_create_bundle', 'vid2') + ->save(); + + // Delete the second vocabulary. + Vocabulary::load('vid2')->delete(); + + // Reload the field config and test again. + $config = $factory->get($id); + + $this->assertIdentical($config->get('settings.handler_settings.target_bundles'), ['vid3' => 'vid3']); + // 'auto_create' is TRUE. + $this->assertTrue($config->get('settings.handler_settings.auto_create')); + // 'auto_create_bundle' was automatically moved to 'vid3'. + $this->assertIdentical($config->get('settings.handler_settings.auto_create_bundle'), 'vid3'); + } + +} diff --git a/core/modules/taxonomy/src/Plugin/EntityReferenceSelection/TermSelection.php b/core/modules/taxonomy/src/Plugin/EntityReferenceSelection/TermSelection.php index a072e29..7c62d8c 100644 --- a/core/modules/taxonomy/src/Plugin/EntityReferenceSelection/TermSelection.php +++ b/core/modules/taxonomy/src/Plugin/EntityReferenceSelection/TermSelection.php @@ -39,12 +39,6 @@ public function entityQueryAlter(SelectInterface $query) { public function buildConfigurationForm(array $form, FormStateInterface $form_state) { $form = parent::buildConfigurationForm($form, $form_state); $form['target_bundles']['#title'] = $this->t('Vocabularies'); - // @todo: Currently allow auto-create only on taxonomy terms. - $form['auto_create'] = array( - '#type' => 'checkbox', - '#title' => $this->t("Create referenced entities if they don't already exist"), - '#default_value' => isset($this->configuration['handler_settings']['auto_create']) ? $this->configuration['handler_settings']['auto_create'] : FALSE, - ); // Sorting is not possible for taxonomy terms because we use // \Drupal\taxonomy\TermStorageInterface::loadTree() to retrieve matches. @@ -61,7 +55,7 @@ public function getReferenceableEntities($match = NULL, $match_operator = 'CONTA return parent::getReferenceableEntities($match , $match_operator, $limit); } - $options = []; + $options = array(); $bundles = $this->entityManager->getBundleInfo('taxonomy_term'); $handler_settings = $this->configuration['handler_settings']; diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module index 01b8981..f7c8c0e 100644 --- a/core/modules/taxonomy/taxonomy.module +++ b/core/modules/taxonomy/taxonomy.module @@ -52,7 +52,7 @@ function taxonomy_help($route_name, RouteMatchInterface $route_match) { $output .= '
' . t('Classifying entity content') . '
'; $output .= '
' . t('A user with the Administer fields permission for a certain entity type may add Taxonomy term reference fields to the entity type, which will allow entities to be classified using taxonomy terms. See the Entity Reference help for more information about reference fields. See the Field module help and the Field UI help pages for general information on fields and how to create and manage them.' , array('!field_ui' => $field_ui_url, '!field' => \Drupal::url('help.page', array('name' => 'field')), '!entity_reference' => \Drupal::url('help.page', array('name' => 'entity_reference')))) . '
'; $output .= '
' . t('Adding new terms during content creation') . '
'; - $output .= '
' . t('Allowing users to add new terms gradually builds a vocabulary as content is added and edited. Users can add new terms if the Autocomplete term widget (tagging) is chosen for a Taxonomy Term reference field, or if either of the two Autocomplete widgets is chosen for an Entity reference field. In this case you need to enable the Create referenced entity option.') . '
'; + $output .= '
' . t('Allowing users to add new terms gradually builds a vocabulary as content is added and edited. Users can add new terms if either of the two Autocomplete widgets is chosen for the Taxonomy term reference field in the Manage form display page for the field. You will also need to enable the Create referenced entities if they don\'t already exist option, and restrict the field to one vocabulary.') . '
'; $output .= '
' . t('Configuring displays and form displays') . '
'; $output .= '
' . t('See the Entity Reference help page for the field widgets and formatters that can be configured for any reference field on the Manage display and Manage form display pages. Taxonomy additionally provides an RSS category formatter that displays nothing when the entity item is displayed as HTML, but displays an RSS category instead of a list when the entity item is displayed in an RSS feed.', array('!entity_reference' => \Drupal::url('help.page', array('name' => 'entity_reference')))) . ''; $output .= '';