Closed (fixed)
Project:
Drupal core
Version:
7.x-dev
Component:
forms system
Priority:
Normal
Category:
Bug report
Assigned:
Issue tags:
Reporter:
Created:
30 Mar 2010 at 11:31 UTC
Updated:
3 Jan 2014 at 01:08 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #1
sun#448132: Comment ACL inconsistency has been marked as duplicate of this issue.
Comment #3
sundrupal.base-form-id.0.patch queued for re-testing.
Comment #4
sunGot it. Fixed those failures.
Comment #5
sunCleaned up that weird $form['#node_edit_form'] condition construct used throughout core. Only the indentation of those functions changed, nothing else.
Comment #7
sunAlrighty, finally figured it out. This #builder_function weirdness will drive me insane one day, likely to happen before we release.
Comment #9
yched commented:-/.
Note, though, that those lines in node_form_submit_build_node() :
were there in D6 (the function was used for the preview workflow), and were just left as is when Field API introduced the infamous #builder_function. I can't say I ever really understood their purpose...
Comment #10
sunI'd never blame you or anyone else who worked on Fields in core! I just wanted to repeat my doubt that we can release D7 with that weirdness ;)
Let's see what the bot thinks of this one. Not touching the logic in node_form() at all.
Comment #12
sunVERY interesting findings for node_form_submit_build_node(). Documented in-code.
Comment #13
sunThis kick-started off simple, but should be in the critical task list now.
Comment #14
yched commentedre sun #10 - yeah sorry if I sounded defensive, I wasn't ;-).
Comment #15
effulgentsia commentedSubscribing.
Comment #16
andypostMYMODULE_node_form_submit() is not documented so why this code invoke it?
Comment #17
sunIt's not MYMODULE_node_form_submit(), but TYPE_node_form_submit().
That is, because the requested $form_id is 'poll_node_form'. Therefore, Form API automatically looks up poll_node_form_validate() and poll_node_form_submit(). This behavior is not changed in this patch and exists at least since D5. But, yes, I was equally not totally aware of that. :)
This patch just automates what had to be done manually before: A shared form constructor had to explicitly define a shared SHAREDFORMID_validate() and SHAREDFORMID_submit() handler, as Form API only looks for handlers explicitly matching the $form_id.
To work around a similar "problem", some genius people thought that it would be a neat idea to introduce a
$form['#node_edit_form']for node_form()'s case, to allow hook_form_alter() implementations of other modules to identify whether a form is a node_form(). In reality, this problem exists for each and every form that uses a shared form constructor callback.Note that #735800: node form triggers form level submit functions on button level submits, without validation also deals with node_form() and should go in first, as it likely simplifies this patch.
Comment #18
andypost@sun I just cares about node-types with names like 'image-gallery' and modules probably could have name TYPE but not define a node type so it lead to unpredictable results.
Comment #19
sun@andypost: TYPE in TYPE_node_form refers to the internal machine name of a node type. Those machine names can only contain [a-z0-9_]. This part of Node API is not changed or touched in any way by this patch, and it works that way since D4.7.x.
Comment #20
sunRe-rolled against HEAD.
Comment #21
andypost#20: drupal.base-form-id.20.patch queued for re-testing.
Comment #23
effulgentsia commentedAs per #17:
Comment #24
effulgentsia commented#735800: node form triggers form level submit functions on button level submits, without validation landed. Can we get a re-roll of #20?
Comment #25
sunLet's see.
Comment #27
TyraelTLK commented#25: drupal.base-form-id.25.patch queued for re-testing.
What have I... I'm sorry. Delete this post.
Comment #29
sunComment #30
sun#29: drupal.base-form-id.29.patch queued for re-testing.
Comment #31
sunDon't let it fool you.
Comment #32
sun#29: drupal.base-form-id.29.patch queued for re-testing.
Comment #34
sunBack into business.
Comment #36
sunI'm a bit stuck here. Only the tests are failing, manual testing (with + without JS) works flawlessly. Don't have a clue why that is.
Also, two rather unrelated issues incorporated now (perhaps ideally 2 split out):
1) Poll choice weights are not taken into account in the poll node form.
2) Poll choices in node form contain a table column "Vote count" (empty), even if the current user is not allowed to enter any.
Comment #38
philbar commentedtag
Comment #39
sunAbsolutely major.
Poll module fixes have been extracted into #445736: Poll does not respect weight in Preview or More button
Comment #40
sunGotcha.
As identified in the @todo in this patch, node_form() requires some more adjustments for D7. :-|
Regardless of that, this looks quite ready to me.
Comment #41
sunDe-derailing this issue.
Removed changes covered in #445736: Poll does not respect weight in Preview or More button
Comment #42
sunRemoved changes covered in #799998: "post comments" permission does not work without "access comments"
Comment #43
sunThe only remaining issue with this patch - which I'd like to move into a separate issue though - is the @todo outlined here: hook_form() implementations of Node API are unable to add #validate and #submit handlers to the main actions/buttons of the node form. Technically, the Node API is invalid - hook_form() would have to get $form + $form_state passed, and the default form elements defined in node_form() should already be contained in $form when hook_form() is invoked.
40 critical left. Go review some!
Comment #44
sunAforementioned separate issue already exists and is #241364: $form_state not passed to hook_validate()/hook_node_validate(), and not passed by reference to hook_form()
Comment #45
sunThis patch looks RTBC to me.
Comment #46
sun#42: drupal.base-form-id.42.patch queued for re-testing.
Comment #48
philbar commentedShouldn't this be priority "Critical" since it is a beta blocker?
Comment #49
sunI don't care about the priority. This patch needs technical code reviews and has to be committed either way.
Comment #50
webchickThis looks like a nice code clean-up, but don't see why it should hold up beta. Removing tag.
Comment #51
sunWell, problem space rather being: This is an API change. A required one, as I have at least one contributed module that isn't really able to map its data to now node type specific comment forms. I'm sure there are other modules facing this problem, too.
But anyway, this merely needs final reviews.
@effulgentsia, @fago, @frando, @chx, any chance?
Comment #52
fagoGenerally, a really nice clean-up + fix!
I know we use that already for node forms, but this is a dumb way of prefixing. It should be comment_form_$type, only that way we can preserve name clashes. Ideally we should fix that for node forms too. mymodule_node_form is reserved for mymodule, not for the node module.
Sounds good, but shouldn't we better use $form['#submit'][] instead? Perhaps someone managed to already set that.
Then, if we fix #validate and #submit to take the base form id into account, we also need to fix #theme.
Comment #53
effulgentsia commentedThis is a re-roll only. Trying to get a passing patch, then will review.
Comment #54
sunre fago #52:
1) Totally agreed on the node form's module namespace violation. That should have been fixed a long time ago already. For D7, I don't know if it's possible to rename Node type form IDs from
$type_node_formtonode_form_$type, so as to be able to make Comment form IDs consistent, i.e.,comment_form_$type. IMHO, we (finally) should. Not even sure whether that actually breaks anything (except of custom modules or themes, perhaps, which should be rare at this stage anyway). I hope that webchick can enlighten us with a yay or nay.2) Sure thing, no-brainer.
3) I somehow thought that #theme would already take care for it, but it's perfectly possible that I may be mistaken.
Thanks for re-rolling, effulgentsia!
Incorporated 2) + 3).
Comment #55
effulgentsia commentedDoes this have any dependencies it's waiting on, or can it be reviewed on its own at this point?
Comment #56
ohnobinki commented+1
Comment #57
sunExcept for the additional node form id namespace clean-up discussed in #52 and #54, this patch is completely self-contained. I.e., the only optional change at this point is the renaming of sub-form ids, so we don't introduce the same namespace violation from Node module in Comment module.
Comment #58
effulgentsia commentedOk, I'll try to review this soon. I would be absolutely +1 for trying to do #798062: Rename TYPE_node_form to node_form_TYPE in D7, but I think that'll be a tough sell to webchick. Regardless, I think we should do comment_TYPE_form and not TYPE_comment_form. TYPE_node_form is wrong. We may have to live with it for one more Drupal version, but we should not feel pressured to propagate the wrongness.
Comment #59
effulgentsia commentedAlso, I just happened to find #317424: Dynamic form ids for hook_forms, and moved it to D8, but wanted to link to it from here, to hopefully get that one onto people's radar for when D8 work begins.
Comment #60
sunwebchick bumped #798062: Rename TYPE_node_form to node_form_TYPE to D8.
Therefore, all we can do is to at least don't make Comment module introduce yet another namespace violation.
Comment #62
sunD'oh, now I get it. Added docs for the default #theme assignment in drupal_build_form().
Comment #64
sun#62: drupal.base-form-id.62.patch queued for re-testing.
Comment #66
effulgentsia commentedThis is really, really nice! The following nits are pretty minor.
This is the hunk responsible for the test failure. There are form ids for which there are no base form ids, that do not have a theme hook. Or, you can have form ids with a base form id, and neither one has a theme hook. We need to keep the call to theme_get_registry(), or else add a new theme function like theme_form_contents(), or theme_element(), whose implementation is
return drupal_render_children($element)to use as a fallback.We don't really need this, do we? When theme() is passed an array, that array should be complete, so the caller can have full control over fallback order.
comment_form__TYPE is clever for automatic theme hook fallback, except unnecessary if we set $form['#theme'] to an array, as we already are in this patch. While I like it for consistency with template file naming (i.e., comment-form--article.tpl.php being essentially the same concept as what already exists for node--article.tpl.php), I'm concerned about introducing function names like comment_form__article_validate() or hook_form_comment_form__article_alter(). Maybe in D8, we can standardize on a convention to end the entire function name with __SPECIFIER, but if in D7, we have suffixes like validate(), submit(), and alter(), then perhaps we should keep to single underscore? I lean slightly to comment_article_form(), since I think of 'form' as a kind of suffix (convention only; no magic meaning like validate, submit, and alter), and one that helps avoid name collision should an administrator decide to use 'validate', 'submit', or 'alter' as a node type name. I.e., is comment_form_validate() the form builder for the the comment form on a 'validate' content type, or is it the validate handler for the base form id? I think a form id of 'comment_validate_form' steers clear of collision danger, even if it's a little ugly. Having written that, I really want D8 to move closer to real OOP: I think we're pushing polymorphism via function name creativity to its breaking point.
This can receive a $form_id too, so let's document that. While hook_form_FORM_ID_alter() receives $form_id as well, that's never useful so its okay to omit that from the hook definition, but for this one, I could see a use-case for wanting $form_id.
Powered by Dreditor.
Comment #67
effulgentsia commentedDo we need to introduce this BC break (i.e., a requirement for node modules to explicitly add their submit handler instead of having it be auto-discovered)? Can we instead have node_form() do it?
Yay, poll module, for once again providing a use-case for catching BC breaks :)
Powered by Dreditor.
Comment #68
sun1) Dang! And I already looked forward to kill yet another early theme initialization. I'll revert the changes, but keep the comment.
2) Since we revert 1), we can revert that, too. But when reverting, we should move it to a separate issue, because I think that we should support the combination of both, forced suggestions and theme function name patterns.
3) If we don't go with a double underscore, yes, then we have to decide on one of the more problematic names:
-
comment_form_TYPEbreaks _validate and _submit and any other auto-suggested suffix.-
comment_TYPE_formpotentially breaks any contributed add-on modules, i.e., whereTYPE == anything && comment_TYPE == module name.-
TYPE_comment_formentirely violates module namespaces, just like Node module.I don't think that
comment_form__TYPEis really problematic. Instead, it rather adds consistency, and it entirely avoids all aforementioned namespace issues.In the end, I'd rather use the double underscore instead of introducing any namespace problems. Even if that means that comment_form form_ids may change in D8 or later on. That's still better than potentially violating other/existing namespaces now.
I disagree that usage of OOP resolves anything here. OOP gets extremely ugly when trying to apply Drupal's modularity. The same likely applies to PHP's new namespaces. Instead, for D8 or beyond, we want to introduce double underscores as a new standard to cleanly separate parts in function names; e.g., MODULE__EXPOSINGMODULE__HOOK(), or similar. TBD.
4) Good catch on the missing $form_id argument in the docs. Will add that.
5) While we could try to automatically add hook_TYPE_node_form_submit() handlers, I'm not sure whether we should. Technically, Node API only contains hook_form(), hook_validate(), and hook_submit(). If we would add auto-suggestion support for hook_TYPE_node_form_submit(), then I'd ask you why there is no auto-suggestion for hook_TYPE_node_form_validate() - and that never was auto-suggested. So this issue boils down to the question why Poll module implements hook_TYPE_node_form_submit() instead of hook_submit() in the first place. I'm highly opposed to add any auto-suggestion magic for regular form validation/submit handlers.
Thoughts?
Comment #69
sunIncorporating #66 - #68.
Comment #70
effulgentsia commentedThanks. I agree with #68.3.
I'm still not sure about #68.5. Just to be clear, we're not talking about hooks, we're talking about FORM_ID_submit() and BASE_FORM_ID_submit(). These are auto-suggested by default for all forms with the former taking precedence over the latter, unless the form builder function explicitly sets its own #validate and #submit. Now, in HEAD, node_form() does not set $form['#submit'], and therefore, poll_node_form_submit gets auto-discovered because $form_id = 'poll_node_form'. This patch adds
$form['#submit'] = array()to node_form(), because you want to stop form.inc from auto-setting it to node_form_submit should $form_id . '_submit' not be there. But, why not have it to do$form['#submit'] = function_exists($form_id . '_submit') ? array($form_id . '_submit') : array()instead? Wouldn't that be backwards compatible with HEAD, and remove the need for the poll.module hunk in this patch?I agree that the cognitive disconnect involved in node_form_validate() being the form-level handler, node_form_submit() being a button-level handler, and TYPE_node_form_submit() being a form-level handler is a WTF. But it's what we have, because we didn't manage to remove this legacy WTF from D7. Do we really want to open that can of worms in this issue though?
Other than above, this looks ready to me. Another review from fago, and perhaps a test, would be nice.
Comment #71
effulgentsia commentedStatus change in #70 wasn't intentional. My suggestion in #70 is just a suggestion, and is open to debate.
Comment #72
sunWhile your explanation in #70 makes sense, I rather meant the following point:
Considering a custom module node type "foo" (like poll)
- you cannot add a foo_node_form_validate() and expect that to be invoked, because node_form() manually sets a #validate, so Form API does not auto-suggest any further validation handlers.
- by coincidence, you were able to just add a foo_node_form_submit(), but only just because node_form() only manually sets a #validate, but no #submit.
Clarified the comments in node_form() based on this discussion.
Note that I'm not totally opposed to manually auto-suggesting a TYPE_node_form_submit handler in node_form(), but well, it just does not make any sense for me, because we'd only auto-suggest #submit, but not #validate.
Btw, in Poll module's case, it's entirely not clear to me why it is implementing TYPE_node_form_submit() in the first place instead of hook_submit() of Node API. Attached patch fixes that.
#WTF
It seems we mistakenly lost Node API's hook_submit() somewhere along the road in D7. http://api.drupal.org/api/function/hook_validate/7 still exists, but hook_submit() is gone.
Only hook_node_submit() remained, but that hook is invoked for all nodes, regardless of node type.
Comment #74
sunok. Discussed this in length with effulgentsia. All lessons learned should be contained in code comments now.
Comment #75
sunFixed that auto-suggested #submit handler logic.
Comment #76
effulgentsia commentedThis looks great. Summary:
1) Review this patch in context, rather than just reading it: most of the +/- signs are just big blocks of code being out-dented via removal of an if condition.
2) There is no BC break in here, except the one that is the purpose of the issue: the automatic calling of hook_form_BASE_FORM_ID_alter() between hook_form_alter() and hook_form_FORM_ID_alter(), and the fallback to BASE_FORM_ID_(submit|validate)() if FORM_ID_(submit|validate)() doesn't exist (and if the form doesn't explicitly set #validate/#submit). While this is a theoretical BC break for modules that implement hook_forms() without wanting this behavior, it is much more likely for this behavior to be desired than undesired. Furthermore, since we have not yet fixed #766146: Support multiple forms with same $form_id on the same page, and may not in D7, this patch allows modules that need multiples instances of the same base form to coexist on a page (e.g., multiple "add to cart" buttons within an e-commerce site) to be implemented much easier than the hacks currently being done in the d6 versions of those modules.
3) The per-type comment form control made possible by this patch is a great use-case to demonstrate the value of the patch, and is an excellent, non-bc-breaking addition to comment.module.
4) The non-bc-breaking replacement of an if statement for #node_edit_form, with a hook_node_form_alter() is a really nice cleanup.
Comment #77
rfaysubscribe
Comment #78
effulgentsia commentedOops. Sorry. I missed this in my #76 review. We need to add
elseif(isset($registry[BASE_FORM_ID]))at the bottom of this. Otherwise, comment-form.tpl.php will no longer be used if it exists in the theme, and that's a regression relative to head. I suggest elseif rather than making #theme an array, since you already have $registry.Powered by Dreditor.
Comment #79
sund'oh, sorry, yes, this was contained earlier already but got lost somehow during the re-rolls since #30 or so. Fixed.
Comment #80
effulgentsia commentedthanks
Comment #81
fagoWow, great improvements! However I don't like the comment_form__TYPE naming thing - function names like comment_form__article_alter() are *really* ugly and a major WTF. From the above examples I like comment_article_form most too as the _form suffix is already common.
For that - I'm not sure about how to deal with the problem of possible conflicting module names with type names, but strictly speeking comment module has already claimed comment_*. Thus module comment_FOO already violates the namespace - so it is up to the module to avoid conflicts with the comment module. Anyway, avoiding that scenario is preferable.
So what about introducing another prefix to the node type for the form ids? We can stick with "comment_form" as base form id and use "comment_node_TYPE_form"?
Comment #82
effulgentsia commented+1. Setting to "needs review" rather than "needs work" in case sun wants to argue against it. But I like this because "comment_node_TYPE" is the bundle name as per comment_entity_info(). Also, I've been thinking that we will need a contrib module that allows comments to be attached to other entity types, not just nodes, so this leaves room for that.
Comment #83
sunHm. Ok, but I disagree with
comment_node_TYPE_form. Sub-IDs of whatever kind should always be suffixes to the original type. Otherwise, there are many more potential namespace conflicts.Therefore, I went with
comment_form_node_TYPE. And made #theme consistent accordingly, except for cases where a regular theme function sub-pattern (e.g., comment__node_TYPE) is required.Comment #84
sunThat was one replacement too much.
Comment #85
effulgentsia commentedThis works for me if it works for fago.
Additionally, since for comments specifically, we have comment__node_TYPE and comment_wrapper__node_TYPE for theme hook names, we could have comment_form() set #theme to 'comment_form__node_TYPE' if that exists in the registry. So we can continue to follow the __ pattern for theme hook names, where that pattern is consistent, while keeping the FAPI functions 'alter', 'validate', 'submit', and the builder callback, all using single underscore.
Comment #86
effulgentsia commentedSorry, one more comment about this. Are we concerned about a site having one node type named "Foo" and another node type named "Foo Submit", such that a function comment_form_node_foo_submit() would run as both the submit handler for the comment form on a 'foo' node, and as the form builder function for the comment form on a 'foo_submit' node? This same problem exists with #79, but can be solved by fago's suggestion in #81 (though maybe #81 comes with its own risks).
Comment #87
sunWe don't care for #86.
Attached patch makes comment form use #theme comment_form__node_TYPE, i.e., the regular theme sub-pattern behavior.
Comment #88
fago@ a) comment_form_node_TYPE vs. b) comment_node_TYPE_form:
1. Resulting function names:
vs
I'd prefer the second as a _form suffix is already commonly used and makes it more clear that associated handlers/hooks deal about a form as it leads to suffixes like form_alter(), form_validate(), form_submit().
2. Possible collisions:
As noted for a) we have the possible collision of type names and builder function for TYPE + TYPE_(submit|validate) - which is rather weird as the user could trigger that just by configuration. For b) the only collision I can see is a possible module called "comment_node_TYPE" implementing the form comment_node_TYPE_form - but with the 'node' prefix I'd say we are on the safe side here.
Consequently I'd prefer comment_node_TYPE_form - thus always keeping _form at the end of the form id. I do not feel very strong about that, but I think it is the better way to go.
Comment #89
sunHonestly, I don't care which variant we choose. @effulgentsia, can you post your feedback and opinion on #88, please? I'll just do what's required to get this in then, if anything.
Comment #90
effulgentsia commentedThis is triggering watchdogs. For now, we need to wrap this in a theme registry check the way form.inc does it. Separately, I'll open an issue for us to register theme implementations of 'comment_form', 'node_form', and other core forms.
Re #88: I don't really care all that much either, and I see pros and cons each way, but I slightly agree with fago. What I don't like about fago's preference is that you lose the ability to grep for 'comment_form' and catch everything, but I agree with fago in thinking about 'form' as a kind of suffix by convention, and it does seem more protected from namespace collision. As long as we're setting #theme the way we are in comment_form(), then ultimately, I'm fine with either.
Comment #91
sunI don't think there should be default implementations for these theme functions. I'd expect no watchdog messages when changing the assignment to an array (containing just one element). I.e., a watchdog would be valid if I want a certain theme function. But when only passing suggestions, then there should be no watchdog messages. If that is not the case yet, then that needs to be fixed in a separate issue, yes.
This is interesting. Normally, we do not set #theme for forms. IIRC, we (I?) skipped this entire problem by removing the #theme definition in node_form() entirely. However, in most cases it makes sense to define theme suggestions - although that shouldn't necessarily mean we have to register and implement a totally useless default theme function.
Comment #92
sunDang. Forgot comment.pages.inc.
Comment #93
sunAny feedback?
Comment #94
effulgentsia commentedSorry. Been short on time. But this is 99% done, so let's finish it. This is still triggering a watchdog, so I don't think it should land as-is. I honestly don't know why theme() triggers watchdogs when a theme key isn't found, especially since drupal_render() is perfectly capable of defaulting to a reasonable implementation (i.e., drupal_render_children()) when theme() returns an empty string. I agree that getting consensus on that is for a separate issue, but my initial feeling is that it should not depend on whether #theme is a string or an array, but rather on whether theme() is called for a render array or not. Alternatively, perhaps allowing #theme to be an array whose last entry is NULL might be a way of indicating that hey, these are all just suggestions, don't panic if none of them are implemented.
Anyway, assuming we don't want to bog down this issue with changes to theme() or drupal_render() let's just add the registry check to comment_form(), or perhaps have drupal_build_form() remove $form['#theme'] if its entries are not implemented, since it already has the registry, so we can avoid polluting comment.module with a theme_get_registry() call. In any case, I think it's better to have some workaround like that until we fix theme() or drupal_render() than it is to try to convince Dries or webchick to commit a patch that is triggering unnecessary watchdogs.
Other than that, I think this patch is ready to go.
Comment #95
webchickThat watchdog stuff was added for DX, to avoid the situation where you call theme('fooo', $bar, $baz); where the theme function is actually called theme_foo() and get absolutely nothing back. See #412730: Theme system should optionally report when a theme key is not found.
Comment #96
sunok, let's fix #theme suggestions in a separate issue. Attached patch implements effulgentsia's suggestion in #94, i.e., checking #theme for all forms, since we have the registry anyway.
Comment #98
sunmeh.
Comment #100
sunWelcome to 100. :)
Comment #101
dries commentedReviewed once more. Committed to CVS HEAD.
Comment #102
sunNeeds documentation in the module upgrade docs.
Comment #103
effulgentsia commentedThanks Dries! Now that all that remains is documentation, no longer "major" (sorry webchick, i can sense you cringing at that).
Comment #104
webchickRAWR! ;)
Comment #105
sunhttp://drupal.org/update/modules/6/7#hook_form_BASE_FORMID_alter
http://drupal.org/update/modules/6/7#comment_form
And also:
http://drupal.org/update/modules/6/7#node_form