In TYPO3 9, the TYPO3 contact form system "Form Framework" (EXT:form) already contains 22 element types that can be used when creating forms. A dropdown element, where the user can select his country from a country list in the form, is unfortunately not included, although this is certainly a requirement in many projects. Therefore we followed the article "How to create TYPO3 Form select element with options selected from database" by Daniel Siepmann and developed a new form element that now offers this possibility.
Requirements
Für das folgende Beispiel basiert auf TYPO3 9 und man benötigt eine Extension, die wir im Folgenden mit EXT:extension bezeichnen. Diese kann die Extension sein, die ihr ohnehin schon im System für euer Templating als Provider Extension habt. Zusätzlich wird mindestens die Extension EXT:static_info_tables benötigt als Datenquelle für die Länder der Welt. Zusätzlich machen weitere Extensions wie EXT:static_info_tables_de, EXT:static_info_tables_es, usw. Sinn, wenn man die Ländernamen auch in anderen Sprachen als englisch haben möchte.
The php class
For a new form element in EXT:form you need a php class which mainly takes care of filling the dropdown options with data. In our example this class is located in EXT:extension/Classes/FormElements/CountryOptions.php
<?php
namespace Vendor\Extension\FormElements;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement;
use TYPO3\CMS\Frontend\Category\Collection\CategoryCollection;
class CountryOptions extends GenericFormElement
{
protected $valueField = '';
protected $labelField = '';
public function setProperty(string $key, $value)
{
// see form element config for the static country column to be used for the select option value
if ($key === 'valueField') {
$this->valueField = $value;
}
// see form element config for the static country column to be used for the select option label
if ($key === 'labelField') {
$this->labelField = $value;
$this->setProperty('options', $this->getOptions($this->valueField, $this->labelField));
return;
}
parent::setProperty($key, $value);
}
protected function getOptions(string $valueField, string $labelField = 'cn_short_en') : array
{
$options = [];
foreach ($this->getCountries($uid) as $country) {
$label = $country[$labelField];
// dynamic label field generation based on current language isocode if marker {currentLanguage} is present
if (strstr($labelField, '{currentLanguage}') !== false) {
$siteLanguage = $GLOBALS['TYPO3_REQUEST']->getAttribute('language')->getTwoLetterIsoCode();
if (isset($country[str_replace('{currentLanguage}', $siteLanguage, $labelField)]) && $country[str_replace('{currentLanguage}', $siteLanguage, $labelField)]) {
$label = $country[str_replace('{currentLanguage}', $siteLanguage, $labelField)];
}
}
$options[$country[$valueField]] = $label;
}
asort($options);
return $options;
}
protected function getCountries() : array
{
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) ->getQueryBuilderForTable('static_countries');
$queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
return $queryBuilder->select('*')->from('static_countries')->execute()->fetchAll();
}
}
The element definition
Then the element must be registered in the Form Framework using the following YAML code. This code can be written in EXT:extension/Configuration/Form/Frontend.yaml:
TYPO3:
CMS:
Form:
prototypes:
standard:
formElementsDefinition:
SingleSelectWithCountries:
__inheritances:
10: 'TYPO3.CMS.Form.prototypes.standard.formElementsDefinition.SingleSelect'
implementationClassName: 'Vendor\Extension\FormElements\CountryOptions'
renderingOptions:
templateName: 'SingleSelect'
With the following Typoscript this YAML configuration is then registered with the form framework:
plugin.tx_form {
settings {
yamlConfigurations {
1490817689 = EXT:extension/Configuration/Form/Frontend.yaml
}
}
}
Use of the element
The element itself can be used in a form with the following YAML code. This element is not yet available for editors in the form editor's creation assistant in the backend. You would have to write more code for it.
With the configuration option "valueField" you can define the column of the static_countries table (this table is part of the extension EXT:static_info_tables), which should be used for the value to be transferred. In the following example this is the English country name.
With the configuration option "labelField" you can define the column of the static_countries table that should be used for the value to be displayed. Here we have developed a little special feature, namely the placeholder "{currentLanguage}", which is then automatically filled with "de", "es", etc. in the above php class based on the current language of the frontend. For this purpose, the other extensions like EXT:static_info_tables_de, EXT:static_info_tables_es, etc. are needed for each language of the website. But you can also simply use a fixed value instead of this marker.
...
-
properties:
fluidAdditionalAttributes:
required: required
valueField: cn_short_en
labelField: 'cn_short_{currentLanguage}'
prependOptionLabel: 'please choose'
defaultValue: ''
type: SingleSelectWithCountries
identifier: country
label: Country
validators:
-
identifier: NotEmpty
...