Skip to content

[Form] Add "reindex" option for the CollectionType #13116

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

[Form] Add "reindex" option for the CollectionType #13116

wants to merge 1 commit into from

Conversation

sergeyfedotov
Copy link
Contributor

Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets #12936
License MIT
Doc PR TODO

Adds a new option to the collection field type. This option allows to reindex the data array if necessary.

TODO:

  • submit changes to the documentation

/**
* @var bool
*/
protected $reindex;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be private

@stof
Copy link
Member

stof commented Dec 31, 2014

Please don't change the permissions on files. the source code has no reason to be executable.

If you are on Windows, you should configure Git to ignore file mode changes because Windows does not support Unix file modes and so Git detects messy changes (this is done by default when installing GitBash but other Windows Git clients may not do it for you): git config --global core.filemode false

$this->assertArrayNotHasKey(1, $event->getData());
$this->assertArrayHasKey(2, $event->getData());
$this->assertArrayHasKey(3, $event->getData());
$this->assertArrayHasKey(4, $event->getData());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, you should not only assert that it has the keys, but also which values are there for each key

@fabpot fabpot added the Form label Jan 2, 2015
@sergeyfedotov
Copy link
Contributor Author

This PR needs to be reviewed again because the logic has been changed.

@stof
Copy link
Member

stof commented Jan 3, 2015

This looks good to me, however I would prefer if @webmozart could review it as well.

@@ -110,6 +116,29 @@ public function preSubmit(FormEvent $event)
throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)');
}

// Fix array indices
if ($this->reindex) {
$originalData = $data;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if $originalData is not an array? At the moment, this method also supports array-like objects, although I don't understand why. The check was introduced in 77bea81, but I don't know why anymore. Any ideas @stof @Tobion?

@sergeyfedotov
Copy link
Contributor Author

@webmozart I rewrote the code to support array-like objects.

@fabpot
Copy link
Member

fabpot commented Jan 25, 2016

Why do we need a new option for that? Can't we always reindex?

@webmozart
Copy link
Contributor

Thanks for your PR @sergeyfedotov! :) Unfortunately it's more complicated than that (suprise).

When we reindex the data submitted by the browser, we lose the ability to assign submitted data to entries of the collection. Imagine:

$data = [
    0 => ['price' => 10],
    2 => ['price' => 20],
];

$collection = [
    0 => Product(id => 1, price => 10),
    1 => Product(id => 2, price => 12),
    2 => Product(id => 3, price => 15),
];

Instead of removing product with ID 2 from the list and updating product 3 to price 20, we now removed product 3 and updated product 2 (which may or may not be what we want to do). Similar issues are already described in #7468 and #7828.

A proper fix, from what I can judge right now without too much investigation, would involve the following steps:

  • Add a new option entry_id that returns a string that uniquely identifies an entry of the collection and is used as name of the entry forms instead of the collection indices. This could be a property path (e.g. id) or a closure with the signature function ($entry, $key) where the default return value is $key to keep BC.
  • On submit (ResizeFormListener::preSubmit()), rearrange the order of the fields to resemble the submitted data. This allows to reorder the collection on the client side.
  • Create a custom data mapper that writes the collection based on equivalence of the field names and the calculated entry_id of each original collection entry. We cannot simply compare the indexes sent by the browser (the entry_id of each field) and in the collection (e.g. sequential integers - or not, depends on the implementation). The if ($this->allowDelete) { block in ResizeFormListener::onSubmit() should probably be moved to that data mapper.
  • Add an option reindex (default false) that generates the property paths of the entry forms as sequential integer if set to true. Additionally, the data mapper must return the new collection with sequential indexes if set to true. This makes sure that error mapping works correctly, as long as the domain model also keeps its collections sequentially indexed (hence this is a BC break and optional).
  • We should set reindex to true by default in Symfony 4. I expect this to become best practice in order to avoid the error mapping problems that we have right now.

@sergeyfedotov
Copy link
Contributor Author

@webmozart thanks for the detailed answer. You are right that a proper solution is more complicated. This pull request only trying to solve a problem with the errors association. In fact is a data association problem.

I think that the PR may be closed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants