Breaking: #97330 - FormEngine element classes must create label or legend¶
See forge#97330
Description¶
When editing records in the Backend, the "FormEngine" class structure located
within EXT:backend/Classes/Form
handles generation of the editing view.
A change has been applied related to the rendering of single field labels, which is no longer done automatically by "container" classes: Single elements have to create the label themselves.
Extension that add own elements to FormEngine must be adapted, otherwise the element label is no longer rendered.
Impact¶
When the required changes are not applied to custom FormEngine element classes, the value of the TCA "label" property is not rendered.
Affected installations¶
Instances with custom FormEngine elements are affected. Custom elements need to be
registered to the FormEngine NodeFactory
, candidates are found by looking at
the $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']
array (for instance
using the EXT:lowlevel
"Configuration" module). Classes registered using the
sub keys keys nodeRegistry
and nodeResolver
may be affected. The
extension scanner does not find affected classes.
Migration¶
Custom elements must create take care of creating a <label>
or <legend>
tag on their own: If the element creates a input
, or select
tag,
the <label>
should have a for
attribute that points to a field having
an id
attribute. This is important especially for accessibility. When no such
target element exists, a <legend>
embedded in a <fieldset>
can be used.
There are two helper methods in AbstractFormElement
to help with this:
renderLabel()
and wrapWithFieldsetAndLegend()
.
In practice, an element having a input
, or select
field should
essentially look like this:
$resultArray = $this->initializeResultArray();
// Next line is only needed for extensions that need to keep TYPO3 v12 compatibility
$resultArray['labelHasBeenHandled'] = true;
$fieldId = StringUtility::getUniqueId('formengine-input-');
$html = [];
$html[] = $this->renderLabel($fieldId);
$html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
$html[] = '<div class="form-wizards-wrap">';
$html[] = '<div class="form-wizards-element">';
$html[] = '<div class="form-control-wrap">';
$html[] = '<input class="form-control" id="' . htmlspecialchars($fieldId) . '" value="..." type="text">';
$html[] = '</div>';
$html[] = '</div>';
$html[] = '</div>';
$html[] = '</div>';
$resultArray['html'] = implode(LF, $html);
return $resultArray;
The renderLabel()
is a helper method to generate a label
tag with a
for
attribute, and the same fieldId is used as id
attribute in the
input
field to connect label
and input
with each other.
If there is no such field, a legend
tag should be used:
$resultArray = $this->initializeResultArray();
// Next line is only needed for extensions that need to keep TYPO3 v12 compatibility
$resultArray['labelHasBeenHandled'] = true;
$html = [];
$html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
$html[] = '<div class="form-wizards-wrap">';
$html[] = '<div class="form-wizards-element">';
$html[] = '<div class="form-control-wrap">';
$html[] = Some custom element html
$html[] = '</div>';
$html[] = '</div>';
$html[] = '</div>';
$html[] = '</div>';
$resultArray['html'] = $this->wrapWithFieldsetAndLegend(implode(LF, $html));
return $resultArray;