En TYPO3 9, el propio sistema de formularios de contacto de TYPO3 "Form Framework" (EXT:form) ya contiene 22 tipos de elementos que se pueden utilizar al crear formularios. Sin embargo, un elemento desplegable que permite al usuario seleccionar su país de una lista de países en el formulario, lamentablemente no está incluido, aunque esto es sin duda un requisito en muchos proyectos. Por ello, nos hemos orientado en el artículo"How to create TYPO3 Form select element with options selected from database" de Daniel Siepmann y hemos desarrollado un nuevo elemento de formulario que ahora ofrece esta opción.
Requisitos
El siguiente ejemplo se basa en TYPO3 9 y 10 y requiere una extensión, a la que nos referiremos a continuación como EXT:extension. Esta puede ser la extensión que ya tiene en el sistema para sus plantillas como extensión de proveedor. Además, se requiere al menos la extensión EXT:static_info_tables como fuente de datos para los países del mundo. Extensiones adicionales como EXT:static_info_tables_en, EXT:static_info_tables_es, etc. tienen sentido si desea tener los nombres de los países en idiomas distintos del inglés.
La clase php
Para un nuevo elemento de formulario en EXT:form se necesita una clase php, que se encarga principalmente de rellenar las opciones desplegables con datos. En nuestro ejemplo, se encuentra en 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(cadena $clave, $valor)
{
// ver la configuración del elemento formulario para la columna estática de país que se usará para el valor de la opción select
if ($key === 'valueField') {
$this->valueField = $valor;
}
// ver la configuración del elemento del formulario para la columna estática del país que se utilizará para la etiqueta de la opción de selección
if ($key === 'labelField') {
$this->labelField = $valor;
$this->setProperty('opciones', $this->getOptions($this->valueField, $this->labelField));
devolver;
}
parent::setProperty($clave, $valor);
}
protected function getOptions(cadena $campo_valor, cadena $campo_etiqueta = 'cn_short_en') : array
{
$opciones = [];
foreach ($this->getCountries($uid) as $country) {
$label = $país[$labelField];
// generación dinámica del campo de etiqueta basada en el isocódigo del idioma actual si el marcador {currentLanguage} está presente
if (strstr($labelField, '{currentLanguage}') !== false) {
$siteLanguage = $GLOBALS['TYPO3_REQUEST']->getAttribute('language')->getTwoLetterIsoCode();
if (isset($country[str_replace('{currentLanguage}', $siteLanguage, $labelField)]) && $country[str_replace('{idiomaactual}', $idiomadelpágina, $labelField)]) {
$label = $country[str_replace('{idiomaactual}', $idiomadelpágina, $labelField)];
}
}
$options[$country[$valueField]] = $label;
}
asort($opciones);
return $opciones;
}
función protegida getCountries() : array
{
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) ->getQueryBuilderForTable('static_countries');
$queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
return $queryBuilder->select('*')->from('static_countries')->execute()->fetchAll();
}
}
La definición del elemento en el frontend
A continuación, el elemento debe registrarse en el marco del formulario utilizando el siguiente código YAML. Este código puede escribirse en EXT:extension/Configuration/Form/Frontend.yaml, por ejemplo:
TYPO3:
CMS:
Form:
prototypes:
standard:
formElementsDefinition:
SingleSelectWithCountries:
__herencias:
10: 'TYPO3.CMS.Form.prototypes.standard.formElementsDefinition.SingleSelect'
implementationClassName: 'Vendor\Extension\FormElements\CountryOptions'
renderingOptions:
templateName: 'SingleSelect'
Con el siguiente Typoscript, esta configuración YAML se registra en el framework de formularios:
plugin.tx_form {
configuración {
yamlConfigurations {
1490817689 = EXT:extension/Configuration/Form/Frontend.yaml
}
}
}
La definición del elemento en el backend
La siguiente parte es básicamente opcional. Esta parte sólo es relevante si desea ser capaz de editar el elemento en el editor de formularios en el CMS TYPO3, si desea una entrada en el asistente de creación, si desea definir un icono, etc. Este código puede ser escrito en EXT:extension/Configuration/Form/Backend.yaml, por ejemplo:
TYPO3:
CMS:
Form:
prototypes:
standard:
formEditor:
formEditorPartials:
FormElement-SingleSelectWithCountries: 'Stage/SimpleTemplate'
dynamicRequireJsModules:
additionalViewModelModules:
- 'TYPO3/CMS/Extension/Backend/FormEditor/SingleSelectWithCountriesViewModel'
formElementsDefinition:
SingleSelectWithCountries:
formEditor:
label: 'Países'
grupo: custom
groupSorting: 1000
iconIdentifier: form-single-select
editores:
100:
identificador: header
templateName: Inspector-FormElementHeaderEditor
200:
identificador: label
templateName: Inspector-EditorDeTexto
label: formEditor.elements.FormElement.editor.label.label
propertyPath: etiqueta
230:
identificador: elementDescription
templateName: Inspector-EditorDeTexto
label: formEditor.elements.FormElement.editor.elementDescription.label
propertyPath: propiedades.elementDescription
250:
identificador: inactiveOption
templateName: Inspector-EditorDeTexto
label: formEditor.elements.SelectionMixin.editor.inactiveOption.label
propertyPath: properties.prependOptionLabel
fieldExplanationText: formEditor.elements.SelectionMixin.editor.inactiveOption.fieldExplanationText
doNotSetIfPropertyValueIsEmpty: true
700:
identificador: gridColumnViewPortConfiguration
templateName: Inspector-GridColumnViewPortConfigurationEditor
label: formEditor.elements.FormElement.editor.gridColumnViewPortConfiguration.label
configurationOptions:
viewPorts:
10:
viewPortIdentifier: xs
label: formEditor.elements.FormElement.editor.gridColumnViewPortConfiguration.xs.label
20:
viewPortIdentifier: sm
label: formEditor.elements.FormElement.editor.gridColumnViewPortConfiguration.sm.label
30:
viewPortIdentifier: md
label: formEditor.elements.FormElement.editor.gridColumnViewPortConfiguration.md.label
40:
viewPortIdentifier: lg
label: formEditor.elements.FormElement.editor.gridColumnViewPortConfiguration.lg.label
numbersOfColumnsToUse:
label: formEditor.elements.FormElement.editor.gridColumnViewPortConfiguration.numbersOfColumnsToUse.label
propertyPath: 'properties.gridColumnClassAutoConfiguration.viewPorts.{@viewPortIdentifier}.numbersOfColumnsToUse'
fieldExplanationText: formEditor.elements.FormElement.editor.gridColumnViewPortConfiguration.numbersOfColumnsToUse.fieldExplanationText
800:
identificador: requiredValidator
templateName: Inspector-RequiredValidatorEditor
label: formEditor.elements.FormElement.editor.requiredValidator.label
validatorIdentifier: NotEmpty
propertyPath: properties.fluidAdditionalAttributes.required
propertyValue: requerido
configurationOptions:
validationErrorMessage:
label: formEditor.elements.FormElement.editor.requiredValidator.validationErrorMessage.label
propertyPath: properties.validationErrorMessages
fieldExplanationText: formEditor.elements.FormElement.editor.requiredValidator.validationErrorMessage.fieldExplanationText
errorCodes:
10: 1221560910
20: 1221560718
30: 1347992400
40: 1347992453
9999:
identificador: removeButton
templateName: Inspector-RemoveElementEditor
properties:
containerClassAttribute: input
elementClassAttribute: ''
elementErrorClassAttribute: error
A continuación, esta configuración YAML se registra en el framework de formularios mediante el siguiente Typoscript:
module.tx_form {
configuración {
yamlConfigurations {
1490817689 = EXT:extension/Configuration/Form/Backend.yaml
}
}
}
También hay actualmente una característica especial en TYPO3 versión 10. Para poder utilizar el elemento completamente en el editor de formularios y obtener una visualización correcta, todavía hay que crear un archivo JavaScript. Esperamos que este paso, que nos parece un poco inútil, se omita en futuras versiones de TYPO3. El archivo JavaScript debe tener el mismo nombre que el elemento y estar ubicado en la siguiente carpeta: EXT:extension/Resources/Public/JavaScript/Backend/FormEditor/SingleSelectWithCountriesViewModel.js. Este es el contenido:
define([
'jquery',
'TYPO3/CMS/Form/Backend/FormEditor/Helper'
], function ($, Helper) {
'use strict';
return (function ($, Helper) {
/**
* @privado
*
* @var objeto
*/
var _formEditorApp = null;
/**
* @private
*
* @return object
*/
function getFormEditorApp() {
return _formEditorApp;
};
/**
* @private
*
* @return object
*/
function getPublisherSubscriber() {
return getFormEditorApp().getPublisherSubscriber();
};
/**
* @private
*
* @return object
*/
function getUtility() {
return getFormEditorApp().getUtility();
};
/**
* @private
*
* @param object
* @return object
*/
function getHelper() {
devuelve Helper;
};
/**
* @private
*
* @return object
*/
function getCurrentlySelectedFormElement() {
return getFormEditorApp().getCurrentlySelectedFormElement();
};
/**
* @private
*
* @param mixed test
* @param string mensaje
* @param int messageCode
* @return void
*/
function assert(test, mensaje, mensajeCódigo) {
return getFormEditorApp().assert(test, mensaje, messageCode);
};
/**
* @private
*
* @return void
* @throws 1491643380
*/
function _helperSetup() {
assert('function' === $.type(Helper.bootstrap),
'El view model helper no implementa el método "bootstrap"',
1491643380
);
Helper.bootstrap(getFormEditorApp());
};
/**
* @private
*
* @return void
*/
function _subscribeEvents() {
/**
* @private
*
* @param string
* @param array
* args[0] = formElement
* args[1] = plantilla
* @return void
*/
getPublisherSubscriber().subscribe('view/stage/abstract/render/template/perform', function (topic, args) {
if (args[0].get('type') === 'SingleSelectWithCountries') {
getFormEditorApp().getViewModel().getStage().renderSimpleTemplateWithValidators(args[0], args[1]);
}
});
};
/**
* @public
*
* @param object formEditorApp
* @return void
*/
function bootstrap(formEditorApp) {
_formEditorApp = formEditorApp;
_helperSetup();
_subscribeEvents();
};
/**
* Publica los métodos públicos.
* Implementa el "Patrón de Módulo Revelador".
*/
return {
bootstrap: bootstrap
};
})($, Helper);
});
Uso del elemento
El elemento en sí puede ser utilizado en un formulario con el siguiente código YAML. Alternativamente, puede utilizar el asistente de creación de nuevos del editor de formularios en el backend si también ha utilizado la parte de código del backend mencionada anteriormente.
Con la opción de configuración "valueField" puede definir la columna de la tabla static_countries (esta tabla forma parte de la extensión EXT:static_info_tables), que debe utilizarse para el valor a transferir. En el siguiente ejemplo, se trata del nombre del país en inglés.
Con la opción de configuración "labelField" puede definir la columna de la tabla static_countries que debe utilizarse para el valor a mostrar. Hemos desarrollado una pequeña característica especial aquí, a saber, el marcador de posición "{currentLanguage}", que luego se rellena automáticamente con "de", "es", etc. en la clase php anterior en función del idioma actual del frontend. Para ello, sin embargo, se requieren extensiones adicionales como EXT:static_info_tables_en, EXT:static_info_tables_es, etc. para cada idioma del sitio web. No obstante, también puede utilizar simplemente un valor fijo en lugar de este marcador.
...
-
propiedades:
fluidAdditionalAttributes:
required: obligatorio
valueField: cn_short_es
labelField: 'cn_short_{idiomaactual}'
prependOptionLabel: 'por favor, elija'
defaultValue: ''
tipo: SingleSelectWithCountries
identificador: country
label: país
validadores:
-
identificador: NotEmpty
...