I've updated this issue to describe a larger issue I discovered while seeking support on a smaller issue. Basically, the gist is the commerce registration module calls a few functions around submission of the checkout pane that work outside of the Field API's expected process, which results in messed up entity structures and a bad $form_state.
Immediate form state issues on submission
commerce_registration_information_checkout_form() mishandles entity forms in the way it adds them to the checkout pane. By disregarding the $form_state when calling regisration_form() and by trying to adjust the fields' parents with a foreach loop after calling field_attach_form(), the $form_state array gets mangled and field elements are rendered with duplicate instance ID's.
This breaks AJAX callbacks and breaks field types that require a properly constructed $form_state array. I originally found this when the Inline Form Entity module was choking on missing data from the $form_state array.
There is a patch below to address part of this issue (#5)
Malformed entity after submission callbacks
Then, the submit handler calls commerce_registration_entity_update_fields(), which takes $form_state values and puts them directly into the entity object for saving as-is. Many field modules will alter the structure of the data in field_attach_submit(), but these alterations are lost when commerce_registration calls commerce_registration_entity_update_fields().
Original issue:
When I am using an Entity reference field on the Registration entity with the Inline Entity Form widget, the Inline Entity Form widget fails because values are missing in the
$form_state, even though they are clearly present in the$formthat is rendered onto the page.Requirements of Inline Entity Form field widget
When the Inline Entity Form field widget prints on the page, it uses a
valuetyped form element to pass information to the form about the "bundle" that needs to be created inline. (It also uses a'select'type if the widget is configured to handle a variety of bundles, but the problem is the same in either case)The Inline Entity Form uses a button to submit this information to an ajax callback.
Missing values in IEF callback
The problem is that for some reason the
$form_state['values']array is missing the "bundle" value. It'sNULL.
I've tried changing the element to be a "hidden" value, a "textfield" and a few others, but no matter what I do, the value is missing from the$form_state['values']array in the submit callback for the IEF Form.The result of the missing value is this error in the AJAX callback:
EntityMalformedException: Missing bundle property on entity of type node. in entity_extract_ids()Source of the problem
I've tried using this exact field on several different entity types and have had no issues. I used Devel to
dpm()the form and I can see that the "bundle" form element is definitely in the form, and definitely has the right value in it.The problem is in the
commerce_registration_information_checkout_form(). The element "bundle" value is lost somehow in the way that form is built. I can't tell if it's in the validation, the submit handler or the way simply the form is built, but something about that form prevents the value from being passed to the$form_stateon submit, even though it is in the$form.
Other related issues
#1787046: Setting #field_parents for the conditional fields module
#1831562: Unlimited file fields on registration entities cause registration_save errors
#1778464: SQL error when saving registration with multi-value entity reference or field collection field
#1803568: Multiple calls to field_attach_form() causes conflicts
#1835852: Multiple same-entity add/edit forms on one page results in duplicate DOM Id's
Comments
Comment #0.0
tmsimont commentedremoving unnecessary header
Comment #0.1
tmsimont commentedclarification about "dropping the value" vs. "not allowing it into the form_state array"
Comment #1
tmsimont commentedI updated the issue to be more clear about an important distinction:
The IEF form values are correctly rendered into the
$formarray on page load. They are just missing from the$form_state['values']array on submit callback. It's almost like the$form_stateis somehow built before the IEF form gets added to the$form.Comment #2
tmsimont commentedI ran a few tests and found that this has to be related to the
commerce_registration_information_checkout_form()function, because the registration form works great on standard registration entities on ER's default/registration/%registration/editpath (which usesregistration_form()directly)Comment #3
tmsimont commentedAround line 86 of commerce_registration.checkout_pane.inc there is some odd use of the
registration_form()function that seems to be the source of this problem:The rest of the function then "glues" together parts of the registration form with the checkout pane form. If i drop out all of the glue and pass the real
$form_stateintoregistration_form(), then my$form_statepasses the right data through to the IEF callbacks and my error goes away.Can anyone explain why there is a need to add the registration form is such a strange way (with use of a phony
$tmp_form_stateand odd corrections of$form['#parents'], etc?Comment #4
tmsimont commentedI'm changing the title to more accurately describe this issue.
The problem arises with IEF because IEF needs the form #parents to be constructed properly in order to function. The #parents array is glued to together in
commerce_registration_information_checkout_form()in a way that breaks the$form_statestructure.This reconstruction of the parents hack can easily be avoided with a small alteration to the code described above.
Rather than going back into the form after calling
field_attach_form()and trying to alter the parents configured there, the parents can be set on the$form[$prodkey][$prodkey . '-reg-' . $i]element before callingfield_attach_form().This is how the documentation on field_attach_form() says how to alter the parents in such situations:
Unfortunately there are some other issues with the way the registration entity form is attached. The instance ID's on individual entity fields are not unique. This causes failures in AJAX callbacks and in the Conditional Fields module when there is more than 1 registration form on the pane.
Attached is a patch to illustrate the correct use of
field_attach_form()and the$form['#parents']param, but I think this needs more work... more patches to come..Comment #4.0
tmsimont commentedmore clarification and formatting
Comment #4.1
tmsimont commentedupdating to cover broader problem, rather than specific symptom
Comment #5
tmsimont commentedReattaching last patch for review. After some testing on my end I can see that this does not noticeably break a basic commerce registration process. Conditional fields and IEF fields, however, are still not fixed.
More work on the way..
Comment #7
jpontani commentedApplied the patch to dev, ce8fe72.
Comment #8
tmsimont commentedThanks jpontani
I found another issue related to this process that was causing more problems for me with use of IEF:
commerce_registration_entity_update_fields()will take form state values and assume they are ready for direct insertion to the entity object:The problem is that some fields, like IEF, will execute code in
field_attach_submit()that will manipulate the form_state, modify the entity object and prepare the field for saving.The problem is that after this might happen,
commerce_registration_entity_update_fields()bulldozes the construction of the entity's field by overwriting it with the exact structure of the$form_statearray.I have to call it a day today, but I will pick it up here and patch tomorrow.
Comment #8.0
tmsimont commentedadded related issue to summary
Comment #8.1
tmsimont commentedfound another related issue
Comment #8.2
tmsimont commentededited to be more about found deeper issues, less about original issue
Comment #9
tmsimont commentedComment #9.0
tmsimont commentedfound another related issue
Comment #10
tmsimont commentedok, so simply removing
commerce_registration_entity_update_fields()does the trick just fine.I've tested this fields with unlimited values (text, file upload and entity reference) and it works great.
I imagine
commerce_registration_entity_update_fields()used to be necessary before the last patch I put up that prevents$form_statefrom coming through all messed up. As far as I can tell the "update fields" function is longer necessary. I need to test results on multiple registrations at once -- i was seeing "Instance ID" problems on individual fields earlier.Attached is an updated patch.
Comment #12
tmsimont commentedcrap there are some issues here i don't think this patch aligns with the most recent 7.x-2.x version -- re-rolling...
Comment #13
tmsimont commentedre-rolled, tested with unlimited values on individual text, file upload and entity reference fields. Still need to fix possible issues with multiple registrations per page.
Comment #14
tmsimont commentedso far so good on multiple registrations with a variety unlimited field types. IEF is acting strange on the AJAX callback, but that might actually turn out to be an issue with IEF
Comment #15
tmsimont commentedI'm still having issues on multiple registrations at once: both the conditional fields module and the IEF module don't do well with the second registration form on one page. The IEF module uses the field instance ID on to identify an area for JS to manipulate. I think conditional fields does the same thing. The problem is that neither module expects to find the entity add/edit form loaded twice onto one page. I wonder which would make more sense:
@jpontani, any thoughts?
Comment #16
tmsimont commentednevermind!
I think the issues I'm still seeing are in fact IEF/Conditional Fields issue. If #13 is committed I think this issue can be closed.
IEF/Conditional Fields issues:
#1803568: Multiple calls to field_attach_form() causes conflicts
#1740074: Fix IEF to work when IEF is nested into another IEF
#1835852: Multiple same-entity add/edit forms on one page results in duplicate DOM Id's
Comment #16.0
tmsimont commentedpatch referenced addresses part of the issue, not the whole issue
Comment #17
tmsimont commentedcrap this breaks the default values of "This registration is for:" when using the "Go Back" button
Comment #18
tmsimont commentednevermind -- that's an unrelated issue. The current 7.x-2.x branch does not work when using "Go Back" even without the mod above. I still stand by #13!
Comment #19
tmsimont commented@jpontani -- did #13 get committed? I'm trying to re-roll this to the most recent version of 7.x-2.x and it looks like it did.
however, there is still a documentation reference to the removed function -- updated patch addresses this
Comment #20
jpontani commentedYea, sorry I thought I had posted saying that. About to do another commit with the removed documentation reference. Going to mark this issue as fixed as the appropriate fixes to CR have been applied, just need to wait on the patch to Conditional Fields/IEF.
Comment #21.0
(not verified) commentedmore related issues