Breaking: #97330 - FormEngine element classes must create label or legend
See forge#97330
Description
When editing records in the backend, the Form
class structure located
within EXT:
handles the 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's Node
, candidates are found by looking at
the $GLOBALS
array (for instance
using the System > Configuration backend module provided by
EXT:lowlevel). Classes registered using the sub keys node
and
node
may be affected. The extension scanner does not find
affected classes.
Migration
Custom elements must take care of creating a <label>
or <legend>
tag on their own: If the element creates an <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
\TYPO3\
to help with this:
render
and wrap
.
In practice, an element having an <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 render
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;