Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Form][FormEvents] Not model transformed data bound to preSetData event #7807

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
maciej-pyszynski opened this issue Apr 23, 2013 · 9 comments

Comments

@maciej-pyszynski
Copy link

On preSetData data send to the event is not processed by modelTransformer. The easiest case to test is creating collection type with attached model transformer.

Data bound to the event is original data instead of transformed one!

This is required for example when transforming collection from array('key' => 'value') format to array(0 => array('key' => 'original_key', 'value' => 'original_value')).

If collection receive 1st format (wrong - not transformed) instead of 2nd one (good - only model transformed) it created bad names for inputs (based on original key, instead of on transformed ones)

@webmozart
Copy link
Contributor

This is expected behavior. When a form or field receives data from your model (i.e. by calling setData() etc.), this data should obviously already be in model format.

@maciej-pyszynski
Copy link
Author

Yes, but form Field also have transformers, so field receive data in model format, but then it should transform data using model transformer since it's attached and pass this data along. This is transformer role:)!

@webmozart
Copy link
Contributor

You are right, but then the data is not in model format anymore, but in normalized respectively view format. You should use the event POST_SET_DATA If you want to access data in transformed format.

@maciej-pyszynski
Copy link
Author

OK, you are right. So the ResizeFormListener should add fields on POST_SET_DATA instead of PRE_SET_DATA. Since to work around this issue I have to create another ResizeFormListener removing all added fields based on not normalized data.

Fix is easy, but I'm not sure about breaking logic of code basing on current ResizeFormListener behaviour.
Still fixing this bug is required, since I have two cases with it in two days period and this is not edge case. I'm sure other people will have it too, or already have it.

@webmozart
Copy link
Contributor

I suggest to contact the Symfony2 Mailing List for your issue, that's where you usually get a lot of support :) For urgent issues, there is also an IRC #symfony on Freenode.

@maciej-pyszynski
Copy link
Author

This is a bug, so please refer to it.

I'll give you detailed example, so you can reproduce it yourself.

Model is returning array of entites: [0 => $entity1, 1 => $entity2, 2 => $entity3].
Collection has attached modelTransformer

Model transformer split entites to arrays: ['en' => array($entity1), 'fr' => array($entity2, $entity3)]

Now what Symfony ResizeFormListener do is creating collection items forms based on not transformed model data resulting in creating forms indexed by: 0, 1; instead of: 'en', 'fr' from transformed data.
Later on fields are filled by transformed data, so no matching one!

It's definitely a BUG. And you cannot tell me this behaviour is expected, did you?

@webmozart
Copy link
Contributor

It's definitely a BUG. And you cannot tell me this behaviour is expected, did you?

I understand that English may not be your first language (nor is it mine), but please be polite here. I'm trying to help you :)

To answer your question: Yes, this behavior is expected. The collection type is not designed to work with associative arrays (i.e. string keys such as 'en' or 'fr'). It is designed to work with numerically indexed collections that can dynamically grow or shrink by adding new elements or removing existing ones.

I opened a feature request for the functionality you need: #7828

@maciej-pyszynski
Copy link
Author

Sorry, for being offensive. I just felt ignored.

Thanks, for opening feature request. But this is not exactly the case.
As you suggested collection could by indexed by custom key and this is my case, since elements cannot be added or removed. Only difference is that this custom key is not unique. As you can see in previous example: 'fr' index contains two entities.

My need is to transform flat collection to collection of collections grouped by some key.
Example:

Synonyms: (1st level collection)

  • en: (2nd level collection)
    • some synonyme
    • another one
  • fr (2nd level collection)
    • fr synonyme

All 2nd level collections are obviously the same type.
I made a change in SF core to test the behaviour and it works perfectly - changing ResizeFormListener preSetData function trigger from PRE_SET_DATA to POST_SET_DATA.

Only one new failing test is Symfony\Component\Form\Tests\Extension\Core\Type\CollectionTypeTest::testThrowsExceptionIfObjectIsNotTraversable
Since data variable type is not checked before data set (and shouldn't since data can be transformed by attached transformers). So exception is thrown in Symfony\Component\Form\Form::setData() in line 386 since data there should be already traversable. This happen a little to late, but doesn't break any Collection behaviour.

Have no idea for now, how to fix it in nice way. When I figure something out, I'll make pull request. Any suggestions from you side will be appreciated.

Thank you for involvement.

@webmozart
Copy link
Contributor

If elements cannot be added, your use case can already be solved right now quite easily:

foreach ($languages as $language) {
    $builder->add('synonyms_' . $language, 'collection', array(
        'type' => 'synonym',
        'property_path' => 'synonyms[' . $language . ']',
    ));
}

This will result in one collection field per language code, which will be mapped to the corresponding key in the "synonyms" collection.

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

No branches or pull requests

2 participants