diff --git a/src/Element/InlineEntityForm.php b/src/Element/InlineEntityForm.php index 8537089..b636edc 100644 --- a/src/Element/InlineEntityForm.php +++ b/src/Element/InlineEntityForm.php @@ -40,6 +40,7 @@ class InlineEntityForm extends RenderElement { '#display_actions' => FALSE, // Will save entity on submit if set to TRUE. '#save_entity' => TRUE, + '#ief_element_validate' => [], '#ief_element_submit' => [], // Needs to be set to FALSE if one wants to implement it's own submit logic. '#handle_submit' => TRUE, @@ -127,7 +128,8 @@ class InlineEntityForm extends RenderElement { // Attach submit callbacks to main submit buttons. if ($element['#handle_submit']) { - static::attachMainSubmit($complete_form); + static::attachMainSubmit($complete_form, '#submit'); + static::attachMainSubmit($complete_form, '#validate'); } return $element; @@ -139,16 +141,20 @@ class InlineEntityForm extends RenderElement { * @param array $complete_form * Form structure. */ - public static function attachMainSubmit(&$complete_form) { + public static function attachMainSubmit(&$complete_form, $type) { $submit_attached = FALSE; - $submit = array_merge([[get_called_class(), 'triggerIefSubmit']], $complete_form['#submit']); + + $trigger_callback = $type == '#submit' ? 'triggerIefSubmit' : 'triggerIefValidate'; + + $submit = array_merge([[get_called_class(), $trigger_callback]], $complete_form[$type]); + if (!empty($complete_form['submit'])) { - if (empty($complete_form['submit']['#submit'])) { - $complete_form['submit']['#submit'] = $submit; + if (empty($complete_form['submit'][$type])) { + $complete_form['submit'][$type] = $submit; } else { - $complete_form['submit']['#submit'] = array_merge([[get_called_class(), 'triggerIefSubmit']], $complete_form['submit']['#submit']); + $complete_form['submit'][$type] = array_merge([[get_called_class(), $trigger_callback]], $complete_form['submit'][$type]); } $complete_form['submit']['#ief_submit_all'] = TRUE; $submit_attached = TRUE; @@ -156,11 +162,11 @@ class InlineEntityForm extends RenderElement { foreach (['submit', 'publish', 'unpublish'] as $action) { if (!empty($complete_form['actions'][$action])) { - if (empty($complete_form['actions'][$action]['#submit'])) { - $complete_form['actions'][$action]['#submit'] = $submit; + if (empty($complete_form['actions'][$action][$type])) { + $complete_form['actions'][$action][$type] = $submit; } else { - $complete_form['actions'][$action]['#submit'] = array_merge([[get_called_class(), 'triggerIefSubmit']], $complete_form['actions'][$action]['#submit']); + $complete_form['actions'][$action][$type] = array_merge([[get_called_class(), $trigger_callback]], $complete_form['actions'][$action][$type]); } $complete_form['actions'][$action]['#ief_submit_all'] = TRUE; $submit_attached = TRUE; @@ -170,7 +176,7 @@ class InlineEntityForm extends RenderElement { // If we didn't attach submit to one of the most common buttons let's search // the form for any submit with #button_type == primary and attach to that. if (!$submit_attached) { - static::recurseAttachMainSubmit($complete_form, $submit); + static::recurseAttachMainSubmit($complete_form, $submit, $type); } } @@ -189,14 +195,14 @@ class InlineEntityForm extends RenderElement { * @return bool * TRUE if appropriate element was found. FALSE otherwise. */ - public static function recurseAttachMainSubmit(&$element, $submit_callbacks) { + public static function recurseAttachMainSubmit(&$element, $submit_callbacks, $type) { foreach (Element::children($element) as $child) { if (!empty($element[$child]['#type']) && $element[$child]['#type'] == 'submit' && $element[$child]['#button_type'] == 'preview') { - $element[$child]['#submit'] = empty($element[$child]['#submit']) ? $submit_callbacks : array_merge($submit_callbacks, $element[$child]['#submit']); + $element[$child][$type] = empty($element[$child]['#submit']) ? $submit_callbacks : array_merge($submit_callbacks, $element[$child][$type]); $element[$child]['#ief_submit_all'] = TRUE; return TRUE; } - elseif (static::recurseAttachMainSubmit($element[$child], $submit_callbacks)) { + elseif (static::recurseAttachMainSubmit($element[$child], $submit_callbacks, $type)) { return TRUE; } } @@ -226,6 +232,21 @@ class InlineEntityForm extends RenderElement { } } + public static function triggerIefValidate($form, FormStateInterface $form_state) { + $triggered_element = $form_state->getTriggeringElement(); + if (!empty($triggered_element['#ief_submit_all'])) { + // The parent form was submitted, process all IEFs and their children. + static::iefValidate($form, $form_state); + } + else { + // A specific entity form was submitted, process it and all of its children. + $array_parents = $triggered_element['#array_parents']; + $array_parents = array_slice($array_parents, 0, -2); + $element = NestedArray::getValue($form, $array_parents); + static::iefValidate($element, $form_state); + } + } + /** * Submits entity forms by calling their #ief_element_submit callbacks. * @@ -252,4 +273,20 @@ class InlineEntityForm extends RenderElement { } } + public static function iefValidate($elements, FormStateInterface $form_state) { + // Recurse through all children. + foreach (Element::children($elements) as $key) { + if (!empty($elements[$key])) { + static::iefValidate($elements[$key], $form_state); + } + } + + // If there are callbacks on this level, run them. + if (!empty($elements['#ief_element_validate'])) { + foreach ($elements['#ief_element_validate'] as $function) { + $function($elements, $form_state); + } + } + } + } diff --git a/src/Form/EntityInlineForm.php b/src/Form/EntityInlineForm.php index 91a09a5..7e05635 100644 --- a/src/Form/EntityInlineForm.php +++ b/src/Form/EntityInlineForm.php @@ -140,8 +140,10 @@ class EntityInlineForm implements InlineFormInterface { */ public function entityForm($entity_form, FormStateInterface $form_state) { $operation = 'default'; - $controller = $this->entityManager->getFormObject($entity_form['#entity']->getEntityTypeId(), $operation); + $controller = $this->entityManager->getFormObject($entity_form['#entity']->getEntityTypeId(), $operation, FALSE); $controller->setEntity($entity_form['#entity']); + $form_state->set(['inline_entity_form', $entity_form['#ief_id'], 'entity_form'], $controller); + $child_form_state = $this->buildChildFormState($controller, $form_state, $entity_form['#entity'], $operation, $entity_form['#parents']); $entity_form = $controller->buildForm($entity_form, $child_form_state); @@ -189,8 +191,8 @@ class EntityInlineForm implements InlineFormInterface { $entity = $entity_form['#entity']; $operation = 'default'; - $controller = \Drupal::entityManager() - ->getFormObject($entity->getEntityTypeId(), $operation); + /** @var \Drupal\Core\Entity\EntityFormInterface $controller */ + $controller = $form_state->get(['inline_entity_form', $entity_form['#ief_id'], 'entity_form']); $child_form_state = static::buildChildFormState($controller, $form_state, $entity, $operation, $entity_form['#parents']); $entity_form['#entity'] = $controller->validateForm($entity_form, $child_form_state); @@ -227,7 +229,8 @@ class EntityInlineForm implements InlineFormInterface { /** @var \Drupal\Core\Entity\EntityInterface $entity */ $entity = $entity_form['#entity']; $operation = 'default'; - $controller = \Drupal::entityManager()->getFormObject($entity->getEntityTypeId(), $operation); + /** @var \Drupal\Core\Entity\EntityFormInterface $controller */ + $controller = $form_state->get(['inline_entity_form', $entity_form['#ief_id'], 'entity_form']); $controller->setEntity($entity); $child_form_state = static::buildChildFormState($controller, $form_state, $entity, $operation, $entity_form['#parents']); diff --git a/src/Plugin/Field/FieldWidget/InlineEntityFormBase.php b/src/Plugin/Field/FieldWidget/InlineEntityFormBase.php index 4cc2db4..8f91545 100644 --- a/src/Plugin/Field/FieldWidget/InlineEntityFormBase.php +++ b/src/Plugin/Field/FieldWidget/InlineEntityFormBase.php @@ -314,6 +314,11 @@ abstract class InlineEntityFormBase extends WidgetBase implements ContainerFacto * @param array $element * Form array structure. */ + public static function addIefValidateCallbacks($element) { + $element['#ief_element_validate'][] = [get_called_class(), 'validateSaveEntity']; + return $element; + } + public static function addIefSubmitCallbacks($element) { $element['#ief_element_submit'][] = [get_called_class(), 'submitSaveEntity']; return $element; @@ -365,7 +370,7 @@ abstract class InlineEntityFormBase extends WidgetBase implements ContainerFacto * @param $form_state * The form state of the parent form. */ - public static function submitSaveEntity($entity_form, FormStateInterface $form_state) { + public static function validateSaveEntity($entity_form, FormStateInterface $form_state) { $ief_id = $entity_form['#ief_id']; $entity = $entity_form['#entity']; @@ -381,7 +386,7 @@ abstract class InlineEntityFormBase extends WidgetBase implements ContainerFacto 'entity' => $entity, '_weight' => $weight, 'form' => NULL, - 'needs_save' => TRUE, + 'needs_save' => FALSE, ); $form_state->set(['inline_entity_form', $ief_id, 'entities'], $entities); } @@ -389,6 +394,27 @@ abstract class InlineEntityFormBase extends WidgetBase implements ContainerFacto $delta = $entity_form['#ief_row_delta']; $entities = $form_state->get(['inline_entity_form', $ief_id, 'entities']); $entities[$delta]['entity'] = $entity; + $entities[$delta]['needs_save'] = FALSE; + $form_state->set(['inline_entity_form', $ief_id, 'entities'], $entities); + } + } + + public static function submitSaveEntity($entity_form, FormStateInterface $form_state) { + $ief_id = $entity_form['#ief_id']; + $entity = $entity_form['#entity']; + + if ($entity_form['#op'] == 'add') { + $entities = $form_state->get(['inline_entity_form', $ief_id, 'entities']); + $item = array_pop($entities); + $item['entity'] = $entity; + $item['needs_save'] = TRUE; + array_push($entities, $item); + $form_state->set(['inline_entity_form', $ief_id, 'entities'], $entities); + } + else { + $delta = $entity_form['#ief_row_delta']; + $entities = $form_state->get(['inline_entity_form', $ief_id, 'entities']); + $entities[$delta]['entity'] = $entity; $entities[$delta]['needs_save'] = TRUE; $form_state->set(['inline_entity_form', $ief_id, 'entities'], $entities); } diff --git a/src/Plugin/Field/FieldWidget/InlineEntityFormComplex.php b/src/Plugin/Field/FieldWidget/InlineEntityFormComplex.php index a7781ff..0d83dd9 100644 --- a/src/Plugin/Field/FieldWidget/InlineEntityFormComplex.php +++ b/src/Plugin/Field/FieldWidget/InlineEntityFormComplex.php @@ -318,7 +318,7 @@ class InlineEntityFormComplex extends InlineEntityFormBase implements ContainerF $element['entities'][$key]['form']['inline_entity_form']['#process'] = [ ['\Drupal\inline_entity_form\Element\InlineEntityForm', 'processEntityForm'], - [get_class($this), 'addIefSubmitCallbacks'], + [get_class($this), 'addIefValidateCallbacks'], [get_class($this), 'buildEntityFormActions'], ]; } @@ -515,6 +515,7 @@ class InlineEntityFormComplex extends InlineEntityFormBase implements ContainerF ]; $element['form']['inline_entity_form']['#process'] = [ ['\Drupal\inline_entity_form\Element\InlineEntityForm', 'processEntityForm'], + [get_class($this), 'addIefValidateCallbacks'], [get_class($this), 'addIefSubmitCallbacks'], [get_class($this), 'buildEntityFormActions'], ]; @@ -655,6 +656,10 @@ class InlineEntityFormComplex extends InlineEntityFormBase implements ContainerF $item['target_id'] = $item['entity']->id(); $items[] = $item; } + else { + $item['target_id'] = NULL; + $items[] = $item; + } } // Sort items by _weight.