diff --git a/config/schema/inline_entity_form.schema.yml b/config/schema/inline_entity_form.schema.yml index a522ec8..90bf5d3 100644 --- a/config/schema/inline_entity_form.schema.yml +++ b/config/schema/inline_entity_form.schema.yml @@ -48,6 +48,9 @@ field.widget.settings.inline_entity_form_complex: allow_existing: type: boolean label: "Allow existing" + empty_mode: + type: string + label: "Empty mode" match_operator: type: string label: "Match operator" diff --git a/inline_entity_form.module b/inline_entity_form.module index 89e27de..6dae042 100644 --- a/inline_entity_form.module +++ b/inline_entity_form.module @@ -168,6 +168,9 @@ function inline_entity_form_reference_form_validate(&$reference_form, FormStateI function inline_entity_form_reference_form_submit($reference_form, FormStateInterface $form_state) { $ief_id = $reference_form['#ief_id']; $form_values = NestedArray::getValue($form_state->getValues(), $reference_form['#parents']); + if (empty($form_values['entity_id'])) { + return; + } $storage = \Drupal::entityTypeManager()->getStorage($reference_form['#entity_type']); $entity = $storage->load($form_values['entity_id']); $entities = &$form_state->get(['inline_entity_form', $ief_id, 'entities']); diff --git a/src/Plugin/Field/FieldWidget/InlineEntityFormComplex.php b/src/Plugin/Field/FieldWidget/InlineEntityFormComplex.php index 92a52fe..03d82ef 100644 --- a/src/Plugin/Field/FieldWidget/InlineEntityFormComplex.php +++ b/src/Plugin/Field/FieldWidget/InlineEntityFormComplex.php @@ -89,6 +89,7 @@ class InlineEntityFormComplex extends InlineEntityFormBase implements ContainerF 'allow_new' => TRUE, 'allow_existing' => FALSE, 'match_operator' => 'CONTAINS', + 'empty_mode' => '', ]; return $defaults; @@ -112,6 +113,18 @@ class InlineEntityFormComplex extends InlineEntityFormBase implements ContainerF '#title' => $this->t('Allow users to add existing @label.', ['@label' => $labels['plural']]), '#default_value' => $this->getSetting('allow_existing'), ]; + $element['empty_mode'] = [ + '#type' => 'select', + '#title' => $this->t('Default form when the field is empty'), + '#default_value' => $this->getSetting('empty_mode'), + '#options' => $this->getEmptyModeOptions(), + '#states' => [ + 'visible' => [ + ':input[name="' . $states_prefix . '[allow_existing]"]' => ['checked' => TRUE], + ':input[name="' . $states_prefix . '[allow_new]"]' => ['checked' => TRUE], + ], + ], + ]; $element['match_operator'] = [ '#type' => 'select', '#title' => $this->t('Autocomplete matching'), @@ -153,6 +166,15 @@ class InlineEntityFormComplex extends InlineEntityFormBase implements ContainerF $summary[] = $this->t('Existing @label can not be referenced.', ['@label' => $labels['plural']]); } + switch ($this->getSetting('empty_mode')) { + case 'new': + $summary[] = $this->t('For empty fields, the form to add new @label is shown.', ['@label' => $labels['plural']]); + break; + case 'existing': + $summary[] = $this->t('For empty fields, the form to add existing @label is shown.', ['@label' => $labels['plural']]); + break; + } + return $summary; } @@ -170,6 +192,20 @@ class InlineEntityFormComplex extends InlineEntityFormBase implements ContainerF } /** + * Returns the options for the empty mode. + * + * @return array + * List of options. + */ + protected function getEmptyModeOptions() { + $labels = $this->getEntityTypeLabels(); + return [ + '' => $this->t('Show buttons to chose'), + 'new' => $this->t('Create new @label', ['@label' => $labels['singular']]), + 'existing' => $this->t('Add existing @label', ['@label' => $labels['singular']]), + ]; + } + /** * {@inheritdoc} */ public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) { @@ -386,14 +422,25 @@ class InlineEntityFormComplex extends InlineEntityFormBase implements ContainerF $create_bundles = $this->getCreateBundles(); $create_bundles_count = count($create_bundles); $allow_new = $settings['allow_new'] && !empty($create_bundles); - $hide_cancel = FALSE; - // If the field is required and empty try to open one of the forms. - if (empty($entities) && $this->fieldDefinition->isRequired()) { - if ($settings['allow_existing'] && !$allow_new) { + $hide_cancel = $switch_mode = FALSE; + + // When no entities are present, determine what to do. + // If the field is required or if a default mode is configured, try to open + // one of the two forms. + if (empty($entities) && ($this->fieldDefinition->isRequired() || !empty($settings['empty_mode']))) { + // Check if the mode switching button was clicked and show the requested form. + $requested_form = $form_state->get(['inline_entity_form', $this->getIefId(), 'form']); + if (!empty($requested_form)) { + $switch_mode = $hide_cancel = $requested_form == 'add' ? $settings['allow_existing'] : $allow_new; + } + // Or show the form to add existing entities. + else if ($settings['allow_existing'] && (!$allow_new || $settings['empty_mode'] == 'existing')) { $form_state->set(['inline_entity_form', $this->getIefId(), 'form'], 'ief_add_existing'); $hide_cancel = TRUE; + $switch_mode = $allow_new; } - elseif ($create_bundles_count == 1 && $allow_new && !$settings['allow_existing']) { + // Or show the form to add new entities. + elseif ($create_bundles_count == 1 && $allow_new && (!$settings['allow_existing'] || $settings['empty_mode'] == 'new')) { $bundle = reset($target_bundles); // The parent entity type and bundle must not be the same as the inline @@ -406,6 +453,7 @@ class InlineEntityFormComplex extends InlineEntityFormBase implements ContainerF 'bundle' => $bundle, ]); $hide_cancel = TRUE; + $switch_mode = $settings['allow_existing']; } } } @@ -513,16 +561,20 @@ class InlineEntityFormComplex extends InlineEntityFormBase implements ContainerF // Pre-opened forms can't be closed in order to force the user to // add / reference an entity. - if ($hide_cancel) { + if ($hide_cancel || $switch_mode) { if ($open_form == 'add') { $process_element = &$element['form']['inline_entity_form']; } elseif ($open_form == 'ief_add_existing') { $process_element = &$element['form']; } - $process_element['#process'][] = [get_class($this), 'hideCancel']; + if ($hide_cancel) { + $process_element['#process'][] = [get_class($this), 'hideCancel']; + } + if ($switch_mode) { + $process_element['#process'][] = [get_class($this), 'switchMode']; + } } - // No entities have been added. Remove the outer fieldset to reduce // visual noise caused by having two titles. if (empty($entities)) { @@ -654,7 +706,7 @@ class InlineEntityFormComplex extends InlineEntityFormBase implements ContainerF * @param array $element * Form array structure. */ - public static function hideCancel($element) { + public static function hideCancel($element, FormStateInterface $form_state) { // @todo Name both buttons the same and simplify this logic. if (isset($element['actions']['ief_add_cancel'])) { $element['actions']['ief_add_cancel']['#access'] = FALSE; @@ -662,7 +714,42 @@ class InlineEntityFormComplex extends InlineEntityFormBase implements ContainerF elseif (isset($element['actions']['ief_reference_cancel'])) { $element['actions']['ief_reference_cancel']['#access'] = FALSE; } + return $element; + } + /** + * Shows a switch mode link. + * + * @param array $element + * Form array structure. + */ + public static function switchMode($element, FormStateInterface $form_state) { + $element['actions']['ief_switch_mode'] = [ + '#type' => 'submit', + '#name' => 'ief-switch-mode-' . $element['#ief_id'], + '#limit_validation_errors' => [], + '#ajax' => [ + 'callback' => 'inline_entity_form_get_element', + 'wrapper' => 'inline-entity-form-' . $element['#ief_id'], + ], + '#submit' => [ + [get_called_class(), 'closeChildForms'], + [get_called_class(), 'closeForm'], + 'inline_entity_form_open_form' + ], + '#attributes' => ['class' => ['link']], + ]; + if (isset($element['actions']['ief_add_cancel'])) { + $element['actions']['ief_switch_mode']['#value'] = t('Add existing @type_singular instead', ['@type_singular' => $element['#ief_labels']['singular']]);; + $element['actions']['ief_switch_mode']['#ief_form'] = 'ief_add_existing'; + } + elseif (isset($element['actions']['ief_reference_cancel'])) { + $element['actions']['ief_switch_mode']['#value'] = t('Create new @type_singular instead', ['@type_singular' => $element['#ief_labels']['singular']]);; + $element['actions']['ief_switch_mode']['#ief_form'] = 'add'; + if (empty($element['#required'])) { + $element['entity_id']['#required'] = FALSE; + } + } return $element; } @@ -752,7 +839,6 @@ class InlineEntityFormComplex extends InlineEntityFormBase implements ContainerF $form_state->set(['inline_entity_form', $ief_id, 'entities', $delta, 'form'], NULL); } - /** * Remove form submit callback. *