====== TYPO3 Form Framework ====== ===== Einführung ===== Die neue Form-Extension wird durch die Auszeichnungssprache //YAML// konfiguriert. Man unterscheidet zwischen Form-Konfiguration und Form-Definition. === Konfiguration von Formularen: === * globale Einstellungen * welche Form-Elemente, Finisher und Validatoren sind verfügbar * wie sind diese Objekte vorkonfiguriert * wie werden diese Objekte im Frontend und Backend ausgegeben === Definition von Formularen: === * gilt jeweils für ein einzelnes Formular * beschreibt alle gewünschten Formularfelder (Typ, Label, Werte, Validatoren, ...) * enthält die sog. Finisher, also die gewünschte Verarbeitung der Formulardaten (E-Mail, Speichern in Datenbank, Meldungen im Frontend, ...) Quelle: [[https://docs.typo3.org/typo3cms/drafts/code.tritum.de/TYPO3.CMS/Form_Documentation/Concepts/FormConfigurationFormDefinition/Index.html|Form configuration vs. form definition - Arbeitsentwurf der offiziellen Dokumentation]] ---- ===== Konfigurationen ===== ==== Finisher Confirmation: Nachricht in Plugin ändern ==== 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' ---- ===== Definitionen ===== ==== Finisher: SaveToDatabase ==== * ''table'': Gewünschter Tabellenname * ''mode'': //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 [[https://docs.typo3.org/typo3cms/drafts/code.tritum.de/TYPO3.CMS/Form_Documentation/ConfigurationReference/prototypes/finishersDefinition/finishers/SaveToDatabase.html?highlight=savetodatabase|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' ==== Finisher: SaveToDatabase und Datei-Upload ==== 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: * In einer eigenen Tabelle für Formular-Einträge wird die UID des //sys_file//-Eintrags gespeichert. * In der Tabelle //sys_file_reference// wird diese UID auf das Feld ''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! ---- ===== TypoScript ===== Laut offizieller Dokumentation lässt sich jede Form-Definition mit TypoScript überschreiben. ==== Default-Werte ü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 ''{form.currentPage}'' 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 } } } } } } } ---- ===== Templating ===== ==== Formular in Fluid-Template rendern ==== 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 = } extbase { pluginName = Formframework controllerExtensionName = Form controllerName = FormFrontend controllerActionName = perform } } **Fluid:** Danke an Daniel Siepmann, der die Lösung am 6. Oktober 2020 in Slack gepostet hat! ---- ==== templateRootPaths für Formulare einrichten ==== 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/' ==== Eigene Templates für E-Mails ==== 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: [[https://forge.typo3.org/issues/80974|Bug #80974: Form Email finisher doesn't support templateRootPaths]] ---- ===== Personalisierte Anrede in E-Mails ===== **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:** Sehr geehrter Herr {form.formState.formValues.lastname}, Sehr geehrte Frau {form.formState.formValues.lastname}, Sehr geehrte Damen und Herren,