Problem/Motivation
Currently there is no standardized method to know for a RenderElement if any child element has an error.
It becomes additionally difficult to get to know this for grouping elements like: details, fieldsets, fieldgroups and containers that have no direct children in the sense as registered in the #array_parents property of those children.
To clarify: it is possible to add elements to a group by providing a #group property (e.g. fieldsetgroup][fieldset][container) without being a descendent of this group in the array structure. The final renderable array will be assembled later in \Drupal\Core\Render\Element\RenderElement->preRenderGroup().
This issue is Major because it is a blocker for the Major issue: #2346773: Details form element should open when there are errors on child elements.
Additionally this can help stabilizing Inline Form Errors, a lot of form elements and widgets could use this extra info to get a good user experience. See #2504847: [meta] Roadmap for stabilizing Inline Form Errors module (IFE) for related issues.
Proposed resolution
Add a RenderElement property which stores all errors of their children and children children's, and so on. Including for grouping elements that have no children in the sense of #parents, but visually do have errors.
Proposed new property: #children_errors, see 'Data Model Changes'.
Remaining tasks
Create patch with basic functionalityDone- Create a test which makes sure that the #children_errors is populated.
User interface changes
None. But this opens the way for a lot of user interface changes and bug fixes. See:
- #2346773: Details form element should open when there are errors on child elements
- #2504847: [meta] Roadmap for stabilizing Inline Form Errors module (IFE)
API changes
None.
Data model changes
Addition of a RenderElement property: #children_errors.
It should contain errors of all children errors keyed by #array_parents of the original problematic RenderElement/Field. Childrens don't need to be direct descendants, but traverse up the tree.
| Comment | File | Size | Author |
|---|---|---|---|
| #44 | interdiff-2754977-37-44.txt | 4.63 KB | dmsmidt |
| #44 | 2754977-44-render_element_children_errors_EXTRA_TEST_ONLY.patch | 2.47 KB | dmsmidt |
| #44 | 2754977-44-render_element_children_errors.patch | 12.38 KB | dmsmidt |
| #32 | 2754977-32-render_element_children_errors.patch | 11.27 KB | dmsmidt |
| #32 | interdiff-2754977-30-32.txt | 3.1 KB | dmsmidt |
Comments
Comment #2
dmsmidtComment #3
dmsmidtAnd the first patch, doing as advertised in the proposed solution.
Comment #4
dmsmidtComment #5
dmsmidtComment #6
dmsmidtComment #8
dmsmidtWill dive into those test failures, woohoo! But still, any insight greatly appreciated.
Comment #9
dmsmidt(sorry wrong interdiff extension)
Comment #11
dmsmidtReal patch is green, woot!
Comment #12
skaughtusing the combined patch from 2346773#57 and errorstyle.module (github) this does pass a manual test run. Details open with children error in Safari 9.0.3
Comment #13
mgiffordOk, so can we remove the "Needs tests" tag now? I'm a bit confused by https://www.drupal.org/files/issues/interdiff-2754977-3-9-render_element...
What's the easiest way to test this? Can we get some screenshots up?
Comment #14
dmsmidt@mgifford, testing this can be done in combination with the patch in #2346773. That combination shows how this patch can help other issues move on. Otherwise you'll need to debug the $form structure to see the effect.
We still need a test for this patch.
The change in the interdiff you mention makes sure all changes are to the original $form, while $form_state never needs to be changed in this method.
Todo: Children errors of elements are now keyed by #parents, however we should key them by #array_parents, since we use it in the literal form structure and are not dealing with values in $form_state.
Comment #15
mohit_aghera commented@dmsmidt
Fixing @Todo point and adding #array_parent as key.
Comment #17
dmsmidt@mohit_aghera, thank! Could you look into tests as well?
Comment #19
lokapujyaWhats this "Undefined index: #array_parents"?
Comment #20
dmsmidt@lokapujya, I proposed using #array_parents instead of #parents as key in comment #14. Maybe mohit_aghera in #15 changed it without checking if it was possible, so someone should (re)do that and look into the test.
Comment #22
getekid commentedHello,
I worked a bit on it during DrupalCon Dublin 2016. I checked the Test fail messages and added the '#array_parents' key to the tests. As I'm quite new to the difference between the #parents/#array_parrents, I simply copy-pasted the values. In case for test purposes other values should be used instead, please let me know.
I also tried to write a test by asserting the 'children_errors' property on a parent element on the form (in FormErrorHandlerTest under the module's test class) but I keep having "Undefined index" errors.
Hope it helps anyways
Comment #23
mohit_aghera commentedChanging status to trigger test bot
Comment #24
tim.plunkettSee #279246-3: FAPI #array_parents is not documented
Comment #25
dmsmidt@tim, ah that one again, a must read for everyone working with forms. I clarified #14 a bit and updated the description to reflect this.
@getekid, nice to see you working on this again. Hopefully I can review soon. For next time could you also provide an interdiff? It makes our live easier.
Comment #26
dmsmidtHappy to see that the tests work again, thanks @getekid!
I created an interdiff, to see what you changed.
One nit, which should be removed in the next patch.Next up: creating a test for the added functionality.
Update: @param was oke.
Comment #27
dmsmidtComment #28
ndf commentedIs it possible to typehint $form and $elements with interfaces?
What do you think of
chainElement...?or
setElementErrorsOnForm($form, ...)Don't get it yet with $elements, $child and $form
Can we document the end-result? What will be the structure of the final array?
BTW Only read the code, did not tested yet with your other patches. Stay tuned :)
Comment #29
dmsmidt@ndf
1. We can't type
$formand$elementsbecause the formBuilder just returns an array. Not an typed object.2. I don't get your second point about
chainElement/setElementErrorsOnForm.3. The extra
$formparameter is needed to keep a reference to the original $form structure. Without it we have a recursive function (traversing up the form tree) that only knows about the current element, and nothing about the complete form structure. We need the complete form structure to populate the grouping elements (like the details form element) with info about the errors of their children, see:$group_element = NestedArray::getValue($form, $parents);. Because those children aren't"real children" in the nested form array structure.
I'll make the code more readable.
Comment #30
dmsmidtHere is a hopefully more understandable patch. Test still needed.
Comment #31
dmsmidtComment #32
dmsmidtTests added! All should be complete now, please review.
(Minor fix for a screw up when rewriting part of the patch in #30).
Comment #33
dmsmidtRemoving 'needs tests' tag.
Comment #34
marcvangendSome minor remarks on the (otherwise excellent) inline docs:
I'm afraid this line of documentation is hard to understand.
The "in the case the method isn't called by itself" confused me, I had to read it 5 times before I got it. I suggest a more direct instruction: "An associative array containing the part of the form structure that will be processed while traversing up the tree. For recursion only; leave empty when calling this method."
Coming up: actual testing (test results will be in #2346773: Details form element should open when there are errors on child elements because they must be tested together).
Comment #35
marcvangendI found a problem, posted it in #2346773-77: Details form element should open when there are errors on child elements, but the problem turns out to be in this patch here. New patch coming up.
Comment #36
dmsmidtThanks, can you add the case also to the automated test?
Comment #37
marcvangendHere's the patch with just the bugfix, I'll see what I can do for the tests.
Comment #38
marcvangendRe #37, I added a test for this in #2346773-83: Details form element should open when there are errors on child elements. It really was a case of different form elements interacting with each other because of a mistake in the code; I'm not sure if / how that could be covered by the unit tests.
Comment #39
tim.plunkettAll tests for this change need to be in this issue, we can't rely on a follow-up for that.
Comment #40
marcvangendI agree, but afaic the separation of those two related issues doesn't help anyway. Can't we merge the issues and fix it in one go?
Comment #41
dmsmidt@marcvangend, this issue is a bit more generic and could potentially be used to fix other IFE issues. I think we are far enough progressed to finish this issue and quickly solve the follow-up later.
We need to enhance/add to the tests provided in this issue's patch to cover the changes in #37.
So a patch without the fix and including the improved test to show that it fails, and a patch with the improved test and the fix of #37 to show that it is fixed.
Comment #42
xjmMarking NW for #41. Thanks all!
As a reminder, this issue is a blocker for Inline Form Errors being marked stable, because it blocks a required fix for that module. We should aim to make progress on this issue before February 1 since it must change stable core code, and therefore can't be changed in patch releases the way that IFE itself can. See #2504847: [meta] Roadmap for stabilizing Inline Form Errors module (IFE) for background.
Comment #43
dmsmidtComment #44
dmsmidt@marcvangend found that I made an error, that consequentially leaked children errors to grouping elements without children errors. Hereby a patch with improved tests that cover this scenario (test only, should fail).
Furthermore I improved the inline docs as suggested.
Comment #46
dmsmidtWoop, green (note to self: upload test only patch first).
Comment #47
chr.fritschLooks really good from my point of view
Comment #49
pierremarcel commentedReviewed it and applied. Also applied patch from https://www.drupal.org/node/2346773#comment-11897477 and so far it's working as expected. More details on https://www.drupal.org/node/2346773#comment-11897477
Comment #50
mgiffordThe bot should test in in 8.4. I wasn't able to retest it from #44 so setting this to Needs review to see if that helps bump things. No concerns with the RTBC.
Comment #51
kattekrab commentedSo that test only patch SHOULD fail. Patch itself is green. Back to RTBC!
Comment #52
dmsmidtManually added 8.4.x tests, also pass!
Comment #53
tim.plunkettThis is the only weird part of the patch that jumps out at me, when would Element::children ever return something that wouldn't pass this check? But it's part of the original code anyway, so not a big deal.
Everything else looks good to me, I feel comfortable signing off on this as a subsystem maintainer.
Thanks for the incredible work and persistence @dmsmidt, and everyone else who pushed this along!
Comment #54
pierremarcel commentedYes as I mentioned, I can assure it's working as well, I'll try to add a bit more comment to here too. I tested it last Saturday for #SprintWeekend. I tested it manually.
I also went ahead and tested issue https://www.drupal.org/node/2346773 which is postponed by this current issue. I also can ensure that patch has worked and so far we didn't see anything weird in the code. It seems we are getting closer.
Thanks guys for the hard work.
Comment #55
alexpottI tried to re-arrange the code to not change the signature of the protected method and to keep it simple - but recursive methods are never simple :). The approach in the patch looks okay and has the sign-off from a sub system maintainer.
Committed and pushed 01ac763 to 8.4.x and 8d8bb34 to 8.3.x. Thanks!
Some comment fixes on commit. Reviewed with @dmsmidt on IRC.