Tell the submitter when a request form's workflow cannot start

Refuses a start the engine cannot honour, before it is attempted.

The handler starts the run in postSave(), which runs after the submission is durably saved, and the start was unguarded. A workflow that cannot run therefore reached the submitter as an error page with their answers stored, no run started, and nothing in the log naming the form or the workflow. Two things get there: the workflow was deleted since the handler was pointed at it, or it has been disabled.

Why a check and not a catch

WorkflowExecutor::start() commits the instance and then, under synchronous execution, drains it inline. A catch around the call could not tell a run that never began from one that began and then failed, and would leave an orphan run with nothing linking it to this submission. So the two conditions are read before the start instead.

What the submitter and the operator get

The submitter is told their answers were saved and the request could not be started, which is not theirs to fix either way. The two causes are logged apart because the remedy differs: point the handler at a workflow that is there, or enable the one it names. Both records carry the form, the workflow and the submission id.

The submission is left unbound, which is the state postSave() already reads as "started nothing", so saving it again once the workflow can run picks it up and does not create a second record.

Tests

Both causes, in the class that owns the handler's submission behaviour. They drive the save the way webform does rather than calling postSave() by hand, which would run the guard twice: the sibling tests get away with that because a bound submission takes the resume branch on the second pass, and a refused start binds nothing.

"Nothing reaches the submitter" is asserted explicitly, so the unguarded code fails on that assertion rather than ending the test as an error that names none. Red without the fix:

The refusal did not reach the submitter as an exception.
Failed asserting that Drupal\Core\Entity\EntityStorageException Object (...) is null.

The throwable is the EntityStorageException the entity storage wraps whatever escapes postSave() in.

Documentation in docs/webform.md and French for the three new strings.

Merge request reports

Loading
Loading