The beloved Table Configuration Array, better known by its abbreviation "TCA", is the glue between the TYPO3 CMS and the database. In the TCA we configure each database table in terms of its behavior, visibility, restrictions and editing interface (aka form engine). It is a central piece of every TYPO3 system and thus has received a lot of love recently.
For example, the amount of render types and eval
options for input fields had been reduced by replacing them with new and unique TCA types. Additionally, some clunky configuration options have been streamlined and also moved to their dedicated new types.
Kudos go to all involved developers, especially to Oliver Bartsch (say Thanks on Twitter) who did a lot of the work in this area, as well as to the TYPO3 documentation team.
Before we look at the newly introduced TCA types in detail and learn how to use them, we will have a quick detour through the goodness that is EXT:styleguide.
Buckle up, let's go.
EXT:styleguide
A quick word on how to get an idea of the state of the TCA feature set for current TYPO3 main branch or any released LTS version:
Use the extension styleguide (GitHub).
So, now you know. Let's carry on.
OK, seriously, EXT:styleguide is the way to go. It is a dev-dependency for the TYPO3 core for a long time and is kept up to date with new features and changes in several areas of the TYPO3 core, one of them being the TCA. With the click of a button, the extension will generate a page tree with example records for every TCA configuration that TYPO3 is capable of, including the new types we are discussing in this post.
In fact, some code examples and screenshots in this post are taken from the styleguide extension example records, because, ... well, they are good examples.
Check it out, if you have not done so yet.
Additionally, there is the quite extensive and well structured official documentation, called TCA Reference. I'll add a link to the documentation for each of the features. If the documentation contradicts this blog post, stick to the documentation and let me know.
With this out of the way, let's dive in.
New in TYPO3 11
With TYPO3 v11, two often needed configuration cases have been addressed, that had a less than ideal solution in older versions. With streamlined TCA types, the configuration of language and category fields became a lot more intuitive.
You can also check out Oli Bartschs article New TCA types in TYPO3 version 11 about this topic over at the b13 blog.
Let's have a closer look.
Language
Since TYPO3 11Patch | Feature RST | Official Documentation
In TYPO3 many records are translatable and the corresponding database tables have a field configured to store the language (id). That is what the [ctrl][languageField]
configuration option of the tables TCA is for. Usually the field for storing the language is called sys_language_uid
but it could be any other field as well.
In TYPO3 versions prior to v11 the corresponding field needed to have a column configuration specifying a relation to the sys_language
database table (type: select
) where all system languages used to be stored.
With the introduction of site handling in TYPO3 v9 a new place to define existing languages had been introduced: site configuration.
Going forward site configurations will be the only place where languages are defined. That is why the whole concept of the sys_language
as well as the database table itself has been deprecated with TYPO3 v11 (Patch and Deprecation RST) and has been removed with TYPO3 v12 (Patch).
Long story short: for language fields of our tables we have to use the following TCA configuration from now on:
'columns' => [
'sys_language_uid' => [
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
'config' => [
'type' => 'language',
],
],
],
The new TCA type automatically takes care of collecting all languages from the site configurations as well as handling the -1
special case (that is not available for pages). Overriding with PageTsConfig is still possible.
There also is a TCA migration in place to remind us in the deprecation log to migrate any legacy column configuration to the new type.
Category
Since TYPO3 11Patch | Feature RST | Official Documentation
Prior to TYPO3 v11 we had to call ExtensionManagementUtility->makeCategorizable()
to add the system categories selection tree to our records. With TYPO3 v11 a simpler way of making a table categorizable has been introduced: The category
TCA type.
All we have to do to add categorization is to configure one column to be of the new type:
'columns' => [
'categories' => [
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.category',
'config' => [
'type' => 'category',
// 'relationship' => 'manyToMany' | 'oneToMany' | 'oneToOne'
],
],
],
By default, this sets up a manyToMany
relationship, meaning that we can select as many categories for our record as we like and the relation is stored in the sys_category_record_mm
relation table. To change this behavior we can set the relationship
option to either:
oneToMany
: We can still select as many categories as we like, but the uids of the selected categories are stored as a comma separated list in our database field.oneToOne
: We can only select one category and the category uid is stored in our database field.manyToMany
: The default. See above.
With the new and more intutitive way in place to register a table for categorization, the before used CategoryRegistry
had been deprecated with TYPO3 v11 (Patch, Deprecation RST) and was removed with TYPO3 v12 (Patch). It also enabled quite some refactoring (check out the patch) to drastically improve performance of the category tree.
Fields configured with the TCA type category
will be automatically created in the database and can be omitted from ext_tables.sql
files.
Let's move on.
New in TYPO3 12
With TYPO3 v12 the focus shifted to the multitude of different field behaviors that used to be possible with the all star type input
, but also with types inline
and group
. By setting the renderType
, specific eval
values or other special options, the parent types behavior could change drastically.
The overall idea of the streamlining during TYPO3 v12 development was to get rid of many special cases and introduce dedicated TCA types for each of them, so that the usage becomes more clear and intuitive.
Let's see what has been achieved.
Password
Since TYPO3 12Patch | Feature RST | Official Documentation
Instead of configuring a field of type input
with an eval
like trim,password,saltedPassword
, we can now simply use the new password type:
'columns' => [
'password' => [
'label' => 'LLL:EXT:my_ext/Resources/Private/Language/locallang_tca.xlf:password',
'config' => [
'type' => 'password',
// 'hashed' => true | false,
],
],
],
With this most basic configuration we'll get an input field that will be concealed once saved and store a hash of the submitted input value. The database entry will only be the plaintext value if we set hashed
explicitly to false
(with true
being the default, obviously). This will have no effect on fe_users
or be_users
tables and in general it is quite hard to come up with a use case where this would be a good idea.
Do not store plaintext passwords in the database!
Just don't.
However, the password
type is capable of much more. Let's look at a full-blown configuration (borrowed from the styleguide Extension):
'columns' => [
'password_5' => [
'label' => 'password_5',
'description' => 'type=password fieldControl=passwordGenerator random=base64 allowEdit=false',
'config' => [
'type' => 'password',
'fieldControl' => [
'passwordGenerator' => [
'renderType' => 'passwordGenerator',
'options' => [
'title' => 'Create random base64 string',
'allowEdit' => false,
'passwordRules' => [
'length' => 35,
'random' => 'base64',
],
],
],
],
],
],
],
Notably, this configuration uses the [fieldControl][passwordGenerator]
, that has been introduced with TYPO3 12.1 (Patch, Feature RST). This feature is also used by the new system extension EXT:reactions (read my article Webhooks and Reactions in TYPO3 to find out more).
The password generator adds a button next to the input field that will generate a random string according to the configuration. In this case we'll get a read only field with 35 characters from base64 random bytes. It would look like this
The official documentation of the password generator field control feature can be found here.
What's next?
File
Since TYPO3 12Patch | Feature RST | Official Documentation
Adding a file relation to our records is a common use case. In TYPO3 versions prior to v12, we had to use the TCA type inline
and set the foreign_table
to sys_file_reference
and then configure it further. There has been an API in place to help with that (ExtensionManagementUtility->getFileFieldTCAConfig()
). All of this is now obsolete because we got the TCA type file
.
Here is how it looks:
'columns' => [
'images' => [
'label' => 'LLL:EXT:my_ext/Resources/Private/Language/locallang_tca.xlf:images',
'config' => [
'type' => 'file',
'maxitems' => 6,
// 'allowed' => 'common-image-types' | 'common-media-types' | 'common-text-types'
'allowed' => ['jpg','youtube'],
// 'disallowed' => ['gif'],
'appearance' => [] // same as before
'behaviour' => [] // same as before
],
],
],
The first thing that we notice is the option allowed
. This can be set to any array of file and media extensions or to one of the three presets:
common-image-types
: This is a placeholder for$GLOBALS[TYPO3_CONF_VARS][GFX][imagefile_ext]
common-media-types
: This is a placeholder for$GLOBALS[TYPO3_CONF_VARS][SYS][mediafile_ext]
common-text-types
: This is a placeholder for$GLOBALS[TYPO3_CONF_VARS][SYS][textfile_ext]
When using one of the presets we can also configure the disallowed
option to exclude file and media extensions.
The above configuration will lead to field that looks like this:
Of course, we can still determine what buttons should be available, as well as their labels and behavior, we can also still use overrideChildTca
to adapt the appearance of the sys_file_reference
fields. The appearance
and behaviour
configuration options are still the same as they were in the inline
type.
To manipulate the controls, three new PSR-14 Events (read my post about PSR-14 Events in TYPO3 for an overview) have been added to the processing of the TCA type file
(Patch, Feature RST). We have to make sure to use the new Events instead of the old TCA type inline
hook, that we might have used before, because this hook is not evaluated for the file
type.
This concludes the new TCA type file
, that allows for a more convenient way to register our fields for FAL relation.
Link
Since TYPO3 12Patch | Feature RST | Official Documentation
A good example of when the TCA type input
was used for an out-of-scope functionality, would be the link popup. With renderType => inputLink
and the configuration of the linkPopup
wizard, an innocent input field turned into a mighty link generator.
To end this madness, the TCA type link
has been introduced.
Here is an example configuration:
'columns' => [
'link' => [
'label' => 'LLL:EXT:my_ext/Resources/Private/Language/locallang_tca.xlf:link',
'config' => [
'type' => 'link',
'allowedTypes' => ['page', 'url', 'record'],
'appearance' => [
// 'enableBrowser' => false,
'allowedFileExtensions' => ['jpg', 'png'],
'allowedOptions' => ['*'],
],
],
],
],
A few things of note here:
Going forward, the link browser can only be configured with allow lists, where prior to TYPO3 v12 disallow lists have been used. This affects the available link types, file extensions for file links and options for the generated <a>
tags.
We now configure the available tabs of the link browser directly in the config
array by setting the allowedTypes
to any number of available link types (The core comes with page
,file
, url
, telephone
and record
). To enable all types, we can simply use ['*']
. Also, the record
type can be made more specific. While record
enables all records, we could replace it with one or more specific record types, like for example tx_news
.
Note, that setting appearance[enableBrowser]
to false
will disable the whole link browser (with true
being the default, obviously).
Finally appearance[allowedFileExtensions]
and appearance[allowedOptions]
let us control what file extensions are available to link to (with enabled file
link type) and what options are available for the generated <a>
tag (the core comes with target
, title
, class
, params
and rel
).
With that we should be able to have nice and working link fields in our records in TYPO3 v12 and beyond. Let's move on.
Number
Since TYPO3 12Patch | Feature RST | Official Documentation
To make the input
type text-only, all integer based field functionality has been moved to the new TCA type number
. This includes everything that was formerly achieved by setting eval
to int
or double2
on fields of type input
.
We now can do the following:
'columns' => [
'number' => [
'label' => 'LLL:EXT:my_ext/Resources/Private/Language/locallang_tca.xlf:number',
'config' => [
'type' => 'number',
// 'format' => 'decimal'
'range' => [
'lower' => 1,
'upper' => 100
],
]
],
],
This configuration leads to a basic input field that we can put numbers into, either with or without decimals, depending on the format
configuration value. If we specify a range
, the field will be validated before submit to ensure the input value lies within the lower
and and upper
limit.
So far, so simple.
The TCA type number
is capable of two more things (that we already know from the former feature set of the input
type):
slider
: This will add a little slider next to the input field (see screenshot below).valuePicker
: This will add a dropdown next to the input field, with predefined values to choose from (see screenshot below).
Let's look at a configuration for both of them:
'columns' => [
'slider' => [
'label' => 'LLL:EXT:my_ext/Resources/Private/Language/locallang_tca.xlf:numberWithSlider',
'description' => 'slider default=14.5 step=0.5 width=150 format=decimal',
'config' => [
'type' => 'number',
'default' => 14.5,
'format' => 'decimal',
'size' => 5,
'slider' => [
'step' => 0.5,
'width' => 150,
],
],
],
'picker' => [
'label' => 'LLL:EXT:my_ext/Resources/Private/Language/locallang_tca.xlf:numberWithPicker',
'description' => 'value picker',
'config' => [
'type' => 'number',
'valuePicker' => [
'items' => [
['One', '1'],
['Two', '2'],
],
],
],
],
],
This configuration turns into the following fields:
That is everything there is to know about the TCA type number
.
But there is more.
Datetime
Since TYPO3 12Patch | Feature RST | Official Documentation
With the TCA type datetime
, another renderType
of type input
bites the dust.
Beginning with TYPO3 v12, all fields that are configured to be of type datetime
will be automatically created in the database and can be omitted from ext_tables.sql
files (the dbType
option is explained below). However, if those fields are present in a ext_tables.sql
, the definition there will take precedence.
Let's look at an example:
'columns' => [
'start_date' => [
'label' => 'LLL:EXT:my_ext/Resources/Private/Language/locallang_tca.xlf:startDate',
'config' => [
'type' => 'datetime',
'dbType' => 'datetime' | 'date' | 'time',
'format' => 'datetime' | 'date' | 'time',
// 'disableAgeDisplay' => true,
// 'nullable' => true,
],
],
],
To break this down, we first look at the configuration option dbType
. If set, the value will not be stored as timestamp in the database, but as native date
, time
or datetime
field. If the dbType
option is not set, the value will be converted to a timestamp and stored as an integer in the database.
When we set nullable
to true
, the field can be disabled and stored as null
in the database. Otherwise, a null value is not possible. The automatically created database column will reflect this setting.
The format
option lets us configure how the date (or time) should be displayed in the backend. It is independent from the format in the database (that is what dbType
is for).
Since the list module will by default calculate the "age" of a field by showing the difference of days for a date value to today, the option disableAgeDisplay
has been introduced back in TYPO3 v7 (Feature RST). If we set this option to true
, the calculation will be skipped to increase backend performance. It is recommended to always set this unless you need the additional "age" display in the list module.
Last but not least, a datetime
field will always have a datepicker unless it is set to be readonly
.
Alright, whats next?
Patch | Feature RST | Official Documentation
This is a quick one. The new TCA type email
replaces the eval => email
option of type input
. It is very straightforward:
'columns' => [
'email' => [
'label' => 'LLL:EXT:my_ext/Resources/Private/Language/locallang_tca.xlf:email',
'config' => [
'type' => 'email',
],
],
],
The value will be trimmed automatically and there is really nothing more to say about this type.
To the next one!
Color
Since TYPO3 12Patch | Feature RST | Official Documentation
The new TCA type color
replaces yet another former render type of TCA type input
(it was called colorpicker
). It will create a field with a colorpicker. The configuration looks like this:
'columns' => [
'color' => [
'label' => 'LLL:EXT:my_ext/Resources/Private/Language/locallang_tca.xlf:color',
'config' => [
'type' => 'color',
// 'nullable' => true,
'valuePicker' => [
'items' => [
['typo3 orange', '#FF8700'],
],
],
],
],
],
As shown in the example, the value picker is still available. The nullable
option will add a checkbox next to the field to disable it and store null
in the database field.
Straightforward again.
Almost done.
Folder
Since TYPO3 12Patch | Feature RST | Official Documentation
For fields that we used to configure with type group
and internal_type => folder
, we now have a dedicated type: folder
.
There is, however, one more thing: We can determine the entry point of the folder browser with the new option elementBrowserEntryPoints
that has also been introduced with TYPO3 12 (Patch, Feature RST).
A field configured with type folder could look like this:
'columns' => [
'folder' => [
'label' => 'LLL:EXT:my_ext/Resources/Private/Language/locallang_tca.xlf:folder',
'config' => [
'type' => 'folder',
'elementBrowserEntryPoints' => [
'_default' => '1:/my_folder/'
// '_default' => '###PAGE_TSCONFIG_ID###'
// 'hideMoveIcons' => false | true
],
],
],
],
This will render a select box with a folder selection button next to it. The button will open the file browser at the configured entry point so that we can choose our folder(s).
If we set hideMoveIcons
to true
, the form engine will ... you guessed it .. hide the move icons that let us change the order of the selected folders.
Awesome.
JSON
Since TYPO3 12Patch | Feature RST | Official Documentation (pending)
This TCA type can be used for database fields containing JSON data. It will render the JSON in a text area field or if the system extension t3editor is installed and the configuration option enableCodeEditor
is not explicitly set to false in a code editor field.
A field configuration could look like this:
'columns' => [
'json' => [
'label' => 'LLL:EXT:my_ext/Resources/Private/Language/locallang_tca.xlf:json',
'config' => [
'type' => 'json',
// 'enableCodeEditor' => false,
// 'readonly' => true,
],
],
],
Not much to say about this one. Few things: enableCodeEditor
defaults to true
. We can also make the filed readonly
, which might make sense, because most of the time JSON is not the ideal input format.
UUID
Since TYPO3 12Patch | Feature RST | Official Documentation
With the new uuid
TCA type, we can generate an universally unique identifier for a database row. Under the hood, it uses the symfony component symfony/uid
(documentation).
An example configuration:
'columns' => [
'uuid' => [
'label' => 'LLL:EXT:my_ext/Resources/Private/Language/locallang_tca.xlf:uuid',
'config' => [
'type' => 'uuid',
'version' => 7,
// 'enableCopyToClipboard' => true,
],
],
],
The form engine will initially generate a uuid according to the specified version
(4, 6 or 7) if the field is configured with type uuid
and contains no value yet. The field is then rendered as a read only field. Optionally, a copy to clipboard button can be enabled.
An example of this can be found in the new-to-v12 system extension EXT:reactions (read my article about reactions and webhooks).
This should make it quite easy to add uuids to our database rows.
Hooray!
Additional Resources
- New TCA Types in version 11, 2023, Blog Post by Oliver Bartsch
- TCA Reference, Official Documentation
That was a lot. Why bother, you might ask?
Well, I put this post together to have all the new stuff in one place that I can refer to and that I can (and will) update when new things are added. I also hope this collection of TCA goodies can be of use to other developers as well (If you are not like me and actually work with the newer versions of TYPO3, it very well might be).
Please let me know if something is missing or wrong.
And that's it - thanks for reading and (if you do) for supporting this blog <3
.