I wanted to make a select field that listed the counties of the UK grouped in to regions. I used the 'Allowed values function' field within the select list settings to specify a custom function uk_county_list() to build the allowed values.

function uk_county_list() {
  return array(
    'North West' => array(
      'Cheshire' => 'Cheshire',
      'Cumbria' => 'Cumbria',
      'Greater Manchester' => 'Greater Manchester',
      'Isle of Man' => 'Isle of Man',
      'Lancashire' => 'Lancashire',
      'Merseyside' => 'Merseyside',
    ),
   ...

This produced the desired select field with optgroups:

<select class="form-select required" name="field_job_county[und]" id="edit-field-job-county-und">
  <optgroup label="North West">
    <option value="Cheshire">Cheshire</option>
    <option value="Cumbria">Cumbria</option>
    <option selected="selected" value="Greater Manchester">Greater Manchester</option>
    <option value="Isle of Man">Isle of Man</option>
    <option value="Lancashire">Lancashire</option>
    <option value="Merseyside">Merseyside</option>
  </optgroup>
  <optgroup label="North East">
    <option value="County Durham">County Durham</option>
    <option value="Northumberland">Northumberland</option>
    ...

However, when a user selects a county on the node edit/creation screen, they get an 'illegal value' error on that field every time, regardless of the value selected.

I believe the problem lies with the list_field_validate() module within list.module of the core field module. The list of allowed_values is returned as a two-dimensional array but this function seems to assume that the list is always flat and in the case of the a select list with optgroups, the validate always fails.

My hack was to flatten the $allowed_values array before validating but there may be a cleaner way of doing it:

function list_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
  $allowed_values = options_array_flatten(list_allowed_values($field)); // Flatten the array to accommodate optgroups
  foreach ($items as $delta => $item) {
    if (!empty($item['value'])) {
      if (!empty($allowed_values) && !isset($allowed_values[$item['value']])) {
        $errors[$field['field_name']][$langcode][$delta][] = array(
          'error' => 'list_illegal_value',
          'message' => t('%name: illegal value.', array('%name' => t($instance['label']))),
        );
      }
    }
  }
}

D7 backport: #1530486: [D7] list_field_validate() doesn't seem to accommodate select lists with <optgroup>

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

bleen’s picture

Version: 7.x-dev » 8.x-dev
Status: Active » Needs review
FileSize
838 bytes

I dont think there is anything hackey about your approach at all...

This bug should be fixed first (or concurrently) in d8. Here is a patch for d8 that uses your approach.

cweagans’s picture

Issue tags: +Needs backport to D7
chimericdream’s picture

Assigned: Unassigned » chimericdream
chimericdream’s picture

Assigned: chimericdream » Unassigned

Sorry. Didn't mean to assign this to myself. Removing assignment.

Simon Georges’s picture

ToRum’s picture

Patch in #1 (https://drupal.org/files/1180992-optgroup-validation.patch) works fine for me (Drupal 7). Can it be added to a following release of Drupal 7?

ToRum’s picture

Update: patch #1 became obsolete as source code has changed in the meanwhile. The following updated patch works fine for me.

Status: Needs review » Needs work

The last submitted patch, 1180992-optgroup-validation-7.patch, failed testing.

ToRum’s picture

Update: patch in #7 is the backport for D7. That's why the test failed.

bleen’s picture

Status: Needs work » Needs review
FileSize
844 bytes

ToRum, the D8 version needs to go in before the D7 version will be considered...

This is a re-roll for D8

bleen’s picture

...ToRum. The best thing you can do to keep the wheels moving so this can get into D7 would be to test out the patch in #10 on D8 and (assuming all is well) mark this issue as RTBC.

Status: Needs review » Needs work

The last submitted patch, 1180992-optgroup-validation.patch, failed testing.

ToRum’s picture

Patch #10 failed because options_array_flatten() does not exist and passed parameters of list_allowed_values() were wrong. New patch for D8 attached.

ToRum’s picture

Status: Needs work » Needs review
ToRum’s picture

Patch #13 contained a duplicate line (for $allowed_values = ...). It is removed in this new version.

bleen’s picture

Issue tags: +Needs tests

This probably needs a quick test

bleen’s picture

Status: Needs review » Needs work
cristiroma’s picture

Re-roll the code work with the current HEAD. Still needs the tests implemented.

cristiroma’s picture

Status: Needs work » Needs review
FileSize
2.04 KB
2.78 KB

Changes:
1. Added a test case that checks the function options_array_flatten
2. Fixed code phpdoc

Status: Needs review » Needs work

The last submitted patch, 1180992-optgroup-validation-19.patch, failed testing.

Anonymous’s picture

Assigned: Unassigned »

re-rolling

YesCT’s picture

Assigned: » Unassigned
Issue summary: View changes
Issue tags: +Needs reroll

feel free to jump in to do the reroll anytime. https://drupal.org/contributor-tasks/reroll

saki007ster’s picture

Assigned: Unassigned » saki007ster
saki007ster’s picture

Status: Needs work » Needs review
FileSize
643.74 KB

re-rolling this patch.

saki007ster’s picture

Sorry , earlier patch was my stupidity. Replaced it with new one.

saki007ster’s picture

Assigned: saki007ster » Unassigned
prateek479’s picture

FileSize
109.53 KB

Select list working fine

martin107’s picture

Issue tags: -Needs reroll

patch currently applies.

jorgegc’s picture

Re-rolling patch in #25

jorgegc’s picture

Just looked for the +Needs reroll tag and couldn't find it... I guess I've just rerolled a patch that applies LOL, my bad!

jhedstrom’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll

Even though this patch still applies, it needs a reroll keeping this change in mind.

ravi.khetri’s picture

Status: Needs work » Needs review
FileSize
3.88 KB

Rerolled.

dcam’s picture

Issue tags: -Needs reroll

#33 applies to HEAD. Removing the "Needs reroll" tag.

jOksanen’s picture

Works for me.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

drumm’s picture

Issue tags: +affects drupal.org

(forgot the tag)

dww’s picture

Title: list_field_validate() doesn't seem to accommodate select lists with <optgroup> » [D8] list_field_validate() doesn't seem to accommodate select lists with <optgroup>

Not clear why this and #1530486: [D7] list_field_validate() doesn't seem to accommodate select lists with <optgroup> are separate issues. Seems like that one is duplicate. But for now, at least prefixing them with core major version so we can tell them apart.

drumm’s picture

I believe the convention for core backports is a separate issue nowadays. This lets the issue credits be awarded for the versions it is resolved in as soon as it is fixed there. May be other benefits too.

xjm’s picture

Yep, we file a separate issue for backport to D7. The D7 and D8 maintainers agreed on that a few years back because the D8 patch usually does not even remotely resemble the D7 patch, so juggling them both on the same issue was very confusing. All they have to do nowadays is wait for commit on the D8 issue to ensure there's no regressions on upgrade.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

catch’s picture

Version: 8.9.x-dev » 9.2.x-dev
Status: Needs review » Closed (outdated)
Issue tags: +Bug Smash Initiative

hook_list_validate() no longer exists. The equivalent code is in ListItemBase::getPossibleValues(), which handles optgroups. Marking outdated.