This initially fixes an innocent @todo added in #635202: Remove #process pattern from option widgets:
// Check if there is a module hook for the option values, otherwise try
// list_allowed_values() for an options list.
// @todo This should be turned into a hook_options_allowed_values(), exposed
// by options.module.
$function = $field['module'] . '_allowed_values';
$options = function_exists($function) ? $function($field) : (array) list_allowed_values($field);
a) hook_allowed_values() doesn't officially exist - it's not even clear to what module it is attached.
b) there's no sense in defaulting to a hardcoded list_allowed_values() function. That's a remnant from CCK where 'allowed values' were handled at the level of content.module. list.module is list.module, it doesn't intend to be anything generic.
Now, things are never simple with optionwidgets, we should know by now.
c) We need to ensure proper sanitization. Currently nothing is sanitized (create a taxo term named foo <script>alert('win !');</script> bar and use the 'radios / checkboxes' widget)
d) different widgets need different sanitization on the options. Selects need strip_tags(), checkboxes need filter_xss(). Having the values come in pre-sanitized in CCK has always been an incredibly fragile mess trying to account for the various sources (list of allowed nodes for noderef, sometimes provided by Views, ugh)
e) optionwidgets in CCK D6 support optgroups in selects (been added after Field API was committed in D7)
What the patch does:
- Officially declares and documents hook_options_list(). Field type modules that want to have option widgets need to implement that hook. How they collect that list is their own business. Most of the time, this will map to some internal function of their own, that they also use for their own processing: list_allowed_values(), taxonomy_allowed_values()... But those are functions, not hook implementations, hook_allowed_values() doesn't exist, that was CCK.
- This hook should return unsanitized data. 1-level deep grouping is supported (will be flattened if the widget is not a select)
- Internally, option widgets formalizes a series of massaging processes to apply to the collected options, depending on the widget and the field settings: sanitize, strip tags, add a 'none' choice, replace 0 with '_0'... Supporting optgroups means there's some recursion in there.
Comes with tests for the sanitization and for the optgroup support.
Fixes a sec hole, thus marking critical.
| Comment | File | Size | Author |
|---|---|---|---|
| #23 | field_hook_options_list-639466-22.patch | 49.91 KB | yched |
| #21 | field_hook_options_list-639466-20.patch | 42.86 KB | yched |
| #20 | field_hook_options_list-639466-20.patch | 42.76 KB | yched |
| #18 | field_hook_options_list-639466-18.patch | 42.84 KB | yched |
| #16 | field_hook_options_list-639466-16.patch | 42.78 KB | yched |
Comments
Comment #1
yched commentedAdditionally, this needs an additional helper module for tests, so there's some files moved and created.
I'll provide a cvs summary once this is RTBC.
Comment #2
yched commentedWow, forgot to run the tests one last time after a late refactor. That one should be better.
Comment #3
yched commentedStupid me. *That* one.
Comment #5
yched commentedShould be there now.
Comment #7
yched commentedLOL at 'devel' in setup().
Comment #8
sunsubscribing
Comment #9
yched commentedBump. #622614: Consider reducing the number of field types depends on this.
Comment #10
yched commentedRerolled after #635094: Unify "language neutral" language codes
Comment #11
yched commentedRerolled. How can we get reviews on this ? ;-)
Comment #12
yched commentedEasier tracking.
Comment #13
sunMissing PHPDoc.
Double spaces and missing trailing comma.
I don't understand how this hook is invoked and why it doesn't need to check for the $field being currently processed. The PHPDoc doesn't explain either. Is this hook required to implement for option type fields? Can multiple modules respond?
oh I also always totally forget to revert such changes ;)
This review is powered by Dreditor.
Comment #14
yched commented1) and 2) Well the patch just moves the existing list.test file as is in a new dir, but fair enough. Fixed.
3) Well, this code is just sample code to demonstrate the expected result format. Of course an actual implementation would most probably build the list out of the $field properties and settings. Updated the PHPdoc and actual sample a bit.
4) forehead slap
Additionally, removed options.module knowing about 'List' field types. list.module enables the widgets for its field types through hook_field_widget_info_alter(), like any other field type (taxonomy, noderef/userref in contrib, other unknown contrib field types)
More accurately: it needs to be implemented by field type modules that want to use 'option widgets' for their field types. Tried to make that clearer in the PHPdoc.
Nope, in this approach only the module defining the field type. It might be seen as a limitation: *any* 3rd party code can theoretically use hook_field_widget_info_alter() to add optionwidgets to any field type, but only the field type module can implement hook_options_list() to specify the options to display.
If this is a blocker, we might change that by moving to a callback approach and adding an entry in option.module's hook_field_widget_info():
'option_callbacks' => array('field_type_1' => 'callback_1', field_type_2' => callback_2', ...)When you add option widgets to a field type in hook_field_widget_info_alter(), you also update the 'options_callbacks' property accordingly.
This entry cannot be a 'setting', though, because we want the callback to be constant for a given field type, and not something you can customize when you setup a given $instance (like $instance['widget']['settings']['option_callbacks'] = 'mymodule_foo').
A custom, unofficial entry in option.module's hook_field_widget_info() should work, even though a bit edgy.
Feedback welcome, but I'll focus on #438570-61: Field API conversion leads to lots of expensive function calls for now.
Comment #15
sunThanks!
Comment #16
yched commentedRerolled after the formatter API changes.
CVS instructions for the patch:
Comment #17
dries commentedShould be 'types', not 'Types'.
Any specific reason we're using 'card_1' and not 'card'? Ditto for 'instance_1'.
Should be 'test', not 'Test'.
Comment #18
yched commented1) Right. Was just fixed in #658358: inconsistencies in field type tests 'Group', it should not be reintroduced here...
2) That part of the code is just moved around to a different directory. I think originally this was copied from options.test, which has 'card_1' and 'card_2' for 'cardinality 1' and '2'. No real meaning here, reworked the names.
3) Fixed.
Back to RTBC after tests come back green.
Comment #20
yched commentedBad reroll. That one should come out better.
Comment #21
yched commentedTry again. In #20 I forgot to edit the patch for newly created files.
Comment #22
yched commentedGreen, but 16 passes in OptionsWidgetsTestCase is not enough, this should be 176.
+ ListFieldUI tests don't even run.
Sigh. Will try to investigate later today.
Comment #23
yched commentedLet's try this one.
Comment #24
yched commentedBetter. Back to RTBC.
Comment #25
dries commentedThis looks like a good step forward. Committed to CVS HEAD. Another critical issue bites the dust.