4

I have the following code.

function mymodule_get_node_create_or_edit_form($nodeType = '', $inputNode = null, $prepopulationFields = array())
{
  if (empty($inputNode))
  {
    $values = array(
      'type' => $nodeType,
    );
    $values = array_merge($values, $prepopulationFields);
    $node = \Drupal::entityTypeManager()
      ->getStorage('node')
      ->create($values);
    $form = \Drupal::service('entity.form_builder')->getForm($node);
  }
  else
  {
    $form = \Drupal::entityTypeManager()
      ->getFormObject('node', 'default')
      ->setEntity($inputNode);
    $form = \Drupal::formBuilder()->getForm($form);
  }

  return \Drupal::service('renderer')->render($form);
}

I use this function to create edit forms for a node. So I can, for example, create a form that can be used to create a form:

print mymodule_get_node_create_or_edit_form('page', null, array());

Or I can get the edit form:

$node = node_load(1);
print mymodule_get_node_create_or_edit_form($node->getType(), $node , array());

The problem is if I execute both on the same page. Eg:

print mymodule_get_node_create_or_edit_form('page', null, array());
$node = node_load(1);
print mymodule_get_node_create_or_edit_form($node->getType(), $node , array());

If I now make changes to node 1, instead of saving it, it creates a new node with the changes I made, Instead of actually editing the existing node.

  • 1
    I believe the answer will be having to have its form builder generate unique IDs, and ttheir submits too. – Kevin Feb 26 at 19:23
  • 4
    Why are you using print and not adding the form to the render array? – Ismail Cherri Mar 8 at 19:55
  • 2
    @IsmailCherri, it seems it solves my problem if I put everything into one form array. – coderama Mar 9 at 20:48
  • 1
    @coderama Should I add it as an answer? – Ismail Cherri Mar 9 at 20:54
  • 1
    @IsmailCherri, yes, it seems to be the most correct answer. So you would get the points :-) – coderama Mar 10 at 5:22
2

I recently had the same issue and found a workaround in the corresponding Drupal core issue: The same form twice on one page with different arguments may process the wrong form when submitted.

The third comment suggests to enable FormState caching, and that worked great for me.

$form_state->setRequestMethod('POST');
$form_state->setCached(TRUE);
  • 1
    My form is of type = NodeForm. I dont seem to have SetRequestMethod and setCached that I can call. – coderama Feb 28 at 10:41
  • 1
    There must be something in the entity form type that could. – Kevin Mar 8 at 20:34
2

To apply the workaround suggested in The same form twice on one page with different arguments may process the wrong form when submitted, you need an instance of a class implementing FormStateInterface. It cannot be applied to the code you are using, since you don't have any instance of a class implementing FormStateInterface.

Altering the form ID for each form, which is essentially the Drupal 8 to achieve what hook_forms() achieved in Drupal 7 (see hook_forms() has been removed), would require to sub-class a class marked as @internal (the NodeForm class), and alter the Node entity to change its edit form.

I would instead implement hook_ENTITY_TYPE_prepare_form().

function mymodule_node_prepare_form(EntityInterface $entity, $operation, FormStateInterface $form_state) {
  if ($operation == 'edit') {
    $form_state->setRequestMethod('POST');
    $form_state->setCached(TRUE);
  }
}

The other function is still required. This is how I would implement it.

function mymodule_get_node_edit_form($node, array $entity_values = []) {
  if (is_string($node)) {
    $node = \Drupal::entityTypeManager()->getStorage('node')
      ->create(array_merge(['type' => $node], $entity_values));
  }
  $form = \Drupal::service('entity.form_builder')->getForm($node, 'edit');
  return \Drupal::service('renderer')->render($form);
}

Essentially, I am applying the workaround given in The same form twice on one page with different arguments may process the wrong form when submitted inside a hook.

1

According to coments in the original question, the issue is resolved by adding the forms to the render array rather than using print directly.

  • 2
    You should show the corrected code, instead of referring to comments. I doubt it's the solution, since there is a bug report open for Drupal core. Drupal core doesn't print the form as the OP does, but the bug about two forms of the same type on the same page is still present. – kiamlaluno Mar 10 at 19:18
  • 1
    I take that back. The form is still giving issues. You might still be right though, but it might also be a bigger issue. I.e. That drupal doesnt like multiple forms on the same page. The search continues... – coderama Mar 11 at 10:53
  • 1
    Ok, no problem. I will look for another solution – Ismail Cherri Mar 11 at 15:10
0

I ran into this problem in Drupal 6 and at the time the solution was to use hook_forms. That function still existed in Drupal 7 (see hook_forms docs for Drupal 7) but it has been removed from Drupal 8. There is a change record for Drupal 8 about how hook_forms has been removed and how to migrate code.

Perhaps from those documentation pages it will be clear what you need to do?

  • 1
    This is what I would do, for a form implemented by a module I wrote. (Possibly, it would be the same module that is showing two forms of the same type in the same page.) In the specific case, this requires to extend a class that is marked as internal (NodeForm). Otherwise, this would be the simpler solution. – kiamlaluno Mar 10 at 22:52
  • 1
    Aha, I missed the (very important) element that this is coming from the NodeForm so this technique won't work. – greggles Mar 11 at 17:14
  • 1
    I think it would work. It's just that a class marked as internal is telling me not to extend it. – kiamlaluno Mar 11 at 18:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.