Custom finisher
Important
Finishers are executed in the order defined in your form definition.
Table of contents
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
finishers
. The property implementation
is to be
utilized to load the finisher implementation.
prototypes:
standard:
finishersDefinition:
CustomFinisher:
implementationClassName: 'MyVendor\MySitePackage\Domain\Finishers\CustomFinisher'
The custom form definition has to be registered.
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
.
Define the default value
Override the option using the form definition
identifier: sample-form
label: 'Simple Contact Form'
prototype: standard
type: Form
finishers:
-
identifier: CustomFinisher
options:
yourCustomOption: 'Björn'
renderables:
# ...
Each finisher has to be programmed to the interface
Finisher
and should extend the
class
Abstract
. In doing so, the logic of the
finisher should start with the method execute
.
Accessing finisher options
If your finisher extends
Abstract
,
you can access your finisher options with the help of the parse
method:
$yourCustomOption = $this->parseOption('yourCustomOption');
parse
is looking for 'yourCustomOption' in your
form definition
. If it cannot be found, the method checks
- the
prototype
configuration for a default value, -
the finisher class itself by searching for a default value within the
$default
property:Options EXT:my_site_package/Classes/Domain/Finishers/CustomFinisher.yaml
If the option cannot be found by processing this fallback chain, null
is
returned.
If the option is found, the process checks whether the option value will
access FormRuntime values.
If the Form
returns a positive result, it is checked whether the
option value can access values of preceding finishers.
At the very end, it tries to translate the finisher options.
Accessing form runtime values
By utilizing a specific notation, finisher options can be populated with
submitted form values (assuming you are using the parse
method).
You can access values of the Form
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.
identifier: simple-contact-form
label: 'Simple Contact Form'
prototype: standard
type: Form
finishers:
-
identifier: Custom
options:
yourCustomOption: '{subject}'
renderables:
-
identifier: subject
label: 'Subject'
type: Text
// $yourCustomOption contains the value of the form element with the
// identifier 'subject'
$yourCustomOption = $this->parseOption('yourCustomOption');
In addition, you can use {__
as a special option value.
It will return the current UNIX timestamp.
Finisher Context
The class
Finisher
takes care of
transferring a finisher context to each finisher. Given the finisher is
derived from
Abstract
the
finisher context will be available via:
$this->finisherContext
The method cancel
prevents the execution of successive finishers:
$this->finisherContext->cancel();
The method get
returns all of the submitted form values.
get
:
$this->finisherContext->getFormValues();
The method get
returns the Form
:
$this->finisherContext->getFormRuntime();
Add finisher to backend UI
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 down
selectOptions:
35:
value: 'CustomFinisher'
label: 'Custom Finisher'
propertyCollections:
finishers:
# add finisher fields
25:
identifier: 'CustomFinisher'
editors:
100:
identifier: header
templateName: Inspector-CollectionElementHeaderEditor
label: "Custom Finisher"
# custom field (input, required)
110:
identifier: 'customField'
templateName: 'Inspector-TextEditor'
label: 'Custom Field'
propertyPath: 'options.customField'
propertyValidators:
10: 'NotEmpty'
# email field
120:
identifier: 'email'
templateName: 'Inspector-TextEditor'
label: 'Subscribers email'
propertyPath: 'options.email'
enableFormelementSelectionButton: true
propertyValidators:
10: 'NotEmpty'
20: 'FormElementIdentifierWithinCurlyBracesInclusive'
9999:
identifier: removeButton
templateName: Inspector-RemoveElementEditor
finishersDefinition:
CustomFinisher:
formEditor:
iconIdentifier: 'form-finisher'
label: 'Custom Finisher'
predefinedDefaults:
options:
customField: ''
email: ''
# displayed when overriding finisher settings
FormEngine:
label: 'Custom Finisher'
elements:
customField:
label: 'Custom Field'
config:
type: 'text'
email:
label: 'Subscribers email'
config:
type: 'text'
Important
Make sure to define an iconIdentifier within the finishersDefinition of your custom finisher; otherwise, the button to remove the finisher from the form will not be visible.
Configuration registration
Make sure the setup file is registered in
either a EXT:
file:
<?php
declare(strict_types=1);
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
defined('TYPO3') or die();
ExtensionManagementUtility::addTypoScriptSetup('
# for the backend
module.tx_form.settings.yamlConfigurations {
123456789 = EXT:yourExtension/Configuration/Form/CustomFormSetup.yaml
}
# for the frontend - otherwise the custom finisher class is not found
# because of the missing "implementationClassName"
plugin.tx_form.settings.yamlConfigurations {
123456789 = EXT:yourExtension/Configuration/Form/Backend.yaml
}
');
See also
Changed in version 13.0
Registration of global TypoScript for the TYPO3 backend has to be done in
an extensions ext_
using method Extension
.
Former methods of global TypoScript registration are not compatible with site sets.