Skip to content

[LiveCollection] LiveCollectionType may reuse removed Doctrine entity when adding a new item due to index reuse #3371

@JacquesMougin

Description

@JacquesMougin

Description

I'm encountering an issue when using LiveComponent + LiveCollectionType with a Doctrine Collection.

The problem seems related to how $formValues indexes are handled when removing and adding items.

Context

Symfony UX LiveComponent version: 2.31
Symfony version: 7.4.1
Doctrine/ORM version: 3.5.7
PHP version: 8.4

I'm using:

  • Symfony UX LiveComponent
  • LiveCollectionType
  • A Doctrine collection inside a form.

Current behaviour

Suppose the collection initially contains 3 elements.

Indexes in $formValues are:

0, 1, 2

If I remove the last element using the remove action from LiveCollectionTrait, index 2 is removed and the array keys become:

0, 1

Then, when adding a new element via the add action, the following code is executed in LiveCollectionTrait -> addCollectionItem (line 36) :

$index = [] !== $data ? max(array_keys($data)) + 1 : 0;

In this case:

max index = 1
new index = 2

So the new item is inserted at index 2.

The issue

Because index 2 previously existed and was mapped to a Doctrine entity, the newly added entry ends up being mapped back to the previously removed entity instead of creating a new one.

This leads to unexpected behavior where:

  • the removed entity appears again
  • a new object is not actually created

Expected behaviour

When adding a new element after a removal, a new entry should always be created, without reusing a previously removed reference.

Possible cause

The issue seems to be that the index used in $formValues is derived from the current max key, which may correspond to a previously removed entry.

This becomes problematic when working with Doctrine collections and form data mapping.

Possible solution ideas

The workaround I've found is :

#[LiveProp]
public int $maxInitialKey = 0;

#[PostMount]
public function postMount(): void
{
    $this->maxInitialKey = max($this->entity->collection->getKeys());
}

#[LiveAction]
public function addCollectionItem(PropertyAccessorInterface $propertyAccessor, #[LiveArg] string $name): void
{
    $key = $this->maxInitialKey + 1;
    if (array_key_exists($key, $this->formValues['collection'])) {
        $key = max(array_keys($this->formValues['collection'])) + 1;
    }

    $this->formValues['collection'][$key] = [];
}

Question

Is this the expected behavior of LiveCollectionType, or could this be considered a bug when working with Doctrine collections?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions