On this page
- dbxForm: forms as one controlled pipeline
- 1. Where dbxForm belongs
- 2. One form run, one state model
- 3. DD and FD responsibilities
- 4. Initialization
- 5. Values and validation
- 6. Saving records
- 7. Callbacks without hidden coupling
- 8. Messages and error presentation
- 9. Ajax is an interaction mode
- 10. Embedded and repeated forms
- 11. Security and acceptance checklist
dbxForm: forms as one controlled pipeline
dbxForm connects DD and FD definitions, request values, validation, messages, form state, Ajax rendering, and persistence. It is a stateful facade for one form run, not merely an HTML helper.
1. Where dbxForm belongs
Use dbxForm whenever a module accepts structured input or changes a record. The router selects the route, the service configures the form, DD and FD provide the data and field contracts, and dbxTPL renders the result. Domain rules stay in the service; database and UI infrastructure stay in the system classes.
2. One form run, one state model
- Load the initial record through dbxDB and the DD.
- Resolve the FD and its language-specific messages.
- Merge request values over the initial values for a submitted form.
- Normalize and validate every accepted field on the server.
- Retain normalized values, field errors, global messages, and submit protection.
- Persist only after the complete validation result is valid.
- Render the current state through dbxTPL.
This sequence is why dbxForm is intentionally stateful. Splitting it into unrelated public helper objects would make modules coordinate state that the form pipeline already owns.
3. DD and FD responsibilities
| Contract | Defines | Does not define |
|---|---|---|
| DD | Table, fields, types, indexes, ownership, and permissions | Page layout |
| FD | Visible fields, order, labels, view options, and messages | Duplicate database permissions |
| Service | Domain rules and orchestration | Driver-specific persistence |
| Template | Form structure and placeholders | Validation or authorization |
Keep message keys identical across language variants. Load visible labels and validation text from the FD so that the form, its errors, and its Ajax response remain synchronized.
4. Initialization
$form = dbx()->get_system_obj('dbxForm');
$form->init('invoice-form', $invoiceDd, $invoiceFd, $rid);
$form->set_tpl('myInvoices|invoice-form');
return $form->run();
The form ID is the stable identity for callbacks, DOM state, messages, and Ajax replacement. The callback owner defaults to the module or service that creates the form. Configure a different owner only when the architecture deliberately requires it.
5. Values and validation
For a new request, initial DD values form the baseline. On submit, accepted request values take precedence so that invalid input can be shown again without losing the user’s work. Unknown fields are ignored; accepted values are normalized and validated against the FD and DD contracts.
Use server-side callbacks for cross-field or domain validation. A client-side check may improve feedback, but it must never be the only safeguard.
6. Saving records
save_post() performs the standard insert or update through dbxDB. Permissions, allowed fields, automatic audit values, tracing, and database abstraction remain active. After an insert, store the returned RID in the form action with set_rid_in_action(); the next submit then updates that record.
7. Callbacks without hidden coupling
The conventional callback name is derived from the form ID and event, represented as {fid}_{event}. This keeps the relationship visible and avoids repetitive callback registration. Use explicit callbacks only when a well-documented variation requires them.
Callbacks may add normalized values, domain errors, or replacement values. They must not print HTML, perform undisclosed redirects, or reimplement request and permission checks.
8. Messages and error presentation
Field errors stay with their fields. Global success, warning, and error messages use the shared form message pipeline. A normal response and an Ajax response must expose the same result and the same translated message; only the replacement scope differs.
9. Ajax is an interaction mode
Add the established dbxAjax attributes to the form and identify the 1 root that should be replaced. The server runs the same route, validation, persistence, and template code as a normal POST. After replacement, the runtime reinitializes the features required by the new fragment.
Always test the form with JavaScript disabled. If the normal POST is incomplete, the Ajax path is masking an architectural defect.
10. Embedded and repeated forms
Give every instance a unique form ID and DOM root. Do not nest HTML <form> elements. When a child editor belongs inside a larger view, render it as a separate window or replaceable region with its own state and submission boundary.
11. Security and acceptance checklist
- Module access and DD write permissions are checked.
- Only declared fields reach validation and persistence.
- Insert, update, invalid input, and a repeated submit are covered.
- The form works without JavaScript and through Ajax.
- Two instances do not share IDs, values, callbacks, or messages.
- Visible labels and all success and error messages are verified in German and English.
- The browser console, Missing counters,
files/dbxError.log, PHP logs, and system messages remain clean.