This documentation will be extended on a constant basis. If you have
problems understanding a certain aspect, or if you notice something
missing, contribute to improve it. This will help you and everyone else!
The form extension acts as a flexible, extendible, yet easy to use form
framework. It equally allows editors, integrators, and developers to build
all types of forms. For this task, different interfaces and techniques are
available.
As a non-technical editor, you can use the "Forms" backend module. It
allows you to create and manage your individual forms with the help of a
nifty drag and drop interface. Your work can be previewed instantly.
As an experienced integrator, you are able to build ambitious forms which
are stored directly in your site package. Those forms can utilize hefty
finishers and ship localization files.
As a developer, you can use the PHP API to forge interfaces with conditional
form elements, register new validators and finishers, as well as create
custom form elements. Plenty of hooks allow you to manipulate the generation
and processing of the both form and data.
Form editor displaying a new form in the abstract view
Features List
The following list names some features of the form framework:
form editor
fully customizable editor for building complex forms
replaceable and extendible form editor components
JS API to extend form editor
PHP API
entire forms via API
own renderers for form and/ or form elements
conditional steps, form elements and validators based on other form
elements
configuration
YAML as configuration and definition language including inheritances
and overrides
file based
behaviour and design of the frontend, plugin, and form editor can be
adapted on a per form basis
'prototypes' can be used as boilerplate
form elements
own form elements possible
uploads handled as FAL objects
finishers
ships a bunch of built-in finishers, like email, redirect, and save to
database
own finishers possible
finisher configuration can be overridden within the form plugin
validators
own validators possible
miscellaneous
multiple language support
multiple step support
multiple forms on one page
built-in spam protection (honeypot)
Installation
This extension is part of the TYPO3 Core, but not installed by default.
Check whether you are already using the extension with:
composer show | grep form
Copied!
This should either give you no result or something similar to:
typo3/cms-form v12.4.11
Copied!
If it is not installed yet, use the composer require command to install
the extension:
composer require typo3/cms-form
Copied!
The given version depends on the version of the TYPO3 Core you are using.
Installation without Composer
In an installation without Composer, the extension is already shipped but might
not be activated yet. Activate it as follows:
In the backend, navigate to the Admin Tools > Extensions
module.
Click the Activate icon for the Form extension.
Extension manager showing Form extension
Quick Start for Editors
You are an editor, your admin installed the form extension and you want
to get started quickly? Follow these steps!
Create a new form
Go to the Forms module, and create a new form there. With the help of
the form editor you can build appealing forms easily.
Insert your form on a page
The next step is inserting the form on the desired page(s).
Open the page module in the backend.
Select the desired page.
Create a new content element of type "Form". You can find this one
under the tab "Form Elements".
Under the tab "Plugin", choose the desired form.
Save the content element.
Repeat steps 2 to 5 until the form is inserted on every page you want.
You can now view your form on your web site. Enjoy!
Quick Start for Integrators
You are an integrator, your admin or you installed the form extension
and you want to get started quickly? Just follow these steps!
Include the site set
New in version 13.3
EXT:form offers a site set that can be included as described here.
Legacy TypoScript includes are still possible
for compability reasons but not recommended anymore.
You can also provide a translation
of your form, if needed. This is done in an .xlf file which has to be
registered in your YAML configuration.
Insert your form in a page
The final step is inserting the form in the desired page(s).
Open the page module in the backend.
Select the desired page.
Create a new content element of type "Form". You can find this one
under the tab "Form Elements".
Under the tab "Plugin", choose the desired form.
If needed, you can select "Override finisher settings" under the
"Plugin" tab. Save the content element.
Repeat steps 2 to 5 until the form is inserted in every page requiring
it.
You should now be able to view your form on the frontend. Enjoy!
Legacy TypoScript includes
Changed in version 13.3
It is recommended to include the TypoScript via site set. The legacy way
of using TypoScript includes, in the past also called "TypoScript sets"
is still possible for compatibility reasons but not recommended anymore.
Open the TypoScript module in the backend and edit your root
TypoScript record. Under the tab "Includes", ensure that "Fluid Content
Elements" (fluid_styled_content) and "Form" (form) are among the selected
items. Save the record.
Then continue with the steps above.
For Developers / API Reference
This chapter is a complete reference of the API of the form framework. It
mainly addresses your concerns as a developer.
This finisher can only be used in programmatically-created forms. It makes it
possible to execute one's own finisher code without having to implement/
declare this finisher.
This finisher sends an email to one recipient.
EXT:form uses 2 EmailFinisher declarations with the identifiers EmailToReceiver and EmailToSender.
Usage within form definition.
identifier:example-formlabel:'example'type:Formfinishers:-identifier:EmailToReceiveroptions:subject:'Your message'recipients:your.company@example.com:'Your Company name'ceo@example.com:'CEO'senderAddress:'form@example.com'senderName:'form submitter'...
Default value (for 'EmailToReceiver' and 'EmailToSender' declarations)
undefined
Description
Subject of the email.
recipients
Data type
array
Mandatory
Yes
Default value (for 'EmailToReceiver' and 'EmailToSender' declarations)
undefined
Description
Email addresses and names of the recipients (To).
senderAddress
Data type
string
Mandatory
Yes
Default value (for 'EmailToReceiver' and 'EmailToSender' declarations)
undefined
Description
Email address of the sender/ visitor (From).
senderName
Data type
string
Mandatory
No
Default value
empty string
Description
Human-readable name of the sender.
replyToRecipients
Data type
array
Mandatory
No
Default value (for 'EmailToReceiver' and 'EmailToSender' declarations)
undefined
Description
Email addresses of to be used as reply-to emails.
carbonCopyRecipients
Data type
array
Mandatory
No
Default value (for 'EmailToReceiver' and 'EmailToSender' declarations)
undefined
Description
Email addresses of the copy recipient.
blindCarbonCopyRecipients
Data type
array
Mandatory
No
Default value (for 'EmailToReceiver' and 'EmailToSender' declarations)
undefined
Description
Email address of the blind copy recipient.
addHtmlPart
Data type
bool
Mandatory
No
Default value (for 'EmailToReceiver' and 'EmailToSender' declarations)
true
Description
If set, mails will contain a plaintext and HTML part, otherwise only a
plaintext part. That way, it can be used to disable HTML and enforce
plaintext-only mails.
attachUploads
Data type
bool
Mandatory
No
Default value (for 'EmailToReceiver' and 'EmailToSender' declarations)
true
Description
If set, all uploaded items are attached to the email.
title
Data type
string
Mandatory
No
Default value (for 'EmailToReceiver' and 'EmailToSender' declarations)
undefined
Description
The title, being shown in the Email.
translation.language
Data type
string
Mandatory
No
Default value (for 'EmailToReceiver' and 'EmailToSender' declarations)
undefined
Description
If not set, the finisher options are translated depending on the current frontend language (if translations exists).
This option allows you to force translations for a given language isocode, e.g 'da' or 'de'.
Read Translate finisher options for more informations.
translation.translationFiles
Data type
array
Mandatory
No
Default value (for 'EmailToReceiver' and 'EmailToSender' declarations)
undefined
Description
If set, this translation file(s) will be used for finisher option translations.
If not set, the translation file(s) from the 'Form' element will be used.
Read Translate finisher options for more informations.
layoutRootPaths
Data type
array
Mandatory
No
Default value (for 'EmailToReceiver' and 'EmailToSender' declarations)
undefined
Description
Fluid layout paths
partialRootPaths
Data type
array
Mandatory
No
Default value (for 'EmailToReceiver' and 'EmailToSender' declarations)
undefined
Description
Fluid partial paths
templateRootPaths
Data type
array
Mandatory
No
Default value (for 'EmailToReceiver' and 'EmailToSender' declarations)
undefined
Description
Fluid template paths; all templates get the current
FormRuntime
assigned as form and the
FinisherVariableProvider assigned
as finisherVariableProvider.
variables
Data type
array
Mandatory
No
Default value (for 'EmailToReceiver' and 'EmailToSender' declarations)
undefined
Description
associative array of variables which are available inside the Fluid template
FlashMessage finisher
A simple finisher that adds a message to the FlashMessageContainer.
Usage within form definition.
identifier:example-formlabel:'example'type:Formfinishers:-identifier:FlashMessageoptions:messageTitle:'Merci'messageCode:201905041245messageBody:'Thx for using %s'messageArguments:-'TYPO3'severity:0...
This performs 2 database operations.
One insert and one update.
You can access the inserted uids through '{SaveToDatabase.insertedUids.<theArrayKeyNumberWithinOptions>}'
If you perform an insert operation, the value of the inserted database row will be stored within the FinisherVariableProvider.
<theArrayKeyNumberWithinOptions> references to the numeric options.* key.
Options
table
Data type
string
Mandatory
Yes
Default value
null
Description
Insert or update values into this table.
mode
Data type
string
Mandatory
No
Default value
'insert'
Possible values
insert/ update
Description
insert will create a new database row with the values from the submitted form and/or some predefined values. @see options.elements and options.databaseFieldMappings
update will update a given database row with the values from the submitted form and/or some predefined values. 'options.whereClause' is then required.
whereClause
Data type
array
Mandatory
Yes, if mode = update
Default value
empty array
Description
This where clause will be used for a database update action
elements
Data type
array
Mandatory
Yes
Default value
empty array
Description
Use options.elements to map form element values to existing database columns.
Each key within options.elements has to match with a form element identifier.
The value for each key within options.elements is an array with additional informations.
Set this to true if the database column should not be written if the value from the submitted form element with the identifier
<formElementIdentifier> is empty (think about password fields etc.). Empty means strings without content, whitespace is valid content.
Set this to true if the database column should not be written if the value from the submitted form element with the identifier
<formElementIdentifier> is empty (think about password fields etc.).
This setting only rules for form elements which creates a FAL object like FileUpload or ImageUpload.
By default, the uid of the FAL object will be written into the database column. Set this to true if you want to store the
FAL identifier (1:/user_uploads/some_uploaded_pic.jpg) instead.
elements.<formElementIdentifier>.dateFormat
Data type
string
Mandatory
No
Default value
'U'
Description
If the internal datatype is
\DateTime which is true for the form element types
DatePicker and
Date, the object needs to be converted into a string value.
This option allows you to define the format of the date in case of such a conversion.
You can use every format accepted by the PHP
date() function (https://php.net/manual/en/function.date.php#refsect1-function.date-parameters).
The default value is "U" which leads to a Unix timestamp.
databaseColumnMappings
Data type
array
Mandatory
No
Default value
empty array
Description
Use this to map database columns to static values.
Each key within options.databaseColumnMappings has to match with an existing database column.
The value for each key within options.databaseColumnMappings is an array with additional informations.
This mapping is done before the options.element mapping.
This means if you map a database column to a value through options.databaseColumnMappings and map a submitted
form element value to the same database column through options.element, the submitted form element value
will override the value you set within options.databaseColumnMappings.
databaseColumnMappings.<databaseColumnName>.value
Data type
string
Mandatory
Yes
Default value
undefined
Description
The value which will be written to the database column.
You can also use the FormRuntime accessor feature to access every getable property from the FormRuntime
In short: use something like {<formElementIdentifier>} to get the value from the submitted form element with the identifier <formElementIdentifier>.
If you use the FormRuntime accessor feature within options.databaseColumnMappings, the functionality is nearly identical
to the options.elements configuration variant.
The basic idea of the abstract view is to give a quick overview of the
configuration of form elements, without having to click them in order to view
the detailed configuration in the Inspector. The form editor requires
for each form element an inline HTML template and the corresponding JavaScript
code. Information matching inline HTML templates to the appropriate form
elements must be configured within prototypes.prototypeIdentifier.formeditor.formEditorPartials.
At this point, the key identifying the form element follows a convention:
FormElement-<formElementTypeIdentifier>. The value for the key tells the
form editor which inline HTML template should be loaded for the respective
form element. This template is then cloned via JavaScript, brought to life
using the form element configuration and shown in the Stage component.
You can read about how particular form elements are mapped to inline HTML
templates and how the corresponding JavaScript code are executed here.
The form element inline HTML templates and the corresponding JavaScript code
are configured for reuse. In this way, most form elements you create should be
able to access the components delivered in EXT:form, without requiring separate
implementations (at least we hope so). For your own implementations, study
EXT:form stage templates, which is found under Resources/Private/Backend/Partials/FormEditor/Stage/*.
The corresponding JavaScript code is found under Resources/Public/JavaScript/Backend/FormEditor/StageComponent.js.
The method _renderTemplateDispatcher() shows, which methods will be used to
render the respective form elements.
Essentially, two different inline HTML templates exists that can be rendered
with two different JavaScript methods, which are described below. The other
inline HTML templates are almost all versions of these two basic variants and
show extra/ other form-element information. The same applies to the
corresponding JavaScript codes.
Stage/SimpleTemplate
This template displays the label property of the form element. Depending on
the JavaScript rendering method used, a validator icon will be shown on the
right as soon as a validator is added to the form element. In this case, the
used validator labels are likewise displayed, if the form element is selected
and/ or the cursor hovers over the form element. This template should generally
be enough for all possible, self-defined form elements.
The Stage/SimpleTemplate can then be rendered
with the method getFormEditorApp().getViewModel().getStage().renderSimpleTemplateWithValidators().
Stage/SelectTemplate
This template behaves like the Stage/SimpleTemplate except that it also
shows the chosen options labels of the form elements. This is naturally only
possible for form elements that have properties.options.* values, e.g.
MultiCheckbox:
You can copy this template variant for your own form element, if that form-
element template also lists array values, which, however, are not found under
properties.options.*. For this purpose, the 'Stage/FileUploadTemplate' is
an example. It is basically the 'Stage/SelectTemplate' template, with one
altered property.
In the FileUpload form element, multiple property values are available
under properties.allowedMimeTypes.* as an array.
data-template-property contains the path to the property, which is to be
read out of the form element and then shown in the template.
The Stage/SelectTemplate can then be rendered
with the method getFormEditorApp().getViewModel().getStage().renderSelectTemplates().
Basic JavaScript Concepts
Events
EXT:form implements the publish/subscribe pattern to put the event handling
into effect. To learn more about this pattern, you should read
https://addyosmani.com/resources/essentialjsdesignpatterns/book/.
Note that the order of the subscriber is not manipulable and that information
flow between the subscribers does not exist. All events must be asynchronously
designed.
This event is called if the Ajax request, which is used to save the form or to
render the current page of the form in the preview view, fails. EXT:form
uses this event to show an error message as a flash message and to show the
received error text in the preview view.
This event is called if the Ajax request that is used to render the current
page of the form in the preview view was successful. EXT:form uses this
event to display the rendered form in the preview view.
This event is called if the Ajax request that is used to save the form was
successful. EXT:form uses this event to display a success message as a flash
message. The form editor is also informed that no unsaved content currently
exists.
The addition/ deletion and movement of form elements und property collection
elements (validators/ finishers) is saved in an internal stack so that the
undo/ redo function can be implemented. This event is called whenever the
current state is added to the stack. EXT:form uses this event to reset the
enabled/ disabled state of the undo/ redo buttons.
The method getFormEditorApp().setCurrentlySelectedFormElement() tells the
form editor which form element should currently be dealt with. This method
calls this event at the end.
Each FormElement model
can write properties into the FormElement model through the methods get
and set. Each property path can register an event name for the publisher
through the method on. This event is then always called when a property
path is written via set. Read FormElement model
for more information. EXT:form automatically registers for all known property
paths of a form element the event core/formElement/somePropertyChanged.
This means that every property written via set calls this event. Among
other things, EXT:form uses this event for, for example, updating the label of
a form element in other components (e.g. Tree component ) when this label
is changed. Furthermore, any validation errors from form element properties
are indicated by this event in the Tree component.
The method getFormEditorApp().getViewModel().movePropertyCollectionElement()
calls this event at the end. EXT:form uses this event to re-render the
Inspector component as soon as a property collection element (validator/
finisher) is moved.
The method getFormEditorApp().getViewModel().createAndAddPropertyCollectionElement()
calls this event at the end. EXT:form uses this event to re-render the
Inspector component as soon as a property collection element (validator/
finisher) is created and added.
The method getFormEditorApp().getViewModel().removePropertyCollectionElement()
calls this event at the end. EXT:form uses this event to re-render the
Inspector component as soon as a property collection element (validator/
finisher) is removed.
The method getFormEditorApp().getViewModel().createAndAddFormElement() and
the event view/insertElements/perform/after
call this event at the end. EXT:form uses this event to set the current
to-be-processed form element (getFormEditorApp().setCurrentlySelectedFormElement())
and to re-render the Tree, Stage and Inspector components.
The method getFormEditorApp().getViewModel().removeFormElement() calls this
event at the end. EXT:form uses this event to set the current to-be-processed
form element (getFormEditorApp().setCurrentlySelectedFormElement()) and to
re-render the Tree, Stage and Inspector components.
The onClick event of the "Close" button in the form editor's header section
calls this event. EXT:form uses this event to display a warning message in case
there are unsaved changes.
The onClick event of the "new page" button in the form editor's header
section calls this event. EXT:form uses this event to display the "new page"
dialog box.
The onClick event of the "save" button in the form editor's header section
calls this event. EXT:form uses this event either to display a dialog box with
the element in question (if there are validation errors) or to save the `form
definition` (if there are no validation errors).
The onClick event of the "settings" button in the form editor's header
section calls this event. EXT:form uses this event to select the root form
element.
This event is called from the "new element" dialog box upon selection of a form
element:
if "After" in the "Create new element" split button in the form-element toolbar for composite elements (e.g. fieldset) is clicked.
if the "Create new element" button in the form-element toolbar for non-composite elements is clicked.
EXT:form uses this event to create a new form element (getFormEditorApp().getViewModel().createAndAddFormElement())
and then move (getFormEditorApp().getViewModel().moveFormElement()) it
below the currently selected element (sibling). At the end of this event, the
event view/formElement/inserted
is called. The event view/formElement/inserted in getFormEditorApp().getViewModel().createAndAddFormElement()
was previously deactivated.
This event is called from the "new element" dialog box upon selection of a form
element:
if, in the abstract view mode, the "Create new element" button at the end of the Stage component is clicked.
EXT:form uses this event to create a new form element (getFormEditorApp().getViewModel().createAndAddFormElement()).
This element is always created as the last element of the currently selected
page.
This event is called from the "new element" dialog box upon selection of a form
element:
if "Inside" in the "Create new element" split button in the form-element toolbar for composite elements (e.g. fieldset) is clicked.
EXT:form uses this event to create a new form element as a child element of the
currently selected element (getFormEditorApp().getViewModel().createAndAddFormElement()).
The inspector editorsValidatorsEditor
and FinishersEditor
are used to display the available validators/ finishers for a form element as a
select box. Furthermore, these inspector editors indicate that in the
form definition, validators/ finishers for the currently selected element
already exist. This occurs through the event view/inspector/collectionElement/existing/selected.
EXT:form uses this event to render these validators/ finishers and their
tentatively configured inspector editors (getFormEditorApp().getViewModel().renderInspectorCollectionElementEditors()).
The inspector editorsValidatorsEditor
and FinishersEditor
are used to display the available validators/ finishers for a form element as a
select box. The onChange event of the select box then calls this event. In
addition, the inspector editorRequiredValidatorEditor
calls this event when a checkbox is chosen. EXT:form uses this event to add and
render the validator/ finisher of the form definition via getFormEditorApp().getViewModel().createAndAddPropertyCollectionElement().
EXT:form uses the library 'SortableJS' for the drag-and-drop functionality.
The 'end' event from 'SortableJS' calls
the view/inspector/collectionElements/dnd/update event if a property
collection element in the Inspector component is sorted. EXT:form uses this
event to move the validator/ finisher in the form definition via the method
getFormEditorApp().getViewModel().movePropertyCollectionElement().
The methods getFormEditorApp().getViewModel().renderInspectorEditors() (to
render all inspector editors for a form element) and getFormEditorApp().getViewModel().renderInspectorCollectionElementEditors()
(to render the inspector editors for a validator/ finisher) call this event
at the end. Strictly speaking, the Inspector component in the method
_renderEditorDispatcher() calls this event.
Each inspector editor has the property templateName,
which gives the form editor two pieces of information. On the one hand the
templateName must match with a key within the prototypes.prototypeIdentifier.formeditor.formEditorPartials.
The form editor can consequently load a corresponding inline HTML template
for the inspector editor. On the other hand, the Inspector component
must be told which JavaScript code should be executed for the
inspector editor. For the inspector editors delivered with EXT:form,
this occurs within the method _renderEditorDispatcher().
An existing hard-coded list of known inspector editors determines, by means
of the property templateName, which corresponding JavaScript method should
be executed for the inspector editor. At the end, the event
view/inspector/editor/insert/perform is called. If you wish to implement
your own inspector editor, you can use this event to execute in
your own JavaScript module.
the corresponding JavaScript code, with the help of the property
templateName.
The inspector editorRequiredValidatorEditor
calls this event, if the checkbox is deselected. EXT:form uses this event to
remove the configured required validator ('NotEmpty') from the `form
definition`` through the method ``getFormEditorApp().getViewModel().removePropertyCollectionElement()`.
If you try to close the form editor with unsaved content, a dialog box
appears, asking whether you really wish to close it. If you confirm it, this
event is called in the check box component. EXT:form uses this event to
close the form editor and return to the form manager.
If you try to remove a validator/ finisher by clicking the remove icon, a
dialog box appears, asking you to confirm this action. If confirmed, this event
is called in the check box component. EXT:form uses this event to remove
the validator/ finisher from the form definition through the method
getFormEditorApp().getViewModel().removePropertyCollectionElement().
If you try to remove a form element by clicking the remove icon, a dialog box
appears, asking you to confirm this action. If confirmed, this event is called
in the check box component. EXT:form uses this event to remove the form
element from the form definition via the method getFormEditorApp().getViewModel().removeFormElement().
If a form element contains a validation error and you try to save the form, a
dialog box appears, listing all form elements with validation errors. One such
form element can be clicked in this dialog box. This event is called by
clicking a form element in the dialog box. EXT:form uses this event to select
and show this form element.
This event is called if the 'pagination next' button in the Stage
component's header section is clicked. EXT:form uses this event to render the
next page of the form.
This event is called, if the 'pagination previous' button in the Stage
component's header section is clicked. EXT:form uses this event to render the
previous page of the form.
EXT:form makes it possible to load your own JavaScript module.
If all modules are loaded, the view-model method _loadAdditionalModules
calls this event. EXT:form uses this event to remove the preloader icon and
finally initialize the form editor.
This event is called if the redo button in the form editor header is
clicked. The addition/ deletion and movement of form elements and property
collection elements (validators/ finishers) is saved in an internal stack in
order to reset the undo/ redo functionality. EXT:form uses this event to reset
this stack to the previous state.
This event is called if the "Create new element" button at the end of the
Stage component in the abstract view mode is clicked. EXT:form uses
this event to display the "new element" dialog box.
EXT:form uses the library 'SortableJS' for the drag-and-drop functionality.
The 'change' event from 'SortableJS' calls
the view/stage/abstract/dnd/change event in the Stage component in the
abstract view mode if form elements are sorted. EXT:form uses this event to
set various CSS classes during the drag-and-drop process.
EXT:form uses the library 'SortableJS' for the drag-and-drop functionality.
The 'start' event from 'SortableJS' calls
the view/stage/abstract/dnd/start event in the Stage component in the
abstract view mode if form elements are sorted. EXT:form uses this event to
set various CSS classes at the start of the drag-and-drop process.
EXT:form uses the library 'SortableJS' for the drag-and-drop functionality.
The 'end' event from 'SortableJS' calls the
view/stage/abstract/dnd/stop event in the Stage component in the
abstract view mode if form elements are sorted. EXT:form uses this event to
to re-render the Tree, Stage and Inspector components at the end of
the drag-and-drop process and to select the moved form element.
EXT:form uses the library 'SortableJS' for the drag-and-drop functionality.
The 'end' event from 'SortableJS' calls
the view/stage/abstract/dnd/update event in the Stage component in the
abstract view mode if form elements are sorted. EXT:form uses this event
to move the form element in the form definition accordingly at the end of
the drag-and-drop process.
This event is called if the "Create new element" button in the form-element
toolbar or "Inside" or "After" in the split button is clicked. EXT:form uses
this event to display the "New element" dialog box.
The methods getFormEditorApp().getViewModel().renderAbstractStageArea()
call this event. Strictly speaking, the Stage component in the method
_renderTemplateDispatcher() calls this event. The form editor requires
for each form element an inline HTML template the corresponding JavaScript
code. Information matching inline HTML templates to the appropriate form
elements must be configured within prototypes.prototypeIdentifier.formeditor.formEditorPartials.
At this point, the key identifying the form element follows a convention:
FormElement-<formElementTypeIdentifier>. The value for the key tells the
form editor which inline HTML template should be loaded for the respective
form element. The _renderTemplateDispatcher() method then identifies, by
means of the form element's <formElementTypeIdentifier>, the corresponding
JavaScript code to fill the inline HTML template with life.
_renderTemplateDispatcher() contains a hard-coded list with the
<formElementTypeIdentifier> that is brought in with the EXT:form, and it
renders the inline HTML templates accordingly. At the end, the
view/stage/abstract/render/template/perform event is called. If you wish to
implement your own form element and show it in the form editor, this event
can be used to execute in your own JavaScript module
the corresponding JavaScript code, with the help of the <formElementTypeIdentifier>.
This is generally enough to allow the Stage/SimpleTemplate and/ or
Stage/SelectTemplate inline HTML template to be rendered for your own form
element and, in the JavaScript code, to access the getFormEditorApp().getViewModel().getStage().renderSimpleTemplateWithValidators()
and/ or getFormEditorApp().getViewModel().getStage().renderSelectTemplates()
method delivered with EXT:form. An overview over the functionality of the
formEditorPartials for the <formElementTypeIdentifier> and its JavaScript
code is found here.
A simple example reusing the EXT:form inline HTML template Stage/SelectTemplate and the EXT:form JavaScript code renderSelectTemplates()
for a custom form element with <formElementTypeIdentifier> = 'GenderSelect'.
In this example, 'GenderSelect' is basically a radio button form element with some predefined options.
This event is called from the Stage component when a form element is
clicked. EXT:form uses this event to select this element and to display the
form-element toolbar. In addition, the Tree and Inspector components
are re-rendered.
This event is called from the onClick event of the Tree component's "Create
new page" button. EXT:form uses this event to display the "new page" dialog
box.
This event is called from the view-model after the Tree component has been
re-rendered. EXT:form uses this event to display potential validation errors
from form elements in the Tree component.
This event is called if the root form element in the Tree component is
clicked. EXT:form uses this event to re-render the Stage, Inspector and
Tree components.
EXT:form uses the library 'SortableJS' for the drag-and-drop functionality.
The 'change' event from 'SortableJS' calls
the view/tree/dnd/change event in der Tree component if form elements
are sorted. EXT:form uses this event to set various CSS classes during the drag
-and-drop process.
EXT:form uses the library 'SortableJS' for the drag-and-drop functionality.
The 'end' event from 'SortableJS' calls the
view/tree/dnd/stop event in the Tree component if form elements are
sorted. EXT:form uses this event to re-render Tree, Stage and
Inspector components at the end of the drag-and-drop process and to select
the moved form element.
EXT:form uses the library 'SortableJS' for the drag-and-drop functionality.
The 'end' event from 'SortableJS' calls
the view/tree/dnd/update event in der Tree component if form elements
are sorted. EXT:form uses this event to move the form element in the `form
definition` accordingly at the end of the drag-and-drop process.
This event is called from the Tree component if a form element is clicked.
EXT:form uses this event to re-render the Stage and Inspector
components and select the form element.
This event is called when the undo button is clicked in the form editor
header. The history of adding / deleting and moving form elements and property
collection elements (validators/ finishers) is stored in an internal stack to
implement the undo / redo functionality. EXT:form uses this event to set this
stack to the next state.
This event is called when the abstract view button is clicked in the header
area of the Stage component. EXT:form uses this event to render the
abstract view in the Stage component.
This event is called when the preview button is clicked in the header area of
the Stage component. EXT:form uses this event to render the `preview
view`` in the ``Stage` component.
__parentRenderable includes the parent element as FormElement model.
Property: __identifierPath
Internally, all form elements are identified by their 'identifier' property,
which must be unique for each form. The __identifierPath property contains
the path to the element (as seen from the first element), separated by a /.
Using this path, you can access the element directly through an API method.
Method: get()
Each property of the FormElement model can be accessed by the get()
method through the property path (separated by .). Prerequisite for this
is that all levels up to the target property are objects.
Access to properties.fluidAdditionalAttributes.placeholder:
// value = 'Name'var value = getFormEditorApp().getFormElementByIdentifierPath('example-form/page-1/name').get('properties.fluidAdditionalAttributes.placeholder');
Copied!
Two exceptions are the two arrays of "finishers" / "validators" (`property
collections``) and the ``renderables`.
Accessing property collection properties
Property collection are identified as form elements through the property
identifier. Because property collection properties are in an array and
their positions in the array are potentially unknown, the getFormEditorApp().buildPropertyPath()
method exists. This can be used to access a property of a property collection
item via its identifier.
Access to options.minimum of the validator StringLength:
var formElement = getFormEditorApp().getFormElementByIdentifierPath('example-form/page-1/name');
var propertyPath = getFormEditorApp().buildPropertyPath('options.minimum', 'StringLength', 'validators', formElement);
// value = 1var value = formElement.get(propertyPath);
Copied!
Accessing renderables
Like property collections, renderables (the child elements) are also in
an array and their position in the array is potentially unknown. Direct access
to child elements through the get() method is impossible.
formElement.get('renderables') supplies an array with the `FormElement
models` of the child elements. You must then loop over this array. Access to a
specific child element should be done using getFormEditorApp().getFormElementByIdentifierPath().
Method: set()
Any property of the FormElement model can be written using the set()
method by means of the property path (separated by .).
Delete the property properties.fluidAdditionalAttributes.placeholder:
// value = 'Name'var value = getFormEditorApp().getFormElementByIdentifierPath('example-form/page-1/name').unset('properties.fluidAdditionalAttributes.placeholder');
Copied!
Example of the FormElement model after the unset() operation:
Delete the property options.minimum of the validator StringLength:
var formElement = getFormEditorApp().getFormElementByIdentifierPath('example-form/page-1/name');
var propertyPath = getFormEditorApp().buildPropertyPath('options.minimum', 'StringLength', 'validators', formElement);
formElement.unset(propertyPath);
Copied!
Remove renderables
To delete a FormElement model, the corresponding API method
getFormEditorApp().removeFormElement() should be used.
Method: on()
Any number of Publisher/Subscriber
events can be assigned to any property path of a FormElement model. Each
set() operation on this property path will then call these events. By
default, EXT:form registers the event core/formElement/somePropertyChanged
for each property path.
Example:
getFormEditorApp().getFormElementByIdentifierPath('example-form/page-1/name').on('properties.fluidAdditionalAttributes.placeholder', 'my/custom/event');
getFormEditorApp().getFormElementByIdentifierPath('example-form/page-1/name').set('properties.fluidAdditionalAttributes.placeholder', 'New Placeholder');
// now, the event 'my/custom/event' will be published
Copied!
Method: off()
Any event registered via on()
can be removed with off().
All FormElement model properties are private and cannot be manipulated
directly from the outside. They can only be accessed via set() or
get(). This method is used internally to obtain all data of a `FormElement
model` in object form so that they can be used in, for example, Ajax requests.
getObjectData() returns a dereferenced object of the FormElement model
with all internal data, thus allowing read access to all data set via
set().
Method: toString()
A method that was implemented for debugging purposes. Returns the object data
supplied by getObjectData() in string form.
console.log(formElement.toString());
Copied!
Method: clone()
If necessary, a form element can be cloned. Returns a dereferenced clone of the
original FormElement model.
var dolly = formElement.clone();
Copied!
Frontend rendering
TYPO3\CMS\Form\Domain\Renderer\FluidFormRenderer
Options
The FluidFormRenderer uses some rendering options which are of particular importance,
as they determine how the form field is resolved to a path in the file system.
All rendering options are retrieved from the FormDefinition, using the TYPO3\CMS\Form\Domain\Model\FormDefinition::getRenderingOptions() method.
templateRootPaths
Used to define several paths for templates, which will be tried in reversed order (the paths are searched from bottom to top).
The first folder where the desired template is found, is used. If the array keys are numeric, they are first sorted and then tried in reversed order.
Within this paths, fluid will search for a file which is named like the <formElementTypeIdentifier>.
Used to define several paths for layouts, which will be tried in reversed order (the paths are searched from bottom to top).
The first folder where the desired layout is found, is used. If the array keys are numeric, they are first sorted and then tried in reversed order.
Used to define several paths for partials, which will be tried in reversed order. The first folder where the desired partial is found, is used.
The keys of the array define the order.
Within this paths, fluid will search for a file which is named like the <formElementTypeIdentifier>.
A class name of a FormFactory.
This factory is used to create the TYPO3\CMS\Form\Domain\Model\FormDefinition which is the form definition Domain Model.
If no factoryClass argument is passed, the factory supplied by EXT:form TYPO3\CMS\Form\ Domain\Factory\ArrayFormFactory is used.
Another factory class is required if the form is to be generated programmatically.
To do this you must implement your own FormFactory in which your own form is generated programmatically and passes this class name to the ViewHelper.
This then renders the form.
The form definition to be found under persistenceIdentifier.
The PersistenceManager now loads the form definition which is found under persistenceIdentifier and passes this configuration to the factoryClass.
In this case, the factoryClass will be given an empty configuration array (if overrideConfiguration is not specified).
A configuration to be superimposed can be entered here.
If a persistenceIdentifier is specified, the form definition which is found under persistenceIdentifier is loaded.
This configuration is then superimposed with overrideConfiguration. This configuration is then passed to the factoryClass.
If no persistenceIdentifier is specified, overrideConfiguration is passed directly to the factoryClass.
This way a configuration can be given to a factoryClass implementation.
prototypeName
The name of the prototype, on which basis the factoryClass should create the form.
If nothing is specified, the configuration (form definition or overrideConfiguration) is searched for the prototype's name.
If no specification exists, the standard prototype standard is used.
Build forms programmatically
Implement a FormFactory and build the form:
declare(strict_types = 1);
namespace VENDOR\MySitePackage\Domain\Factory;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Validation\Validator\NotEmptyValidator;
use TYPO3\CMS\Extbase\Validation\Validator\StringLengthValidator;
use TYPO3\CMS\Form\Domain\Configuration\ConfigurationService;
use TYPO3\CMS\Form\Domain\Factory\AbstractFormFactory;
use TYPO3\CMS\Form\Domain\Model\FormDefinition;
class CustomFormFactory extends AbstractFormFactory
{
/**
* Build a FormDefinition.
* This example build a FormDefinition manually,
* so $configuration and $prototypeName are unused.
*
* @param array $configuration
* @param string $prototypeName
* @return FormDefinition
*/
public function build(array $configuration, string $prototypeName = null): FormDefinition
{
$prototypeName = 'standard';
$configurationService = GeneralUtility::makeInstance(ConfigurationService::class);
$prototypeConfiguration = $configurationService->getPrototypeConfiguration($prototypeName);
$form = GeneralUtility::makeInstance(FormDefinition::class, 'MyCustomForm', $prototypeConfiguration);
$form->setRenderingOption('controllerAction', 'index');
$page1 = $form->createPage('page1');
$name = $page1->createElement('name', 'Text');
$name->setLabel('Name');
$name->addValidator(GeneralUtility::makeInstance(NotEmptyValidator::class));
$page2 = $form->createPage('page2');
$message = $page2->createElement('message', 'Textarea');
$message->setLabel('Message');
$message->createValidator('StringLength', ['minimum' => 5, 'maximum' => 20]);
// Creating a RadioButton/MultiCheckbox
$page3 = $form->createPage('page3');
$radio = $page3->createElement('checkbox', 'RadioButton');
$radio->setProperty('options', ['value1' => 'Label1', 'value2' => 'Label2']);
$radio->setLabel('My Radio ...');
$form->createFinisher('EmailToSender', [
'subject' => 'Hello',
'recipients' => [
'your.company@example.com' => 'Your Company name'
],
'senderAddress' => 'bar@example.com',
]);
$this->triggerFormBuildingFinished($form);
return $form;
}
}
You can use this method to prefill form element data for example from database tables.
All the classes you can see above extends from the TYPO3\CMS\Form\Domain\Model\FormElement\AbstractFormElement.
AbstractFormElement implements this method like this:
public function initializeFormElement()
{
if (
isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['initializeFormElement'])
&& is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['initializeFormElement'])
) {
foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['initializeFormElement'] as $className) {
$hookObj = GeneralUtility::makeInstance($className);
if (method_exists($hookObj, 'initializeFormElement')) {
$hookObj->initializeFormElement(
$this
);
}
}
}
}
Copied!
If you extend your custom implementation from AbstractFormElement (and you should do this),
it enables you to override the 'initializeFormElement' method within your custom implementation class.
If you do not call the parents 'initializeFormElement' then no hook will be thrown.
If your use case for a custom form element implementation means that you only want to initialize you form element
programmatically (e.g to get database data) and no other special things are to do, you might prefer the hook.
You only need a class which connects to this hook. Then detect the form element you wish to initialize.
Further API Methods
TYPO3\CMS\Form\Domain\Model\FormRuntime
overrideCurrentPage()
Override the current page taken from the request, rendering the page with index $pageIndex instead.
This is typically not needed in production code.
You might prefer the hook afterInitializeCurrentPage
Signature:
public function overrideCurrentPage(int $pageIndex);
Get the request this object is bound to.
This is mostly relevant inside Finishers, where you f.e. want to redirect the user to another page.
Signature:
public function getRequest(): Request;
Copied!
getResponse()
Get the response this object is bound to.
This is mostly relevant inside Finishers, where you f.e. want to set response headers or output content.
Signature:
public function getResponse(): Response;
Copied!
getCurrentPage()
Returns the currently selected page.
Signature:
public function getCurrentPage(): Page;
Copied!
getPreviousPage()
Returns the previous page of the currently selected one or NULL if there is no previous page.
Signature:
public function getPreviousPage();
Copied!
getNextPage()
Returns the next page of the currently selected one or NULL if there is no next page.
Signature:
public function getNextPage();
Copied!
getType()
Abstract "type" of the form element.
For example, the type is used during the rendering process to determine the template file.
Signature:
public function getType(): string;
Copied!
getElementValue()
Returns the value of the specified element.
Signature:
public function getElementValue(string $identifier);
Copied!
getPages()
Return the form's pages in the correct order.
Signature:
public function getPages(): array;
Copied!
getRenderingOptions()
Get all rendering options of the form element.
Signature:
public function getRenderingOptions(): array;
Copied!
getRendererClassName()
Get the renderer class name.
Signature:
public function getRendererClassName(): string;
Copied!
getLabel()
Get the label of the form element.
Signature:
public function getLabel(): string;
Copied!
getTemplateName()
Get the template name of the form element.
Signature:
public function getTemplateName(): string;
Copied!
getFormDefinition()
Get the underlying form definition from the runtime.
Signature:
public function getFormDefinition(): FormDefinition;
Copied!
TYPO3\CMS\Form\Domain\Model\FormDefinition
addPage()
Add a new page at the end of the form.
Instead of this method, you should use createPage instead.
Signature:
public function addPage(Page $page);
Copied!
createPage()
Create a page with the given $identifier and attach this page to the form.
Create Page object based on the given $typeName
set defaults inside the Page object
attach Page object to this form
return the newly created Page object
Signature:
public function createPage(string $identifier, string $typeName = 'Page'): Page;
Copied!
getPages()
Return the form's pages in the correct order.
Signature:
public function getPages(): array;
Copied!
hasPageWithIndex()
Check whether a page with the given $index exists.
Signature:
public function hasPageWithIndex(int $index): bool;
Copied!
getPageByIndex()
Get the page with the passed index. The first page has index zero.
If page at $index does not exist, an exception is thrown.
Signature:
public function getPageByIndex(int $index);
Copied!
addFinisher()
Adds the specified finisher to the form.
Instead of this method, you should use createFinisher instead.
Signature:
public function addFinisher(FinisherInterface $finisher);
Copied!
createFinisher()
Create a finisher with the given $identifier and given $options and attach this finisher to the form.
Signature:
public function createFinisher(string $finisherIdentifier, array $options = []): FinisherInterface;
Copied!
getFinishers()
Gets all finishers of the form.
Signature:
public function getFinishers(): array;
Copied!
getElementByIdentifier()
Get a form element by its identifier.
If identifier does not exist, returns NULL.
Signature:
public function getElementByIdentifier(string $elementIdentifier);
Copied!
movePageAfter()
Move $pageToMove after $referencePage.
Signature:
public function movePageAfter(Page $pageToMove, Page $referencePage);
Copied!
removePage()
Remove $pageToRemove from the form.
Signature:
public function removePage(Page $pageToRemove);
Copied!
bind()
Bind the current request and response to this form instance, effectively creating a new "instance" of the Form.
Signature:
public function bind(Request $request): FormRuntime;
Copied!
getProcessingRule()
Get the processing rule which contains information for property mappings and validations.
Signature:
public function getProcessingRule(string $propertyPath): ProcessingRule;
Copied!
getType()
Abstract "type" of the form element.
For example, the type is used during the rendering process to determine the template file.
Signature:
public function getType(): string;
Copied!
getIdentifier()
Returns the identifier of the form element.
Signature:
public function getIdentifier(): string;
Copied!
setIdentifier()
Set the identifier of the form element.
Signature:
public function setIdentifier(string $identifier);
Copied!
setOptions()
Set multiple properties of this object at once.
Every property which has a corresponding set* method can be set using the passed $options array.
Signature:
public function setOptions(array $options);
Copied!
addValidator()
Registers a validator for the form element.
Signature:
public function addValidator(ValidatorInterface $validator);
Copied!
setDataType()
The target data type the data should be converted through the property mapper.
Signature:
public function setDataType(string $dataType);
Copied!
Example:
public function initializeFormElement()
{
$this->setDataType('TYPO3\CMS\Extbase\Domain\Model\FileReference');
parent::initializeFormElement();
}
Copied!
getRendererClassName()
Get the renderer class name.
Signature:
public function getRendererClassName(): string;
Copied!
setRendererClassName()
Set the renderer class name.
Signature:
public function setRendererClassName(string $rendererClassName);
Copied!
getRenderingOptions()
Get all rendering options of the form element.
Signature:
public function getRenderingOptions(): array;
Copied!
setRenderingOption()
Set a rendering option.
Signature:
public function setRenderingOption(string $key, $value);
Copied!
getParentRenderable()
Return the parent form element.
Signature:
public function getParentRenderable();
Copied!
setParentRenderable()
Set the new parent renderable. You should not call this directly.
It is automatically called by addRenderable.
Signature:
public function setParentRenderable(CompositeRenderableInterface $renderable);
Copied!
getRootForm()
Get the root form the element belongs to.
Signature:
public function getRootForm(): FormDefinition
Copied!
getLabel()
Get the label of the form element.
Signature:
public function getLabel(): string;
Copied!
setLabel()
Set the label of the form element.
Signature:
public function setLabel(string $label);
Copied!
getTemplateName()
Get the template name of the form element.
Signature:
public function getTemplateName(): string;
Copied!
TYPO3\CMS\Form\Domain\Model\FormElements\Page
getElements()
Get the child form elements.
Signature:
public function getElements(): array;
Copied!
getElementsRecursively()
Returns all RenderableInterface instances of this composite renderable recursively.
Signature:
public function getElementsRecursively(): array;
Copied!
addElement()
Add a new form element at the end.
Instead of this method, you should use createElement instead.
Signature:
public function addElement(FormElementInterface $formElement);
Copied!
createElement()
Create a form element with the given $identifier and attach it to the page.
Create Form Element object based on the given $typeName
set defaults inside the Form Element (based on the parent form's field defaults)
attach Form Element to the Page
return the newly created Form Element object
Signature:
public function createElement(string $identifier, string $typeName): FormElementInterface;
Copied!
moveElementBefore()
Move FormElement $elementToMove before $referenceElement.
Both $elementToMove and $referenceElement must be direct descendants of this Section/Page.
Signature:
public function moveElementBefore(FormElementInterface $elementToMove, FormElementInterface $referenceElement);
Copied!
moveElementAfter()
Move FormElement $elementToMove after $referenceElement.
Both $elementToMove and $referenceElement must be direct descendants of this Section/Page.
Signature:
public function moveElementAfter(FormElementInterface $elementToMove, FormElementInterface $referenceElement);
Copied!
removeElement()
Remove $elementToRemove from this Section/Page.
Signature:
public function removeElement(FormElementInterface $elementToRemove);
Copied!
getType()
Abstract "type" of the form element.
For example, the type is used during the rendering process to determine the template file.
Signature:
public function getType(): string;
Copied!
getIdentifier()
Returns the identifier of the form element.
Signature:
public function getIdentifier(): string;
Copied!
setIdentifier()
Set the identifier of the form element.
Signature:
public function setIdentifier(string $identifier);
Copied!
setOptions()
Set multiple properties of this object at once.
Every property which has a corresponding set* method can be set using the passed $options array.
Signature:
public function setOptions(array $options);
Copied!
addValidator()
Registers a validator for the form element.
Signature:
public function addValidator(ValidatorInterface $validator);
Copied!
createValidator()
Create a validator for the element.
Signature:
public function createValidator(string $validatorIdentifier, array $options = []);
Copied!
setDataType()
The target data type the data should be converted through the property mapper.
Signature:
public function setDataType(string $dataType);
Copied!
Example:
public function initializeFormElement()
{
$this->setDataType('TYPO3\CMS\Extbase\Domain\Model\FileReference');
parent::initializeFormElement();
}
Copied!
getRendererClassName()
Get the renderer class name.
Signature:
public function getRendererClassName(): string;
Copied!
getRenderingOptions()
Get all rendering options of the form element.
Signature:
public function getRenderingOptions(): array;
Copied!
setRenderingOption()
Set a rendering option.
Signature:
public function setRenderingOption(string $key, $value);
Copied!
getParentRenderable()
Return the parent form element.
Signature:
public function getParentRenderable();
Copied!
setParentRenderable()
Set the new parent renderable. You should not call this directly.
It is automatically called by addRenderable.
Signature:
public function setParentRenderable(CompositeRenderableInterface $renderable);
Copied!
getRootForm()
Get the root form the element belongs to.
Signature:
public function getRootForm(): FormDefinition
Copied!
getLabel()
Get the label of the form element.
Signature:
public function getLabel(): string;
Copied!
setLabel()
Set the label of the form element.
Signature:
public function setLabel(string $label);
Copied!
getTemplateName()
Get the template name of the form element.
Signature:
public function getTemplateName(): string;
Copied!
TYPO3\CMS\Form\Domain\Model\FormElements\Section
initializeFormElement()
Will be called as soon as the element is (tried to be) added to a form.
Signature:
public function initializeFormElement();
Copied!
getUniqueIdentifier()
Returns a unique identifier of the element. While element identifiers are only unique within one form,
this identifier includes also the identifier of the form itself, and therefore making it "globally" unique.
Get all element-specific configuration properties.
Signature:
public function getProperties(): array;
Copied!
isRequired()
Whether or not the element is required.
An element is required if the TYPO3\CMS\Extbase\Validation\Validator\NotEmptyValidator is attached to the element.
Signature:
public function isRequired(): bool;
Copied!
getElements()
Get the child form elements.
Signature:
public function getElements(): array;
Copied!
getElementsRecursively()
Returns all RenderableInterface instances of this composite renderable recursively.
Signature:
public function getElementsRecursively(): array;
Copied!
addElement()
Add a new form element at the end.
Instead of this method, you should use createElement instead.
Signature:
public function addElement(FormElementInterface $formElement);
Copied!
createElement()
Create a form element with the given $identifier and attach it to the section.
Create Form Element object based on the given $typeName
set defaults inside the Form Element (based on the parent form's field defaults)
attach Form Element to the Section
return the newly created Form Element object
Signature:
public function createElement(string $identifier, string $typeName): FormElementInterface;
Copied!
moveElementBefore()
Move FormElement $elementToMove before $referenceElement.
Both $elementToMove and $referenceElement must be direct descendants of this Section/Page.
Signature:
public function moveElementBefore(FormElementInterface $elementToMove, FormElementInterface $referenceElement);
Copied!
moveElementAfter()
Move FormElement $elementToMove after $referenceElement.
Both $elementToMove and $referenceElement must be direct descendants of this Section/Page.
Signature:
public function moveElementAfter(FormElementInterface $elementToMove, FormElementInterface $referenceElement);
Copied!
removeElement()
Remove $elementToRemove from this Section/Page.
Signature:
public function removeElement(FormElementInterface $elementToRemove);
Copied!
getType()
Abstract "type" of the form element.
For example, the type is used during the rendering process to determine the template file.
Signature:
public function getType(): string;
Copied!
getIdentifier()
Returns the identifier of the form element.
Signature:
public function getIdentifier(): string;
Copied!
setIdentifier()
Set the identifier of the form element.
Signature:
public function setIdentifier(string $identifier);
Copied!
setOptions()
Set multiple properties of this object at once.
Every property which has a corresponding set* method can be set using the passed $options array.
Signature:
public function setOptions(array $options);
Copied!
addValidator()
Registers a validator for the form element.
Signature:
public function addValidator(ValidatorInterface $validator);
Copied!
createValidator()
Create a validator for the element.
Signature:
public function createValidator(string $validatorIdentifier, array $options = []);
Copied!
setDataType()
The target data type the data should be converted through the property mapper.
Signature:
public function setDataType(string $dataType);
Copied!
Example:
public function initializeFormElement()
{
$this->setDataType('TYPO3\CMS\Extbase\Domain\Model\FileReference');
parent::initializeFormElement();
}
Copied!
getRendererClassName()
Get the renderer class name.
Signature:
public function getRendererClassName(): string;
Copied!
getRenderingOptions()
Get all rendering options of the form element.
Signature:
public function getRenderingOptions(): array;
Copied!
setRenderingOption()
Set a rendering option.
Signature:
public function setRenderingOption(string $key, $value);
Copied!
getParentRenderable()
Return the parent form element.
Signature:
public function getParentRenderable();
Copied!
setParentRenderable()
Set the new parent renderable. You should not call this directly.
It is automatically called by addRenderable.
Signature:
public function setParentRenderable(CompositeRenderableInterface $renderable);
Will be called as soon as the element is (tried to be) added to a form.
Signature:
public function initializeFormElement();
Copied!
getUniqueIdentifier()
Returns a unique identifier of the element. While element identifiers are only unique within one form,
this identifier includes also the identifier of the form itself, and therefore making it "globally" unique.
Get the default value with which the form element should be initialized during display.
Signature:
public function getDefaultValue();
Copied!
setDefaultValue()
Set the default value with which the form element should be initialized during display.
Signature:
public function setDefaultValue($defaultValue);
Copied!
setProperty()
Set an element-specific configuration property.
Signature:
public function setProperty(string $key, $value);
Copied!
getProperties()
Get all element-specific configuration properties.
Signature:
public function getProperties(): array;
Copied!
isRequired()
Whether or not the element is required.
An element is required if the TYPO3\CMS\Extbase\Validation\Validator\NotEmptyValidator is attached to the element.
Signature:
public function isRequired(): bool;
Copied!
getType()
Abstract "type" of the form element.
For example, the type is used during the rendering process to determine the template file.
Signature:
public function getType(): string;
Copied!
getIdentifier()
Returns the identifier of the form element.
Signature:
public function getIdentifier(): string;
Copied!
setIdentifier()
Set the identifier of the form element.
Signature:
public function setIdentifier(string $identifier);
Copied!
setOptions()
Set multiple properties of this object at once.
Every property which has a corresponding set* method can be set using the passed $options array.
Signature:
public function setOptions(array $options);
Copied!
addValidator()
Registers a validator for the form element.
Signature:
public function addValidator(ValidatorInterface $validator);
Copied!
createValidator()
Create a validator for the element.
Signature:
public function createValidator(string $validatorIdentifier, array $options = []);
Copied!
setDataType()
The target data type the data should be converted through the property mapper.
Signature:
public function setDataType(string $dataType);
Copied!
Example:
public function initializeFormElement()
{
$this->setDataType('TYPO3\CMS\Extbase\Domain\Model\FileReference');
parent::initializeFormElement();
}
Copied!
getRendererClassName()
Get the renderer class name.
Signature:
public function getRendererClassName(): string;
Copied!
getRenderingOptions()
Get all rendering options of the form element.
Signature:
public function getRenderingOptions(): array;
Copied!
setRenderingOption()
Set a rendering option.
Signature:
public function setRenderingOption(string $key, $value);
Copied!
getParentRenderable()
Return the parent form element.
Signature:
public function getParentRenderable();
Copied!
setParentRenderable()
Set the new parent renderable. You should not call this directly.
It is automatically called by addRenderable.
Signature:
public function setParentRenderable(CompositeRenderableInterface $renderable);
Copied!
getRootForm()
Get the root form the element belongs to.
Signature:
public function getRootForm(): FormDefinition
Copied!
getLabel()
Get the label of the form element.
Signature:
public function getLabel(): string;
Copied!
setLabel()
Set the label of the form element.
Signature:
public function setLabel(string $label);
Copied!
getTemplateName()
Get the template name of the form element.
Signature:
public function getTemplateName(): string;
Copied!
TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher
The following classes extends from AbstractFinisher and therefore contain the following API methods.
Executes the finisher. AbstractFinisher::execute() call $this->executeInternal() at the end. Own finisher
implementations which extends from AbstractFinisher: must start their own logic within executeInternal().
Signature:
public function execute(FinisherContext $finisherContext);
Copied!
setOptions()
Set the finisher options. Instead of directly accessing them, you should rather use parseOption().
Signature:
public function setOptions(array $options);
Copied!
setOption()
Sets a single finisher option.
Signature:
public function setOption(string $optionName, $optionValue);
public function getPrototypeConfiguration(string $prototypeName): array;
Copied!
TYPO3\CMS\Form\Domain\Factory\AbstractFormFactory
triggerFormBuildingFinished()
Helper to be called by every FormFactory which extends from AbstractFormFactory after
everything has been built to call the "afterBuildingFinished" hook on all form elements.
Signature:
protected function triggerFormBuildingFinished(FormDefinition $form);
Build a form definition, depending on some configuration.
Signature:
public function build(array $configuration, string $prototypeName = null): FormDefinition;
Copied!
TYPO3\CMS\Form\Domain\Renderer\RendererInterface
render()
Renders the FormDefinition. This method is expected to call the beforeRendering hook on each form element:
public function render(): string;
Copied!
setFormRuntime()
Set the current FormRuntime:
public function setFormRuntime(FormRuntime $formRuntime);
Copied!
getFormRuntime()
Get the current FormRuntime:
public function getFormRuntime(): FormRuntime;
Copied!
Runtime manipulation
Hooks
initializeFormElement
You can connect to this hook and initialize a form element without defining a
custom implementation to access the element's initializeFormElement method.
You only need a class which connects to this hook. Then detect the form
element you wish to initialize. For example, you can use this hook to prefill
form element data from database tables. Note that this hook will be called
after all properties from the prototype configuration are set in the form
element but before the properties from the form definition are set in the
form element. If you want to prefill form element data after the complete
form element is configured you should use the
afterBuildingFinished hook.
The initializeFormElement hook is invoked by the methods TYPO3\CMS\Form\Domain\Model\FormElements\Page::createElement()
and TYPO3\CMS\Form\Domain\Model\FormElements\Section::createElement().
That means the hook will not be triggered for Pages. At this point
you do not have access to submitted form element values.
Leaving the section <useATimestampAsKeyPlease> as is is not recommended.
It does nothing except cause the extension to fail and an error message to be
delivered. Nor should it be replaced with a function like time(), as the key
should be unalterable. Instead, replace this section with the current UNIX
timestamp the moment you are implementing the hook. Check out the following
example:
The purpose of timestamps is to prevent conflicts that arise when two or more
extensions within one TYPO3 installation use identical keys (e.g.
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/form']['initializeFormElement']['foo']).
When timestamps are used, even a one-second difference in the time different
hooks were connected ensures that one hook does not override the other.
beforeRemoveFromParentRenderable
This hook is invoked by the methods TYPO3\CMS\Form\Domain\Model\FormDefinition::removePage(), TYPO3\CMS\Form\Domain\Model\FormElements\Page::removeElement()
and TYPO3\CMS\Form\Domain\Model\FormElements\Section::removeElement()
/**
* @param \TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface $renderable
* @return void
*/
public function beforeRemoveFromParentRenderable(\TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface $renderable)
{
}
Copied!
afterBuildingFinished
This hook is called for each form element after the class TYPO3\CMS\Form\Domain\Factory\ArrayFormFactory
has built the entire form. This hook is triggered just before the
FormRuntime object is generated. At this point, no run-time information
(e.g. assigned form values) is yet available. It can, for example, be used to
generate new form elements within complex forms. The ArrayFormFactory is
used by EXT:form via the RenderViewHelper to render forms using a `form
definition` YAML file. Each form factory implementation must deal with the
calling of this hook themselves. EXT:form itself uses this hook to initialize
the property-mapper configuration for FileUpload elements.
/**
* @param \TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface $renderable
* @return void
*/
public function afterBuildingFinished(\TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface $renderable)
{
}
Copied!
afterInitializeCurrentPage
EXT:form automatically detects the page that should be shown and allow users
only to jump to the directly following (or previous) pages. This hook enables
you to implement a custom behavior, for example pages that are shown only when
other form elements have specific values.
/**
* @param \TYPO3\CMS\Form\Domain\Runtime\FormRuntime $formRuntime
* @param null|\TYPO3\CMS\Form\Domain\Model\Renderable\CompositeRenderableInterface $currentPage
* @param null|\TYPO3\CMS\Form\Domain\Model\Renderable\CompositeRenderableInterface $lastPage
* @param mixed $elementValue submitted value of the element *before post processing*
* @return null|\TYPO3\CMS\Form\Domain\Model\Renderable\CompositeRenderableInterface
*/
public function afterInitializeCurrentPage(\TYPO3\CMS\Form\Domain\Runtime\FormRuntime $formRuntime, \TYPO3\CMS\Form\Domain\Model\Renderable\CompositeRenderableInterface $currentPage = null, \TYPO3\CMS\Form\Domain\Model\Renderable\CompositeRenderableInterface $lastPage = null, array $requestArguments = []): ?\TYPO3\CMS\Form\Domain\Model\Renderable\CompositeRenderableInterface
{
return $currentPage;
}
Copied!
afterSubmit
You can use it for example for dynamic validations which depends on other submitted form element values.
This hook is invoked by the FormRuntime for each form element before values are property mapped, validated and pushed within the FormRuntime's FormState.
If the first page is submitted at the first time you cannot access the form element values from the first page by just calling $formRuntime['<someOtherFormElementIdentifier>'] to access
the submitted form element values from the first page. In this case you can access the submitted raw data through $requestArguments.
EXT:form itself uses this hook to dynamically add validation errors for AdvancedPassword form elements.
/**
* @param \TYPO3\CMS\Form\Domain\Runtime\FormRuntime $formRuntime
* @param \TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface $renderable
* @param mixed $elementValue submitted value of the element *before post processing*
* @param array $requestArguments submitted raw request values
* @return mixed element value that should be used for further processing
*/
public function afterSubmit(\TYPO3\CMS\Form\Domain\Runtime\FormRuntime $formRuntime, \TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface $renderable, $elementValue, array $requestArguments = [])
{
return $elementValue;
}
Copied!
beforeRendering
This is a hook that is invoked by the rendering system before the corresponding element is rendered.
Use this to access previously submitted values and/or modify the FormRuntime before an element is outputted to the browser.
This hook is called after all validations and property mappings are done.
Within this chapter, you will learn the basic concepts of the form framework.
It addresses your concerns as backend editor and integrator. Some of the
chapters also cover topics for developers.
As mentioned earlier, the form extension can be
seen as a framework which allows editors, integrators, and developers to
create and manage all kind of forms. For this task, different interfaces
and techniques are available.
Conceptually, EXT:form always tries to consider the form editor first.
The requirements for the form editor differ between the defined target
groups. On the one hand, as an integrator, you may want to manage HTML
class attributes. On the other hand, as a developer you may want to use the
form editor as a kick starter for complex form definitions, and you
may want to edit all possible (technical) properties you can think of.
The form extension tries to find a compromise for such cases. Since the
form editor is mainly used by backend editors, only simple,
nontechnical properties are displayed and editable. However, EXT:form
allows you to easily extend the form editor by writing some YAML
configurations.
If this is not enough for your specific project, EXT:form provides a way to
integrate your own JavaScript code by utilizing the JavaScript API. Thus,
it should be possible to meet all your requirements.
Your forms can be created and defined globally in the form module and/
or loaded from extensions. Within the Mail form content element, one of
those forms can be referenced.
Furthermore, certain aspects of a form can be overridden in the plugin. This
concept allows you to reuse the same form on different pages with the same,
or a different, configuration.
The following explanations will show you that there are many ways to
manipulate the form framework in different contexts.
Those explanations are partly contradictory, depending on your use case. It
is up to you how you want to use the form framework. Be creative and share
your solution with the TYPO3 community!
This chapter attempts to describe the basics of the form framework. Check
out the reference and the example sections to get a deeper understanding of
the framework.
Configuration
A lot of configuration. Why?
The requirements for building forms in a declarative and programmatic way
are complex. What we have learned so far is that the program code must be
kept as generic as possible to handle the dynamics of forms, but a generic
program code means a lot of configurative overhead.
Initially, the configuration may overwhelm you, but it also has some great
advantages. Many aspects of EXT:form can be manipulated in a purely
configurative manner without involving a developer.
Furthermore, we wanted to avoid the configuration being done at places
whose context actually suggests something different. This pedantry,
however, leads to the situation in which certain settings have to be
defined multiple times at multiple places. This may seem nonsensical, but
it avoids unpredictable behaviour. Within the form framework, nothing
happens magically. It is all about configuration.
Why YAML?
Former versions of EXT:form used a subset of TypoScript to describe the
definition of a specific form and the behaviour of the included form
elements. This led to a lot of confusion from integrators because the
implemented definition language looked like TypoScript but did not behave
like TypoScript.
Since the definition of forms and form elements must be declarative, the
EXT:form team decided to use YAML. Just through the visual appearance of
YAML, it should be clear to everyone that neither magic nor TypoScript
stdWrap functionality are possible.
YAML registration
At the moment, configuration via YAML is not natively integrated into the
core of TYPO3. You have to make a short detour by using TypoScript in order
to register your YAML configuration. Furthermore, there is a "speciality"
regarding the integration of your YAML configuration for the backend
module.
Hint
We recommend using a site package.
This will make your life easier if you want to customize EXT:form
heavily in order to suit the customer's needs.
Tip
For debugging purposes or for getting an overview about the available
configuration use the SYSTEM > Configuration module. Select in
the menu the Form: YAML Configuration item to display the
parsed YAML form setup. If the module is not available install the lowlevel
system extension.
YAML registration for the frontend
For the frontend the whole YAML configuration is loaded via the following
TypoScript (see EXT:form/Configuration/TypoScript/setup.typoscript):
Since the key 10 is already taken, we recommend registering
your own configuration beginning with a unique number (for instance current timestamp)
in a EXT:my_extension/ext_localconf.php file:
The backend module of EXT:form is based on Extbase. Such backend modules
can, like frontend plugins, be configured via TypoScript. The frontend
plugins are configured below plugin.tx_form. For the
configuration of the backend module.tx_form is used.
The recommended way to include "global" backend TypoScript is by using the API function
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTypoScriptSetup()
in a EXT:my_extension/ext_localconf.php file. This registers
TypoScript as "global" snippet: TypoScript is usually bound to pages and page
uids in some way - via sys_template records, or via site sets. The form backend module
however is not bound to a page, and the extbase backend bootstrap did a lot of magic in
the past to find an appropriate page if none is given.
YAML loading
TYPO3 is using a custom 'YAML loader' for handling
YAML in TYPO3 based on the Symfony YAML package. This YAML loader is able to resolve
environment variables. In addition, EXT:form comes with an own YAML loader which
has some limitations/ restrictions, especially when it comes to resolve environment
variables. Those limitations are necessary security-wise.
EXT:form differentiates between form configuration and form definition.
In addition, a form definition can be stored
in the file system (FAL) or can be shipped with a custom extension. Depending on those
parameters different YAML loaders are used and thus, different features are available.
YAML file
YAML loader
YAML configuration
TYPO3 core
YAML definition stored in file system (default when using the form editor)
TYPO3 Form Framework
YAML definition stored in custom extension
TYPO3 core
Configuration aspects
In EXT:form, four aspects can be configured:
the behaviour of the frontend rendering,
the behaviour of the form editor,
the behaviour of the form manager, and
the behaviour of the form plugin.
Those aspects are defined in separate files which are only loaded in the
frontend/ backend when needed. This approach has two advantages:
increased clarity,
increased performance, e.g. the form editor configuration is not
needed in the frontend and therefore not loaded.
It is up to you if you want to follow this guideline or if you want to put
the whole configuration into one large file.
There are some configurational aspects which cannot explicitly be assigned
to either the frontend or the backend. Instead, the configuration is
valid for both areas. For example, within the backend, the whole frontend
configuration is required in order to allow the form preview to work
properly. In addition, as soon as the form is rendered via the `form
plugin``, the ``FormEngine` configuration is needed to interpret the
overridden finisher configuration correctly.
Inheritances
The final YAML configuration is not based on one huge file. Instead, it is
a compilation of a sequential process:
First of all, all registered configuration files are parsed as YAML and
are overlaid according to their order.
After that, the __inheritances operator is applied. It is a unique
operator introduced by the form framework.
Finally, all configuration entries with a value of null are deleted.
Additionally, the frontend configuration can be extended/ overridden by
TypoScript:
Your TypoScript overrides are not interpreted by the form editor,
i.e. those settings are ignored.
Note
The described process is quite handy for you. As soon as you are working
with your own configuration files,
you only have to define the differences compared to the previously
loaded configuration files.
For example, if you want to override the fluid templates and you therefore
register an additional configuration file via
plugin.tx_form {
settings {
yamlConfigurations {
# register your own additional configuration# choose a number higher than 30 (below is reserved)100 = EXT:my_site_package/Configuration/Form/CustomFormSetup.yaml
}
}
}
Copied!
... you only have to define the following YAML setup in EXT:my_site_package/Configuration/Form/CustomFormSetup.yaml:
The values of your own configuration file will overrule the corresponding
values of the basic configuration file (EXT:form/Configuration/Yaml/FormSetup.yaml).
__inheritances operator
The __inheritances operator is an extremely useful instrument. Using it
helps to significantly reduce the configuration effort. It behaves similar
to the < operator in TypoScript. That is, the definition of the source
object is copied to the target object. The configuration can be inherited
from several parent objects and can be overridden afterwards. Two simple
examples will show you the usage and behaviour of the __inheritances
operator.
EXT:form heavily uses the __inheritances operator, in particular, for
the definition of form elements. The following example shows you how to use
the operator to define a new form element which behaves like the parent
element but also has its own properties.
The YAML configuration defines a new form element called GenderSelect.
This element inherits its definition from the RadioButton element but
additionally ships four predefined options. Without any problems, the new
element can be used and overridden within the form definition.
It will probably take some time to fully understand the awesomeness of
this operator. If you are eager to learn more about this great instrument,
check out the unit tests defined in EXT:form/Tests/Unit/Mvc/Configuration/InheritancesResolverServiceTest.php.
Prototypes
Most of the configurational aspects of the form framework are defined
in so-called prototypes. By default, EXT:form defines a prototype
named standard. The definition of form elements - including their
rendering in the frontend, form editor and form plugin - reside
within those prototypes. As soon as you create a new form, the specific
form definition references such a prototype.
This allows you to do a lot of nifty stuff. Let your imagination run free.
For example:
based on the referenced prototype, the same form can load
...varying templates
...varying form editor configurations
...varying form plugin finisher overrides
within the form manager, depending on the selected prototype
...varying form editor configurations can be loaded
...varying pre-configured form templates (boilerplates) can be chosen
different prototypes can define different/ extended form elements and
display them in the frontend/ form editor accordingly
Check out the following use case to fully understand the concept behind
prototypes. Imagine that there are two defined prototypes: "noob" and
"poweruser".
Prototype "noob"
Prototype "poweruser"
Available form elements within the ``form editor``
Text, Textarea
No changes. Default behaviour.
Available finisher within the ``form editor``
Only the email finisher is available. It offers a field for setting
the subject of the mail. All remaining fields are hidden and filled
with default values.
No changes. Default behaviour.
Finisher overrides within the ``form plugin``
It is not possible to override the finisher configuration.
No changes. Default behaviour.
Form configuration vs. form definition
So far, we have only described the configuration of the form framework.
Once again, based on prototypes, the form configuration allows you to
define:
which form elements, finishers, and validators are available,
how those objects are pre-configured,
how those objects will be displayed within the frontend and backend.
In contrast, the form definition describes the specific form, including
all form elements and their corresponding validators,
the order of the form elements within the form, and
the finishers which are fired as soon as the form has been submitted.
Furthermore, it defines the concrete values of each property of the
mentioned aspects.
In other words, the prototype configuration defines the existence of a
form element of type Text globally. The form definition declares
that such a form element of type Text is located on page 1 at position
1 of a specific form. In addition, it carries the information that this form
element comes with the HTML attribute "placeholder" with value "Your name
here". The form definition is written by the form editor.
Example form definition
identifier:ext-form-simple-contact-form-examplelabel:'Simple Contact Form'prototype:standardtype:Formfinishers:-identifier:EmailToReceiveroptions:subject:'Your message'recipients:your.company@example.com:'Your Company name'ceo@example.com:'CEO'senderAddress:'{email}'senderName:'{name}'renderables:-identifier:page-1label:'Contact Form'type:Pagerenderables:-identifier:namelabel:'Name'type:Textproperties:fluidAdditionalAttributes:placeholder:'Name'defaultValue:''validators:-identifier:NotEmpty-identifier:subjectlabel:'Subject'type:Textproperties:fluidAdditionalAttributes:placeholder:'Subject'defaultValue:''validators:-identifier:NotEmpty-identifier:emaillabel:'Email'type:Textproperties:fluidAdditionalAttributes:placeholder:'Email address'defaultValue:''validators:-identifier:NotEmpty-identifier:EmailAddress-identifier:messagelabel:'Message'type:Textareaproperties:fluidAdditionalAttributes:placeholder:''defaultValue:''validators:-identifier:NotEmpty-identifier:hiddenlabel:'Hidden Field'type:Hidden-identifier:summarypagelabel:'Summary page'type:SummaryPage
Copied!
Form/ File storages
EXT:form stores the form definitions within the file system (FAL) and thus needs
write access to this storage. By default, the file mount form_definitions is
used. It is possible to configure a different and/ or an additional
file mount, which is then utilized for storing and reading forms.
The backend user will only see form definitions that are stored in
file mounts where the user has at least read access. The form editor and
the form plugin respect those access rights. In this way, you are able
to implement ACLs. If you have configured more than one file mount and the
backend user is able to access those, the form manager will allow the
user to choose the preferred storage in which the form will be saved.
Even cooler, form definitions can be stored in and shipped with your custom
extensions. If configured accordingly, the backend user will be able to
embed those forms. Furthermore, you can configure that these form
definitions:
can be edited within the form editor,
can be deleted with the help of the form manager.
By default, the aforementioned options are turned off. We decided to do so
because having dynamic content within an extension - which is possibly
version-controlled - is usually not a good idea. Furthermore, there is no
ACL system available.
File uploads will be saved within file mounts as well. They are handled
as FAL objects. The available file mounts for such uploads can be configured.
When adding/ editing a file upload element, the backend user can select the
desired upload storage.
Note
In principle, files in file mounts are publicly accessible. If the
uploaded files could contain sensitive data, you should suppress any
HTTP access to the file mount. This may, for example, be achieved by
creating a .htaccess file, assuming you are using an Apache web
server. The directive of the .htaccess file is fairly easy:
The following code block shows you how to configure additional file mounts
for form definitions.
persistenceManager:allowedFileMounts:# default file mount, no need to redeclare it again# just to show you the structure# 10: 1:/form_definitions/# additional file mounts100:1:/custom/forms/110:2:/cloudstorage/forms/
Copied!
The following code block shows you how to allow an extension path as an
additional file mount for form definitions.
The Fluid templates of the form framework are based on Bootstrap.
Custom templates
If you want to use custom Fluid templates for the frontend output of the
form elements, you cannot register an additional template path using
TypoScript. Instead, the registration of new template paths has to be done
via YAML. The settings are part of the prototypes configuration.
For each form definition - which references the prototype standard -
the form framework will additionally look for Fluid templates within the
path EXT:my_site_package/Resources/Private/Frontend/[*] as set above.
Apart from the 'Form' element, the process will search for templates within
the partialRootPaths folder. The name of the partial is derived from the
property formElementTypeIdentifier. For example, the template of the
form element Text must be stored within the partialRootPaths folder
named Text.html. In contrast, the template of the Form element must
reside within the templateRootPaths folder. According to the introduced
logic, the template name must be Form.html.
Access single values in finisher templates
You can access single form values and place them freely in your finisher templates.
The
RenderFormValueViewHelper does the job. The viewhelper accepts a single form
element and renders it. Have a look at the following example. In order to output
the value of the field message the
RenderFormValueViewHelper
is called with two parameters.
{formValue.processedValue} contains the specific
value which can be manipulated with Fluid or styled etc.
If you don't know the names of your form elements, you could look them up in your
form definition. In addition, you can use the following snippet to lists all of
the available elements.
<f:debug>{page.rootForm.elements}</f:debug>
Copied!
Translation
Translate form definition
The translation of form definitions works differently to the translation
of the backend aspects. Currently, there is no graphical user interface
supporting the translation process.
If the backend editor needed to translate the form definition properties
in the same way the backend aspects are translated, he/ she would see long
and unwieldy translation keys while editing a form within the form editor.
In order to avoid this, rather the element properties are translated than
their values. Thus, the form framework does not look for translation keys
within the translation file. Instead, the system searches for translations
of the form element properties independent of their property values. The
property values are ignored if the process finds a proper entry within the
translation file. As a result, the property values are overridden by the
translated value.
This approach is a compromise between two scenarios: the exclusive usage of
the form editor and/ or the manual creation of form definitions
which can afterwards (theoretically) be edited with the form editor. In
addition, the described compromise allows the editor to create forms in the
default language whose form element property values are displayed as
specified in the form editor. Based on this, an integrator could provide
additional language files which automatically translate the specific form.
Additional translation files can be defined as follows:
The array is processed from the highest key to the lowest, i.e. your
translation file with the key 20 is processed first. If the look-up
process does not find a key within all of the provided files, the
property value will be displayed unmodified.
The following properties can be translated:
label
properties.[*]
properties.options.[*]
properties.fluidAdditionalAttributes.[*]
renderingOptions.[*]
The translation keys are put together based on a specific pattern. In
addition, a fallback chain that depends on the form element identifiers
exists. As a result, the following translation scenarios are possible:
translation of a form element property for a specific form and form
element
translation of a form element property for a specific form element and
various forms
translation of a form element property for an element type and various
forms, e.g. the Page element
The look-up process searches for translation keys in all given translation
files based on the following order:
identifier:ApplicationFormtype:FormprototypeName:standardlabel:'Application form'renderables:-identifier:GeneralInformationtype:Pagelabel:'General information'renderables:-identifier:LastNametype:Textlabel:'Last name'properties:placeholder:'Please enter your last name.'defaultValue:''-identifier:Softwaretype:MultiSelectlabel:'Known software'properties:options:value1:TYPO3value2:Neos
Copied!
For the form element LastName, the process will look for the following
translation keys within the translation files:
ApplicationForm.element.LastName.properties.label
element.LastName.properties.label
element.Text.properties.label
If none of the above-mentioned keys exist, 'Last name' will be displayed.
For the form element Software, the process will look for the following
translation keys within the translation files:
ApplicationForm.element.Software.properties.label
element.Software.properties.label
element.MultiSelect.properties.label
If none of the above-mentioned keys exist, 'Known software' will be
displayed. The option properties are addressed as follows:
If none of the above-mentioned keys exist, 'TYPO3' will be displayed as
label for the first option and 'Neos' as label for the second option.
Translation of validation messages
The translation of validation messages is similar to the translation of
form definitions. The same translation files can be used. If the look-up
process does not find a key within the provided files, the appropriate
message of the Extbase framework will be displayed. EXT:form already
translates all of those validators by default.
As mentioned above, the translation keys are put together based on a
specific pattern. Furthermore, the fallback chain exists here as well. Thus,
the following translation scenarios are possible:
translation of validation messages for a specific validator of a concrete
form element and concrete form
translation of validation messages for a specific validator of various
form elements within a concrete form
translation of validation messages for a specific validator of a concrete
form element in various forms
translation of validation messages for a specific validator within various
forms
In Extbase, the validation messages are identified with the help of
numerical codes (UNIX timestamps). For the same validator, different codes
are valid. Read more about concrete validator configurations.
The look-up process searches for translation keys in all given translation
files based on the following order:
Amongst others, the NotEmpty validator sends 1221560910 as <validationErrorCode>.
If a user submits this form without providing a value for the field "Last
name", the NotEmpty validator fails. Now, the look-up process searches
for the following translation keys for the NotEmpty validator combined
with the form element LastName:
ContactForm.validation.error.LastName.1221560910
ContactForm.validation.error.1221560910
validation.error.LastName.1221560910
validation.error.1221560910
As mentioned above, if there is no corresponding translation key available,
the default message of the Extbase framework will be shown.
Translation of finisher options
The translation of finisher options is similar to the translation of
form definitions. The same translation files can be used. If the look-up
process does not find a key within all provided files, the property value
will be displayed unmodified.
As mentioned above, the translation keys are put together based on a
specific pattern. Furthermore, the fallback chain exists here as well. Thus,
the following translation scenarios are possible:
translation of finisher options for a specific finisher of a concrete form
translation of finisher options for a specific finisher of various forms
The look-up process searches for translation keys in all given translation
files based on the following order:
identifier:ContactFormtype:FormprototypeName:standardlabel:'Contact us'finishers:-identifier:Confirmationoptions:message:'Thank you for your inquiry.'renderables:...
Copied!
The look-up process searches for the following translation keys for the
<finisherIdentifier> 'Confirmation' and the option 'message':
ContactForm.finisher.Confirmation.message
finisher.Confirmation.message
If no translation key exists, the message 'Thank you for your inquiry.' will
be shown.
Form element translation arguments
Form element property translations and finisher option translations can use
placeholders to output translation arguments. Translations can be enriched
with variable values by passing arguments to form element properties. The
feature was introduced with forge#81363.
Form element properties
Pure YAML is sufficient to add simple, static values:
This will produce the label: This is a useful feature.
Alternatively, translation arguments can be set via
formDefinitionOverrides in TypoScript. A common usecase is a checkbox for
user confirmation linking to details of the topic. Here it makes sense to use
YAML hashes instead of YAML lists to give sections named keys. This simplifies
references in TypoScript a lot since named keys are way more readable and also
keep the setup working in case elements are reordered. With lists and numeric
keys the TypoScript setup would also need to be updated in this case.
In the following example the list of
renderables has been replaced with
a hash of
renderables and the field
field-with-translation-arguments
has received a named key
fieldWithTranslationArguments. This key can be anything
as long as it is unique on the same level, usually simply copying the
identifier
should be enough:
In case the label defines HTML markup - like in the above example, it must
be wrapped into CDATA tags in the corresponding path/to/locallang.xlf file,
to prevent analysing of the character data by the parser. Additionally, the
corresponding label should be rendered using the
<f:format.raw>
view helper in fluid templates, to prevent escaping of the HTML tags.
<trans-unitid="<form-id>.element.field-with-translation-arguments.properties.label"><source><![CDATA[I agree to the <a href="%s">terms and conditions</a>]]></source></trans-unit>
Copied!
The following TypoScript setup uses the named key
fieldWithTranslationArguments to refer
to the field and adds a page URL as translation argument:
The
Page element of the form definition was not registered with a named key so a numeric
key
0 must be used which, as mentioned above, is prone to errors when more pages are added
or pages are reordered.
Important
There must be at least one translation file with a translation for the
configured form element property. Arguments are not inserted into default
values defined in a form definition.
Finishers
The same mechanism (YAML, YAML + TypoScript) works for finisher options:
finishers:finisherWithTranslationArguments:identifier:EmailToReceiveroptions:subject:My%ssubjectrecipients:your.company@example.com:'Your Company name'ceo@example.com:'CEO'senderAddress:bar@example.orgtranslation:translationFiles:10:path/to/locallang.xlfarguments:subject:-awesome
Copied!
This will produce My awesome subject.
Basic code components
Basic code components
TYPO3\CMS\Form\Domain\Model\FormDefinition
The class TYPO3\CMS\Form\Domain\Model\FormDefinition encapsulates
a complete form definition, with all of its
pages,
form elements,
applicable validation rules, and
finishers, which should be executed when the form is submitted.
The FormDefinition domain model is not modified when the form is executed.
The anatomy of a form
A FormDefinition domain model consists of multiple Page objects.
When a form is displayed, only one Page is visible at any given time.
Moreover, there is a navigation to go back and forth between those pages. A
Page consists of multiple FormElements which represent the input
fields, textareas, checkboxes, etc. shown on a page. The FormDefinition
domain model, Page and FormElement objects have identifier
properties which must be unique for each given <formElementTypeIdentifier>,
i.e. the FormDefinition domain model and a FormElement object may
have the same identifier but having the same identifier for two
FormElement objects is disallowed.
Example
Basically, you can manually create a FormDefinition domain model just
by calling the API methods on it, or you can use a FormFactory to build
the form from a different representation format such as YAML:
$formDefinition = GeneralUtility::makeInstance(FormDefinition::class, 'myForm');
$page1 = GeneralUtility::makeInstance(Page::class, 'page1');
$formDefinition->addPage($page);
// second argument is the <formElementTypeIdentifier> of the form element
$element1 = GeneralUtility::makeInstance(GenericFormElement::class, 'title', 'Text');
$page1->addElement($element1);
Copied!
Creating a form using abstract form element types
While you can use the TYPO3\CMS\Form\Domain\Model\FormDefinition::addPage()
or TYPO3\CMS\Form\Domain\Model\FormElements\Page::addElement() methods
and create the Page and FormElement objects manually, it is often
better to use the corresponding create* methods (TYPO3\CMS\Form\Domain\Model\FormDefinition::createPage()
and TYPO3\CMS\Form\Domain\Model\FormElements\Page::createElement()), as
you pass them an abstract <formElementTypeIdentifier> such as Text
or Page. EXT:form will automatically resolve the implementation class
name and set default values.
The simple example
shown above should be rewritten as follows:
// we will come back to this later on
$prototypeConfiguration = [];
$formDefinition = GeneralUtility::makeInstance(FormDefinition::class, 'myForm', $prototypeConfiguration);
$page1 = $formDefinition->createPage('page1');
$element1 = $page1->addElement('title', 'Text');
Copied!
You might wonder how the system knows that the element Text is
implemented by using a GenericFormElement. This is configured in the
$prototypeConfiguration. To make the example from above actually work,
we need to add some meaningful values to $prototypeConfiguration:
For each abstract <formElementTypeIdentifier> we have to add some
configuration. In the snippet above, we only define the `implementation
class name`. Apart from that, it is always possible to set default values
for all configuration options of such elements, as the following example
shows:
$prototypeConfiguration = [
'formElementsDefinition' => [
'Page' => [
'implementationClassName' => 'TYPO3\CMS\Form\Domain\Model\FormElements\Page',
'label' => 'This is the label of the page if nothing else is specified'
],
'Text' => [
'implementationClassName' => 'TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement',
'label' = >'Default Label',
'defaultValue' => 'Default form element value',
'properties' => [
'placeholder' => 'Text that is shown if element is empty'
],
],
],
];
Copied!
Using pre-configured $prototypeConfiguration
Often, it does not make sense to manually create the $prototypeConfiguration
array. Bigger parts of this array are pre-configured in the extensions's
YAML settings. The TYPO3\CMS\Form\Domain\Configuration\ConfigurationService
contains helper methods which return the ready-to-use $prototypeConfiguration.
Rendering a FormDefinition
To trigger the rendering of a FormDefinition domain model, the current
TYPO3\CMS\Extbase\Mvc\Web\Request needs to be bound to the
FormDefinition. This binding results in a TYPO3\CMS\Form\Domain\Runtime\FormRuntime
object which contains the Runtime State of the form. Among other things,
this object includes the currently inserted values:
// $currentRequest needs to be available.
// Inside a controller, you would use $this->request
$form = $formDefinition->bind($currentRequest);
// now, you can use the $form object to get information about the currently entered values, etc.
Copied!
TYPO3\CMS\Form\Domain\Runtime\FormRuntime
This class implements the runtime logic of a form, i.e. the class
decides which page is currently shown,
determines the current values of the form
triggers validation and property mappings.
You generally receive an instance of this class by calling TYPO3\CMS\Form\Domain\Model\FormDefinition::bind().
Rendering a form
Rendering a form is easy. Just call render() on the FormRuntime:
In order to get the values the user has entered into the form, you can
access the FormRuntime object like an array. If a form element with the
identifier firstName exists, you can use $form['firstName'] to
retrieve its current value. You can set values the same way.
Rendering internals
The FormRuntime inquires the FormDefinition domain model regarding
the configured renderer (TYPO3\CMS\Form\Domain\Model\FormDefinition::getRendererClassName())
and then triggers render() on this Renderer.
This allows you to declaratively define how a form should be rendered.
This class is a TYPO3\CMS\Form\Domain\Renderer\RendererInterface
implementation which used to render a FormDefinition domain model. It
is the default EXT:form renderer.
EXT:form ships a decent amount of hooks which are available at crucial
points of the life cycle of a FormElement. Most of the time, own
implementations are therefore unnecessary. An own form element can be
defined by:
writing some configuration, and
utilizing the standard implementation of TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement.
If you insist on your own implementation, the abstract class TYPO3\CMS\Form\Domain\Model\FormElements\AbstractFormElement
offers a perfect entry point. In addition, we recommend checking-out TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable.
All of your own form element implementations must be programmed to the
interface TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface.
It is a good idea to derive your implementation from TYPO3\CMS\Form\Domain\Model\FormElements\AbstractFormElement.
"render" viewHelper
The RenderViewHelper is the actual starting point for form rendering and
not the typical Extbase Controller as you may know it.
For more technical insights read more about the viewHelper's arguments.
Point the property controllerAction to the desired action name and
provide values for the other parameters displayed below (you might need
those).
type:Formidentifier:'example-form'label:'TYPO3 is cool'prototypeName:standardrenderingOptions:controllerAction:performaddQueryString:falseargumentsToBeExcludedFromQueryString:[]additionalParams:[]renderables:...
Copied!
Note
In general, you can override each and every form definition with the help
of TypoScript (see 'TypoScript overrides').
When using the RenderViewHelper, there is a second way:
The 'overrideConfiguration' parameter.
This way, you can override the form definition within your template.
Provide an according array as shown in the example below.
<formvh:renderpersistenceIdentifier="EXT:my_site_package/Resources/Private/Forms/MyForm.yaml"overrideConfiguration="{renderables: {0: {renderables: {0: {label: 'My shiny new label'}}}}}"/>
Copied!
Build forms programmatically
To learn more about this topic, head to the chapter 'Build forms programmatically'
which is part of the API reference section.
Runtime manipulation
Hooks
EXT:form implements a decent amount of hooks that allow the manipulation of
your forms during runtime. In this way, it is possible to, for example,
... prefill form elements with values from your database,
... skip a whole page based on the value of a certain form element,
... mark a form element as mandatory depending of the chosen value of another
form element.
Each and every form definition can be overridden via TypoScript if the
FormFrontendController of EXT:form is used to render the form. Normally,
this is the case if the form has been added to the page using the form
plugin or when rendering the form via FLUIDTEMPLATE.
The overriding of settings with TypoScript's help takes place after the custom finisher settings
of the form plugin have been loaded. In this way, you are able to manipulate
the form definition for a single page. In doing so, the altered
form definition is passed to the RenderViewHelper which then
generates the form programmatically. At this point, you can still change the
form elements using the above-mentioned concept of hooks.
Variants allow you to change properties of form elements, validators,
and finishers and are activated by conditions. This allows you among
other things:
translating form element values depending on the frontend language
setting and removing validators of one form element depending on the
value of another form element
hiding entire steps (form pages) depending on the value of a form
element
setting finisher options depending on the value of a form element
hiding a form element in certain finishers and on the summary step
Variants are defined on the form element level either statically in
form definitions or created programmatically through an API. The
variants defined within a form definition are automatically applied to
the form based on their conditions at runtime. Programmatically,
variants can be applied at any time.
Furthermore, conditions of a variant can be evaluated programmatically
at any time. However, some conditions are only available at runtime,
for example a check for a form element value.
Custom conditions and operators can be added easily.
Only the form element properties listed in a variant are applied to the
form element, all other properties are retained. An exception to this
rule are finishers and validators. If finishers or validators are
not defined within a variant, the original finishers and validators
will be used. If at least one finisher or validator is defined in a
variant, the originally defined finishers or validators are overwritten
by the list of finishers and validators of the variant.
Variants defined within a form definition are all processed and
applied in the order of their matching conditions. This means if
variant 1 sets the label of a form element to "X" and variant 2 sets
the label to "Y", then variant 2 is applied, i.e. the label will be "Y".
Note
At the current state it is not possible to define variants in
the UI of the form editor.
Rendering option enabled
The rendering option
enabled is available for all finishers and
all form elements - except the root form element and the first form
page. The option accepts a boolean value (
true or
false).
Setting
enabled: true for a form element renders it in the
frontend and enables processing of its value including property mapping
and validation. Setting
enabled: false disables the form
element in the frontend. All form elements and finishers except the root form element and the first form page can be enabled
or disabled.
Setting
enabled: true for a finisher executes it when
submitting forms. Setting
enabled: false skips the finisher.
By default,
enabled is set to
true.
See examples
below to learn more about using this rendering option.
Definition of variants
Variants are defined on the form element level. Check the following -
incomplete - example:
type:Textidentifier:text-1label:Foovariants:-identifier:variant-1condition:'traverse(formValues, "checkbox-1") == 1'# If the condition matches, the label property of the form# element is set to the value 'Bar'label:Bar
Copied!
As usual,
identifier must be a unique name of the variant on
the form element level.
Each variant has a single
condition which applies the variants'
changes as soon as the condition matches. In addition, the remaining
properties are applied to the form element as well. In the
aforementioned example the label of the form element
text-1 is
changed to Bar if the checkbox
checkbox-1 is checked.
The following properties can be overwritten by variants within the
topmost element (
Form):
label
renderingOptions
finishers
rendererClassName
The following properties can be overwritten by variants within all of
the other form elements:
enabled
label
defaultValue
properties
renderingOptions
validators
Note
To selectively unset list items in variants like select options the special value __UNSET can be used as value for the item to remove.
Conditions
The form framework uses the Symfony component expression language.
Here, an expression is a one-liner that returns a boolean value like
applicationContext matches "#Production/Local#". Please check
the Symfony docs
to learn more about this topic. The form framework extends the
expression language with some variables which can be used to access
form values and environment settings.
formRuntime (object)
You can access every public method from the
\TYPO3\CMS\Form\Domain\Runtime\FormRuntime ,
learn more here.
For example:
formRuntime.getIdentifier() == "test".
renderable (VariableRenderableInterface)
renderable holds the instance of renderable, the condition
is applied to. This can be used e.g. to access the identifier of the
current renderable without having to duplicate it.
In this extensive example the form element
email-address has
been enabled explicitly but it is fine to leave this out since this is
the default state. The form element
text-3 has been disabled
completely, for example to temporarily remove it from the form. The
field
text-1 is hidden in all finishers and on the summary step.
The
EmailToSender finisher takes the fact into account that
finishers can refer to form values. It is only enabled if the form
element
checkbox-1 has been activated by the user. Otherwise,
the finisher is skipped.
type:FormprototypeName:standardidentifier:hidden-field-formlabel:Hiddenfieldformfinishers:-identifier:EmailToReceiveroptions:subject:Yes,Iamreadyrecipients:your.company@example.com:'Your Company name'senderAddress:tritum@example.orgsenderName:tritum@example.org-identifier:EmailToSenderoptions:subject:Thisisacopyoftheformdatarecipients:{email-address}:'{name}'senderAddress:tritum@example.orgsenderName:tritum@example.orgrenderingOptions:enabled:'{checkbox-1}'renderables:-type:Pageidentifier:page-1label:Generaldatarenderables:-type:Textidentifier:text-1label:Afieldhiddenonconfirmationstepandinallmails(finishers)variants:-identifier:hide-1renderingOptions:enabled:falsecondition:'stepType == "SummaryPage" || finisherIdentifier in ["EmailToSender", "EmailToReceiver"]'-type:Textidentifier:email-addresslabel:Emailaddressproperties:fluidAdditionalAttributes:required:requiredrenderingOptions:enabled:true-type:Textidentifier:text-3label:AtemporarilydisabledfieldrenderingOptions:enabled:false-type:Checkboxidentifier:checkbox-1label:Checkthisandthesendergetsanemail-type:SummaryPageidentifier:summarypage-1label:Confirmation
Copied!
Hide steps
In this example the second step
page-2 is disabled if the field
checkbox-1 is checked. Furthermore, the form element
checkbox-1 is disabled on the summary step.
If you need to extend the expression language with custom functions you
can extend it. For more information check the official docs
and the appropriate TYPO3 implementation details.
Register the expression language provider in the extension file
Configuration/ExpressionLanguage.php. Make sure your expression
language provider implements
\Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface.
The form framework ships a set of server-side validators, which implement
Extbase validators. Be aware that not all of the existing validators are
available for each form element, e.g. the "Date range validator" is
only available for the "Date" element. Furthermore, some form elements
(like "Email") already contain reasonable validators.
With the help of the form element property validationErrorMessages
you can define custom validation error messages. The message can also
be set within the form editor.
Client-side validation
If a form element is configured accordingly, the form framework adds
HTML 5 based frontend validation. Nevertheless, there is no JavaScript
validation included by default. We as the TYPO3 core have no plans to
opt for a specific solution. This has to be integrated manually.
Reliable and maintained projects are Parsley
and jQuery Validation.
Localization of client side validations
The displayed validation message is a browser specific text. The output
is not generated by TYPO3 and therefore you cannot change it easily.
Nevertheless, there is a JavaScript solution for changing the validation
message. See Stack Overflow
for more information.
Server-side validation
Alphanumeric validator (
Alphanumeric)
The "Alphanumeric validator"
checks for alphanumeric strings. Alphanumeric is defined as a combination of
alphabetic and numeric characters [A-Z + 0-9].
Minimum [
options.minimum]: The minimum count to accept.
Maximum [
options.maximum]: The maximum count to accept.
Date range validator (
DateRange)
The "Date range validator"
checks if the given value is a valid DateTime object and in-between a specified
date range. The range can be defined by providing a minimum and/or maximum date.
The validator has 2 options:
Format [
options.format]: The format of the minimum and maximum option.
Default: [
Y-m-d].
Minimum date [
options.minimum]: The minimum date formatted as Y-m-d.
Maximum date [
options.maximum]: The maximum date formatted as Y-m-d.
The options
minimum and
maximum must have the format 'Y-m-d' which
represents the RFC 3339
'full-date' format.
The input must be a DateTime object. This input can be tested against a minimum
date and a maximum date. The minimum date and the maximum date are strings. The minimum
and maximum date can be configured through the validator options.
Date/time validator (
DateTime)
The "Date/time validator"
checks if the given value is a valid DateTime object. The date string is
expected to be formatted according to the W3C standard
which is YYYY-MM-DDT##:##:##+##:##, for example 2005-08-15T15:52:01+00:00.
Email validator (
EmailAddress)
The "Email validator"
checks if the given value is a valid email address. The format of a valid email
address is defined in RFC 3696.
The standard allows international characters and the multiple appearance
of the @ sign.
File size validator (
FileSize)
The "File size validator"
validates a file resource regarding its file size. The validator has 2 options:
Minimum [
options.minimum]: The minimum filesize to accept. Use the
format <size>B|K|M|G. For example: 10M means 10 Megabytes.
Maximum [
options.maximum]: The maximum filesize to accept. Use the
format <size>B|K|M|G. For example: 10M means 10 Megabytes.
Use the format <size>B|K|M|G when entering file sizes. For example: 10M
means 10 megabytes. Please keep in mind that the maximum file size also
depends on the php.ini settings of your environment.
Floating-point number validator (
Float)
The "Floating-point number validator"
checks if the given value is of type float or a string matching the regular
expression [0-9.e+-].
The "Number range validator"
checks if the given value is a number in the specified range. The validator has
2 options:
Minimum [
options.minimum]: The minimum value to accept.
Maximum [
options.maximum]: The maximum value to accept.
Regular expression validator (
RegularExpression)
The "Regular expression validator"
checks if the given value matches the specified regular expression. Delimiters
or modifiers are not supported. The validator has 1 option:
Regular expression [
options.regularExpression]: The regular expression
to use for validation, used as given.
Imagine the following example. You want the user to provide a domain name. The
submitted value shall only contain the second and the top level domain, e.g.
"typo3.org" instead of "https://typo3.org". The regular expression for this use
case would be /^[-a-z0-9]+\.[a-z]{2,6}$/.
String length validator (
StringLength)
The "String length validator"
checks if the given value is a valid string and its length is in the specified
range. The validator has 2 options:
Minimum [
options.minimum]: The minimum length for a valid string.
Maximum [
options.maximum]: The maximum length for a valid string.
Non-XML text validator (
Text)
The "Non-XML text validator"
checks if the given value is a valid text (contains no XML tags). This basically
means, that tags are stripped. In this special case quotes are not encoded
(see filter_var() for more information.
Be aware that the value of this check entirely depends on the output
context. The validated text is not expected to be secure in any circumstance.
If you want to be sure of that, use a customized regular expression or filter on
output.
Translation of validation messages
To learn more about this topic, please continue here.
Custom validator implementations
Validators belong to a certain prototype and are defined within the
validatorsDefinition. The property implementationClassName is used
for the validator implementation.
You can provide options for your validator using the property options.
Those will be used as default values which can be overridden within a
specific form definition.
Define the default value of the option yourCustomOption:
As mentioned above EXT:form implements Extbase validators. That said,
your own validators should extend
\TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator .
Read more about this topic in "TYPO3 Explained":
Custom Extbase validator implementation.
Finishers
The form framework ships a bunch of finishers, which will be briefly
described here. For more details, please head to the API reference and check
out the section regarding Finisher Options.
Important
Finishers are executed in the order defined in your form definition. This is
especially important when you are using the Redirect finisher. Make sure
this finisher is the very last one to be executed. The Redirect finisher
stops the execution of all subsequent finishers in order to perform the redirect.
I.e. finishers defined after the Redirect finisher will not be executed in
any case.
Closure finisher
The 'Closure finisher' can only be used within forms that are created
programmatically. It allows you to execute your own finisher code without
implementing/ declaring a finisher.
Confirmation finisher
The 'Confirmation finisher' is a simple finisher that outputs a given
text after the form has been submitted.
DeleteUploads finisher
The 'DeleteUploads finisher' removes submitted files. Use this finisher,
for example, after the email finisher if you do not want to keep the files
within your TYPO3 installation.
Note
Finishers are only executed on successfully submitted forms. If a user uploads
a file but does not finish the form successfully, the uploaded files will not
be deleted.
Email finisher
The
EmailFinisher sends an email to one recipient. EXT:form uses two
EmailFinisher declarations with the identifiers EmailToReceiver and
EmailToSender.
Working with BCC recipients
Both email finishers support different recipient types, including Carbon Copy
(CC) and Blind Carbon Copy (BCC). Depending on the configuration of the server
and the TYPO3 instance, it may not be possible to send emails to BCC recipients.
The configuration of the
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_sendmail_command']
value is crucial. As documented in CORE API,
TYPO3 recommends the parameter
-bs (instead of
-t -i) when using
sendmail. The parameter
-bs tells TYPO3 to use the SMTP standard
and that way the BCC recipients are properly set. Symfony
refers to the problem of using the
-t parameter as well. Since TYPO3 7.5
(#65791)
the
transport_sendmail_command is automatically set from the PHP runtime
configuration and saved. Thus, if you have problems with sending emails to BCC
recipients, check the above mentioned configuration.
About FluidEmail
Changed in version 12.0
The
EmailFinisher always sends email via
FluidEmail.
FluidEmail allows to send mails in a standardized way.
The option
title is available which can
be used to add an email title to the default FluidEmail template. This option is
capable of rendering form element variables using the known bracket syntax and can
be overwritten in the FlexForm configuration of the form plugin.
To customize the templates being used following options can be set:
templateName: The template name (for both HTML and plaintext) without the
extension
templateRootPaths: The paths to the templates
partialRootPaths: The paths to the partials
layoutRootPaths: The paths to the layouts
Note
The formerly available field
templatePathAndFilename is not evaluated
anymore.
A finisher configuration could look like this:
identifier:contacttype:FormprototypeName:standardfinishers:-identifier:EmailToSenderoptions:subject:'Your Message: {message}'title:'Hello {name}, your confirmation'templateName:ContactFormtemplateRootPaths:100:'EXT:my_site_package/Resources/Private/Templates/Email/'partialRootPaths:100:'EXT:my_site_package/Resources/Private/Partials/Email/'addHtmlPart:true
Copied!
In the example above the following files must exist in the specified
template path:
ContactForm.html
ContactForm.txt
FlashMessage finisher
The 'FlashMessage finisher' is a simple finisher that adds a message to the
FlashMessageContainer.
Redirect finisher
The 'Redirect finisher' is a simple finisher that redirects to another page.
Additional link parameters can be added to the URL.
Important
This finisher stops the execution of all subsequent finishers in order to perform
the redirect. Therefore, this finisher should always be the last finisher to be
executed.
SaveToDatabase finisher
The 'SaveToDatabase finisher' saves the data of a submitted form into a
database table.
Here is an example for adding uploads to ext:news (fal_related_files and fal_media).
To learn more about this topic, please continue here.
Write a custom finisher
If you want to make the finisher configurable in the backend UI read here.
Finishers are defined as part of a prototype within a
finishersDefinition. The property implementationClassName is to be
utilized to load the finisher implementation.
If the finisher requires options, you can define those within the
options property. The options will be used as default values and can
be overridden using the form definition.
Each finisher has to be programmed to the interface TYPO3\CMS\Form\Domain\Finishers\FinisherInterface
and should extend the class TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher.
In doing so, the logic of the finisher should start with the method
executeInternal().
Accessing finisher options
If your finisher extends TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher,
you can access your finisher options with the help of the parseOption()
method:
By utilizing a specific notation, finisher options can be populated with
submitted form values (assuming you are using the parseOption() method).
You can access values of the FormRuntime and thus values of each single
form element by encapsulating the option values with {}. If there is a
form element with the identifier 'subject', you can access its value
within the finisher configuration. Check out the following example to
get the whole idea.
// $yourCustomOption contains the value of the form element with the
// identifier 'subject'
$yourCustomOption = $this->parseOption('yourCustomOption');
Copied!
In addition, you can use {__currentTimestamp} as a special option value.
It will return the current UNIX timestamp.
Finisher Context
The class TYPO3\CMS\Form\Domain\Finishers\FinisherContext takes care of
transferring a finisher context to each finisher. Given the finisher is
derived from TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher the
finisher context will be available via:
$this->finisherContext
Copied!
The method cancel prevents the execution of successive finishers:
$this->finisherContext->cancel();
Copied!
The method getFormValues returns all of the submitted form values.
getFormValues:
$this->finisherContext->getFormValues();
Copied!
The method getFormRuntime returns the FormRuntime:
$this->finisherContext->getFormRuntime();
Copied!
Share data between finishers
The method getFinisherVariableProvider returns an object (TYPO3\CMS\Form\Domain\Finishers\FinisherVariableProvider)
which allows you to store data and transfer it to other finishers. The data
can be easily accessed programmatically or within your configuration:
The data is stored within the FinisherVariableProvider and is addressed
by a user-defined 'finisher identifier' and a custom option value path. The
name of the 'finisher identifier' should consist of the name of the finisher
without the potential 'Finisher' appendix. If your finisher is derived from
the class TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher, the name of
this construct is stored in the following variable:
$this->shortFinisherIdentifier
Copied!
For example, if the name of your finisher class is 'CustomFinisher', the
mentioned variable will contain the value 'Custom'.
There are a bunch of methods to access and manage the finisher data:
In this way, each finisher can access data programmatically. Moreover, it is
possible to retrieve the data via configuration, provided that a finisher
stores the values within the FinisherVariableProvider.
Assuming that a finisher called 'Custom' sets data as follows:
After adding a custom finisher you can also add the finisher to the
form editor GUI to let your backend users configure it visually. Add the
following to the backend yaml setup:
prototypes:standard:formElementsDefinition:Form:formEditor:editors:900:# Extend finisher drop downselectOptions:35:value:'CustomFinisher'label:'Custom Finisher'propertyCollections:finishers:# add finisher fields25:identifier:'CustomFinisher'editors:100:identifier:headertemplateName:Inspector-CollectionElementHeaderEditorlabel:"Custom Finisher"# custom field (input, required)110:identifier:'customField'templateName:'Inspector-TextEditor'label:'Custom Field'propertyPath:'options.customField'propertyValidators:10:'NotEmpty'# email field120:identifier:'email'templateName:'Inspector-TextEditor'label:'Subscribers email'propertyPath:'options.email'enableFormelementSelectionButton:truepropertyValidators:10:'NotEmpty'20:'FormElementIdentifierWithinCurlyBracesInclusive'9999:identifier:removeButtontemplateName:Inspector-RemoveElementEditorfinishersDefinition:CustomFinisher:formEditor:iconIdentifier:'form-finisher'label:'Custom Finisher'predefinedDefaults:options:customField:''email:''# displayed when overriding finisher settingsFormEngine:label:'Custom Finisher'elements:customField:label:'Custom Field'config:type:'text'email:label:'Subscribers email'config:type:'text'
Copied!
Make sure the setup file is registered for the backend in a EXT:my_extension/ext_localconf.php file:
The form manager can be accessed by opening the backend module 'Forms'.
It allows the editor to administer all of the existing forms stored on the
accessible file mounts. The central element of the form manager is a
table view which...
lists all forms
allows users to create, edit, duplicate, and delete forms
names the storage folder
gives a broad overview on which pages the listed forms are used in.
The creation and duplication of forms is supported by a so-called `form
wizard`. The wizard guides the editor through the process and offers a
variety of settings depending on the form configuration. Those settings
include choosing file mounts, prototypes, and start templates.
TYPO3 Backend with opened module 'Forms' displaying the form manager.
Start templates
This is a very nifty feature. When creating a new form, the form manager
allows the backend editor to select a so-called Start template. Such a
template is a predefined form definition without the property
prototypeName which is normally used as a foundation of a new form.
As an integrator, you can specify as many Start templates as you desire
for a given prototype. After you have defined such a template, follow
these easy steps to use your defined Start templates as a foundation:
open the Forms module
create a new form by clicking on the appropriate button
enter the 'Form name' and click the checkbox 'Advanced settings'
during the next steps you can select a Start template
For each prototype, you have to define a Start template in order to
enable the editor to choose one. Additionally, the same Start template
can be used for several prototypes. To do so, make sure the included
form elements of the template are defined in the corresponding prototype.
For example, imagine your integrator has configured
a prototype called 'routing' which contains a custom form element with the
<formElementTypeIdentifier> 'locationPicker'. The element is only
defined for this prototype. The integrator has created a Start template
which carries the 'locationPicker' form element. A backend editor could now
select and use this Start template, including the custom form element,
as long as the prototype is set to 'routing'. If the integrator also
adds this custom form element to another prototype, the process would
crash. The custom form element is only known by the prototype 'routing'.
The following code block shows the minimal configuration of a `Start
template`. You need at least the root form element ('Form') and a 'Page'.
As mentioned previously, the form wizard within the form manager offers
a list of all existing, pre-configuredStart templates. As soon as the backend editor creates a form with the
help of such a template, a new form definition is generated based on the
one of the selected Start template. The form definition will be
enriched by the property propertyName defining the chosen prototype.
The identifier of the root form element ('Form') is automatically set
based on the entered "Form name". Additionally, this name is used for the
property label of the 'Form' element. Finally, the form editor is
loaded and displays the newly created form.
Translation of the form manager
All option values which reside below the following configuration keys can be
translated:
formManager:
Copied!
The translation files of the form manager are loaded as follows:
The process searches for each option value within all of the defined
translation files. If a translation is found, the translated option value
will be used in preference.
Imagine, the following is defined for an option value:
First of all, the process searches for the translation key formManager.selectablePrototypesConfiguration.standard.label
within the file 20: 'EXT:my_site_package/Resources/Private/Language/Form/Database.xlf'
and after it inside the file 10: 'EXT:form/Resources/Private/Language/Database.xlf'
(loaded by default). If nothing is found, the option value will be
displayed unmodified.
Form editor
What does it do?
The form editor is a powerful graphical user interface which allows the
backend editor to create form definitions without writing a single line
of code. Those form definitions will be used by the frontend process to
render beautiful forms.
The form editor is a modular interface which consists of several
components:
Stage: central visual component of the form editor which displays the
form elements in an abstract view and a frontend preview
Tree: displays the structure of the form as a tree
Inspector: context specific toolbar which handles the visual display of
form element options and allows editing those
Core: includes core functionalities of the form editor
ViewModel: defines and steers the visual display
Mediator: delegates events of the components
Modals: processes modals
FormEditor: provides API functions
Helper: helper functions which mainly allow the manipulation of DOM
elements
Generally speaking, the Modals, Inspector, and Stage components
can be adapted through configuration. Especially the Inspector component
is modular and extremely flexible. As an integrator, you can reuse so-called
inspector editors. Those elements are input fields of different types
which allow the backend editor to alter all of the available form element
options.
JavaScript module interaction
There is a general form editor configuration which can be found below
the following configuration path:
prototypes:standard:formEditor:
Copied!
Furthermore, you are able to configure the form editor regarding its
different aspects. The configuration can be found below the following
configuration paths:
The Stage is the central visual component of the form editor which
displays the form elements in two different modes:
abstract view: all form elements of a Page are presented in an
abstract way,
frontend preview: renders the form like it will (nearly) be displayed in
the frontend ('nearly' since you have to make sure that your frontend CSS
is also loaded in the backend in order to get the exact preview).
Per default, the frontend templates of EXT:form are based on Bootstrap.
Since the backend of TYPO3 CMS also depends on this CSS framework,
the corresponding CSS files are already loaded in the backend context.
Nevertheless, certain parts of the CSS were overridden and extended in order
to meet the specific needs of the TYPO3 backend. Thus, the frontend preview
in the backend could differ compared to the "real" frontend.
If your frontend preview requires loading additional CSS or a CSS framework
then go ahead and configure a specific prototype accordingly.
Beside the frontend templates, there are also templates for the abstract
view, i.e. you can customize the rendering of the abstract view for each
form element. If you have created your own form elements, in most cases you
will fall back to the already existing Fluid templates. But remember, you
are always able to create your own Fluid templates and adapt the abstract view
till it suits your needs.
The Inspector component is situated on the right side of the `form
editor`. It is a modular, extremely flexible, and context specific toolbar
which depends on the chosen form element. The Inspector allows editing
the form element's options with the help of so-called inspector editors.
For the most parts, the interface can be easily customized by writing
YAML configuration. For each form element you can define which properties
are available and in which way they can be edited.
In addition to the editable form element properties (like properties.placeholder)
there are so-called property collections which can be written by the
form editor as well. Their definition is stored on the hierarchical
level of a form element. Right now, there are the following `property
collections`:
validators
finishers
Property collections also make use of inspector editors in order to
configure them properly. Due to this, we can do a lot of cool stuff. Imagine
we have got a validator "Number range" with two validator options called
"Minimum" and "Maximum". Additionally, we have got two form elements "Age
spouse" and "Age infant". For both form elements the validator is available
but for the form element "Age child" the validator option "Minimum" is not
editable and the option "Maximum" is pre-filled with a certain value.
Translation of the form editor
All option values which reside below the following configuration keys can be
translated:
The process searches for each option value within all of the defined
translation files. If a translation is found, the translated option value
will be used in preference.
Imagine, the following is defined for an option value:
First of all, the process searches for the translation key formEditor.elements.Form.editor.finishers.label
within the file 20: 'EXT:my_site_package/Resources/Private/Language/Database.xlf'
and after it inside the file 10: 'EXT:form/Resources/Private/Language/Database.xlf'
(loaded by default). If nothing is found, the option value will be
displayed unmodified.
Customization of the form editor
As mentioned earlier, the interface can be customized by writing YAML
configuration. The configuration is not stored within one central configuration
file. Instead, the configuration is defined for each element the form framework
provides (see EXT:form/form/Configuration/Yaml/FormElements/). In addition,
the
Form element itself (see EXT:form/Configuration/Yaml/FormElements/Form.yaml)
ships some basic configuration of the form editor.
A common use case for customization is to remove form elements from the form
editor. In contrast to other TYPO3 modules, the form editor cannot be configured
via backend user groups and the well known Access Lists. Within the form module
this has to be done via YAML configuration. Please keep in mind, it is not possible
to configure the form editor depending on the user's group / access rights.
Quite often, integrators tend to unset whole form elements as shown below.
In this example, the
AdvancedPassword form element is removed from
the form framework completely. This way, integrators and developers won't be able
to use this element in their manually created YAML definitions or via API anymore.
The correct way is to unset the group property.
This property defines within which group within the form editor "new Element"
modal the form element should be shown. Unsetting this property will remove the
form element safely from the form editor. Check out the following example. The
configuration removes the
AdvancedPassword form element from.
Learn here
how to make the finisher configurable in the backend UI.
Basic JavaScript concepts
The form framework was designed to be as extendible as possible. Sooner or
later, you want to customize the components of the form editor using
JavaScript. This is especially true if you want to create your own
inspector editors. In order to achieve this, you can implement your own
JavaScript modules. Those modules will include the required algorithms for
the inspector editors and the abstract view as well as your own
event listing.
Register custom JavaScript modules
The following YAML configuration registers an additional JavaScript module.
According to the example configuration shown above, the JavaScript files have to
be stored within the folder
my_site_package/Resources/Public/JavaScript/backend/form-editor/view-model.js.
Check out the following base template which shows you the recommended way
for setting up your own module.
The event handling of EXT:form is based on the Publish/Subscribe Pattern.
To learn more about this terrific pattern, check out this website: https://addyosmani.com/resources/essentialjsdesignpatterns/book/.
Please note that the processing sequence of the subscribers cannot be
influenced. Furthermore, there is no information flow between the
subscribers. All events have to be arranged asynchronously.
For more information, head to the API reference and read the section about
'Events'.
FormElement model
Within the JavaScript code, each form element is represented by a
`FormElement model. This model can be seen as a copy of the form
definition'' enriched by some additional data. The following example shows
you a form definition and the debug output of the corresponding
FormElement model.
identifier:javascript-form-element-modellabel:'JavaScript FormElement model'type:Formfinishers:-identifier:EmailToReceiveroptions:subject:'Your message: {subject}'recipients:your.company@example.com:'Your Company name'ceo@example.com:'CEO'senderAddress:'{email}'senderName:'{name}'replyToRecipients:replyTo.company@example.com:'Your Company name'carbonCopyRecipients:cc.company@example.com:'Your Company name'blindCarbonCopyRecipients:bcc.company@example.com:'Your Company name'addHtmlPart:trueattachUploads:'true'translation:language:''title:''renderables:-identifier:page-1label:'Contact Form'type:Pagerenderables:-identifier:namelabel:Nametype:Textproperties:fluidAdditionalAttributes:placeholder:NamedefaultValue:''validators:-identifier:NotEmpty
For each form element which has child elements, you will find a property
called renderables. Those renderables are arrays whose elements
consists of FormElement models of the particular child elements.
As previously mentioned, the FormElement model is a conglomerate of the
data of the form definition and some additional information:
__parentRenderable
__identifierPath
The following methods can be utilized in order to access the data of a
FormElement model:
get()
set()
unset()
on()
off()
getObjectData()
toString()
clone()
For more information, head to the API reference and read the section about
the 'FormElement model'.
Form plugin
What does it do?
The form plugin allows you to assign a form - created with the `form
editor` or shipped with your extension - to a specific page. This enables
you to re-use forms throughout the whole TYPO3 installation. Furthermore, it
offers the backend editor the possibility to override certain aspects of the
form definition. At the moment, only finisher options can be overridden. The
possibilities depend on the configuration of the underlying prototype.
Imagine, your form contains a redirect finisher. The redirect target is set
globally and valid for the whole form definition . While adding the form
to a specific page, the backend editor can define a different redirect target. This
setting is only valid for the page containing the plugin.
Sometimes, it is useful to exclude specific options from being overridden via the
form plugin. This can be achieved by unsetting the options concerned in your
custom YAML configuration. For unsetting options use the YAML NULL (
~) value.
The following example unsets four fields of the EmailToReceiver finisher. The
options will only be removed from the form plugin. The Form editor is not affected
by this.
The process searches for each option value within all of the defined
translation files. If a translation is found, the translated option value
will be used in preference.
Imagine, the following is defined for an option value:
First of all, the process searches for the translation key
tt_content.finishersDefinition.EmailToReceiver.label within the file
20: 'EXT:my_site_package/Resources/Private/Language/Database.xlf' and
afterwards inside the file 10: 'EXT:form/Resources/Private/Language/Database.xlf'
(loaded by default). If nothing is found, the option value will be
displayed unmodified.
Autocomplete
The Autocomplete select in the form editor can be used to
define
autocomplete properties for input fields. This extension
predefines the most common of the input purposes that are widely
recognized by assistive technologies and
recommended by the W3C. The
HTML standard allows arbitrary values.
If you need to provide additional fields, you can reconfigure the autocomplete
field with additional select options:
plugin.tx_form {
settings {
yamlConfigurations {
# register your own additional configuration# choose a number higher than 10 (10 is reserved)100 = EXT:my_sitepackage/Configuration/Form/CustomFormSetup.yaml
}
}
}
prototypes:standard:formElementsDefinition:Text:formEditor:editors:600:selectOptions:# Choose an index that is not in use yet12345:value:'cc-name'label:'cc-name - Full name as given on the payment instrument'
Copied!
Configuration Reference
This chapter is a complete reference of the possible configuration settings.
It addresses your concerns as and integrator and developer.
EXT:form stores the form definitions within the file system and thus needs
write access to this storage. By default, the folder form_definitions is
created and used. It is possible to configure a different and/ or an additional
file mount which is then utilized for storing and reading forms.
This array key identifies the prototype``. Every ``form definition`` references to such a ``<prototypeIdentifier>`` through the property ``prototypeName`.
If set this string/ array will be used as default value of the form
element. Array is in place for multi value elements (e.g. the
MultiSelect form element).
If the form element lies within a GridRow you can define the number of columns which the form element should occupy.
Each viewPorts configuration key has to match with on ofe the defined viewports within prototypes.<prototypeIdentifier>.formElementsDefinition.GridRow.properties.gridColumnClassAutoConfiguration.viewPorts
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Identifies the current inspector editor within the current form element.
The identifier is a text of your choice but must be unique within the optionpath prototypes.prototypeIdentifier.formElementsDefinition.formelementtypeidentifier.formEditor.editors.
The inline HTML template which is used for this inspector editor.
Must be equal to an existing array key within prototypes.<prototypeIdentifier>.formEditor.formEditorPartials and must be started with 'Inspector-' by convention.
The inline HTML template which is used for this inspector editor.
Must be equal to an existing array key within prototypes.<prototypeIdentifier>.formEditor.formEditorPartials and must be started with 'Inspector-' by convention.
Identifies the current inspector editor within the current form element.
The identifier is a text of your choice but must be unique within the optionpath prototypes.prototypeIdentifier.formElementsDefinition.formelementtypeidentifier.formEditor.editors.
The path to the property of the form element which should be written by this inspector editor.
[CollectionElementHeaderEditor]
Introduction
This is not really an editor because this editor don't write values into the form definition.
This editor show the header area for collection elements (finishers/ validators) with it's icon and label.
The inline HTML template which is used for this inspector editor.
Must be equal to an existing array key within prototypes.<prototypeIdentifier>.formEditor.formEditorPartials and must be started with 'Inspector-' by convention.
Identifies the current inspector editor within the current form element.
The identifier is a text of your choice but must be unique within the optionpath prototypes.prototypeIdentifier.formElementsDefinition.formelementtypeidentifier.formEditor.editors.
The inline HTML template which is used for this inspector editor.
Must be equal to an existing array key within prototypes.<prototypeIdentifier>.formEditor.formEditorPartials and must be started with 'Inspector-' by convention.
Identifies the current inspector editor within the current form element.
The identifier is a text of your choice but must be unique within the optionpath prototypes.prototypeIdentifier.formElementsDefinition.formelementtypeidentifier.formEditor.editors.
Has to match with a prototypes.<prototypeIdentifier>.finishersdefinition configuration key.
selectOptions.[*].label
Data type
string
Needed by
Backend (form editor)
Mandatory
Yes
Description
The label which is shown within the select field.
[FormElementHeaderEditor]
Introduction
This is not really an editor because this editor don't write values into the form definition.
This editor show the header area for the form element with it's icon and label.
The inline HTML template which is used for this inspector editor.
Must be equal to an existing array key within prototypes.<prototypeIdentifier>.formEditor.formEditorPartials and must be started with 'Inspector-' by convention.
Identifies the current inspector editor within the current form element.
The identifier is a text of your choice but must be unique within the optionpath prototypes.prototypeIdentifier.formElementsDefinition.formelementtypeidentifier.formEditor.editors.
[GridColumnViewPortConfigurationEditor]
Introduction
Shows a viewport selector as buttons and an input field. With this editor, you can define how many columns per viewPort an form element should occupy.
The inline HTML template which is used for this inspector editor.
Must be equal to an existing array key within prototypes.<prototypeIdentifier>.formEditor.formEditorPartials and must be started with 'Inspector-' by convention.
Identifies the current inspector editor within the current form element.
The identifier is a text of your choice but must be unique within the optionpath prototypes.prototypeIdentifier.formElementsDefinition.formelementtypeidentifier.formEditor.editors.
Has to match with a prototypes.<prototypeIdentifier>.formElementsDefinition.<formElementTypeIdentifier>.properties.gridColumnClassAutoConfiguration.viewPorts configuration key.
configurationOptions.viewPorts.[*].label
Data type
string
Needed by
Backend (form editor)
Mandatory
Yes
Description
The label for the viewport button.
configurationOptions.numbersOfColumnsToUse.label
Data type
string
Needed by
Backend (form editor)
Mandatory
Yes
Description
The label for the "Numbers of columns" input field.
A text which is shown at the bottom of the "Numbers of columns" input field.
[MultiSelectEditor]
Introduction
Shows a multiselect list with values. If one or more selectoptions are selected, then the option value will be written within a form element property which is defined by the "propertyPath" option.
The inline HTML template which is used for this inspector editor.
Must be equal to an existing array key within prototypes.<prototypeIdentifier>.formEditor.formEditorPartials and must be started with 'Inspector-' by convention.
Identifies the current inspector editor within the current form element.
The identifier is a text of your choice but must be unique within the optionpath prototypes.prototypeIdentifier.formElementsDefinition.formelementtypeidentifier.formEditor.editors.
The path to the property of the form element which should be written by this inspector editor.
selectOptions.[*].value
Data type
string
Needed by
Backend (form editor)
Mandatory
Yes
Description
The value which should be written into the corresponding form elements property.
The corresponding form elements property is identified by the propertyPath option.
selectOptions.[*].label
Data type
string
Needed by
Backend (form editor)
Mandatory
Yes
Description
The label which is shown within the select field.
[PropertyGridEditor]
Introduction
Shows a grid which allows you to add (and remove) multiple rows and fill values for each row.
The inline HTML template which is used for this inspector editor.
Must be equal to an existing array key within prototypes.<prototypeIdentifier>.formEditor.formEditorPartials and must be started with 'Inspector-' by convention.
Identifies the current inspector editor within the current form element.
The identifier is a text of your choice but must be unique within the optionpath prototypes.prototypeIdentifier.formElementsDefinition.formelementtypeidentifier.formEditor.editors.
There must be at least one existing row within this inspector editor. If the last existing row is tried to be removed a flash message is shown.
This property defines the title for the flash message.
There must be at least one existing row within this inspector editor. If the last existing row is tried to be removed a flash message is shown.
This property defines the text for the flash message.
The inline HTML template which is used for this inspector editor.
Must be equal to an existing array key within prototypes.<prototypeIdentifier>.formEditor.formEditorPartials and must be started with 'Inspector-' by convention.
Identifies the current inspector editor within the current form element.
The identifier is a text of your choice but must be unique within the optionpath prototypes.prototypeIdentifier.formElementsDefinition.formelementtypeidentifier.formEditor.editors.
[RequiredValidatorEditor]
Introduction
Shows a checkbox. If set, a validator ('NotEmpty' by default) will be written into the form definition. In addition another property could be written into the form definition.
The inline HTML template which is used for this inspector editor.
Must be equal to an existing array key within prototypes.<prototypeIdentifier>.formEditor.formEditorPartials and must be started with 'Inspector-' by convention.
Identifies the current inspector editor within the current form element.
The identifier is a text of your choice but must be unique within the optionpath prototypes.prototypeIdentifier.formElementsDefinition.formelementtypeidentifier.formEditor.editors.
The value for the property path which should be written into the form definition` if the checkbox is set.
[SingleSelectEditor]
Introduction
Shows a single select list with values. If a selectoption is selected, then the option value will be written within a form element property which is defined by the "propertyPath" option.
The inline HTML template which is used for this inspector editor.
Must be equal to an existing array key within prototypes.<prototypeIdentifier>.formEditor.formEditorPartials and must be started with 'Inspector-' by convention.
Identifies the current inspector editor within the current form element.
The identifier is a text of your choice but must be unique within the optionpath prototypes.prototypeIdentifier.formElementsDefinition.formelementtypeidentifier.formEditor.editors.
The path to the property of the form element which should be written by this inspector editor.
selectOptions.[*].value
Data type
string
Needed by
Backend (form editor)
Mandatory
Yes
Description
The value which should be written into the corresponding form elements property.
The corresponding form elements property is identified by the propertyPath option.
The inline HTML template which is used for this inspector editor.
Must be equal to an existing array key within prototypes.<prototypeIdentifier>.formEditor.formEditorPartials and must be started with 'Inspector-' by convention.
Identifies the current inspector editor within the current form element.
The identifier is a text of your choice but must be unique within the optionpath prototypes.prototypeIdentifier.formElementsDefinition.formelementtypeidentifier.formEditor.editors.
The inline HTML template which is used for this inspector editor.
Must be equal to an existing array key within prototypes.<prototypeIdentifier>.formEditor.formEditorPartials and must be started with 'Inspector-' by convention.
Identifies the current inspector editor within the current form element.
The identifier is a text of your choice but must be unique within the optionpath prototypes.prototypeIdentifier.formElementsDefinition.formelementtypeidentifier.formEditor.editors.
If set to true then the property which should be written through this inspector editor will be removed within the form definition if the
value from the inspector editor is empty instead of writing an empty value ('') for this property.
This inspector editors is able to validate it's value through JavaScript methods.
This JavaScript validators can be registered through getFormEditorApp().addPropertyValidationValidator().
The first method argument is the identifier for such a validator.
Every array value within propertyValidators must be equal to such an identifier.
The inline HTML template which is used for this inspector editor.
Must be equal to an existing array key within prototypes.<prototypeIdentifier>.formEditor.formEditorPartials and must be started with 'Inspector-' by convention.
Identifies the current inspector editor within the current form element.
The identifier is a text of your choice but must be unique within the optionpath prototypes.prototypeIdentifier.formElementsDefinition.formelementtypeidentifier.formEditor.editors.
This inspector editors is able to validate it's value through JavaScript methods.
This JavaScript validators can be registered through getFormEditorApp().addPropertyValidationValidator().
The first method argument is the identifier for such a validator.
Every array value within propertyValidators must be equal to such an identifier.
The inline HTML template which is used for this inspector editor.
Must be equal to an existing array key within prototypes.<prototypeIdentifier>.formEditor.formEditorPartials and must be started with 'Inspector-' by convention.
Identifies the current inspector editor within the current form element.
The identifier is a text of your choice but must be unique within the optionpath prototypes.prototypeIdentifier.formElementsDefinition.formelementtypeidentifier.formEditor.editors.
Has to match with a prototypes.<prototypeIdentifier>.validatorsDefinition configuration key.
selectOptions.[*].label
Data type
string
Needed by
Backend (form editor)
Mandatory
Yes
Description
The label which is shown within the select field.
[ValidationErrorMessageEditor]
Introduction
Shows a textarea. It allows the definition of custom validation error messages. Within the form editor, one can set
those error messages for all existing validators.
The inline HTML template which is used for this inspector editor.
Must be equal to an existing array key within prototypes.<prototypeIdentifier>.formEditor.formEditorPartials and must be started with 'Inspector-' by convention.
Identifies the current inspector editor within the current form element.
The identifier is a text of your choice but must be unique within the optionpath prototypes.prototypeIdentifier.formElementsDefinition.formelementtypeidentifier.formEditor.editors.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
The form framework contains a form element called 'Date' which is technically an HTML5 'date' form element.
The DateRange validator is the server side validation equivalent to the client side validation through the min
and max HTML attribute and should always be used in combination. If the DateRange validator is added to the
form element within the form editor, the min and max HTML attributes are added automatically.
Browsers which do not support the HTML5 date element gracefully degrade to a text input. The HTML5 date element always
normalizes the value to the format Y-m-d (RFC 3339 'full-date'). With a text input, by default the browser has no
recognition of which format the date should be in. A workaround could be to put a pattern attribute on the date input.
Even though the date input does not use it, the text input fallback will.
By default, the HTML attribute pattern="([0-9]{4})-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" is rendered on the
date form element. Note that this basic regular expression does not support leap years and does not check for the
correct number of days in a month. But as a start, this should be sufficient. The same pattern is used by the form
editor to validate the properties defaultValue and the DateRange validator options minimum and maximum.
The display format defines the display format of the submitted value within the
summary step, email finishers etc. but not for the form element value itself.
The display format of the form element value depends on the browser settings and
can not be defined!
The properties defaultValue, properties.fluidAdditionalAttributes.min,
properties.fluidAdditionalAttributes.max must have the format 'Y-m-d' which represents the RFC 3339
'full-date' format.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
The location (file mount) for the uploaded files.
If this file mount or the property "saveToFileMount" does not exist
the folder in which the form definition lies (persistence identifier) will be used.
If the form is generated programmatically and therefore no persistence identifier exist
the default storage "1:/user_upload/" will be used.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Each configuration key within properties.gridColumnClassAutoConfiguration.viewPorts represents an viewport of the CSS grid system (bootstrap by default).
Defines the CSS class pattern for the CSS grid system.
Each viewport classPattern will be wrapped around a form element within a grid row.
The {@numbersOfColumnsToUse} placeholder will be replaced by the number of columns which the respective form element should occupy.
The number of columns which the respective form element should occupy has to defined within the respective form elements within a GridRow.
If a form element has no number of columns defined, the {@numbersOfColumnsToUse} are calculated automatically.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
By default the honeypot will be rendered as a regular text form element (input type "text"). renderAsHiddenField renders the honeypot as a hidden form element (input type "hidden").
By default the honeypot will be rendered as a regular text form element (input type "text"). The styleAttribute is written to the honeypot form element to make it "invisible" for humans.
The location (file mount) for the uploaded images.
If this file mount or the property "saveToFileMount" does not exist
the folder in which the form definition lies (persistence identifier) will be used.
If the form is generated programmatically and therefore no persistence identifier exist
the default storage "1:/user_upload/" will be used.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
Define within which group within the form editor "new Element" modal the form element should be shown.
The group value must be equal to an array key within formElementGroups.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the finisher is selected.
Finisher options are overwritable within the form plugin.
If the "Override finisher settings" checkbox is selected within the form plugin, every finisher who has a - "FormEngine" configuration, is shown in a separate tab.
label is the label for such a tab.
Every array key must match to the related finisher option name.
For example, the - "[Redirect] finisher" has the option - "pageUid".
If you want to make the pageUid overwritable within the form plugin, then an array key pageUid has to exists within prototypes.prototypeIdentifier.finishersDefinition.finisheridentifier.FormEngine.elements.
The configuration within prototypes.prototypeIdentifier.finishersDefinition.Redirect.FormEngine.elements.pageUid must follow the TCA syntax.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the finisher is selected.
If set, this translation file(s) will be used for finisher option translations.
If not set, the translation file(s) from the 'Form' element will be used.
Read Translate finisher options for more informations.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the finisher is selected.
If set, mails will contain a plaintext and HTML part, otherwise only a
plaintext part. That way, it can be used to disable HTML and enforce
plaintext-only mails.
The title, being shown in the email. The templates are based onFluidEmail.
The template renders the title field in the header section right above the
email body. Do not confuse this field with the subject of the email.
If not set, the finisher options are translated depending on the current frontend language (if translations exists).
This option allows you to force translations for a given language isocode, e.g 'da' or 'de'.
Read Translate finisher options for more informations.
If set, this translation file(s) will be used for finisher option translations.
If not set, the translation file(s) from the 'Form' element will be used.
Read Translate finisher options for more informations.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the finisher is selected.
Finisher options are overwritable within the form plugin.
If the "Override finisher settings" checkbox is selected within the form plugin, every finisher who has a - "FormEngine" configuration, is shown in a separate tab.
label is the label for such a tab.
Every array key must match to the related finisher option name.
For example, the - "[Redirect] finisher" has the option - "pageUid".
If you want to make the pageUid overwritable within the form plugin, then an array key pageUid has to exists within prototypes.prototypeIdentifier.finishersDefinition.finisheridentifier.FormEngine.elements.
The configuration within prototypes.prototypeIdentifier.finishersDefinition.Redirect.FormEngine.elements.pageUid must follow the TCA syntax.
If set, mails will contain a plaintext and HTML part, otherwise only a
plaintext part. That way, it can be used to disable HTML and enforce
plaintext-only mails.
The title, being shown in the email. The templates are based onFluidEmail.
The template renders the title field in the header section right above the
email body. Do not confuse this field with the subject of the email.
If not set, the finisher options are translated depending on the current frontend language (if translations exists).
This option allows you to force translations for a given language isocode, e.g 'da' or 'de'.
Read Translate finisher options for more informations.
If set, this translation file(s) will be used for finisher option translations.
If not set, the translation file(s) from the 'Form' element will be used.
Read Translate finisher options for more informations.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the finisher is selected.
Finisher options are overwritable within the form plugin.
If the "Override finisher settings" checkbox is selected within the form plugin, every finisher who has a - "FormEngine" configuration, is shown in a separate tab.
label is the label for such a tab.
Every array key must match to the related finisher option name.
For example, the - "[Redirect] finisher" has the option - "pageUid".
If you want to make the pageUid overwritable within the form plugin, then an array key pageUid has to exists within prototypes.prototypeIdentifier.finishersDefinition.finisheridentifier.FormEngine.elements.
The configuration within prototypes.prototypeIdentifier.finishersDefinition.Redirect.FormEngine.elements.pageUid must follow the TCA syntax.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the finisher is selected.
If set, this translation file(s) will be used for finisher option translations.
If not set, the translation file(s) from the 'Form' element will be used.
Read Translate finisher options for more informations.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the finisher is selected.
If set, this translation file(s) will be used for finisher option translations.
If not set, the translation file(s) from the 'Form' element will be used.
Read Translate finisher options for more informations.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the finisher is selected.
Finisher options are overwritable within the form plugin.
If the "Override finisher settings" checkbox is selected within the form plugin, every finisher who has a - "FormEngine" configuration, is shown in a separate tab.
label is the label for such a tab.
Every array key must match to the related finisher option name.
For example, the - "[Redirect] finisher" has the option - "pageUid".
If you want to make the pageUid overwritable within the form plugin, then an array key pageUid has to exists within prototypes.prototypeIdentifier.finishersDefinition.finisheridentifier.FormEngine.elements.
The configuration within prototypes.prototypeIdentifier.finishersDefinition.Redirect.FormEngine.elements.pageUid must follow the TCA syntax.
insert will create a new database row with the values from the submitted form and/or some predefined values. @see options.elements and options.databaseFieldMappings
update will update a given database row with the values from the submitted form and/or some predefined values. 'options.whereClause' is then required.
Use options.elements to map form element values to existing database columns.
Each key within options.elements has to match with a form element identifier.
The value for each key within options.elements is an array with additional informations.
Set this to true if the database column should not be written if the value from the submitted form element with the identifier
<formElementIdentifier> is empty (think about password fields etc.).
This setting only rules for form elements which creates a FAL object like FileUpload or ImageUpload.
By default, the uid of the FAL object will be written into the database column. Set this to true if you want to store the
FAL identifier (1:/user_uploads/some_uploaded_pic.jpg) instead.
Set this to true if the database column should not be written if the value from the submitted form element with the identifier
<formElementIdentifier> is empty (think about password fields etc.). Empty means strings without content, whitespace
is valid content.
If the internal Datatype is DateTime which is true for the form element types "DatePicker" and "Date",
the object needs to be converted into a string value.
This option allows you to define the format of the date.
You can use every format accepted by PHP's date() function (https://php.net/manual/en/function.date.php#refsect1-function.date-parameters).
The default value is "U" which means a Unix timestamp.
Use this to map database columns to static values.
Each key within options.databaseColumnMappings has to match with an existing database column.
The value for each key within options.databaseColumnMappings is an array with additional informations.
This mapping is done before the options.element mapping.
This means if you map a database column to a value through options.databaseColumnMappings and map a submitted
form element value to the same database column through options.element, the submitted form element value
will override the value you set within options.databaseColumnMappings.
The value which will be written to the database column.
You can also use the FormRuntime accessor feature to access every getable property from the FormRuntime
In short: use something like {<formElementIdentifier>} to get the value from the submitted form element with the identifier <formElementIdentifier>.
If you use the FormRuntime accessor feature within options.databaseColumnMappings the functionality is nearly equal
to the options.elements configuration variant.
Set this to true if the database column should not be written if the value from options.databaseColumnMappings.
<databaseColumnName>.value is empty. Empty means strings without content, whitespace is valid content.
If set, this translation file(s) will be used for finisher option translations.
If not set, the translation file(s) from the 'Form' element will be used.
Read Translate finisher options for more informations.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the finisher is selected.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the validator is selected.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the validator is selected.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the validator is selected.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the validator is selected.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the validator is selected.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the validator is selected.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the validator is selected.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the validator is selected.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the validator is selected.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the validator is selected.
An icon identifier which must be registered through the
\TYPO3\CMS\Core\Imaging\IconRegistry .
This icon will be shown within the - "Inspector [CollectionElementHeaderEditor]" if the validator is selected.