Remove item in UI not working, ajax error - internal server error

Created on 16 October 2023, 8 months ago

Problem/Motivation

There is a bug in src/Plugin/Field/FieldWidget/FieldCollectionEmbedWidget.php removeSubmit renumber mechanism.
It leads the form state field storage to grow unexpectedly and nesting deeper and deeper for every next processed item, then form state cache cannot be saved in database because it's too big and item cannot be removed from UI - ajax call returns internal server error.
I had a node with over 15 field collection items added. (6 fields) and form state cache was calculated to be over 800MB when I tried to remove one of the first items.
I think this issue was reported here: https://www.drupal.org/project/field_collection/issues/2887246 β†’ but it was ignored and closed.

      $old_element_address = array_merge($address, ['widget', $i + 1]);
      $old_element_state_address = array_merge($address_state, [$i + 1]);
      $new_element_state_address = array_merge($address_state, [$i]);

      $moving_element = NestedArray::getValue($form, $old_element_address);

      $moving_element_value = NestedArray::getValue($form_state->getValues(), $old_element_state_address);
      $moving_element_input = NestedArray::getValue($form_state->getUserInput(), $old_element_state_address);
      $moving_element_field = NestedArray::getValue($form_state->get('field_storage'), array_merge(['#parents'], $address));

      // Tell the element where it's being moved to.
      $moving_element['#parents'] = $new_element_state_address;

      // Move the element around.
      $form_state->setValueForElement($moving_element, $moving_element_value);
      $user_input = $form_state->getUserInput();
      NestedArray::setValue($user_input, $moving_element['#parents'], $moving_element_input);
      $form_state->setUserInput($user_input);
      NestedArray::setValue($form_state->get('field_storage'), array_merge(['#parents'], $moving_element['#parents']), $moving_element_field);

$moving_element_field take the whole field storage, instead of single element storage and save it in new element position, for the next item the whole field storage is taken again(with updates made by previous loop execution), so it's growing and growing for every next element.

Steps to reproduce

Method 1:
1. Add field collection field with multiple fields to a node type.
2. Add a new node with multiple field collection items and save it.
3. Edit the node and try to remove one of the first items.

Method 2:
1. Basic field collection setup
2. Debug remove item button.

Proposed solution

$moving_element_field = NestedArray::getValue($form_state->get('field_storage'), array_merge(['#parents'], $address));

is changed to:

$moving_element_field = NestedArray::getValue($form_state->get('field_storage'), array_merge(['#parents'], $old_element_state_address));

so $moving_element_field contains specific element storage only(not the whole field storage as it is now) to save it in new position when it happens - NestedArray::setValue($form_state->get('field_storage'), array_merge(['#parents'], $moving_element['#parents']), $moving_element_field);

πŸ› Bug report
Status

Needs review

Version

3.0

Component

Code

Created by

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.69.0 2024