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 .= '