[TASK] Synchronize the form documentation
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Documentation / Concepts / FrontendRendering / Index.rst
1 .. include:: ../../Includes.txt
2
3
4 .. _concepts-frontendrendering:
5
6 ==================
7 Frontend rendering
8 ==================
9
10
11 .. _concepts-frontendrendering-basiccodecomponents:
12
13 Basic code components
14 =====================
15
16 .. figure:: ../../Images/basic_code_components.png
17 :alt: Basic code components
18
19 Basic code components
20
21
22 .. _concepts-frontendrendering-basiccodecomponents-formdefinition:
23
24 TYPO3\\CMS\\Form\\Domain\\Model\\FormDefinition
25 -----------------------------------------------
26
27 The class ``TYPO3\\CMS\\Form\\Domain\\Model\\FormDefinition`` encapsulates
28 a complete ``form definition``, with all of its
29
30 - pages,
31 - form elements,
32 - applicable validation rules, and
33 - finishers, which should be executed when the form is submitted.
34
35 The FormDefinition domain model is not modified when the form is executed.
36
37
38 .. _concepts-frontendrendering-basiccodecomponents-formdefinition-anatomy:
39
40 The anatomy of a form
41 """""""""""""""""""""
42
43 A ``FormDefinition`` domain model consists of multiple ``Page`` objects.
44 When a form is displayed, only one ``Page`` is visible at any given time.
45 Moreover, there is a navigation to go back and forth between those pages. A
46 ``Page`` consists of multiple ``FormElements`` which represent the input
47 fields, textareas, checkboxes, etc. shown on a page. The ``FormDefinition``
48 domain model, ``Page`` and ``FormElement`` objects have ``identifier``
49 properties which must be unique for each given ``<formElementTypeIdentifier>``,
50 i.e. the ``FormDefinition`` domain model and a ``FormElement`` object may
51 have the same ``identifier`` but having the same identifier for two
52 ``FormElement`` objects is disallowed.
53
54
55 .. _concepts-frontendrendering-basiccodecomponents-formdefinition-anatomy-example:
56
57 Example
58 '''''''
59
60 Basically, you can manually create a ``FormDefinition`` domain model just
61 by calling the API methods on it, or you can use a ``FormFactory`` to build
62 the form from a different representation format such as YAML::
63
64 $formDefinition = $this->objectManager->get(FormDefinition::class, 'myForm');
65
66 $page1 = $this->objectManager->get(Page::class, 'page1');
67 $formDefinition->addPage($page);
68
69 // second argument is the <formElementTypeIdentifier> of the form element
70 $element1 = $this->objectManager->get(GenericFormElement::class, 'title', 'Text');
71 $page1->addElement($element1);
72
73
74 .. _concepts-frontendrendering-basiccodecomponents-formdefinition-createformusingabstracttypes:
75
76 Creating a form using abstract form element types
77 """""""""""""""""""""""""""""""""""""""""""""""""
78
79 While you can use the ``TYPO3\CMS\Form\Domain\Model\FormDefinition::addPage()``
80 or ``TYPO3\CMS\Form\Domain\Model\FormElements\Page::addElement()`` methods
81 and create the ``Page`` and ``FormElement`` objects manually, it is often
82 better to use the corresponding create* methods (``TYPO3\CMS\Form\Domain\Model\FormDefinition::createPage()``
83 and ``TYPO3\CMS\Form\Domain\Model\FormElements\Page::createElement()``), as
84 you pass them an abstract ``<formElementTypeIdentifier>`` such as ``Text``
85 or ``Page``. EXT:form will automatically resolve the implementation class
86 name and set default values.
87
88 The :ref:`simple example <concepts-frontendrendering-basiccodecomponents-formdefinition-anatomy-example>`
89 shown above should be rewritten as follows::
90
91 // we will come back to this later on
92 $prototypeConfiguration = [];
93
94 $formDefinition = $this->objectManager->get(FormDefinition::class, 'myForm', $prototypeConfiguration);
95 $page1 = $formDefinition->createPage('page1');
96 $element1 = $page1->addElement('title', 'Text');
97
98 You might wonder how the system knows that the element ``Text`` is
99 implemented by using a ``GenericFormElement``. This is configured in the
100 ``$prototypeConfiguration``. To make the example from above actually work,
101 we need to add some meaningful values to ``$prototypeConfiguration``::
102
103 $prototypeConfiguration = [
104 'formElementsDefinition' => [
105 'Page' => [
106 'implementationClassName' => 'TYPO3\CMS\Form\Domain\Model\FormElements\Page'
107 ],
108 'Text' => [
109 'implementationClassName' => 'TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement'
110 ],
111 ],
112 ];
113
114 For each abstract ``<formElementTypeIdentifier>`` we have to add some
115 configuration. In the snippet above, we only define the ``implementation
116 class name``. Apart form that, it is always possible to set default values
117 for all configuration options of such elements, as the following example
118 shows::
119
120 $prototypeConfiguration = [
121 'formElementsDefinition' => [
122 'Page' => [
123 'implementationClassName' => 'TYPO3\CMS\Form\Domain\Model\FormElements\Page',
124 'label' => 'This is the label of the page if nothing else is specified'
125 ],
126 'Text' => [
127 'implementationClassName' => 'TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement',
128 'label' = >'Default Label',
129 'defaultValue' => 'Default form element value',
130 'properties' => [
131 'placeholder' => 'Text that is shown if element is empty'
132 ],
133 ],
134 ],
135 ];
136
137
138 .. _concepts-frontendrendering-basiccodecomponents-formdefinition-preconfiguredconfiguration:
139
140 Using pre-configured $prototypeConfiguration
141 """"""""""""""""""""""""""""""""""""""""""""
142
143 Often, it does not make sense to manually create the $prototypeConfiguration
144 array. Bigger parts of this array are pre-configured in the extensions's
145 YAML settings. The ``TYPO3\CMS\Form\Domain\Configuration\ConfigurationService``
146 contains helper methods which return the ready-to-use ``$prototypeConfiguration``.
147
148
149 .. _concepts-frontendrendering-basiccodecomponents-formdefinition-rednering:
150
151 Rendering a FormDefinition
152 """"""""""""""""""""""""""
153
154 To trigger the rendering of a ``FormDefinition`` domain model, the current
155 ``TYPO3\CMS\Extbase\Mvc\Web\Request`` needs to be bound to the
156 ``FormDefinition``. This binding results in a ``TYPO3\CMS\Form\Domain\Runtime\FormRuntime``
157 object which contains the ``Runtime State`` of the form. Among other things,
158 this object includes the currently inserted values::
159
160 // $currentRequest and $currentResponse need to be available
161 // inside a controller, you would use $this->request and $this->response;
162 $form = $formDefinition->bind($currentRequest, $currentResponse);
163 // now, you can use the $form object to get information about the currently entered values, etc.
164
165
166 .. _concepts-frontendrendering-basiccodecomponents-formruntime:
167
168 TYPO3\\CMS\\Form\\Domain\\Runtime\\FormRuntime
169 ----------------------------------------------
170
171 This class implements the runtime logic of a form, i.e. the class
172
173 - decides which page is currently shown,
174 - determines the current values of the form
175 - triggers validation and property mappings.
176
177 You generally receive an instance of this class by calling ``TYPO3\CMS\Form\Domain\Model\FormDefinition::bind()``.
178
179
180 .. _concepts-frontendrendering-basiccodecomponents-formruntime-render:
181
182 Rendering a form
183 """"""""""""""""
184
185 Rendering a form is easy. Just call ``render()`` on the ``FormRuntime``::
186
187 $form = $formDefinition->bind($request, $response);
188 $renderedForm = $form->render();
189
190
191 .. _concepts-frontendrendering-basiccodecomponents-formruntime-accessingformvalues:
192
193 Accessing form values
194 """""""""""""""""""""
195
196 In order to get the values the user has entered into the form, you can
197 access the ``FormRuntime`` object like an array. If a form element with the
198 identifier ``firstName`` exists, you can use ``$form['firstName']`` to
199 retrieve its current value. You can set values the same way.
200
201
202 .. _concepts-frontendrendering-basiccodecomponents-formruntime-renderinginternals:
203
204 Rendering internals
205 """""""""""""""""""
206
207 The ``FormRuntime`` inquires the ``FormDefinition`` domain model regarding
208 the configured renderer (``TYPO3\CMS\Form\Domain\Model\FormDefinition::getRendererClassName()``)
209 and then triggers render() on this Renderer.
210
211 This allows you to declaratively define how a form should be rendered.
212
213 .. code-block:: yaml
214
215 TYPO3:
216 CMS:
217 Form:
218 prototypes:
219 standard:
220 formElementsDefinition:
221 Form:
222 rendererClassName: 'TYPO3\CMS\Form\Domain\Renderer\FluidFormRenderer'
223
224
225 .. _concepts-frontendrendering-basiccodecomponents-fluidformrenderer:
226
227 TYPO3\\CMS\\Form\\Domain\\Renderer\\FluidFormRenderer
228 -----------------------------------------------------
229
230 This class is a ``TYPO3\CMS\Form\Domain\Renderer\RendererInterface``
231 implementation which used to render a ``FormDefinition`` domain model. It
232 is the default EXT:form renderer.
233
234 Learn more about the :ref:`FluidFormRenderer Options<apireference-frontendrendering-fluidformrenderer-options>`.
235
236
237 .. _concepts-frontendrendering-codecomponents-customformelementimplementations:
238
239 Custom form element implementations
240 -----------------------------------
241
242 EXT:form ships a decent amount of hooks which are available at crucial
243 points of the life cycle of a ``FormElement``. Most of the time, own
244 implementations are therefore unnecessary. An own form element can be
245 defined by:
246
247 - writing some configuration, and
248 - utilizing the standard implementation of ``TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement``.
249
250 .. code-block:: yaml
251
252 TYPO3:
253 CMS:
254 Form:
255 prototypes:
256 standard:
257 formElementsDefinition:
258 CustomFormElementIdentifier:
259 implementationClassName: 'TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement'
260
261 With the provided hooks, this ``FormElement`` can now be manipulated.
262
263 If you insist on your own implementation, the abstract class ``TYPO3\CMS\Form\Domain\Model\FormElements\AbstractFormElement``
264 offers a perfect entry point. In addition, we recommend checking-out ``TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable``.
265 All of your own form element implementations must be programmed to the
266 interface ``TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface``.
267 It is a good idea to derive your implementation from ``TYPO3\CMS\Form\Domain\Model\FormElements\AbstractFormElement``.
268
269
270 .. _concepts-frontendrendering-codecomponents-customfinisherimplementations:
271
272 Custom finisher implementations
273 -------------------------------
274
275 Finishers are defined as part of a ``prototype`` within a
276 ``finishersDefinition``. The property ``implementationClassName`` is to be
277 utilized to load the finisher implementation.
278
279 .. code-block:: yaml
280
281 TYPO3:
282 CMS:
283 Form:
284 prototypes:
285 standard:
286 finishersDefinition:
287 CustomFinisher:
288 implementationClassName: 'VENDOR\MySitePackage\Domain\Finishers\CustomFinisher'
289
290 If the finisher requires options, you can define those within the
291 ``options`` property. The options will be used as default values and can
292 be overridden using the ``form definition``.
293
294 Define the default value:
295
296 .. code-block:: yaml
297
298 TYPO3:
299 CMS:
300 Form:
301 prototypes:
302 standard:
303 finishersDefinition:
304 CustomFinisher:
305 implementationClassName: 'VENDOR\MySitePackage\Domain\Finishers\CustomFinisher'
306 options:
307 yourCustomOption: 'Ralf'
308
309 Override the option using the ``form definition``:
310
311 .. code-block:: yaml
312
313 identifier: sample-form
314 label: 'Simple Contact Form'
315 prototype: standard
316 type: Form
317
318 finishers:
319 -
320 identifier: CustomFinisher
321 options:
322 yourCustomOption: 'Björn'
323
324 renderables:
325 ...
326
327 Each finisher has to be programmed to the interface ``TYPO3\CMS\Form\Domain\Finishers\FinisherInterface``
328 and should extend the class ``TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher``.
329 In doing so, the logic of the finisher should start with the method
330 ``executeInternal()``.
331
332
333 .. _concepts-frontendrendering-codecomponents-customfinisherimplementations-accessingoptions:
334
335 Accessing finisher options
336 """"""""""""""""""""""""""
337
338 If your finisher extends ``TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher``,
339 you can access your finisher options with the help of the ``parseOption()``
340 method::
341
342 $yourCustomOption = $this->parseOption('yourCustomOption');
343
344 ``parseOption()`` is looking for 'yourCustomOption' in your
345 ``form definition``. If it cannot be found, the method checks
346
347 1. the ``prototype`` configuration for a default value,
348
349 2. the finisher class itself by searching for a default value within the
350 ``$defaultOptions`` property::
351
352 declare(strict_types = 1);
353 namespace VENDOR\MySitePackage\Domain\Finishers;
354
355 class CustomFinisher extends \TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher
356 {
357
358 protected $defaultOptions = [
359 'yourCustomOption' => 'Olli',
360 ];
361
362 // ...
363 }
364
365 If the option cannot be found by processing this fallback chain, ``null`` is
366 returned.
367
368 If the option is found, the process checks whether the option value will
369 access :ref:`FormRuntime values<concepts-frontendrendering-codecomponents-customfinisherimplementations-accessingoptions-formruntimeaccessor>`.
370 If the ``FormRuntime`` returns a positive result, it is checked whether the
371 option value :ref:`can access values of preceding finishers<concepts-frontendrendering-codecomponents-customfinisherimplementations-finishercontext-sharedatabetweenfinishers>`.
372 At the very end, it tries to :ref:`translate the finisher options<concepts-frontendrendering-translation-finishers>`.
373
374
375 .. _concepts-frontendrendering-codecomponents-customfinisherimplementations-accessingoptions-formruntimeaccessor:
376
377 Accessing form runtime values
378 '''''''''''''''''''''''''''''
379
380 By utilizing a specific notation, finisher options can be populated with
381 submitted form values (assuming you are using the ``parseOption()`` method).
382 You can access values of the ``FormRuntime`` and thus values of each single
383 form element by encapsulating the option values with ``{}``. If there is a
384 form element with the ``identifier`` 'subject', you can access its value
385 within the the finisher configuration. Check out the following example to
386 get the whole idea.
387
388 .. code-block:: yaml
389
390 identifier: simple-contact-form
391 label: 'Simple Contact Form'
392 prototype: standard
393 type: Form
394
395 finishers:
396 -
397 identifier: Custom
398 options:
399 yourCustomOption: '{subject}'
400
401 renderables:
402 -
403 identifier: subject
404 label: 'Subject'
405 type: Text
406
407 ::
408
409 // $yourCustomOption contains the value of the form element with the
410 // identifier 'subject'
411 $yourCustomOption = $this->parseOption('yourCustomOption');
412
413 In addition, you can use ``{__currentTimestamp}`` as a special option value.
414 It will return the current UNIX timestamp.
415
416
417 .. _concepts-frontendrendering-codecomponents-customfinisherimplementations-finishercontext:
418
419 Finisher Context
420 """"""""""""""""
421
422 The class ``TYPO3\CMS\Form\Domain\Finishers\FinisherContext`` takes care of
423 transferring a finisher context to each finisher. Given the finisher is
424 derived from ``TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher`` the
425 finisher context will be available via::
426
427 $this->finisherContext
428
429 The method ``cancel`` prevents the execution of successive finishers::
430
431 $this->finisherContext->cancel();
432
433 The method ``getFormValues`` returns all of the submitted form values.
434
435 ``getFormValues``::
436
437 $this->finisherContext->getFormValues();
438
439 The method ``getFormRuntime`` returns the ``FormRuntime``::
440
441 $this->finisherContext->getFormRuntime();
442
443
444 .. _concepts-frontendrendering-codecomponents-customfinisherimplementations-finishercontext-sharedatabetweenfinishers:
445
446 Share data between finishers
447 ''''''''''''''''''''''''''''
448
449 The method ``getFinisherVariableProvider`` returns an object (``TYPO3\CMS\Form\Domain\Finishers\FinisherVariableProvider``)
450 which allows you to store data and transfer it to other finishers. The data
451 can be easily accessed programmatically or within your configuration::
452
453 $this->finisherContext->getFinisherVariableProvider();
454
455 The data is stored within the ``FinisherVariableProvider`` and is addressed
456 by a user-defined 'finisher identifier' and a custom option value path. The
457 name of the 'finisher identifier' should consist of the name of the finisher
458 without the potential 'Finisher' appendix. If your finisher is derived from
459 the class ``TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher``, the name of
460 this construct is stored in the following variable::
461
462 $this->shortFinisherIdentifier
463
464 For example, if the name of your finisher class is 'CustomFinisher', the
465 mentioned variable will contain the value 'Custom'.
466
467 There are a bunch of methods to access and manage the finisher data:
468
469 - Add data::
470
471 $this->finisherContext->getFinisherVariableProvider()->add(
472 $this->shortFinisherIdentifier,
473 'unique.value.identifier',
474 $value
475 );
476
477 - Get data::
478
479 $this->finisherContext->getFinisherVariableProvider()->get(
480 $this->shortFinisherIdentifier,
481 'unique.value.identifier',
482 'default value'
483 );
484
485 - Check the existence of data::
486
487 $this->finisherContext->getFinisherVariableProvider()->exists(
488 $this->shortFinisherIdentifier,
489 'unique.value.identifier'
490 );
491
492 - Delete data::
493
494 $this->finisherContext->getFinisherVariableProvider()->remove(
495 $this->shortFinisherIdentifier,
496 'unique.value.identifier'
497 );
498
499 In this way, each finisher can access data programmatically. Moreover, it is
500 possible to retrieve the data via configuration, provided that a finisher
501 stores the values within the ``FinisherVariableProvider``.
502
503 Assuming that a finisher called 'Custom' sets data as follows::
504
505 $this->finisherContext->getFinisherVariableProvider()->add(
506 $this->shortFinisherIdentifier,
507 'unique.value.identifier',
508 'Wouter'
509 );
510
511 ... you are now able to access the value 'Wouter' via ``{Custom.unique.value.identifier}``
512 in any other finisher.
513
514 .. code-block:: yaml
515
516 identifier: sample-form
517 label: 'Simple Contact Form'
518 prototype: standard
519 type: Form
520
521 finishers:
522 -
523 identifier: Custom
524 options:
525 yourCustomOption: 'Frans'
526
527 -
528 identifier: SomeOtherStuff
529 options:
530 someOtherCustomOption: '{Custom.unique.value.identifier}'
531
532
533 .. _concepts-frontendrendering-codecomponents-customvalidatorimplementations:
534
535 Custom validator implementations
536 --------------------------------
537
538 Validators belong to a certain ``prototype`` and are defined within the
539 ``validatorsDefinition``. The property ``implementationClassName`` is used
540 for the validator implementation.
541
542 .. code-block:: yaml
543
544 TYPO3:
545 CMS:
546 Form:
547 prototypes:
548 standard:
549 validatorsDefinition:
550 Custom:
551 implementationClassName: 'VENDOR\MySitePackage\Domain\Validation\CustomValidator'
552
553 You can provide options for your validator using the property ``options``.
554 Those will be used as default values which can be overridden within a
555 specific ``form definition``.
556
557 Define the default value of the option ``yourCustomOption``:
558
559 .. code-block:: yaml
560
561 TYPO3:
562 CMS:
563 Form:
564 prototypes:
565 standard:
566 validatorsDefinition:
567 Custom:
568 implementationClassName: 'VENDOR\MySitePackage\Domain\Validation\CustomValidator'
569 options:
570 yourCustomOption: 'Jurian'
571
572 Override the default value within your ``form definition``:
573
574 .. code-block:: yaml
575
576 identifier: sample-form
577 label: 'Simple Contact Form'
578 prototype: standard
579 type: Form
580
581 renderables:
582 -
583 identifier: subject
584 label: 'Name'
585 type: Text
586 validators:
587 -
588 identifier: Custom
589 options:
590 yourCustomOption: 'Mathias'
591
592 EXT:form implements Extbase validators. That said, your own validators should
593 extend ``TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator``.
594
595
596 .. _concepts-frontendrendering-renderviewHelper:
597
598 "render" viewHelper
599 ===================
600
601 The ``RenderViewHelper`` is the actual starting point for form rendering and
602 not the typical Extbase Controller as you may know it.
603
604 For more technical insights read more about the viewHelper's :ref:`arguments<apireference-frontendrendering-renderviewHelper-arguments>`.
605
606
607 .. _concepts-frontendrendering-fluidtemplate:
608
609 Render through FLUIDTEMPLATE (without controller)
610 -------------------------------------------------
611
612 .. code-block:: typoscript
613
614 tt_content.custom_content_element = COA_INT
615 tt_content.custom_content_element {
616 10 = < lib.stdheader
617 20 = FLUIDTEMPLATE
618 20 {
619 file = EXT:my_site_package/Resources/Private/Templates/CustomContentElement.html
620 settings {
621 persistenceIdentifier = EXT:my_site_package/Resources/Private/Forms/MyForm.yaml
622 }
623 extbase.pluginName = Form
624 extbase.controllerExtensionName = Formframework
625 extbase.controllerName = FormFrontend
626 extbase.controllerActionName = perform
627 }
628 }
629
630 ``my_site_package/Resources/Private/Templates/CustomContentElement.html``:
631
632 .. code-block:: html
633
634 <formvh:render persistenceIdentifier="{settings.persistenceIdentifier}" />
635
636
637 .. _concepts-frontendrendering-extbase:
638
639 Render within your own Extbase extension
640 ----------------------------------------
641
642 It is straight forward. Use the ``RenderViewHelper`` like this and you are
643 done:
644
645 .. code-block:: html
646
647 <formvh:render persistenceIdentifier="EXT:my_site_package/Resources/Private/Forms/MyForm.yaml"/>
648
649 Point the property ``controllerAction`` to the desired action name and
650 provide values for the other parameters displayed below (you might need
651 those).
652
653 .. code-block:: yaml
654
655 type: Form
656 identifier: 'example-form'
657 label: 'TYPO3 is cool'
658 prototypeName: standard
659 renderingOptions:
660 controllerAction: perform
661 addQueryString: false
662 argumentsToBeExcludedFromQueryString: []
663 additionalParams: []
664
665 renderables:
666 ...
667
668
669 .. _concepts-frontendrendering-programmatically:
670
671 Build forms programmatically
672 ============================
673
674 To learn more about this topic, head to the chapter ':ref:`Build forms programmatically<apireference-frontendrendering-programmatically>`'
675 which is part of the API reference section.
676
677
678 .. _concepts-frontendrendering-runtimemanipulation:
679
680 Runtime manipulation
681 ====================
682
683
684 .. _concepts-frontendrendering-runtimemanipulation-hooks:
685
686 Hooks
687 -----
688
689 EXT:form implements a decent amount of hooks that allow the manipulation of
690 your forms during runtime. In this way, it is possible to, for example,
691
692 - ... prefill form elements with values from your database,
693 - ... skip a whole page based on the value of a certain form element,
694 - ... mark a form element as mandatory depending of the chosen value of another
695 form element.
696
697 Please check out the ':ref:`API reference section<apireference-frontendrendering-runtimemanipulation-hooks>`'
698 for more details.
699
700
701 .. _concepts-frontendrendering-runtimemanipulation-typoscriptoverrides:
702
703 TypoScript overrides
704 --------------------
705
706 Each and every ``form definition`` can be overridden via TypoScript if the
707 ``FormFrontendController`` of EXT:form is used to render the form. Normally,
708 this is the case if the form has been added to the page using the form
709 plugin or when rendering the form via :ref:`FLUIDTEMPLATE <concepts-frontendrendering-fluidtemplate>`.
710
711 The overriding of settings with TypoScript's help takes place after the :ref:`custom finisher settings<concepts-formplugin>`
712 of the form plugin have been loaded. In this way, you are able to manipulate
713 the ``form definition`` for a single page. In doing so, the altered
714 ``form definition`` is passed to the ``RenderViewHelper`` which then
715 generates the form programmatically. At this point, you can still change the
716 form elements using the above-mentioned concept of :ref:`hooks<concepts-frontendrendering-runtimemanipulation-hooks>`.
717
718 .. code-block:: typoscript
719
720 plugin.tx_form {
721 settings {
722 formDefinitionOverrides {
723 <formDefinitionIdentifier> {
724 renderables {
725 0 {
726 renderables {
727 0 {
728 label = TEXT
729 label.value = Overridden label
730 }
731 }
732 }
733 }
734 }
735 }
736 }
737 }
738
739
740 .. _concepts-frontendrendering-templates:
741
742 Templates
743 =========
744
745 The Fluid templates of the form framework are based on Twitter Bootstrap.
746
747
748 .. _concepts-frontendrendering-templates-customtemplates:
749
750 Custom templates
751 ----------------
752
753 If you want to use custom Fluid templates for the frontend output of the
754 form elements, you cannot register an additional template path using
755 TypoScript. Instead, the registration of new template paths has to be done
756 via YAML. The settings are part of the ``prototypes`` configuration.
757
758 .. code-block:: yaml
759
760 TYPO3:
761 CMS:
762 Form:
763 prototypes:
764 standard:
765 formElementsDefinition:
766 Form:
767 renderingOptions:
768 templateRootPaths:
769 100: 'EXT:my_site_package/Resources/Private/Frontend/Templates/'
770 partialRootPaths:
771 100: 'EXT:my_site_package/Resources/Private/Frontend/Partials/'
772 layoutRootPaths:
773 100: 'EXT:my_site_package/Resources/Private/Frontend/Layouts/'
774
775 For each ``form definition`` - which references the prototype ``standard`` -
776 the form framework will additionally look for Fluid templates within the
777 path 'EXT:my_site_package/Resources/Private/Frontend/[*]' as set above.
778 Apart from the 'Form' element, the process will search for templates within
779 the ``partialRootPaths`` folder. The name of the partial is derived from the
780 property ``formElementTypeIdentifier``. For example, the template of the
781 form element ``Text`` must be stored within the ``partialRootPaths`` folder
782 named ``Text.html``. In contrast, the template of the ``Form`` element must
783 reside within the ``templateRootPaths`` folder. According to the introduced
784 logic, the template name must be ``Form.html``.
785
786
787 .. _concepts-frontendrendering-translation:
788
789 Translation
790 ===========
791
792
793 .. _concepts-frontendrendering-translation-formdefinition:
794
795 Translate form definition
796 -------------------------
797
798 The translation of ``form definitions`` works differently to the translation
799 of the backend aspects. Currently, there is no graphical user interface
800 supporting the translation process.
801
802 If the backend editor needed to translate the ``form definition`` properties
803 in the same way the backend aspects are translated, he/ she would see long
804 and unwieldy translation keys while editing a form within the ``form editor``.
805 In order to avoid this, rather the element properties are translated than
806 their values. Thus, the form framework does not look for translation keys
807 within the translation file. Instead, the system searches for translations
808 of the form element properties independent of their property values. The
809 property values are ignored if the process finds a proper entry within the
810 translation file. As a result, the property values are overridden by the
811 translated value.
812
813 This approach is a compromise between two scenarios: the exclusive usage of
814 the ``form editor`` and/ or the manual creation of ``form definitions``
815 which can afterwards (theoretically) be edited with the ``form editor``. In
816 addition, the described compromise allows the editor to create forms in the
817 default language whose form element property values are displayed as
818 specified in the ``form editor``. Based on this, an integrator could provide
819 additional language files which automatically translate the specific form.
820
821 Additional translation files can be defined as follows:
822
823 .. code-block:: yaml
824
825 TYPO3:
826 CMS:
827 Form:
828 prototypes:
829 standard:
830 formElementsDefinition:
831 Form:
832 renderingOptions:
833 translation:
834 translationFile:
835 # translation files for the frontend
836 10: 'EXT:form/Resources/Private/Language/locallang.xlf'
837 20: 'EXT:my_site_package/Resources/Private/Language/locallang.xlf'
838
839 Due to compatibility issues, the setting ``translationFile`` is not defined
840 as an array in the default configuration. To load your own translation files,
841 you should define an array containing 'EXT:form/Resources/Private/Language/locallang.xlf'
842 as first entry (key ``10``) followed by your own file (key ``20``) as
843 displayed in the example above. The array is processed from the highest key
844 to the lowest, i.e. your translation file with the key ``20`` is processed
845 first. If the look-up process does not find a key within all of the provided
846 files, the property value will be displayed unmodified.
847
848 The following properties can be translated:
849
850 - label
851 - properties.[*]
852 - properties.options.[*]
853 - properties.fluidAdditionalAttributes.[*]
854 - renderingOptions.[*]
855
856 The translation keys are put together based on a specific pattern. In
857 addition, a fallback chain that depends on the form element identifiers
858 exists. As a result, the following translation scenarios are possible:
859
860 - translation of a form element property for a specific form and form
861 element
862 - translation of a form element property for a specific form element and
863 various forms
864 - translation of a form element property for an element type and various
865 forms, e.g. the ``Page`` element
866
867 The look-up process searches for translation keys in all given translation
868 files based on the following order:
869
870 - ``<formDefinitionIdentifier>.element.<elementIdentifier>.properties.<propertyName>``
871 - ``element.<formElementIdentifier>.properties.<propertyName>``
872 - ``element.<elementType>.properties.<propertyName>``
873
874 Form elements with option properties (``properties.options``), like the
875 ``Select`` element, feature the following look-up process:
876
877 - ``<formDefinitionIdentifier>.element.<elementIdentifier>.properties.options.<propertyValue>``
878 - ``element.<elementIdentifier>.properties.options.<propertyValue>``
879
880
881 Example
882 """""""
883
884 .. code-block:: yaml
885
886 identifier: ApplicationForm
887 type: Form
888 prototypeName: standard
889 label: 'Application form'
890
891 renderables:
892 -
893 identifier: GeneralInformation
894 type: Page
895 label: 'General information'
896
897 renderables:
898 -
899 identifier: LastName
900 type: Text
901 label: 'Last name'
902 properties:
903 placeholder: 'Please enter your last name.'
904 defaultValue: ''
905 -
906 identifier: Software
907 type: MultiSelect
908 label: 'Known software'
909 properties:
910 options:
911 value1: TYPO3
912 value2: Neos
913
914 For the form element ``LastName``, the process will look for the following
915 translation keys within the translation files:
916
917 - ``ApplicationForm.element.LastName.properties.label``
918 - ``element.LastName.properties.label``
919 - ``element.Text.properties.label``
920
921 If none of the above-mentioned keys exist, 'Last name' will be displayed.
922
923 For the form element ``Software``, the process will look for the following
924 translation keys within the translation files:
925
926 - ``ApplicationForm.element.Software.properties.label``
927 - ``element.Software.properties.label``
928 - ``element.MultiSelect.properties.label``
929
930 If none of the above-mentioned keys exist, 'Known software' will be
931 displayed. The option properties are addressed as follows:
932
933 - ``ApplicationForm.element.Software.properties.options.value1``
934 - ``element.Software.properties.options.value1``
935 - ``ApplicationForm.element.Software.properties.options.value2``
936 - ``element.Software.properties.options.value2``
937
938 If none of the above-mentioned keys exist, 'TYPO3' will be displayed as
939 label for the first option and 'Neos' as label for the second option.
940
941
942 .. _concepts-frontendrendering-translation-validationerrors:
943
944 Translation of validation messages
945 ----------------------------------
946
947 The translation of validation messages is similar to the translation of
948 ``form definitions``. The same translation files can be used. If the look-up
949 process does not find a key within the provided files, the appropriate
950 message of the Extbase framework will be displayed. EXT:form already
951 translates all of those validators by default.
952
953 As mentioned above, the translation keys are put together based on a
954 specific pattern. Furthermore, the fallback chain exists here as well. Thus,
955 the following translation scenarios are possible:
956
957 - translation of validation messages for a specific validator of a concrete
958 form element and concrete form
959 - translation of validation messages for a specific validator of various
960 form elements within a concrete form
961 - translation of validation messages for a specific validator of a concrete
962 form element in various forms
963 - translation of validation messages for a specific validator within various
964 forms
965
966 In Extbase, the validation messages are identified with the help of
967 numerical codes (UNIX timestamps). For the same validator, different codes
968 are valid. Read more about :ref:`concrete validator configurations <typo3.cms.form.prototypes.\<prototypeidentifier>.validatorsdefinition.\<validatoridentifier>-concreteconfigurations>`.
969
970 The look-up process searches for translation keys in all given translation
971 files based on the following order:
972
973 - ``<formDefinitionIdentifier>.validation.error.<elementIdentifier>.<validationErrorCode>``
974 - ``<formDefinitionIdentifier>.validation.error.<validationErrorCode>``
975 - ``validation.error.<elementIdentifier>.<validationErrorCode>``
976 - ``validation.error.<validationErrorCode>``
977
978
979 Example
980 """""""
981
982 .. code-block:: yaml
983
984 identifier: ContactForm
985 type: Form
986 prototypeName: standard
987 label: 'Contact us'
988
989 renderables:
990 -
991 identifier: Page1
992 type: Page
993 label: 'Page 1'
994
995 renderables:
996 -
997 identifier: LastName
998 type: Text
999 label: 'Last name'
1000 properties:
1001 fluidAdditionalAttributes:
1002 required: required
1003 validators:
1004 -
1005 identifier: NotEmpty
1006
1007 Amongst others, the ``NotEmpty`` validator sends 1221560910 as ``<validationErrorCode>``.
1008 If a user submits this form without providing a value for the field "Last
1009 name", the ``NotEmpty`` validator fails. Now, the look-up process searches
1010 for the following translation keys for the ``NotEmpty`` validator combined
1011 with the form element ``LastName``:
1012
1013 - ContactForm.validation.error.LastName.1221560910
1014 - ContactForm.validation.error.1221560910
1015 - validation.error.LastName.1221560910
1016 - validation.error.1221560910
1017
1018 As mentioned above, if there is no corresponding translation key available,
1019 the default message of the Extbase framework will be shown.
1020
1021
1022 .. _concepts-frontendrendering-translation-finishers:
1023
1024 Translation of finisher options
1025 -------------------------------
1026
1027 The translation of finisher options is similar to the translation of
1028 ``form definitions``. The same translation files can be used. If the look-up
1029 process does not find a key within all provided files, the property value
1030 will be displayed unmodified.
1031
1032 As mentioned above, the translation keys are put together based on a
1033 specific pattern. Furthermore, the fallback chain exists here as well. Thus,
1034 the following translation scenarios are possible:
1035
1036 - translation of finisher options for a specific finisher of a concrete form
1037 - translation of finisher options for a specific finisher of various forms
1038
1039 The look-up process searches for translation keys in all given translation
1040 files based on the following order:
1041
1042 - ``<formDefinitionIdentifier>.finisher.<finisherIdentifier>.<optionName>``
1043 - ``finisher.<finisherIdentifier>.<optionName>``
1044
1045
1046 Example
1047 """""""
1048
1049 .. code-block:: yaml
1050
1051 identifier: ContactForm
1052 type: Form
1053 prototypeName: standard
1054 label: 'Contact us'
1055
1056 finishers:
1057 -
1058 identifier: Confirmation
1059 options:
1060 message: 'Thank you for your inquiry.'
1061
1062 renderables:
1063 ...
1064
1065 The look-up process searches for the following translation keys for the
1066 ``<finisherIdentifier>`` 'Confirmation' and the option 'message':
1067
1068 - ``ContactForm.finisher.Confirmation.message``
1069 - ``finisher.Confirmation.message``
1070
1071 If no translation key exists, the message 'Thank you for your inquiry.' will
1072 be shown.
1073
1074
1075 .. _concepts-frontendrendering-translation-arguments:
1076
1077 Form element translation arguments are supported
1078 ================================================
1079
1080 Form element property translations and finisher option translations can use
1081 placeholders to output translation arguments. Translations can be enriched
1082 with variable values by passing arguments to form element properties. The
1083 feature was introduced with :issue:`81363`.
1084
1085
1086 Form element properties
1087 -----------------------
1088
1089 Pure YAML is sufficient to add simple, static values:
1090
1091 .. code-block:: yaml
1092
1093 renderables:
1094 fieldWithTranslationArguments:
1095 identifier: field-with-translation-arguments
1096 type: Checkbox
1097 label: This is a %s feature
1098 renderingOptions:
1099 translation:
1100 translationFile: path/to/locallang.xlf
1101 arguments:
1102 label:
1103 - useful
1104
1105 This will produce the label: `This is a useful feature`.
1106
1107 Alternatively, translation arguments can be set via
1108 :ts:`formDefinitionOverrides` in TypoScript. A common usecase is a checkbox for
1109 user confirmation linking to details of the topic:
1110
1111 .. code-block:: yaml
1112
1113 renderables:
1114 fieldWithTranslationArguments:
1115 identifier: field-with-translation-arguments
1116 type: Checkbox
1117 label: I agree to the <a href="%s">terms and conditions</a>
1118 renderingOptions:
1119 translation:
1120 translationFile: path/to/locallang.xlf
1121
1122 .. code-block:: typoscript
1123
1124 plugin.tx_form {
1125 settings {
1126 formDefinitionOverrides {
1127 <form-id> {
1128 renderables {
1129 0 {
1130 # Page
1131 renderables {
1132 fieldWithTranslationArguments {
1133 renderingOptions {
1134 translation {
1135 arguments {
1136 label {
1137 0 = TEXT
1138 0.typolink {
1139 # Terms and conditions page, could be
1140 # set also via TypoScript constants
1141 parameter = 42
1142 returnLast = url
1143 }
1144 }
1145 }
1146 }
1147 }
1148 }
1149 }
1150 }
1151 }
1152 }
1153 }
1154 }
1155 }
1156 }
1157 }
1158 }
1159 }
1160
1161 .. important::
1162
1163 There must be at least one translation file with a translation for the
1164 configured form element property. Arguments are not inserted into default
1165 values defined in a form definition.
1166
1167
1168 Finishers
1169 ---------
1170
1171 The same mechanism (YAML, YAML + TypoScript) works for finisher options:
1172
1173 .. code-block:: yaml
1174
1175 finishers:
1176 finisherWithTranslationArguments:
1177 identifier: EmailToReceiver
1178 options:
1179 subject: My %s subject
1180 recipientAddress: foo@example.org
1181 senderAddress: bar@example.org
1182 translation:
1183 translationFile: path/to/locallang.xlf
1184 arguments:
1185 subject:
1186 - awesome
1187
1188 This will produce `My awesome subject`.