Closed (fixed)
Project:
Drupal core
Version:
7.x-dev
Component:
forms system
Priority:
Normal
Category:
Bug report
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
5 Sep 2010 at 05:24 UTC
Updated:
7 Jul 2012 at 17:31 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #1
sunThis patch introduces new #type 'machine_name'.
Motivation: It is our intention to make more APIs and modules implement machine-readable names, since that is required to make stored data exportable (e.g., to build Features). However, it is quite complex to implement a proper machine-readable name form element handling in modules currently. Thus, if we want to change the situation, then we have to make it easy.
This patch makes it trivial. And at the same time, it introduces a standard way to handle machine names.
A minimum implementation looks this way:
The second form element is entirely sufficient to get a fully-fledged "Machine name" form element in the form, which uses the 'name' field as source. That is, because the #type 'machine_name' element is expanded into the following:
First hunk in this patch is a stop-gap variant of #763376: Not validated form values appear in $form_state, just to make this patch possible.
Comment #3
sunThe test failure for Date type configuration is a very nice example of even Drupal core getting machine names wrong. There's not even a single form validation handler for a date type's machine name currently. Which turns this issue into a bug report.
Comment #5
sunwow, I didn't expect to reveal so many bugs with this issue.
Comment #6
tobiasbNow my version:
different to suns patch:
%max -> <em class="placeholder">27</em>Comment #7
tobiasbComment #8
sunThanks, but your patch contained other, unrelated changes.
Comment #9
jbrown commentedThis is a really great idea!
Comment #10
sunRemoved debug code, clarified comments.
I think we should update all #process and #after_build callbacks in core accordingly, so that developers do not find deprecated examples.
Comment #12
sunComment #13
sun#903730: Missing drupal_alter() for text formats and filters depends on this issue now.
Comment #14
moshe weitzman commentedSubscribe. I'll have more to say later. Looks nice so far.
Comment #15
sunActually, I hoped for a RTBC already. :) Happy to discuss any details or questions though, so please don't hesitate to post 'em!
Comment #16
fagoInteresting - making providing machine names simpler would be definitely useful.
I just had a short look at the patch:
* The naming of
#machine_name_existsdoesn't make clear it's a callback when reading the FAPI structure.Question:
Why is that necessary? The process / after_build callbacks are run on the cached copy again nevertheless.
Comment #17
sun- re: #machine_name_exists: possible, though #process and #after_build and #pre_render don't make that clear either - any better suggestion?
- form_process_machine_name() is invoked for the #type 'machine_name' form element, but needs to add a #field_suffix to another element in the form (given with #machine_name_source). Therefore, it needs to be able to not only access the complete form, but also be able to alter the complete form. This may sound dangerous, but it's not really different to a regular hook_form_alter(), which is also by reference. I always wanted to do this, but wasn't able to - it seems like our Form API improvements for D7 finally allow to do it.
chx already asked me whether this isn't the same as #type 'filter_format'. I say it is not, because #type 'filter_format' has a unique presumption: The value and format may only ever exist together and form a compound user interface widget that can be understood as a single widget. That is not the case for machine names, as they are optional and only happen to use another field as source, but technically, they could even work without a source field. Furthermore, the inheritance of form element properties in filter_process_format() is really really ugly, error-prone, and not alterable in any way - you simply cannot set certain properties for the injected child elements.
Therefore, the idea is to have a #type 'machine_name' element, which can be loosely coupled with a source element, but otherwise fully customized to your needs, if required.
Comment #18
q0rban commentedSubscribe
Comment #19
bleen commentedvery cool ... subscribing
Comment #20
sunRe-rolled for #763376: Not validated form values appear in $form_state
Any other feedback?
Comment #21
sunComment #22
sunRe-rolled against HEAD.
Comment #24
sunSorry, forgot the new .js.
Comment #25
moshe weitzman commentedany reason these are not in hook_element_info()?
are we worried about multiple machine name elements on same page. seems like their js settings would collide. this is a minor issue and not a new problem so should be addressed elsewhere (if needed).
once tests pass, this is rtbc IMO.
Comment #26
sunThanks for the review, moshe!
1) I had the defaults in system_element_info() at first, but then figured that you most likely cannot alter those defaults anyway, and so it would make more sense to have them within the context of the #process and the #element_validate functions, where they are actually used and also documented. Additionally, I wasn't sure whether we'd keep the properties separate, or merge them into a single #machine_name property that would be an associative array of settings, perhaps even using the identical key names as the JS behavior. I've no strong preference myself, so happy to change it in any way. If you think that putting them into hook_element_info() would be better, since more consistent, then we can do that. Though not sure whether you still prefer it, given this reasoning. Just let me know.
2) I personally don't see a need for that, and it would only be an issue, if you'd have multiple machine name elements that try to use the same source element, so quite an edge-case. Also agreed on the separate issue, if needed.
3) Tests pass already :)
Comment #27
moshe weitzman commentedI do think it is more consistent to consolidate to a single #machine_name key with various properties. This would match how #cache and #attached look. I also think it is consistent to move to system_element_info(). Thanks.
Comment #28
sunTurned #machine_name into an array, as suggested. However, I realized that form constructors would override/unset all other defaults in #machine_name, when defining them in hook_element_info(), so I kept the default values in the #process and added a code comment to explain why they are there.
Comment #30
tobiasb#28: drupal.machine.28.patch queued for re-testing.
Comment #31
moshe weitzman commentedLooks good to me and to the bot.
To summarize, we have a bug where Date Type (whatever that is) has no machine name validation at all. Rather than add yet another custom implementation, sun made a generic #machine_name FAPI element and converted menu, vocab, etc. to use it. Thats a terrific bug fix in my book. It fixes the core bug and prevents many more in Contrib.
@tha_sun - a different issue related to element defaults is now at #914792: Custom element properties entirely override default element info properties
Comment #32
mlncn commented++ Fantastic developer experience improvement and all-around code rationalization.
Comment #33
andypostThis could help with #606598: Human readable image-style names
Comment #34
sunRe-rolled against HEAD.
Comment #35
webchickI see nothing in this issue that justifies API changes of this nature 12 months after API freeze. Sounds like a great feature for D8 though.
Comment #36
moshe weitzman commented@webchick - i posted a summary in #31 where i try to answer that question. i can't tell if you missed it or you disagree.
Comment #37
webchickI read it. It's very difficult for me to justify a 45K patch that changes multiple parts of the system when the actual fix for the bug that was accidentally found as a result of adding this feature 12 months after API freeze is like a line or two of code.
If Dries thinks otherwise, that's fine, but it's a no from me.
Comment #38
sunmmm, can we revisit this decision? I've really worked hard to ensure to retain full API compatibility, so this patch does not break anything at all, while fixing a major bug in Drupal core that is too easily repeated in contributed modules. The patch removes more lines than it adds, and the removed lines are partially bogus, which only testifies that machine names are too hard to implement. (if not even Drupal core with hundreds of eyeballs reviewing gets it right, who will?)
In any case, I guess Dries won't notice if the version isn't 7.x.
Comment #39
alan d. commented+1 for this feature. And a back port to 6 even if core doesn't use it ;)
Comment #40
webchickI'm also curious why this couldn't be implemented in contrib, with hook_element_info()? Then Drupal 6 really could use it.
Comment #41
sun@webchick: Currently, form #process callbacks are needlessly limited to perform changes on the passed in $element only. The essential change that allows this advanced #process callback to actually do its job is the ability to alter other form elements in $form_state['complete form'] by reference. This may sound anxious, but there is really no difference to hook_form_alter() and form element validation handlers, which are also altering things by reference already.
Effectively, by removing the needless limitation, this advanced #process callback is able to append a #field_suffix to the form element that is used as the source for the machine name (i.e., a placeholder for the "Machine name: foo_bar [edit]" markup):
So after figuring this out and making it work, all existing machine name form elements throughout core have been standardized and simplified to use this new #type, allowing us to remove plenty of duplicate code. While doing so, I recognized that Date format types in HEAD do not implement any kind of machine name validation, and that's effectively what this patch solves: Don't make developers have to re-implement a complex construct of a textfield that requires lots of carefully crafted validation routines, a weird JavaScript settings definition, and for which there is not even a single valid code example throughout entire Drupal core.
I would not have worked on this patch for D7 if I would not see an urgent need to fix this issue. There are too many other critical and major issues on my plate.
Comment #42
sunIf you need yet another proof that this patch is badly needed: #292790: Menu machine-name validation error (The menu name can't be longer than 27 characters)
It is not clear to me why we prefer to waste lots of developer time instead of fixing the cause.
Comment #43
rickvug commentedThe case as to why this patch is needed was made well in #41 and elsewhere in this issue. Can we get this in and move on to #903730: Missing drupal_alter() for text formats and filters before we're stuck with these problems for another release?
Comment #44
webchickWe have a period of the release, called "code thaw" to put in new features like this. That period lasted 18 months and ended last September. There was not then, and isn't now, an exception to code thaw to build exportable support into Drupal 7 core. We are currently actively trying to get Drupal 7.0 out the door, not keep stuffing more stuff in to an already over-stuffed release.
sun's argument for this patch seems to be "security," which is the only reason I'm leaving it for Dries to make a call on, and not immediately returning it to D8 where it actually belongs. The arguments for any other exportable-related patches are on incredibly shaky ground from my POV. If there are patches in the queue at this point that don't directly lead to Drupal 7.0 shipping faster and more bug-free, then they're all D8 as far as I'm concerned. Hopefully those concerned about core exportable support can rally quickly during the D8 code thaw to ensure it's fixed for good then.
So, no. We can't "get this in" and "move on" to other exportable issues. Unless you and Dries have some secret pact I don't know about that exempts exportable-related features from feature freeze.
Comment #45
rickvug commented@webchick - I apologize if my comment came off as trying to skirt the rules of code freeze. I understand that freeze was ages ago. However, various other issues dealing with inconsistencies and "WTF" DX issues have been committed. I hope that an exception is made here based on the value of this fix relative to the extent of the changes. Contrib is hurting because core does not handle machine names in a consistent manner.
Comment #46
sunDo you realize that this patch fixes 2 major bugs in core and therefore massively helps to get D7 out of the door? Do you realize that this patch prevents hundreds of contributed modules to introduce the same bugs and mistakes that are currently in core?
If the answer to both is "yes", then I fail to see the logic in not committing this patch.
@rickvug: Other patches are never a reason to commit a patch.
Comment #47
nedjoYes, it's very late for API changes, and this issue and the accompanying #903730: Missing drupal_alter() for text formats and filters have the potential to further drag on D7 readiness. However useful , these changes should be considered only if there is a compelling case that D7 would be effectively broken without them.
Here's the case as I understand it.
Text formats are a key element of Drupal's security system. They are also one of the most complex, difficult, and error-prone areas of site configuration, particularly if a WYSIWYG editor is in use. Current stats for Fckeditor, Ckeditor, WYIWYG, and Drupal as a whole suggest that more than half of all D6 sites (~178,000) have a WYSIWYG editor in use. WYSIWYG editors generate a range of tags, some of which require specific attributes, some of which are not allowed by the drupal core tag filter. Configuring a rich text editor to work with an input format is difficult and frustrating, even with specialized contrib tools like WYSIWYG Filter.
As a result, an unknown but probably large number of site admins throw up their hands and abandon tag filtering altogether, allowing full HTML for the simple reason that they can't figure out how to get WYSIWYG to work without it. I know that I personally have encountered multiple sites with anonymous comment input on which full html had been set as the default input format purely because site admins couldn't figure out how to configure a filter for rich text editing.
The only effective way to address this issue is going to be through exportables. By enabling text formats to be exportable, we can provide polished configurations that achieve a high level of functionality without sacrificing security.
The Features module is the leading solution for distributing exportables, but input formats are not supported. Actually, the code is there in Features, but by design it is inactive. The reason is that input formats lack a machine name. This lack means not only that text formats themselves can't effectively be exported. Equally important, it means that associated data - WYSIWYG configurations, filter configurations, default formats per role, etc. - are keyed by format ID in numerous places throughout core and contrib.
There have been numerous efforts to solve this issue in contrib. None could be called successful. A recent article demoed WYSIWYG as a Feature, but a closer examination of the patch used leads to a tangled patchwork of half solutions.
Only a fix in core can provide a clean D7 solution to this significant security concern.
As a side benefit, exportable filter formats will help address a serious usability barrier, by making it possible to provide richly featured WYSIWYG and other text format-based Features.
And as for why this patch is so late coming, the reason is plain: sun was plenty busy with other contributions, and - despite the plethora of commentators - no one else had the clarity of thought to solve this issue at its source.
Does all this add up to sufficient basis for a code freeze exception? It's hard for me to judge. I am convinced, though, that once again sun has provided the combination of insight and excellent coding needed to fully address a glaring need in core.
Personally, I can commit to reviewing any follow up patches that may be required.
[Edited to finish an incomplete sentence.]
Comment #48
sunAdditionally, this patch along with the patch in #903730: Missing drupal_alter() for text formats and filters helps to unblock and do the remaining necessary follow-up changes for the critical issue #914458: Remove the format delete reassignment "feature"
Comment #49
sun#34: drupal.machine.34.patch queued for re-testing.
Comment #51
sunAlthough badly needed, this is D8 material according to the rules (I had to learn today). It may be backported at a later point in time (though that's unlikely).
Someone needs to create a bug report to fix the currently not validated date type format machine names.
Comment #52
mlncn commentedThis kick to 8.x is hard to watch. I hope Drupal adopts a philosophy of making code rationalization and API additions to major versions even after release, and we will see this - and other work, especially sun's, in 7.
sun++
Comment #54
nedjoRe my comments in #47, today I posted an attempt at the best workaround available currently for D6/D7 to address WYSIWYG feature: Debut WYSIWYG. It's a good illustration of what we need to fix, but I guess it also demonstrates that, with many hacks and limitations, we can do something in the meantime.
[edited to correct the link]
Comment #55
sun@webchick: Can we at least commit the Form API improvement of (optionally) allowing #process callbacks to alter elements (and therefore the complete form) by reference? Without that adjustment, it's close to impossible to implement this functionality from contrib. It does not change any functionality or API in Drupal core or any contributed module, and merely recommends #process callbacks to process elements by reference, but they are still able to return a new copy of $element, like they are now. That's all I'm asking for.
Comment #56
webchickYeah, I'd be willing to take a look at what a patch like that looks like. That sounds like a more under-the-hood change, as opposed to an API change that would affect module developers directly.
Comment #57
sunThanks for offering to review it.
Technically, only the changes for form_builder() are required, but the patch updates all #process and #after_build callbacks throughout core to make sure that developers only see the recommended way when searching for example callbacks.
Comment #59
sunSorry, removed one too many change.
Comment #60
sunIf this patch would have a chance, then I would add some tests to confirm and ensure that "old-school" #process and #after_build callbacks still work in the expected way (which I already tested manually). Alternatively, we could simply revert just any of the existing callbacks (e.g., form_process_password_confirm), which would lead to the testbot not being able to install, if it wouldn't work as expected.
Comment #61
mlncn commentedLooks good. Everything works, date type machine name doesn't let me use all caps, etc. Ready for webchick, at least!
Comment #62
sunHold on. I just realized that we don't have to change #process and #after_build callbacks at all. It is sufficient to keep the by-reference assignment change of 'complete form' internal to form_builder(), which recursively invokes itself.
So the only API change that remains is:
Compared to how many existing bugs this patch fixes, and how many bugs it will prevent in core and contrib, and that the outlined API change only affects extreme edge-cases (as a module would actually have to rely on the form element #type, or expecting the JS behavior in system.js), and considering that any module that is affected by this API change will actually be happy about it in the first place (because it is implementing a machine name), and lastly, since existing machine name form elements will still work (only the JS is missing; but will not even break), it would be ridiculous to not do this for D7.
Comment #63
dagmarComment #64
moshe weitzman commentedOK, this one even more focused on the bug fix and standardizing these elements for Contrib. I much agree with Sun's case. Please take another look.
Comment #65
dixon_subscribing
Comment #66
fagoThe new patch looks better. Now there are effectively no FAPI changes, but a small improvement. Similarly the patch helps a lot when introducing machine names. As I've done some machine name form elements already for D7 I very much agree that *properly* doing this machine name form element is way too complicated now.
Hm, without reading the docs I'd assume this is the pattern for valid chars. But it is the pattern for finding non valid characters.
Looking up the docs, they are wrong:
Anyway, what about using
[a-z][a-z0-9_]*as default pattern for valid machine names? That way we'd ensure they start with a letter and disallow solely numeric machine names. First of numeric machine names don't make much sense. Secondly this allows for using a "magic" $identifier variable, which may contain either the machine name or the id + writing a loader function that just checks withis_numeric()whether to load by numeric id or machine name. Having this in place, any references to the entity can be easily changed to machine names or just kept by ids.Comment #67
sunThanks for reviewing, fago!
I think I've fixed the docs. But the additional point you are raising is valid, too. To make it obvious for everyone:
patternshould actually be renamed toantipatternor similar. The regular expression is primarily used by the JavaScript to find all characters that need to be transliterated.[anti]patternis also used by form_validate_machine_name() to validate whether a machine name is correct. Technically, that's an entirely different operation and the currentpatternis not really sufficient. So fago just found even more issues with the current machine name validations throughout core:___).[a-z][a-z0-9]+). AFAIK, none of the core machine names has problems with a starting digit, but I think it is a valid use-case. Note that such an implementation would have to additionally implement server-side validators for the corresponding *_presave() operations, so as to prevent programmed saves from storing invalid machine names. Overall, that's out of scope for this issue.antipattern(used for client-side transliteration) andpattern(used for server-side machine name value validation). Better name suggestions are highly welcome.Comment #68
sunImplemented additional validation to ensure that a machine name does not only consist of the replacement token. Additionally fixed a few descriptions and error messages.
Comment #70
sunComment #71
sunMassively improved the code comments.
I'd like to propose to go with this path as is. Right now, I don't know of any code that tries to use a machine name directly in PHP function names, and even if such code exists, it's probably a good idea to use a MODULE_MACHINENAME() function name pattern anyway. Which means that point 2) of #67 does not have to be done for D7.
Comment #72
moshe weitzman commentedSummary is in #62
Comment #73
fagoAgreed that
[a-z][a-z0-9]*is out of scope.As said, I'd assume without reading the docs 'pattern' describes the regex for valid machine names. Perhaps better rename it to 'replace_pattern' to make this more clear?
Comment #74
Crell commented"pattern" is the name of the HTML5 attribute that does the same thing (validate based on a regex), so I think it's fine to use the same name (especially if we are able to later expand that same property for more HTML5 goodness later).
Comment #75
fagoHTML 5 pattern does exactly what one would assume for "pattern", it states the pattern that the element has to fulfill. See here.
But the #machine_name pattern specifies the characters to remove/replace. Perhaps we can rewrite the JS to work like the HTML 5 pattern? That would be certainly the best DX and potentially allow use to make use of the mentioned HTML5 goodness later.
Comment #76
sunI don't think that this documentation/comment change should hold up this patch. The current documentation for 'pattern' sufficiently describes its current usage and intention. The similarity with HTML5's 'pattern' attribute might be there, but in the end, there's no test and no code that proves that the current 'pattern' would actually work as HTML5 attribute. Figuring this out can happily left for http://drupal.org/project/html5 and other contributed attempts.
Comment #77
Crell commentedHm. fago is correct; I misread the patch when I was just skimming the issue. Given that it is a post-process pattern rather than a validation pattern it may be wise to name it as such to avoid collision later (with the html5 project and similar efforts that would likely want to add such a property if they can).
Comment #78
sunChanged 'pattern' into 'replace_pattern'. After closer inspection of the HTML5 docs about the 'pattern' attribute, it's definitely not the same -- rather what fago proposed above; i.e., a regular expression that precisely matches valid user input. 'replace_pattern' is more or less the opposite: A regular expression to match one or more subsequent characters that are *not* valid and need to be transliterated, resp., replaced with the replacement token.
Since I had to touch menu_edit_menu() for this once again, I tried to review and ensure that the applied changes in there are correct, but I was once again highly confused by the logic that is going on in there. So I additionally cleaned that code up, so as to ensure that resulting logic is correct.
Comment #79
sunAdditionally fixed the #maxlength mismatch for vocabulary machine names. The existing form defined 255, but the form validation handler manually limited to 21. Weird.
Comment #80
dries commentedThis patch looks good.
The other files use dashes instead of underscores. For example
misc/vertical-tabs.js.Comment #81
sunRenamed machine_name.js into machine-name.js.
Comment #82
fagoPatch looks good to me too. 'replace_pattern' is much better and tells me what it is about really, thanks.
Comment #83
jgraham commentedrecap of #62:
1. appears to be done
2. This appears to be solved for menu. AFAICT the remaining work is deferred to other tickets waiting on this patch.
3. appears to be done
It appears that #75 is the only potential remaining issue, is that correct?
If so I think the rework from #78 avoids any ambiguity and should address the concerns presented by crell in #77. This appears to be a reasonable interim solution and if a better solution is desired we appropriately defer to contrib to flesh out the details.
Comment #84
sun#75 has been resolved in #78. Unless you mean the suggested usage of HTML5 'pattern', which is definitely left to contrib and will not be tackled here.
Comment #85
sun#81: drupal.machine.81.patch queued for re-testing.
Comment #86
dries commentedThis patch fixes a bug, but is also a last minute clean-up that will help with better distribution support. We discussed this in #933846: Better distro support.
Committed to CVS HEAD. Thanks!
Comment #87
klausiNice, how do we get that to http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.... ?
Comment #88
rfayThis broke HEAD - machine-name.js doesn't seem to have gotten committed.
Comment #89
webchickOops. :P Committed that to HEAD.
A system module hunk flew by too. Hope that didn't break anything.
Comment #90
claar commentedResetting status back due to #87
Comment #91
jgraham commentedJust chatted with rfay in IRC and I am working on a patch for the documentation issues. Will post for feedback.
Comment #92
jgraham commentedAdjustments to forms_reference_api.html to address #87
Attached is a diff and the complete html file please review.
Comment #94
rfay@jgraham, the patch is pretty hard to review. Could you just put the relevant updated HTML (the main content part) into this issue? Alternately, you could put the html file somewhere and give us a link to it.
Thanks!
-Randy
Comment #95
claar commented@rfay: Here's a copy-paste from the zip file in #92 -- hope it helps.
@jgraham: I checked the below "Properties" against the above table and found some discrepancies:
machine_name
Description: Provides a unique machine-readable name.
By default provides a machine name that is validated such that it contains only alphanumeric and '_'. All characters not meeting this criteria are replaced with '_'. The validation routines also fail if the element value is comprised solely of '_'.
Non-standard form element properties:
Properties: #access, #after_build, #array_parents, #attached, #description, #disabled,#element_validate, #parents,#post_render, #prefix,#pre_render, #process,#required, #states,#suffix, #theme, #theme_wrappers,#title, #tree,#type
Usage example (menu.admin.inc):
Comment #96
jgraham commented@claar: thanks for making that more readable to everyone.
Adjusted as per claar's comments in #95
1. The table was an omission.
2. I meant #type and #weight
3. fixed
Comment #98
sunNow we have some duplicate code. Please revert.
Comment #99
webchickWell. That explains why I had extra hunks in that commit I did just before hopping on a phone call. :D Thanks!
Committed #98 to HEAD. Back to needs review for docs?
Comment #100
sunSome definitions were not correct. Most are actually identical to #type textfield, so I fixed that.
Thanks for reporting, reviewing, and testing! Committed to HEAD.
This change will be visible on api.drupal.org within the next 24 hours.
Comment #102
traviscarden commentedRe-tagging.