Problem/Motivation

When forward navigation is enabled, the final submit calls WebformNavigationHelper::validateAllPages() (WebformNavigationHandler::validateForm(), line 188 in 2.0.5). For each accessible wizard page it calls validateSubmission(), which creates a new webform_submission form object and runs FormBuilder::submitForm() (src/WebformNavigationHelper.php:398-428 and :443-477).

Each iteration is therefore a full form build: retrieve, every hook_form_alter() / hook_webform_submission_form_alter(), every handler alterForm(), element processing, then validation. On a webform with N pages, the final submit builds the complete form N + 1 times.

Cost grows with pages × elements × site alters. On a 12-page webform with ~840 elements (~340 #states, many composites), final submits took 100–200 s in production, while ordinary page steps on the same form took ~20 s.

The loop also calls logPageVisit() for every page (:410). That is a SELECT plus a possible INSERT per page, and it records pages as visited that the user never opened.

Steps to reproduce

  1. Create a webform with many wizard pages and elements. Add the Webform Navigation handler with forward navigation enabled.
  2. Add a hook_form_alter() that logs each call.
  3. Fill in the form and click Submit on the last page.
  4. Observe the alter running once per page, plus the normal build and rebuild.

Proposed resolution

Validate the whole submission with a single form build instead of one build per page. Options:

  • A. Build once with an operation that renders every page together (e.g. edit_all), collect the errors, and map each error to its page with the existing getElementPage(). Needs evaluation: edit_all must respect the same element access and #states as the regular wizard, and must not expose admin-only elements.
  • B. Keep per-page validation but skip pages that have been visited and have no logged errors since the last save, so only unknown or failing pages are rebuilt.

In either case, stop logging page visits during validation. A page should only count as visited when the user actually views it.

Remaining tasks

  • Choose an approach, then write an MR.
  • Add a test that the per-page errors are the same as before for a multi-page form with conditional pages.
  • Add a test that alters run a bounded number of times on final submit.

User interface changes

None intended. Error messages and per-page error lists should stay the same.

API changes

validateAllPages() keeps its signature. validateSubmission() is private and may change.

Data model changes

None. Fewer "page visited" rows get written, because visits are no longer logged during validation.

Command icon 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

rymcveigh created an issue. See original summary.

rymcveigh’s picture

Assigned: Unassigned » rymcveigh
Status: Active » Needs review

The MR is ready for testing.

rymcveigh’s picture

Version: 2.0.x-dev » 2.1.x-dev
shubhamgoel’s picture

Hi @rymcveigh,

The MR looks fine to me. Thanks.

rymcveigh’s picture

Status: Needs review » Reviewed & tested by the community

  • rymcveigh committed 93d1376c on 2.1.x
    fix: #3632737 Final submit validation rebuilds the entire form once per...
rymcveigh’s picture

Status: Reviewed & tested by the community » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

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