diff -u b/src/Tests/ComplexWidgetWebTest.php b/src/Tests/ComplexWidgetWebTest.php --- b/src/Tests/ComplexWidgetWebTest.php +++ b/src/Tests/ComplexWidgetWebTest.php @@ -434,7 +434,7 @@ */ public function testReferencingExistingEntitiesNoSubmit() { // Allow addition of existing nodes. - $this->setAllowExisting(TRUE); + $this->updateSetting('allow_existing', TRUE); $title = $this->randomMachineName(); $this->drupalCreateNode([ only in patch2: unchanged: --- a/README +++ b/README @@ -32,9 +32,9 @@ Integrating with Inline Entity Form An entity type can add support for this module by declaring the inline entity form controller class in its entity info: -$entity_info['commerce_line_item']['inline_form'] = array( +$entity_info['commerce_line_item']['inline_form'] = [ 'controller' => 'CommerceLineItemInlineEntityFormController', -); +]; The controller needs to extend EntityInlineEntityFormController and at least override entityForm() to provide a functioning entity form. only in patch2: unchanged: --- a/src/Plugin/Field/FieldWidget/InlineEntityFormComplex.php +++ b/src/Plugin/Field/FieldWidget/InlineEntityFormComplex.php @@ -3,7 +3,10 @@ namespace Drupal\inline_entity_form\Plugin\Field\FieldWidget; use Drupal\Component\Utility\NestedArray; +use Drupal\Component\Utility\Tags; +use Drupal\Core\Entity\Element\EntityAutocomplete; use Drupal\Core\Entity\EntityDisplayRepositoryInterface; +use Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface; use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; @@ -36,6 +39,13 @@ class InlineEntityFormComplex extends InlineEntityFormBase implements ContainerF */ protected $moduleHandler; + /** + * Selection Plugin Manager service. + * + * @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface + */ + protected $selectionManager; + /** * Constructs a InlineEntityFormComplex object. * @@ -57,10 +67,13 @@ class InlineEntityFormComplex extends InlineEntityFormBase implements ContainerF * The entity display repository. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * Module handler service. + * @param \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface $selection_manager + * The selection plugin manager. */ - public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, array $third_party_settings, EntityTypeBundleInfoInterface $entity_type_bundle_info, EntityTypeManagerInterface $entity_type_manager, EntityDisplayRepositoryInterface $entity_display_repository, ModuleHandlerInterface $module_handler) { + public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, array $third_party_settings, EntityTypeBundleInfoInterface $entity_type_bundle_info, EntityTypeManagerInterface $entity_type_manager, EntityDisplayRepositoryInterface $entity_display_repository, ModuleHandlerInterface $module_handler, SelectionPluginManagerInterface $selection_manager) { parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings, $entity_type_bundle_info, $entity_type_manager, $entity_display_repository); $this->moduleHandler = $module_handler; + $this->selectionManager = $selection_manager; } /** @@ -76,7 +89,8 @@ class InlineEntityFormComplex extends InlineEntityFormBase implements ContainerF $container->get('entity_type.bundle.info'), $container->get('entity_type.manager'), $container->get('entity_display.repository'), - $container->get('module_handler') + $container->get('module_handler'), + $container->get('plugin.manager.entity_reference_selection') ); } @@ -598,12 +612,68 @@ class InlineEntityFormComplex extends InlineEntityFormBase implements ContainerF // If the inline entity form is still open, then its entity hasn't // been transferred to the IEF form state yet. if (empty($values) && !empty($widget_state['form'])) { - // @todo Do the same for reference forms. if ($widget_state['form'] == 'add') { $element = NestedArray::getValue($form, [$field_name, 'widget', 'form']); $entity = $element['inline_entity_form']['#entity']; $values[] = ['entity' => $entity]; } + elseif ($widget_state['form'] == 'ief_add_existing') { + $element = NestedArray::getValue($form, [$field_name, 'widget', 'form'])['entity_id']; + if (!empty($element['#value'])) { + $options = [ + 'target_type' => $element['#target_type'], + 'handler' => $element['#selection_handler'], + 'handler_settings' => $element['#selection_settings'], + ]; + /** @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface $handler */ + $handler = $this->selectionManager->getInstance($options); + $input_values = $element['#tags'] ? Tags::explode($element['#value']) : [$element['#value']]; + + foreach ($input_values as $input) { + $match = EntityAutocomplete::extractEntityIdFromAutocompleteInput($input); + if ($match === NULL) { + // Try to get a match from the input string when the user didn't use + // the autocomplete but filled in a value manually. + $entities_by_bundle = $handler->getReferenceableEntities($input, '='); + $entities = array_reduce($entities_by_bundle, function ($flattened, $bundle_entities) { + return $flattened + $bundle_entities; + }, []); + $params = [ + '%value' => $input, + '@value' => $input, + ]; + if (empty($entities)) { + $form_state->setError($element, t('There are no entities matching "%value".', $params)); + } + elseif (count($entities) > 5) { + $params['@id'] = key($entities); + // Error if there are more than 5 matching entities. + $form_state->setError($element, t('Many entities are called %value. Specify the one you want by appending the id in parentheses, like "@value (@id)".', $params)); + } + elseif (count($entities) > 1) { + // More helpful error if there are only a few matching entities. + $multiples = []; + foreach ($entities as $id => $name) { + $multiples[] = $name . ' (' . $id . ')'; + } + $params['@id'] = $id; + $form_state->setError($element, t('Multiple entities match this reference; "%multiple". Specify the one you want by appending the id in parentheses, like "@value (@id)".', ['%multiple' => implode('", "', $multiples)] + $params)); + } + else { + // Take the one and only matching entity. + $values += [ + 'target_id' => key($entities), + ]; + } + } + else { + $values += [ + 'target_id' => $match, + ]; + } + } + } + } } // Sort values by weight. uasort($values, '\Drupal\Component\Utility\SortArray::sortByWeightElement');