-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Form] ViewData from a submitted form is not an object #20880
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
Comments
Some more investigation: Setup 1: Results in no prefill. I provided some text in the field, submitted the form and got that text as a string from getData() - works correctly. Setup 2:
Results in a prefilled field with the text provided by the Object. After submitting, the getData() returns a string. Implicit data_class from data gets ignored, eplicit data_class gets ignored as well, ObjectType does nothing with it. Setup 3:
No prefill, filled in text, got Object with text from getData() - works correctly. Setup 4: This triggers the error "The form's view data is expected to be an instance of class Symfony\BugBundle\ValueObject\Object, but is a(n) string. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms a(n) string to an instance of Symfony\BugBundle\ValueObject\Object." Setup 4b: This is the easiest solution. It's not clear to me why I would not use data_class for this, and why it would be blocked to do so? It works, but it seems like ignoring the problem, and moving it to some safer ground. Setup 4c: I can prefill with the Object data. But when I submit, the reverseTransform from my ViewTransformer is failing, as it receives not an object, but a string as $viewData. Is this expected? This also means I cannot simply use the ReversedTransformer. I would expect to not need a ViewTransformer however, so I tried to remove the if block, removed the ViewTransformer and submitted my form again. And it succeeds! So why is this error holding me back to do this? Is it needed for some other use cases? |
Hi @MetalArend, I will try to answer, IMO everything looks expected here. Basically a compound form can have either an array or an object as underlying data. Only its children will reach an actual view data as string (in most cases the data that shows up in an input). Internally the compound form uses its view data to map the data of the children. So if the view data is an array because of your model transformer, setting the
The simplest way to handle your case IMO is to implement the See also the discussion in #20641.
In setup 3, the pre set data is
There are globally two cases:
|
@HeahDude I don't get it... Isn't view data supposed to be what you can receive from an HTTP requests? And what you use to set values of html input fields? How an object can be used for that? BTW - I asked also a question on StackOverflow about the difference between model/norm/view data: http://stackoverflow.com/questions/41116099/form-norm-data-vs-view-data-whats-the-difference Could you explain what is the difference between these three types of data in the context of what you say above? |
Wow, thanks for the complete explanation, @HeahDude. So, I checked if I was using a compound form, but it's actually the only thing that stays all the time on false. So all my examples were on a not compound form. However, that is on purpose. Noted that a DataMapper might be a solution, but I still want to see what is going on with the ViewTransformer. So, instead of all these different setups, let me explain which specific situation feels strange to me. Two questions remain... First: my form is not compound, and I'm fine with my view data always being a string or null. What I'm confused about, is that if I set my data_class to something not null, the only thing that seems to go wrong is that if statement, 'cause when I remove that, all works correctly. So I'm still wondering which use case it is protecting, or if it might be obsolete to protect this? Second: the error thrown should probably have some extra check on being a compound field or not, because in case of a not compound field setting the data_class to not null, adding a view transformer will never work correctly. The error tells me to create a ViewTransformer that will change my normData to viewData that is an object. Adding such a ViewTransformer will remove the error, but submitting will trigger the reverseTransform, as it will be coded as suspecting the viewData to be an object, while it seems clear that will never be the case (if I understood your explanation correctly). |
Your statement is true for non compound forms only.
You shouldn't use
The component is not able to decide such things, the dev is responsible for the configuration, and this case is exactly why I suggested to use a custom DataMapper. Again I'll take the IMHO this is more a documentation issue that I'll try to address early next year (which is soon now). |
@HeahDude If I understand correctly then concept of view data is actually overloaded? Besides being view data it is also some kind of internal mapping data? Shouldn't it be explicitly separated? Also I found article by webmozart about DataMapper and value objects in Symfony forms. Should be helpful. |
That link is interesting, but there's nothing there that helps to understand why adding a perfectly correct ViewTransformer is not helping at all. If you look at this page: http://symfony.com/doc/current/form/data_transformers.html, the explanation of normData, viewData and modelData looks very clear to me. From that, I get that if I have a ViewTransformer where the transform ... eh ... transforms my normData=string to viewData=object, the reverseTransform should transform viewData=object to normData=string. The error tells me that adding a ViewTransformer with a transform method like here mentioned will solve the issue, and while that is correct, it also introduces a new issue, because the reverseTransform will trigger a new error after submitting the form. Why? Because it seems that the reverseTransform never gets anything else than a string. |
the reverse transformation of a view transformer expects either
|
Why is the error doing an instanceof from the viewData at L358, if viewData will only be null, a string or an array? If I look at that Is there a good explanation on why this check needs to be there? And if it needs to be there, does it make sense to actually use it to check the |
Ok after discussing it again in private on the new Symfony Devs slack with @MetalArend, it looks like this issue is a kind of duplicate of #20526, therefore I propose to close here. |
So, the possible solutions are:
But the two original questions still remain. There seems to be no way to use data_class AND create a ViewTransformer that actually will work correctly in the same FormType. So I would not mark this closed, as this was the actual problem. We can solve it by working around the problem, but the problem seems to be still there. |
One can "use data_class AND create a ViewTransformer" but the EDIT: |
I've done little bit more research: As you say the compound option determines if PropertyPathMapper will be used. That's OK. Also as you say the Form class is using the mapper to map the view data to the forms. That's OK too. Then PropertyPathMapper mapper is setting the data on the forms. Hmm... Why PropertyPathMapper trough Form is setting ViewData on forms that expect ModelData? How did the ViewData changed to ModelData in the mapper? Why ModelData are not mapped on the forms? Why It looks for me like this line: |
Because children are submitted and transformed before being mapped in the parent while it's being submitted. |
@HeahDude You mean this line? https://github.com/symfony/form/blob/master/Form.php#L618 The same issue applies, doesn't it? Data mapper is setting ViewData on forms that expect ModelData. |
Yes, which is coming after this one. |
How does it change the fact that the PropertyPathMapper is mapping ViewData to ModelData and ModelData to ViewData? Here mapper is wrongly setting ViewData as ModelData in child forms: Here mapper is wrongly getting ModelData from child forms and sets them in ViewData: |
If the view data was not expected one would get this exception first https://github.com/symfony/form/blob/master/Form.php#L358, which is behind the cause of this issue in the first place. But again, this is expected. |
@HeahDude Then how do you explain the inconsistencies? The view data is not supposed to be object, the "if" there is wrong. I've checked with other people and I'm not loosing my mind ( I hope ;) ). The ViewData is supposed to be strings, arrays or maybe null: http://stackoverflow.com/questions/41116099/form-norm-data-vs-view-data-whats-the-difference The names of data as used by PropertyPathMapper and Form do not match. |
Please just remember this: EDIT: |
Do you really think that |
HTTP protocol handles arrays of strings. I used to not understand it as you, you can read here #18053 (comment) that it was so strange to me that I've proposed to change it. But |
We are going off-topic but don't you think that what are you doing here is cargo cult programming (no offense, I really appreciate the time you are committing to the issue and in general)? The inconsistency is there, it should be fixed or well documented if it is too late to fix it, but denying existence of the inconsistencies and illogicality of the current state is not the solution in any case. |
You can see symfony/symfony-docs#6265 and all the issues linked to it, and that's not all of them :) My vote goes for a better documentation, because keeping BC here can be very complex. Trust me, since I've opened that PR, I've learned a lot, also thanks to issues like this before, any feedback there will be gladly appreciated. Thanks! |
Symfony: 3.2
What is the reasoning behind checking if the viewdata is an instance of the data_class in Form.php? Is this check preventing some situations that would be bad?
I got the corresponding LogicException in a situation that issued some strange demands on my code. Simplest code is in the zip in attachment: a ValueObject that encapsulates a string, and a formtype using this VO.
I used a ModelTransformer to convert my data from string to VO and back. The error demands that I set my data_class to null, or add a ViewTransformer. I added the ViewTransformer, as a ReversedTransformer from my ModelTransformer (not sure why ViewData would need to be an object). That did not work, so I changed the data_class to another option "data_class_my", to test if this would help. It did, untill I added some data to my formtype. I had to explicitly set the data_class to null, which makes no sense to do, as all seems to work if I simply remove the if block in Form.php on line 358.
I know I can do this some other way with datamappers, DTO's, and so on..., but I'm really puzzled why this is not working. Is this actually a bug, or is it avoiding some more terrible situations?
Symfony.zip
Did a little digging, @webmozart, do you remember what is going on here? It was added in 2012, so might be hard to remember...
The text was updated successfully, but these errors were encountered: