itemsProcessors: Processing of items for select, check and radio type fields
The TCA option items provides a structured and extensible way
to process items for select, check, and radio type fields. It
supersedes items by allowing multiple processors to be applied
in a defined order using a strictly typed API.
The option is defined as an array of processors. Each processor is executed sequentially based on its numerical array key, with lower values executed first. This makes it possible for extensions or integrators to add additional processing steps without replacing existing logic.
items can still be used, but items is the recommended
approach. If both items and items are configured,
both are executed. In that case, items is executed first.
TCA item processor registration
The time zone of a conference gets its items from a processor:
<?php
use MyVendor\MyExtension\Backend\ItemsProcessor\TimezoneItemsProcessor;
use MyVendor\MyExtension\Backend\TimezoneSorter;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
defined('TYPO3') or die();
ExtensionManagementUtility::addTCAcolumns('tx_myextension_conference', [
'timezone' => [
'label' => 'my_extension.db:conference.timezone',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'items' => [
['label' => '', 'value' => ''],
],
'itemsProcessors' => [
100 => [
'class' => TimezoneItemsProcessor::class,
'parameters' => [
'regions' => 'Europe,America',
],
],
],
'itemGroups' => [
'Europe' => 'my_extension.db:conference.timezone.europe',
'America' => 'my_extension.db:conference.timezone.america',
],
'sortItems' => [
'label' => 'asc',
// Then by the offset to UTC, the time zones with the same offset
// stay sorted by label
'offset' => TimezoneSorter::class . '->sortByOffset',
],
'dbFieldLength' => 64,
'behaviour' => [
'allowLanguageSynchronization' => true,
],
],
],
]);
ExtensionManagementUtility::addToAllTCAtypes(
'tx_myextension_conference',
'timezone',
'',
'after:location',
);
A further processor with a key lower than 100 would run before it.
TCA item processor implementation
All processors must implement the
Items.
Processors have two parameters:
- A
Selectinstance containing the current items.Item Collection - An
Itemsinstance providing access to table, field, row data, and configuration.Processor Context
A processor must return a
Select. Since items
are handled as objects, newly added items can no longer be represented as
untyped arrays.
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Backend\ItemsProcessor;
use TYPO3\CMS\Core\DataHandling\ItemsProcessorContext;
use TYPO3\CMS\Core\DataHandling\ItemsProcessorInterface;
use TYPO3\CMS\Core\Schema\Struct\SelectItem;
use TYPO3\CMS\Core\Schema\Struct\SelectItemCollection;
/**
* Offers the time zones of the regions given in the parameter "regions",
* grouped by region
*/
final readonly class TimezoneItemsProcessor implements ItemsProcessorInterface
{
public function processItems(
SelectItemCollection $items,
ItemsProcessorContext $context,
): SelectItemCollection {
$regions = explode(',', (string)($context->processorParameters['regions'] ?? 'Europe'));
foreach (\DateTimeZone::listIdentifiers() as $identifier) {
[$region, $city] = array_pad(explode('/', $identifier, 2), 2, '');
if ($city === '' || !in_array($region, $regions, true)) {
continue;
}
$items->add(new SelectItem(
type: 'select',
label: str_replace('_', ' ', $city),
value: $identifier,
group: $region,
));
}
return $items;
}
}
You can add your own parameters to processors. They are exposed via the processor context.
Add parameters via TCA or page TSconfig and access them through
$context->processor.
For example, the time zone processor reads the regions from its parameters:
<?php
use MyVendor\MyExtension\Backend\ItemsProcessor\TimezoneItemsProcessor;
use MyVendor\MyExtension\Backend\TimezoneSorter;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
defined('TYPO3') or die();
ExtensionManagementUtility::addTCAcolumns('tx_myextension_conference', [
'timezone' => [
'label' => 'my_extension.db:conference.timezone',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'items' => [
['label' => '', 'value' => ''],
],
'itemsProcessors' => [
100 => [
'class' => TimezoneItemsProcessor::class,
'parameters' => [
'regions' => 'Europe,America',
],
],
],
'itemGroups' => [
'Europe' => 'my_extension.db:conference.timezone.europe',
'America' => 'my_extension.db:conference.timezone.america',
],
'sortItems' => [
'label' => 'asc',
// Then by the offset to UTC, the time zones with the same offset
// stay sorted by label
'offset' => TimezoneSorter::class . '->sortByOffset',
],
'dbFieldLength' => 64,
'behaviour' => [
'allowLanguageSynchronization' => true,
],
],
],
]);
ExtensionManagementUtility::addToAllTCAtypes(
'tx_myextension_conference',
'timezone',
'',
'after:location',
);
The processor accesses $context->processor. The value
can be overridden or extended, for example via a site setting defined in
page TSconfig:
TCEFORM.tx_myextension_conference.timezone.itemsProcessors.100.regions = {$myExtension.regions}
Registering item processors in FlexForms
Registration of processors is also possible inside FlexForms:
<T3DataStructure>
<sheets>
<sDEF>
<ROOT>
<sheetTitle>my_extension.db:plugin.conferencelist.sheet.general</sheetTitle>
<type>array</type>
<el>
<settings.mode>
<label>my_extension.db:plugin.conferencelist.mode</label>
<onChange>reload</onChange>
<config>
<type>select</type>
<renderType>selectSingle</renderType>
<items>
<numIndex index="0">
<label>my_extension.db:plugin.conferencelist.mode.upcoming</label>
<value>upcoming</value>
</numIndex>
<numIndex index="1">
<label>my_extension.db:plugin.conferencelist.mode.past</label>
<value>past</value>
</numIndex>
<numIndex index="2">
<label>my_extension.db:plugin.conferencelist.mode.selected</label>
<value>selected</value>
</numIndex>
</items>
</config>
</settings.mode>
<settings.conferences>
<label>my_extension.db:plugin.conferencelist.conferences</label>
<displayCond>FIELD:settings.mode:=:selected</displayCond>
<config>
<type>group</type>
<allowed>tx_myextension_conference</allowed>
</config>
</settings.conferences>
<settings.categories>
<label>my_extension.db:plugin.conferencelist.categories</label>
<config>
<type>category</type>
</config>
</settings.categories>
<settings.display>
<label>my_extension.db:plugin.conferencelist.display</label>
<config>
<type>check</type>
<items>
<numIndex index="0">
<label>my_extension.db:plugin.conferencelist.display.logo</label>
</numIndex>
<numIndex index="1">
<label>my_extension.db:plugin.conferencelist.display.location</label>
</numIndex>
<numIndex index="2">
<label>my_extension.db:plugin.conferencelist.display.speakers</label>
</numIndex>
<numIndex index="3">
<label>my_extension.db:plugin.conferencelist.display.date</label>
</numIndex>
</items>
<cols>3</cols>
<default>15</default>
</config>
</settings.display>
<settings.limit>
<label>my_extension.db:plugin.conferencelist.limit</label>
<displayCond>
<or>
<value1>FIELD:settings.mode:=:upcoming</value1>
<value2>FIELD:settings.mode:=:past</value2>
</or>
</displayCond>
<config>
<type>number</type>
<default>10</default>
</config>
</settings.limit>
<settings.country>
<label>my_extension.db:plugin.conferencelist.country</label>
<config>
<type>country</type>
<labelField>localizedName</labelField>
<size>4</size>
<prioritizedCountries>
<numIndex index="0">CH</numIndex>
<numIndex index="1">DE</numIndex>
<numIndex index="2">AT</numIndex>
</prioritizedCountries>
</config>
</settings.country>
<settings.timezone>
<label>my_extension.db:plugin.conferencelist.timezone</label>
<config>
<type>select</type>
<renderType>selectSingle</renderType>
<items>
<numIndex index="0">
<label></label>
<value></value>
</numIndex>
</items>
<itemsProcessors>
<numIndex index="100">
<class>MyVendor\MyExtension\Backend\ItemsProcessor\TimezoneItemsProcessor</class>
<parameters>
<regions>Europe</regions>
</parameters>
</numIndex>
</itemsProcessors>
</config>
</settings.timezone>
</el>
</ROOT>
</sDEF>
<sHighlights>
<ROOT>
<sheetTitle>my_extension.db:plugin.conferencelist.sheet.highlights</sheetTitle>
<sheetDescription>my_extension.db:plugin.conferencelist.sheet.highlights.description</sheetDescription>
<type>array</type>
<el>
<settings.introduction>
<label>my_extension.db:plugin.conferencelist.introduction</label>
<config>
<type>text</type>
<enableRichtext>1</enableRichtext>
</config>
</settings.introduction>
<settings.highlights>
<title>my_extension.db:plugin.conferencelist.highlights</title>
<type>array</type>
<section>1</section>
<el>
<highlight>
<title>my_extension.db:plugin.conferencelist.highlight</title>
<type>array</type>
<el>
<title>
<label>my_extension.db:plugin.conferencelist.highlight.title</label>
<config>
<type>input</type>
</config>
</title>
<link>
<label>my_extension.db:plugin.conferencelist.highlight.link</label>
<config>
<type>link</type>
</config>
</link>
</el>
</highlight>
</el>
</settings.highlights>
</el>
</ROOT>
</sHighlights>
</sheets>
</T3DataStructure>