Problem/Motivation
The "Webform navigation settings" fieldset added to a webform's third-party settings form (webformnavigation_webform_third_party_settings_form_alter()) includes two checkboxes, forward_navigation and prevent_next_validation, that are saved directly as webform third-party settings. Neither checkbox has an #element_validate callback, so Form API submits their raw values as-is — the string '1' when checked, and either '0' or nothing at all when unchecked, depending on the browser/JS state handling — rather than a real boolean. Over time this lets non-boolean values ('1'/'0' strings, or missing/NULL) get written into third_party_settings.webformnavigation.* on saved webform config entities.
This is compounded by the module's config schema (config/schema/webformnavigation.schema.yml) only declaring a type for forward_navigation — prevent_next_validation, the additional_error_message setting, and the webform_navigation handler's debug setting have no schema entries at all. Because prevent_next_validation was never declared as boolean in schema, Drupal's config schema validation had no way to flag the bad values being stored for it in the first place, so the problem could go unnoticed.
Concretely, this means:
$webform->getThirdPartySetting('webformnavigation', 'prevent_next_validation')can return a string like'1'instead ofTRUE, which breaks strict (===) boolean comparisons anywhere calling code assumes a real boolean.drush config:export/config:importround-trips can produce spurious diffs once schema coverage is added, since existing saved config doesn't match thebooleantype.- Config schema validation (
drush config:statuswith strict schema checking, orConfigSchemaCheckerin tests) cannot catch bad data forprevent_next_validationtoday because there's no schema rule to check it against.
Steps to reproduce
- Install Webform + Webform Navigation 2.0.4.
- Edit a webform's third-party settings, check "Allow forward navigation" and/or "Prevent validation when the user presses the Next Page button", and save.
- Inspect the saved config (
drush config:get webform.webform.<id> third_party_settings.webformnavigation, or via the UI's config export tab). - The saved values for
forward_navigation/prevent_next_validationare the raw submitted strings (e.g.'1'), not real YAML booleans (true).
Proposed resolution
-
Add an
#element_validatecallback to both checkboxes inwebformnavigation_webform_third_party_settings_form_alter()that casts the submitted value to a real boolean before it's stored:function webformnavigation_element_validate_boolean(array &$element, FormStateInterface $form_state) { $form_state->setValueForElement($element, (bool) $element['#value']); }...and reference it from both the
forward_navigationandprevent_next_validationcheckbox definitions via'#element_validate' => ['webformnavigation_element_validate_boolean']. -
Complete
config/schema/webformnavigation.schema.ymlwith entries forprevent_next_validation(boolean),additional_error_message(label), and thewebform.handler.webform_navigationmapping'sdebugsetting (boolean), so schema validation actually covers everything the module writes. -
Add an update hook that walks existing webform config entities and casts any non-boolean
forward_navigation/prevent_next_validationvalues already on disk to real booleans, so sites upgrading don't carry forward corrupted data from before the fix. Using\Drupal\Core\Config\Entity\ConfigEntityUpdaterkeeps this batch-safe for sites with many webforms:function webformnavigation_update_8002(&$sandbox) { \Drupal::classResolver(\Drupal\Core\Config\Entity\ConfigEntityUpdater::class) ->update($sandbox, 'webform', function (\Drupal\webform\WebformInterface $webform): bool { $changed = FALSE; foreach (['forward_navigation', 'prevent_next_validation'] as $key) { $value = $webform->getThirdPartySetting('webformnavigation', $key); if ($value !== NULL && !is_bool($value)) { $webform->setThirdPartySetting('webformnavigation', $key, (bool) $value); $changed = TRUE; } } return $changed; }); }
Remaining tasks
- We have a working patch against 2.0.4 implementing all three pieces above; will attach it here (or open an MR, whichever the maintainers prefer).
- No automated test coverage currently exercises this scenario; a kernel test asserting that
forward_navigation/prevent_next_validationround-trip as real booleans after form submission, and that the update hook normalizes pre-existing bad data, would be worth adding. - Needs review from a maintainer.
Data model changes
Sites upgrading to the fixed version may have existing webform config entities with non-boolean values stored under third_party_settings.webformnavigation.forward_navigation and/or third_party_settings.webformnavigation.prevent_next_validation (e.g. '1'/'0' strings instead of true/false). The new update hook (webformnavigation_update_8002() in the proposed patch) walks all webform config entities and normalizes any non-boolean value for these two keys to a real boolean, so existing sites don't fail config schema validation once the schema is completed.
Issue fork webformnavigation-3612604
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
rymcveighComment #4
rymcveighThe code in the Merge Request is now ready for review.
Comment #6
rymcveighI tested this on a production site. It is working.
Comment #7
rymcveigh