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.

Comments

yched’s picture

Additionally, 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.

yched’s picture

StatusFileSize
new39.59 KB

Wow, forgot to run the tests one last time after a late refactor. That one should be better.

yched’s picture

StatusFileSize
new39.61 KB

Stupid me. *That* one.

Status: Needs review » Needs work

The last submitted patch failed testing.

yched’s picture

Status: Needs work » Needs review
StatusFileSize
new39.39 KB

Should be there now.

Status: Needs review » Needs work

The last submitted patch failed testing.

yched’s picture

Status: Needs work » Needs review
StatusFileSize
new39.38 KB

LOL at 'devel' in setup().

sun’s picture

yched’s picture

yched’s picture

yched’s picture

StatusFileSize
new42.11 KB

Rerolled. How can we get reviews on this ? ;-)

yched’s picture

Assigned: Unassigned » yched

Easier tracking.

sun’s picture

Assigned: yched » Unassigned
+++ modules/field/modules/list/tests/list.test	4 Dec 2009 21:05:01 -0000
@@ -0,0 +1,91 @@
+class ListFieldTestCase extends DrupalWebTestCase {

Missing PHPDoc.

+++ modules/field/modules/list/tests/list.test	4 Dec 2009 21:05:01 -0000
@@ -0,0 +1,91 @@
+      'name'  => 'List field',
+      'description'  => "Test the List field type.",
+      'group' => 'Field Types'

Double spaces and missing trailing comma.

+++ modules/field/modules/options/options.api.php	4 Dec 2009 20:55:44 -0000
@@ -0,0 +1,46 @@
+function hook_options_list($field) {
+  // Sample structure.
+  $options = array(
...
+  );
+
+  return $options;
+}

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?

+++ modules/field/modules/options/options.test	4 Dec 2009 20:55:44 -0000
@@ -110,7 +111,7 @@ class OptionsWidgetsTestCase extends Dru
-  function testCheckBoxes() {
+  function atestCheckBoxes() {

@@ -331,12 +367,45 @@ class OptionsWidgetsTestCase extends Dru
-  function testOnOffCheckbox() {
+  function atestOnOffCheckbox() {

oh I also always totally forget to revert such changes ;)

This review is powered by Dreditor.

yched’s picture

StatusFileSize
new43.61 KB

1) 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)

Is this hook required to implement for option type fields?

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.

Can multiple modules respond?

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.

sun’s picture

Status: Needs review » Reviewed & tested by the community

Thanks!

yched’s picture

StatusFileSize
new42.78 KB

Rerolled after the formatter API changes.

CVS instructions for the patch:

cvs rm modules/field/modules/list/list.test
cvs add modules/field/modules/list/tests/list.test
cvs add modules/field/modules/list/tests/list_test.module
cvs add modules/field/modules/list/tests/list_test.info
cvs add modules/field/modules/options/options.api.php
dries’s picture

+++ modules/field/modules/list/tests/list.test	13 Dec 2009 00:57:46 -0000
@@ -0,0 +1,98 @@
+      'group' => 'Field Types',

Should be 'types', not 'Types'.

+++ modules/field/modules/list/tests/list.test	13 Dec 2009 00:57:46 -0000
@@ -0,0 +1,98 @@
+      'field_name' => 'card_1',

Any specific reason we're using 'card_1' and not 'card'? Ditto for 'instance_1'.

+++ modules/field/modules/list/tests/list_test.info	13 Dec 2009 00:57:46 -0000
@@ -0,0 +1,8 @@
+name = "List Test"

Should be 'test', not 'Test'.

yched’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new42.84 KB

1) 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.

Status: Needs review » Needs work

The last submitted patch failed testing.

yched’s picture

Status: Needs work » Needs review
StatusFileSize
new42.76 KB

Bad reroll. That one should come out better.

yched’s picture

StatusFileSize
new42.86 KB

Try again. In #20 I forgot to edit the patch for newly created files.

yched’s picture

Status: Needs review » Needs work

Green, 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.

yched’s picture

Status: Needs work » Needs review
StatusFileSize
new49.91 KB

Let's try this one.

yched’s picture

Status: Needs review » Reviewed & tested by the community

Better. Back to RTBC.

dries’s picture

Status: Reviewed & tested by the community » Fixed

This looks like a good step forward. Committed to CVS HEAD. Another critical issue bites the dust.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.