Skip to content

[Form] Guarantee that setData() was called on each form element after initialize() #8748

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
webmozart opened this issue Aug 14, 2013 · 2 comments

Comments

@webmozart
Copy link
Contributor

When the call to FormInterface::initialize() completes, setData() should have been called at least once on each element in the form tree to guarantee that all *_SET_DATA listeners were triggered. Currently, this is not the case for unmapped fields or fields with empty property paths, because these are skipped by the data mapper, thus setData() is not called before initialize() ends, but only later.

@webda2l
Copy link

webda2l commented Aug 14, 2013

Related to #8253 and #8607

fabpot added a commit that referenced this issue Aug 23, 2013
This PR was merged into the 2.2 branch.

Discussion
----------

[Form][2.2] Fixed Form::submit() to react to dynamic form modifications

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

ref #3767, #3768, #4548, #8748
cc @Burgov

This PR ensures that fields that are added during the submission process of a form are submitted as well. For example:

```php
$builder = $this->createFormBuilder()
    ->add('country', 'choice', ...)
    ->getForm();

$builder->get('country')->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
    $form = $event->getForm()->getParent();
    $country = $event->getForm()->getData();

    $form->add('province', 'choice', /* ... something with $country ... */);
});
```

Currently, the field "province" will not be submitted, because the submission loop uses `foreach`, which ignores changes in the underyling array.

Additionally, this PR ensures that `setData()` is called on *every* element of a form (except those inheriting their parent data) when `setData()` is called on the root element (i.e., during initialization). Currently, when some of the intermediate nodes (e.g. embedded forms) are submitted with an empty value, `setData()` won't be called on the nodes below (i.e. the fields of the embedded form) until `get*Data()` is called on them. If `getData()` is *not* called before `createView()`, any effects of `*_DATA` event listeners attached to those fields will not be visible in the view.

Commits
-------

cd27e1f [Form] Extracted ReferencingArrayIterator out of VirtualFormAwareIterator
ccaaedf [Form] PropertyPathMapper::mapDataToForms() *always* calls setData() on every child to ensure that all *_DATA events were fired when the initialization phase is over (except for virtual forms)
19b483f [Form] Removed superfluous reset() call
00bc270 [Form] Fixed: submit() reacts to dynamic modifications of the form children
fabpot added a commit that referenced this issue Aug 23, 2013
This PR was merged into the 2.3 branch.

Discussion
----------

[Form][2.3] Fixed Form::submit() and Form::setData() to react to dynamic form modifications

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

ref #3767, #3768, #4548, #8748
cc @Burgov

This PR ensures that fields that are added during the submission process of a form are submitted as well. For example:

```php
$builder = $this->createFormBuilder()
    ->add('country', 'choice', ...)
    ->getForm();

$builder->get('country')->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
    $form = $event->getForm()->getParent();
    $country = $event->getForm()->getData();

    $form->add('province', 'choice', /* ... something with $country ... */);
});
```

Currently, the field "province" will not be submitted, because the submission loop uses `foreach`, which ignores changes in the underyling array.

Contrary to #8827 (for 2.2), this PR also allows dynamic modifications during `setData()`:

```php
$builder = $this->createFormBuilder()
    ->add('country', 'choice', ...)
    ->getForm();

$builder->get('country')->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
    $form = $event->getForm()->getParent();
    $country = $event->getData();

    $form->add('province', 'choice', /* ... something with $country ... */);
});
```

For 2.2, this fix is not possible, because it would require changing the signature `DataMapperInterface::mapDataToForms($data, array $forms)` to `DataMapperInterface::mapDataToForms($data, array &$forms)`, which would be a BC break. For 2.3, this change is not necessary (instead of an array we now pass an iterator, which is passed by reference anyway).

Additionally, this PR ensures that `setData()` is called on *every* element of a form (except those inheriting their parent data) when `setData()` is called on the root element (i.e., during initialization). Currently, when some of the intermediate nodes (e.g. embedded forms) are submitted with an empty value, `setData()` won't be called on the nodes below (i.e. the fields of the embedded form) until `get*Data()` is called on them. If `getData()` is *not* called before `createView()`, any effects of `*_DATA` event listeners attached to those fields will not be visible in the view.

Commits
-------

7a34d96 Merge branch 'form-submit-2.2' into form-submit-2.3
cd27e1f [Form] Extracted ReferencingArrayIterator out of VirtualFormAwareIterator
3cb8a80 [Form] Added a test that ensures that setData() reacts to dynamic modifications of a form's children
07d14e5 [Form] Removed exception in Button::setData(): setData() is now always called for all elements in the form tree during the initialization of the tree
b9a3770 [Form] Removed call to deprecated method
878e27c Merge branch 'form-submit-2.2' into form-submit-2.3
ccaaedf [Form] PropertyPathMapper::mapDataToForms() *always* calls setData() on every child to ensure that all *_DATA events were fired when the initialization phase is over (except for virtual forms)
19b483f [Form] Removed superfluous reset() call
5d60a4f Merge branch 'form-submit-2.2' into form-submit-2.3
00bc270 [Form] Fixed: submit() reacts to dynamic modifications of the form children
@webmozart
Copy link
Contributor Author

replaced by #8834

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

No branches or pull requests

2 participants