Benutzer-Werkzeuge

Webseiten-Werkzeuge


typo3:form

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: 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 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 <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
                        }
                    }
                }
            }
        }
    }
}

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 = <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!


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: 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:

<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>
typo3/form.txt · Zuletzt geändert: 2023/04/26 20:02 von admin