Skip to content

Dehydrate an action modal's form data on submit - #73

Merged
ONyklicek merged 1 commit into
1.xfrom
1.17.5
Sep 6, 2026
Merged

Dehydrate an action modal's form data on submit#73
ONyklicek merged 1 commit into
1.xfrom
1.17.5

Conversation

@ONyklicek

Copy link
Copy Markdown
Owner

The write path has had a named seam since ADR 0021 — a field shapes its own value on the way out — but it had exactly two hosts: Form::save() through SaveHandler, and an editable table cell through updateTableCell(). An action modal was not one of them. submitActionModal() / callMountedAction() read mountedActions.{depth}.data and handed it to the callback untouched, so the same schema wrote different values depending on which host persisted it: Select::dehydrateState()'s documented '' -> null rule simply did not apply inside a modal, and a cleared numeric field reached the column as '' — SQLSTATE[22007] "Incorrect decimal value: ''" on any strict MySQL.

The schema walk moves out of SaveHandler into Forms\Runtime\StateDehydrator, the canonical owner both hosts now call, and the action runtime gains the seam next to the validation one it already had: dehydrateMountedActionFormData(), a no-op in core, overridden by the wire-forms bridge, so a form-free host is unaffected. Wizards dehydrate every step, not only the one on screen at submit; repeater children are dehydrated per item. Footer actions are deliberately excluded — they read the form mid-edit and write back into the same bag, so dehydrating there would hand the callback a value the form no longer holds, and would run a FileUpload's store on a form the user never submitted.

TextInput had no dehydration at all, so numeric() was a rendering hint and nothing more — this half reached Form::save() too. A field whose HTML type is number now stores null when it is left empty; every other type is untouched on purpose, because '' is a legitimate string and nulling it would break a non-nullable text column rather than save it.

The tests are mutation-checked: removing either call site fails them.

The write path has had a named seam since ADR 0021 — a field shapes its own
value on the way out — but it had exactly two hosts: Form::save() through
SaveHandler, and an editable table cell through updateTableCell(). An action
modal was not one of them. submitActionModal() / callMountedAction() read
mountedActions.{depth}.data and handed it to the callback untouched, so the
same schema wrote different values depending on which host persisted it:
Select::dehydrateState()'s documented '' -> null rule simply did not apply
inside a modal, and a cleared numeric field reached the column as '' —
SQLSTATE[22007] "Incorrect decimal value: ''" on any strict MySQL.

The schema walk moves out of SaveHandler into Forms\Runtime\StateDehydrator,
the canonical owner both hosts now call, and the action runtime gains the seam
next to the validation one it already had: dehydrateMountedActionFormData(),
a no-op in core, overridden by the wire-forms bridge, so a form-free host is
unaffected. Wizards dehydrate every step, not only the one on screen at submit;
repeater children are dehydrated per item. Footer actions are deliberately
excluded — they read the form mid-edit and write back into the same bag, so
dehydrating there would hand the callback a value the form no longer holds, and
would run a FileUpload's store on a form the user never submitted.

TextInput had no dehydration at all, so numeric() was a rendering hint and
nothing more — this half reached Form::save() too. A field whose HTML type is
number now stores null when it is left empty; every other type is untouched on
purpose, because '' is a legitimate string and nulling it would break a
non-nullable text column rather than save it.

The tests are mutation-checked: removing either call site fails them.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@ONyklicek
ONyklicek merged commit 88fca3d into 1.x Sep 6, 2026
17 of 19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant