Custom inputs (user) 

Table of contents:

Introduction 

There are three columns config types that do similar things, but still have subtle differences between them. These are the none type, the passthrough type and the user type.

Characteristics of user:

  • A value sent to the DataHandler is just kept as is and put into the database field. Default FormEngine however never sends values.
  • Unlike none, the type user must have a database field.
  • FormEngine only renders a dummy element for type user fields by default. It should be combined with a custom renderType.
  • Type user field values are rendered as-is at other places in the backend. They for instance can be selected to be displayed in the Content > Records module "single table view".
  • Field updates by the DataHandler get logged and the history/undo function will work with such values.

The user field can be useful, if:

  • A special rendering and evaluation is needed for a value when editing records via FormEngine.

Examples 

A frontend user can have a name of their own for the badge of a conference. The field shows a preview of the badge.

The example registers an own node element, a TCA field using it and a class implementing a rendering. See FormEngine docs for more details on this.

  1. Verify Extension Compatibility with Dependency Injection (DI)

    Changed in version 13.0

    Make sure your extension contains a Configuration/Services.yaml file with the minimal configuration. For the minimal content, see the section about Services.yaml declaring service defaults in the TYPO3 documentation.

  2. Register the new renderType node element

    Add to ext_localconf.php:

    EXT:my_extension/ext_localconf.php
    <?php
    
    use MyVendor\MyExtension\Controller\ConferenceController;
    use MyVendor\MyExtension\Evaluation\AbstractEvaluation;
    use MyVendor\MyExtension\Evaluation\HashtagEvaluation;
    use MyVendor\MyExtension\Form\Element\BadgeNameElement;
    use MyVendor\MyExtension\Form\FieldInformation\InformationText;
    use MyVendor\MyExtension\Form\FieldInformation\TalkOrderInformation;
    use MyVendor\MyExtension\Form\FieldWizard\ReferencesToThisRecordWizard;
    use TYPO3\CMS\Core\PasswordPolicy\Generator\PasswordGenerator;
    use TYPO3\CMS\Extbase\Utility\ExtensionUtility;
    
    defined('TYPO3') or die();
    
    ExtensionUtility::configurePlugin(
      'MyExtension',
      'ConferenceList',
      [ConferenceController::class => ['list', 'show']],
    );
    
    // Classes that TCA fields name in 'eval'
    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][HashtagEvaluation::class] = '';
    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'][AbstractEvaluation::class] = '';
    
    // The information above the talks of a conference, see
    // Configuration/TCA/Overrides/120-tx_myextension_conference-talks.php
    $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1791234567] = [
      'nodeName' => 'talkOrderInformation',
      'priority' => 30,
      'class' => TalkOrderInformation::class,
    ];
    
    // The badge name of a frontend user, see
    // Configuration/TCA/Overrides/650-fe_users-tx_myextension_badge_name.php
    $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1791300000] = [
      'nodeName' => 'badgeName',
      'priority' => 40,
      'class' => BadgeNameElement::class,
    ];
    
    // The information text of fields, see for example
    // Configuration/TCA/Overrides/310-tx_myextension_speaker-email.php
    $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1791310000] = [
      'nodeName' => 'informationText',
      'priority' => 30,
      'class' => InformationText::class,
    ];
    
    // The references to a conference above its form, see
    // Configuration/TCA/Overrides/101-tx_myextension_conference-references.php
    $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1791320000] = [
      'nodeName' => 'referencesToThisRecord',
      'priority' => 30,
      'class' => ReferencesToThisRecordWizard::class,
    ];
    
    // The password policies of the password generators, see
    // Configuration/TCA/Overrides/445-tx_myextension_location-door_code.php and
    // Configuration/TCA/Overrides/345-tx_myextension_speaker-upload_token.php
    $GLOBALS['TYPO3_CONF_VARS']['SYS']['passwordPolicies']['myExtensionDigits'] = [
      'generator' => [
        'className' => PasswordGenerator::class,
        'options' => [
          'length' => 8,
          'lowerCaseCharacters' => false,
          'upperCaseCharacters' => false,
          'digitCharacters' => true,
        ],
      ],
      'validators' => [],
    ];
    $GLOBALS['TYPO3_CONF_VARS']['SYS']['passwordPolicies']['myExtensionBase64'] = [
      'generator' => [
        'className' => PasswordGenerator::class,
        'options' => [
          'length' => 35,
          'random' => 'base64',
        ],
      ],
      'validators' => [],
    ];
    
    Copied!
  3. Use the renderType in a TCA field definition

    Add the field to the TCA definition, here in an override of the table fe_users:

    EXT:my_extension/Configuration/TCA/Overrides/650-fe_users-tx_myextension_badge_name.php
    <?php
    
    use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
    
    defined('TYPO3') or die();
    
    // The name printed on the conference badge of a frontend user. The column
    // is defined in ext_tables.sql, as TYPO3 does not create it for type user.
    ExtensionManagementUtility::addTCAcolumns('fe_users', [
      'tx_myextension_badge_name' => [
        'label' => 'my_extension.db:fe_users.tx_myextension_badge_name',
        'config' => [
          'type' => 'user',
          // Registered in ext_localconf.php
          'renderType' => 'badgeName',
          'parameters' => [
            'color' => '#ff8700',
          ],
        ],
      ],
    ]);
    ExtensionManagementUtility::addToAllTCAtypes(
      'fe_users',
      'tx_myextension_badge_name',
      '',
      'after:name',
    );
    
    Copied!
  4. Define the database column

    TYPO3 does not create the column of a field of type user. Define it in the ext_tables.sql file:

    EXT:my_extension/ext_tables.sql
    -- The sorting of each side of a partnership. TYPO3 creates all other
    -- columns from the TCA.
    CREATE TABLE tx_myextension_partnership (
      conference_sorting int(11) unsigned DEFAULT '0' NOT NULL,
      partner_sorting int(11) unsigned DEFAULT '0' NOT NULL
    );
    
    -- TYPO3 does not create columns for fields of type user
    CREATE TABLE fe_users (
      tx_myextension_badge_name varchar(255) DEFAULT '' NOT NULL
    );
    
    -- TYPO3 does not create columns for fields of type none
    CREATE TABLE tx_myextension_talk (
      feedback_opened int(11) DEFAULT '0' NOT NULL,
      rating decimal(2,1) DEFAULT '0.0' NOT NULL,
      feedback_count int(11) unsigned DEFAULT '0' NOT NULL
    );
    
    Copied!
  5. Implement the FormElement class

    The renderType can be implemented by extending the class AbstractFormElement and overriding the function render() :

    EXT:my_extension/Classes/Form/Element/BadgeNameElement.php
    <?php
    
    declare(strict_types=1);
    
    namespace MyVendor\MyExtension\Form\Element;
    
    use TYPO3\CMS\Backend\Form\Element\AbstractFormElement;
    use TYPO3\CMS\Core\Utility\GeneralUtility;
    use TYPO3\CMS\Core\Utility\StringUtility;
    
    /**
     * An input for the name on the badge, with a preview of the badge
     */
    final class BadgeNameElement extends AbstractFormElement
    {
      public function render(): array
      {
        $parameterArray = $this->data['parameterArray'];
        $color = (string)($parameterArray['fieldConf']['config']['parameters']['color'] ?? '#ff8700');
        $value = (string)$parameterArray['itemFormElValue'];
        // Without a badge name, the badge shows the name of the frontend user
        $preview = $value !== '' ? $value : (string)($this->data['databaseRow']['name'] ?? '');
    
        $fieldInformationResult = $this->renderFieldInformation();
        $resultArray = $this->mergeChildReturnIntoExistingResult(
          $this->initializeResultArray(),
          $fieldInformationResult,
          false,
        );
    
        $fieldId = StringUtility::getUniqueId('formengine-input-');
        $attributes = [
          'id' => $fieldId,
          'type' => 'text',
          'value' => $value,
          'name' => $parameterArray['itemFormElName'],
          'data-formengine-input-name' => $parameterArray['itemFormElName'],
          'placeholder' => $preview,
          'class' => 'form-control',
        ];
    
        $html = [];
        $html[] = $this->renderLabel($fieldId);
        $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
        $html[] = $fieldInformationResult['html'];
        $html[] = '<div class="form-control-wrap">';
        $html[] = '<input ' . GeneralUtility::implodeAttributes($attributes, true) . ' />';
        $html[] = '</div>';
        $html[] = '<p class="mt-2"><span class="badge" style="background-color: ' . htmlspecialchars($color) . '">';
        $html[] = htmlspecialchars($preview);
        $html[] = '</span></p>';
        $html[] = '</div>';
        $resultArray['html'] = implode(LF, $html);
        return $resultArray;
      }
    }
    
    Copied!

    The label of a custom field does not get rendered automatically but must be rendered with $this->renderLabel($fieldId) or $this->wrapWithFieldsetAndLegend() .

    The array $this->data consists of the following parts:

    • The row of the currently edited record in $this->data['databaseRow']
    • The configuration from the TCA in $this->data['parameterArray']['fieldConf']['config']
    • The name of the input field in $this->data['parameterArray']['itemFormElName']
    • The current value of the field in $this->data['parameterArray']['itemFormElValue']

    In order for the field to work, it is vital, that the corresponding HTML input field has a unique id attribute, fills the attributes name and data-formengine-input-name with the correct name, as provided in the itemFormElName.

The field would then look like this in the backend:

The name on the badge of a frontend user, with a preview of the badge

The name on the badge of a frontend user, with a preview of the badge

Properties of the TCA column type user 

renderType
Type
integer
TCA path
$GLOBALS['TCA'][$table]['columns'][$field]['config']['renderType']
Scope
Display

The default renderType simply displays a dummy entry, indicating that a custom renderType should be added. Additional render types can be defined based on the requirements of the user type field. These render types determine how the field is displayed and interacted with in the TYPO3 backend, allowing for specialized rendering and user interaction. Custom render types provide a tailored experience for editing records via the FormEngine.