dbxForm ist die zentrale Eingabe- und Formularpipeline von dbxapp. Sie verbindet Template, DD/FD, Request-Auswertung, Validierung, Meldungen, Formularzustand, AJAX und Speichern.
Einordnung im Golden Path
Das vollständig zusammengesetzte Formbeispiel mit DD, FD, Template, Ajax und Service steht unter Verbindliches Modulhandbuch. Dieses Kapitel erläutert die erweiterten Fähigkeiten und Varianten von dbxForm.
dbxForm ist bewusst eine zustandsbehaftete Fassade. Feldquelle, Requestwerte, Fehler, Submit-Schutz, Meldungen und Rendering gehören zu einem Formularlauf. Eine Aufteilung allein nach Dateigröße würde diesen Vertrag auf mehrere öffentliche Teilobjekte verteilen und die Modulnutzung komplizierter machen.
Wann dbxForm verwendet wird
- Datensätze anlegen und bearbeiten.
- Filter- und Konfigurationsmasken.
- Login-, Kontakt- und Checkoutformulare.
- Admin-Panels mit {obj:*}-Teilbereichen.
- Formulare, die Reports oder andere Module einbetten.
- Mehrstufige Formulare mit Remember-/Workflow-State.
Ein Formular sollte nicht als großer PHP-HTML-String gebaut werden. PHP bereitet Zustand und Fachlogik vor; das Template bestimmt die Anordnung.
Lebenszyklus
submit() und errors() lösen die zentrale Request-Auswertung aus. Felder müssen deshalb vor der Submit-Prüfung angelegt sein.
Reales CRUD-Formular
Dieses Muster entspricht dem vom Modul-Wizard erzeugten Code und dem aktuellen Workflow-Adminformular:
Wichtige Punkte:
- get_system_obj('dbxForm') liefert eine von dbxapp verwaltete Instanz.
- init() setzt den Formularzustand zurück und erzeugt den Submit-Schutz.
- _data enthält den Ausgangsdatensatz; Request-Werte erhalten beim Submit Vorrang.
- add_flds() muss vor submit() laufen.
- save_post() speichert nur die durch die Feldpipeline geprüften Werte.
- dbxDB setzt create_date, create_uid, owner, update_date und update_uid automatisch, sofern diese Felder in der DD vorhanden sind.
- run() wird auch nach Fehlern ausgeführt, damit Werte und Feldmeldungen erhalten bleiben.
Ein reales Beispiel steht in dbx/modules/dbxWorkflow_admin/include/dbxWorkflowAdmin.class.php in der Methode für Workflow-Definitionen.
Passendes Template
| Marker | Aufgabe |
|---|---|
| {i} | Eindeutige Instanznummer für mehrfach verwendete Formulare |
| {action} | Wert aus _action |
| [dbx:form] | Alle angelegten Formularfelder |
| {obj:form_msg} | Standardmeldungen der Formpipeline |
| {obj:extra} | Beliebiges mit add_obj() gesetztes Teilobjekt |
| [dbx:js] | Von der Pipeline registrierte Initialisierung |
DD, FD und manuelle Felder
Alle Felder aus der FD
Die aktive Sprache bestimmt automatisch die Datei: task-form_en.fd.php, task-form_es.fd.php, task-form_de.fd.php oder als Fallback task-form.fd.php. Die FD liefert neben $fields auch ihre Meldungen:
Nach save_post() zeigt dbxForm bei Erfolg save_success; schlägt dbxDB->save() fehl, wird save_error als allgemeiner Formularfehler verwendet. Modulcode muss diese beiden Standardmeldungen nicht nochmals setzen. Eigene fachliche Meldungen werden in derselben FD sprachabhängig ergänzt und nach dem Laden der Felder über get_fd_message() gelesen:
Werden Titel oder Meldungen bereits vor add_fld()/add_flds() benötigt, lädt load_fd_messages() nur den Meldungsvertrag, ohne ein Feld anzulegen:
Dynamische Werte bleiben ebenfalls in der FD. format_fd_message() ersetzt benannte Platzhalter zentral; das Modul benötigt kein eigenes str_replace():
Damit bleiben auch fachliche Hinweise im Sprachvertrag der Formulardefinition. Der optionale zweite Parameter von get_fd_message() ist ausschließlich ein Fallback für ältere FDs. Alle Sprachvarianten einer FD müssen dieselben Meldungsschlüssel besitzen; nur die Texte unterscheiden sich.
Verbindliche Quelle für sichtbare Formulartexte
Labels, Optionen, Platzhalter, Bar-Titel, Validierungs-, Erfolgs-, Fehler- und Confirmtexte einer Fachmaske kommen aus ihrer aktiven FD. Modulcode enthält dafür keine parallelen deutschen Konstanten. Die Reihenfolge ist verbindlich:
Benötigt ein Service nur Texte für eine Seite, ein Dialogfenster oder einen zweiten Report, wird ein leichter FD-Kontext ohne init() verwendet:
init() gehört zum tatsächlichen Formularlauf. Ein reiner Textkontext ruft es nicht auf, weil sonst unnötig Formularzustand, Hilfelogik und Instanzmetadaten entstehen. Der Kontext darf pro Service und FD zwischengespeichert werden.
Sprachdateien übersetzen die Oberfläche, nicht automatisch gespeicherte Fachdaten. Einsprachige Artikel-, Statusbeschreibungs- oder Konfigurationswerte bleiben Datenbankinhalt, bis das Datenmodell echte Sprachtabellen vorsieht. Eine DD wird allein für übersetzte Labels niemals dupliziert.
Alle Felder direkt aus der DD
Nur ausgewählte Felder
FD übernehmen und gezielt überschreiben
Die Marker bedeuten:
- fd::: Wert aus der aktiven FD; ohne FD fällt die Quelle auf DD zurück.
- dd::: Wert ausdrücklich aus der DD.
- Konkreter Wert: diese Eigenschaft bewusst überschreiben.
Beispiel: eigenes Template, aber DD-Label und sonst FD-Werte:
Gängige Templates sind text-label, textarea-label, checkbox-label, select-single-label, select-multible-label/multiselect2, date-label, integer-label, password-label und hidden. Vorhandene Module und die Templateauswahl im Editor sind die verbindliche Quelle für tatsächlich installierte Varianten.
Werte lesen und zusätzlich validieren
- get_post() liest Request-Werte und nutzt standardmäßig striktere alphanumerische Regeln.
- get_post_data() ist für freiere Inhalte gedacht und verwendet standardmäßig parameter.
- get_fld_val() bezieht zusätzlich Formularzustand und _data ein.
Fachliche Fehler werden am Feld und in der Formularmeldung angezeigt:
Für Pflicht-E-Mailfelder wird die vollständige Regel verwendet:
email prüft genau ein @, lokale und gesamte Längen, Punkte im Local-Part, Domainlabels, vollständige TLD, optionale IDN-Normalisierung und abschließend FILTER_VALIDATE_EMAIL. Ein Pflichtfeld bleibt zusätzlich durch min=1 gekennzeichnet und wird bei leerem Submit als Feldfehler gerendert.
Automatische DD-Systemfelder werden nicht über das Formular gesetzt:
dbxDB übernimmt Benutzer, Owner und Zeitstempel. set_post() oder der dritte Parameter von save_post() sind nur für echte fachliche Werte gedacht, die das Modul bewusst fest vorgibt und die in der DD existieren. Sie sind kein Ersatz für die Systemfeldautomatik.
Speichermöglichkeiten
Standard: save_post()
Für ein normales DD-Formular:
Nach einem Insert übernimmt dbxForm die neue ID und kann den Datensatz erneut lesen. Feldwerte und Formularzustand sind danach synchron.
Eigene Fachtransaktion
Wenn mehrere Tabellen, externe Provider oder komplexe Regeln beteiligt sind, liest das Modul validierte Werte aus dbxForm und delegiert an einen Service:
dbxForm bleibt für Request, Felder und Fehler zuständig; der Service übernimmt die fachliche Operation. Dadurch wird save_post() nicht zu einer vermeintlich universellen Transaktionslogik überladen.
Replaces und Objekte
add_rep() setzt einfache Templatewerte:
replaces() wendet die gesammelten Werte auch auf einen bereits geladenen Teilinhalt an:
Alternativ kann ein explizites Array übergeben werden. dbxReport erbt beide Funktionen. Dadurch können während eines Record-Callbacks spät gesetzte Summen im anschließenden Footer ersetzt werden, ohne dass ein Modul eine eigene str_replace()-Methode benötigt.
add_obj() setzt gerenderte Teilbereiche:
- obj-value übernimmt bewusst bereits gerendertes HTML.
- obv-value escaped den Wert für eine sichere Textausgabe.
- Bei einem Template-Namen rendert add_obj() das Teiltemplate über dbxTPL.
Standard-Shell und Modulbar
Für einheitliche Adminformulare kann dbxForm die vorhandenen Shell-Marker vorbereiten:
Diese Variante passt zu Templates mit form-shell-head und form-shell-foot. Ein eigenes Modultemplate ist sinnvoll, wenn die Anordnung fachlich stark abweicht.
Die Formularhilfe wird in buildModuleBarObj() aufgelöst. Das Hilfe-Symbol steht über bar_extra immer ganz rechts. dbxAdminHelp::formButton() liefert auch für Formulare ohne fest registriertes Thema eine robuste Fallback-Hilfe. Eingebettete Steuerformulare, die bereits die Hilfe ihres Elternbereichs anzeigen, schalten die automatische Schaltfläche gezielt ab:
Jedes Formtemplate muss {obj:form_msg} oder den passenden #form_msg_error#-/Erfolgsplatzhalter an der vorgesehenen Stelle besitzen. Unersetzte Marker dürfen niemals als sichtbarer Text ausgegeben werden.
Fehlversuche und Rücksetzung
check_try_count() begrenzt wiederholte fehlerhafte Submits. Neben der kurzzeitigen Sperre existiert _try_count_reset mit aktuell 600 Sekunden. Ist der letzte Fehlversuch länger her, beginnen dbx_try_count und die Sperrstufe wieder bei null. Die Sperrmeldung gehört in das betroffene Formular und nicht als freistehende Meldung in den umgebenden Seitencontent.
Callbacks
Callbacks erlauben kleine, definierte Eingriffe, ohne die Pipeline zu kopieren:
Der direkte Aufrufer von init() wird automatisch als Callback-Owner übernommen. Die normalisierte Formular-ID liefert die Defaultnamen:
set_form_callback_owner() und die set_*_callback()-Methoden bleiben für bewusste Abweichungen kompatibel, sind im normalen Modulablauf aber nicht notwendig.
Der Rückgabewert muss zum jeweiligen Callback passen. Fachlogik sollte nicht verdeckt in Render-Callbacks wandern; sie bleibt im Service oder Controller.
Formular mit eingebettetem Report
Formular- und Report-Target müssen eindeutig sein. Eine Aktion des Reports darf nicht versehentlich das gesamte übergeordnete Formular ersetzen.
AJAX und normale Requests
Der Server liefert im üblichen dbxForm-Ablauf wieder HTML für dasselbe Target. Ohne dbxAjax funktioniert das Formular als normaler Request. Reine JSON- Endpunkte sind separate API-Aktionen und geben keine Formularansicht zurück.
Submit-Schutz und Action-Token
dbxForm::init() erzeugt den versteckten, formularspezifischen Submit-Schutz. submit() vergleicht ihn zeitkonstant und rotiert ihn nach einem gültigen POST. Das gilt identisch für Ajax und den normalen Browser-Submit.
Eine normale Form-Route erhält keinen zusätzlichen dbx_token. dbx_token gehört zu automatisch erkannter, zustandsändernder Link-Navigation. dbxForm führt seine Action durch denselben Resolver: Enthält die Action ausdrücklich delete oder save als Aktionsbestandteil und zugleich rid, wird sie automatisch signiert; alle anderen Form-Actions bleiben unverändert. Der Formular-POST behält unabhängig davon seinen eigenen Submit-Schutz. Modulcode fügt keinen Token manuell hinzu.
Sicherheits- und Qualitätsregeln
- Felder vor submit() anlegen.
- DD/FD und Validator-Regeln verwenden; Request-Daten nie ungeprüft speichern.
- save_post() für Standard-CRUD, Service-Methoden für komplexe Fachlogik.
- Automatische Systemfelder von dbxDB setzen lassen.
- HTML-Struktur in Templates; nur kleine Aktionsfragmente bewusst als Objekt.
- Eindeutige {i}-Targets für mehrere Instanzen und AJAX.
- Fehlermeldungen über add_fld_error() und _msg_error führen.
- Geheimnisse und Passwörter weder zurückrendern noch protokollieren.
- obj-value nur für kontrolliertes, bereits gerendertes HTML verwenden.
- Pflicht-E-Mailfelder mit email|min=1 validieren.
- Hilfe rechts in der Modulbar und Formularmeldungen im Formtemplate prüfen.
- Normale Formular-Actions nicht manuell mit dbx_token doppelt absichern.
Reale Referenzen
- dbx/modules/dbxWorkflow_admin/include/dbxWorkflowAdmin.class.php: Formular mit FD, eigenen Feldern und fachlicher JSON-Aufbereitung.
- dbx/modules/dbxAdmin/include/dbxWizard.class.php: generiertes CRUD-Muster mit save_post(), Callbacks und Aktionen.
- dbx/modules/dbxUser/include/dbxUser_profil.class.php: gegliedertes Profilformular mit Shell und Teilobjekten.
- dbx/modules/dbxShop: Checkout- und Adminformulare mit Fachservice.
- Verbindliches Modulhandbuch — verbindliches Gesamtbeispiel.
- dbxDB, dbxDD und FD — DD-/FD- und Datenreferenz.
- JavaScript-Systemlibs — Ajax- und Confirm-Vertrag.