Skip to content
Snippets Groups Projects
Commit d23131ca authored by kaythay's avatar kaythay
Browse files

Issue #2830328 by idimopoulos, pfrenssen, alunyov, DuneBL, Darvanen, kaythay,...

Issue #2830328 by idimopoulos, pfrenssen, alunyov, DuneBL, Darvanen, kaythay, andrey.troeglazov: Fix complex widget submit for existing entities
parent b4a3b1b4
No related branches found
No related tags found
No related merge requests found
......@@ -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.
......@@ -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, $this->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, $this->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, $this->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');
......
......@@ -429,6 +429,42 @@ class ComplexWidgetWebTest extends InlineEntityFormTestBase {
}
}
/**
* Tests if referencing an existing entity works without submitting the form.
*/
public function testReferencingExistingEntitiesNoSubmit() {
// Allow addition of existing nodes.
$this->updateSetting('allow_existing', TRUE);
$title = $this->randomMachineName();
$this->drupalCreateNode([
'type' => 'ief_reference_type',
'title' => $title,
'first_name' => $this->randomMachineName(),
'last_name' => $this->randomMachineName(),
]);
$node = $this->drupalGetNodeByTitle($title);
$this->assertTrue($node, 'Created ief_reference_type node "' . $node->label() . '"');;
$this->drupalGet($this->formContentAddUrl);
$this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @value="Add existing node" and @data-drupal-selector="edit-multi-actions-ief-add-existing"]'));
$this->assertResponse(200, 'Opening inline form for existing entity was successful.');
$parent_title = $this->randomMachineName();
$edit = [
'multi[form][entity_id]' => $node->getTitle() . ' (' . $node->id() . ')',
'title[0][value]' => $parent_title,
];
// Create ief_test_complex node.
$this->assertFieldByName('multi[form][entity_id]', NULL, 'Existing entity reference autocomplete field found.');
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertResponse(200, 'Submission of parent entity was successful.');
$this->assertNoText(t("This value should not be null."), "The error message 'This value should not be null.' was not found in the page.");
$node = $this->drupalGetNodeByTitle($parent_title);
$this->assertTrue($node, 'Created ief_reference_type node.');
}
/**
* Test if invalid values get correct validation messages in reference existing entity form.
*
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment