Die neue Form-Extension wird durch die Auszeichnungssprache YAML konfiguriert. Man unterscheidet zwischen Form-Konfiguration und Form-Definition.
Quelle: Form configuration vs. form definition - Arbeitsentwurf der offiziellen Dokumentation
Mit der folgenden Konfiguration lässt sich die Nachricht, die nach Absenden des Formulars angezeigt wird, vom Redakteur über das Plugin individuell anpassen.
TYPO3: CMS: Form: prototypes: standard: finishersDefinition: Confirmation: FormEngine: label: 'formEditor.element.AdvancedPassword.editor.confirmationLabel.predefinedDefaults' elements: message: label: 'formEditor.elements.Form.finisher.Confirmation.editor.header.label' config: type: 'input'
table
: Gewünschter Tabellennamemode
: insert oder update. Letztere Option benötigt auch die Anweisung whereClause
databaseColumnMappings
: Hiermit lassen sich Werte in die Datenbank schreiben, die nicht in Formularfeldern stehen.elements
: Auflistung der Formularfelder, deren Inhalte in die Datenbank geschrieben werden sollen. Logischerweise müssen die mit mapOnDatabaseColumn
deklarierten Datenbankfelder auch vorhanden sein.
{__currentTimestamp}
ist ein spezieller Wert, der den aktuellen Unix-Timestamp zurückgibt.
Wichtig ist die Schreibweise als Array innerhalb von options
mittels Bindestrich -
, sonst erhält man beim Absenden des Formulars eine TYPO3 Exception.
Details sind in der offiziellen Dokumentation (Arbeitsentwurf) zu finden.
finishers: - identifier: SaveToDatabase options: - table: 'tx_formtemplates_domain_model_data' mode: insert databaseColumnMappings: pid: value: 123 tstamp: value: '{__currentTimestamp}' elements: company: mapOnDatabaseColumn: 'company' title: mapOnDatabaseColumn: 'title' firstname: mapOnDatabaseColumn: 'firstname' lastname: mapOnDatabaseColumn: 'lastname' email: mapOnDatabaseColumn: 'email' street: mapOnDatabaseColumn: 'street' zipcode: mapOnDatabaseColumn: 'zipcode' phone: mapOnDatabaseColumn: 'phone' message: mapOnDatabaseColumn: 'message'
Wenn das Formular ein Feld des Typs FileUpload oder ImageUpload enthält, wird beim Hochladen der Datei automatisch ein Eintrag in der Datenbanktabelle sys_file erzeugt.
Mit dem SaveToDatabase
Finisher lassen sich nun die benötigten Datei-Referenzen erzeugen:
uid_local
gemappt. Außerdem werden in weiteren Feldern der eigene Tabellenname, das dazugehörige Feld und – unter uid_foreign
– die UID des neu angelegten Datensatzes in der eigenen Tabelle referenziert.Im TYPO3-Backend ist die hochgeladene Datei damit korrekt dem Datensatz in der eigenen Datenbanktabelle zugeordnet.
type: Form identifier: UploadForm label: 'Upload form' prototypeName: standard finishers: - identifier: SaveToDatabase options: - table: 'tx_deine_datenbanktabelle' mode: insert databaseColumnMappings: pid: value: 6 crdate: value: '{__currentTimestamp}' tstamp: value: '{__currentTimestamp}' formtitle: value: 'Upload form' elements: fileupload: mapOnDatabaseColumn: 'feld_in_deiner_datenbanktabelle' - table: sys_file_reference mode: insert elements: fileupload: mapOnDatabaseColumn: 'uid_local' databaseColumnMappings: # Achtung: ab TYPO3 v12 müssen die beiden nachfolgenden Zeilen entfernt werden! table_local: value: 'sys_file' tablenames: value: 'tx_deine_datenbanktabelle' fieldname: value: 'feld_in_deiner_datenbanktabelle' tstamp: value: '{__currentTimestamp}' crdate: value: '{__currentTimestamp}' uid_foreign: value: '{SaveToDatabase.insertedUids.0}' renderables: - type: Page identifier: page-1 label: Page renderables: - properties: saveToFileMount: '1:/user_upload/' allowedMimeTypes: - application/pdf fluidAdditionalAttributes: required: required type: FileUpload identifier: fileupload label: 'Datei hochladen' validators: - identifier: NotEmpty
Der Ruhm hierfür gilt Olaf Schmidt-Wischhöfer; er hat die Lösung am 26. Juni 2017 in Slack veröffentlicht!
Laut offizieller Dokumentation lässt sich jede Form-Definition mit TypoScript überschreiben.
Ein möglicher Anwendungsfall ist, den Titel der aktuellen Seite im Formular mit zu übergeben. Oder einen GET-Parameter auszulesen und damit ein Feld vorauszufüllen. Mit TypoScript, formDefinitionOverrides
und getText können Formularfelder dynamisch befüllt werden.
Die Anzahl und Verschachtelung der renderables
sowie die Indexnummer des Feldes ist für jedes Formular individuell verschieden, da es von den verwendeten Feldern und der Nutzung von Fieldsets und Grids abhängt.
Die korrekte Verschachtelung entnimmt man am besten direkt der Konfiguration. Im folgenden Beispiel habe ich versucht, dies zu verdeutlichen. Die Indexnummern der renderables
beginnen immer bei 0
.
Mit <f:debug>{form.currentPage}</f:debug>
lassen sich zwar auch die renderables ausgeben, hier werden aber noch versteckte Felder wie der Honeypot hinzugefügt, wodurch sich die Indexnummer ändern kann.
ContactForm.yaml
identifier: contactForm label: ContactForm type: Form prototypeName: standard renderables: - identifier: page-1 label: 'Contact Form' type: Page renderables: - defaultValue: '' identifier: name label: Name type: Text properties: fluidAdditionalAttributes: placeholder: Name validators: - identifier: NotEmpty - defaultValue: '' identifier: subject label: Subject type: Text properties: fluidAdditionalAttributes: placeholder: Subject validators: - identifier: NotEmpty - defaultValue: '' identifier: email label: Email type: Text properties: fluidAdditionalAttributes: placeholder: 'Email address' validators: - identifier: NotEmpty - identifier: EmailAddress - defaultValue: '' type: Hidden identifier: pagetitle label: Page title - defaultValue: '' identifier: message label: Message type: Textarea properties: fluidAdditionalAttributes: placeholder: '' validators: - identifier: NotEmpty
TypoScript:
plugin.tx_form.settings { formDefinitionOverrides { // bitte den richtigen Formular-Identifier eintragen: contactForm { // auf root-Ebene der Formular-Definition: renderables { // Erstes Element - identifier: page-1 0 { renderables { // Viertes Element unterhalb von page-1 - identifier: pagetitle 3 { defaultValue = TEXT defaultValue.data = page:title } } } } } } }
Aufgrund eines Bugs können Formulare nur mit einem Workaround in Website-Templates integriert werden.
- Issue: https://forge.typo3.org/issues/92406
TypoScript:
lib.embeddedForm = FLUIDTEMPLATE lib.embeddedForm { template = TEXT template { value = <formvh:render persistenceIdentifier="EXT:sitepackage/Resources/Private/Forms/embeddedForm.form.yaml" /> } extbase { pluginName = Formframework controllerExtensionName = Form controllerName = FormFrontend controllerActionName = perform } }
Fluid:
<f:cObject typoscriptObjectPath="lib.embeddedForm" />
Danke an Daniel Siepmann, der die Lösung am 6. Oktober 2020 in Slack gepostet hat!
TYPO3: CMS: Form: prototypes: myCustomForm: __inheritances: 10: 'TYPO3.CMS.Form.prototypes.standard' formElementsDefinition: Form: renderingOptions: templateRootPaths: 100: 'EXT:form_distribution/Resources/Private/Frontend/Templates/' partialRootPaths: 100: 'EXT:form_distribution/Resources/Private/Frontend/Partials/' layoutRootPaths: 100: 'EXT:form_distribution/Resources/Private/Frontend/Layouts/'
Aktuell ist das Form Framework so eingerichtet, dass die o.g. templateRootPaths nicht für die E-Mail-Templates gelten.
Bis dies behoben ist, können alternative Templates direkt im Finisher des Formulars verknüpft werden.
ContactForm.yaml
finishers: - identifier: EmailToSender options: subject: '{subject}' recipientAddress: your.company@example.com recipientName: '{name}' senderAddress: '{email}' senderName: '' replyToAddress: '' carbonCopyAddress: '' blindCarbonCopyAddress: '' format: html attachUploads: 'true' templatePathAndFilename: 'EXT:form_distribution/Resources/Private/Frontend/Templates/Finishers/Email/{@format}.html'
Forge: Bug #80974: Form Email finisher doesn't support templateRootPaths
Form Definition:
renderables: - identifier: page-1 label: 'Contact Form' type: Page renderables: - properties: options: Herr: Herr Frau: Frau prependOptionLabel: 'Bitte wählen ...' fluidAdditionalAttributes: required: required type: SingleSelect identifier: title label: Title validators: - identifier: NotEmpty - defaultValue: '' type: Text identifier: lastname label: 'Nachname' properties: fluidAdditionalAttributes: required: required placeholder: 'Nachname' validators: - identifier: NotEmpty
/Finishers/Email/Html.html:
<f:switch expression="{form.formState.formValues.title}"> <f:case value="Herr">Sehr geehrter Herr {form.formState.formValues.lastname},</f:case> <f:case value="Frau">Sehr geehrte Frau {form.formState.formValues.lastname},</f:case> <f:defaultCase>Sehr geehrte Damen und Herren,</f:defaultCase> </f:switch>