TYPO3 v15 dev-main snapshot ()

This commit is contained in:
2026-08-10 22:31:09 +02:00
commit af8cc155b5
6818 changed files with 642608 additions and 0 deletions
@@ -0,0 +1,71 @@
.. include:: /Includes.rst.txt
.. _deprecation-102326-1699703964:
=================================================================================
Deprecation: #102326 - RegularExpressionValidator validator option "errorMessage"
=================================================================================
See :issue:`102326`
Description
===========
The :php:`errorMessage` validator option provides a custom string
as error message for validation failures of the :php:`RegularExpressionValidator`.
In order to streamline error message translation keys with other validators,
the :php:`errorMessage` validator option has been marked as deprecated in
TYPO3 v13 and will be removed in TYPO3 v14.
Impact
======
Using the :php:`errorMessage` validator option with the :php:`RegularExpressionValidator`
will trigger a PHP deprecation warning.
Affected installations
======================
TYPO3 installations using the validator option :php:`errorMessage` with the
:php:`RegularExpressionValidator`.
Migration
=========
The new :php:`message` validator option should be used to provide a custom
translatable error message for failed validation.
Before:
.. code-block:: php
use TYPO3\CMS\Extbase\Annotation as Extbase;
#[Extbase\Validate([
'validator' => 'RegularExpression',
'options' => [
'regularExpression' => '/^simple[0-9]expression$/',
'errorMessage' => 'Error message or LLL schema string',
],
])]
protected string $myProperty = '';
After:
.. code-block:: php
use TYPO3\CMS\Extbase\Annotation as Extbase;
#[Extbase\Validate([
'validator' => 'RegularExpression',
'options' => [
'regularExpression' => '/^simple[0-9]expression$/',
'message' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:my.languageKey'
],
])]
protected string $myProperty = '';
.. index:: Backend, NotScanned, ext:extbase
@@ -0,0 +1,50 @@
.. include:: /Includes.rst.txt
.. _deprecation-102337-1715591179:
==========================================================
Deprecation: #102337 - Deprecate hooks for record download
==========================================================
See :issue:`102337`
Description
===========
The previously used hooks
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList']['customizeCsvHeader']`
and
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList']['customizeCsvRow']`,
used to manipulate the download / export configuration of records, triggered
in the :guilabel:`Web > List` backend module, have been deprecated in favor of a
new PSR-14 event :php:`TYPO3\CMS\Backend\RecordList\Event\BeforeRecordDownloadIsExecutedEvent`.
Details for migration and functionality can be found in :ref:`feature-102337-1715591178`
Impact
======
When the hook :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList']['customizeCsvHeader']`
or
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList']['customizeCsvRow']`
is executed, this will trigger a PHP deprecation warning.
The extension scanner will find possible usages with a weak match.
Affected installations
======================
All installations using
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList']['customizeCsvHeader']`
or
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList']['customizeCsvRow']`
are affected.
Migration
=========
The new PSR-14 event :php:`TYPO3\CMS\Backend\RecordList\Event\BeforeRecordDownloadIsExecutedEvent`
can be used as a near drop-in replacement.
.. index:: PHP-API, FullyScanned, ext:core
@@ -0,0 +1,49 @@
.. include:: /Includes.rst.txt
.. _deprecation-103752-1714304437:
========================================================================================
Deprecation: #103752 - Obsolete `$GLOBALS['TYPO3_CONF_VARS']['FE']['addRootLineFields']`
========================================================================================
See :issue:`103752`
Description
===========
Configuration option :php:`$GLOBALS['TYPO3_CONF_VARS']['FE']['addRootLineFields']`
is obsolete and has been removed in TYPO3 Core v13.2.
This option is well-known to integrators who add relations to the TCA :sql:`pages`
table. It triggers relation resolving of page relations for additional fields when
rendering a frontend request in the default language. The most common usage is
TypoScript "slide".
Impact
======
Integrators can simply forget about this option: relations of table :sql:`pages`
are now resolved with nearly no performance penalty in comparison to not
having them resolved.
Affected installations
======================
Many instances add additional relations to the :sql:`pages` table then add
this field in :php:`addRootLineFields`. This option is no longer evaluated.
Relation fields attached to :sql:`pages` are always resolved in frontend.
There should be hardly any extensions using this option, since it was
an internal option of class :php:`RootlineUtility`. Extensions using
:php:`$GLOBALS['TYPO3_CONF_VARS']['FE']['addRootLineFields']` *may* trigger a
PHP warning level error because the array key has been removed. The extension scanner
is configured to locate such usages.
Migration
=========
The option is no longer evaluated in TYPO3 Core. It is removed from
:php:`settings.php` during upgrade, if given.
.. index:: Frontend, LocalConfiguration, PHP-API, FullyScanned, ext:core
@@ -0,0 +1,44 @@
.. include:: /Includes.rst.txt
.. _deprecation-103785-1714720280:
========================================================================
Deprecation: #103785 - Deprecate MathUtility::convertToPositiveInteger()
========================================================================
See :issue:`103785`
Description
===========
TYPO3 has the method :php:`MathUtility::convertToPositiveInteger()` to ensure
that an integer is always positive. However, the method is rather
"heavy" as it calls :php:`MathUtility::forceIntegerInRange()` internally and
therefore misuses a clamp mechanism to convert the integer to a positive number.
Also, the method name doesn't reflect what the method actually does. Negative
numbers are not converted to their positive counterpart, but are swapped with
`0`. Due to the naming issue and the fact that the method can be replaced by a
simple :php:`max()` call, the method is therefore deprecated.
Impact
======
Calling :php:`MathUtility::convertToPositiveInteger()` will trigger a PHP
deprecation warning.
Affected installations
======================
All installations using :php:`MathUtility::convertToPositiveInteger()`.
Migration
=========
To recover the original behavior of the deprecated method, its call can be
replaced with :php:`max(0, $number)`. To actually convert negative numbers to
their positive counterpart, call :php:`abs($number)`.
.. index:: PHP-API, FullyScanned, ext:core
@@ -0,0 +1,86 @@
.. include:: /Includes.rst.txt
.. _deprecation-103965-1717335369:
================================================================================
Deprecation: #103965 - Deprecate namespaced shorthand validator usage in Extbase
================================================================================
See :issue:`103965`
Description
===========
It is possible to use undocumented namespaced shorthand notation in Extbase
to add validators to properties or arguments. For example,
:php:`TYPO3.CMS.Extbase:NotEmpty` will be resolved as
:php:`TYPO3\CMS\Extbase\Validation\Validator\NotEmptyValidator` and
:php:`Vendor.Extension:Custom` will be resolved as
:php:`\Vendor\MyExtension\Validation\Validator\CustomValidator`.
The namespaced shorthand notation for Extbase validators has been marked as
deprecated and will be removed in TYPO3 v14.
Impact
======
Using namespaced shorthand notation in Extbase will trigger a PHP deprecation
warning.
Affected installations
======================
All installations using namespaced shorthand notation in Extbase.
Migration
=========
Extensions using the namespaced shorthand notation must use the FQCN of the
validator instead. For Extbase core validators, the well known
shorthand validator name can be used.
Before
------
.. code-block:: php
/**
* @Extbase\Validate("TYPO3.CMS.Extbase:NotEmpty")
*/
protected $myProperty1;
/**
* @Extbase\Validate("Vendor.Extension:Custom")
*/
protected $myProperty2;
After
-----
.. code-block:: php
/**
* @Extbase\Validate("NotEmpty")
*/
protected $myProperty1;
/**
* @Extbase\Validate("Vendor\Extension\Validation\Validator\CustomValidator")
*/
protected $myProperty2;
or
.. code-block:: php
#[Extbase\Validate(['validator' => \TYPO3\CMS\Extbase\Validation\Validator\NotEmptyValidator::class])]
protected $myProperty1;
#[Extbase\Validate(['validator' => \Vendor\Extension\Validation\Validator\CustomValidator::class])]
protected $myProperty2;
.. index:: Frontend, NotScanned, ext:extbase
@@ -0,0 +1,115 @@
.. include:: /Includes.rst.txt
.. _deprecation-104108-1718354448:
================================================================
Deprecation: #104108 - Table dependant definition of columnsOnly
================================================================
See :issue:`104108`
Description
===========
When linking to the edit form it's possible to instruct the
:php:`EditDocumentController` to only render a subset of available
fields for relevant records using the `columnsOnly` functionality,
by adding the fields to be rendered as a comma-separated list.
However, the edit form can render records from many tables, and not just
a single table, in the same request.
Therefore, the limit fields functionality has been extended to allow
setting the fields to be rendered on a per-table basis. This means that
passing a comma-separated list of fields as a value for `columnsOnly`
has been deprecated.
Impact
======
Passing a comma-separated list of fields as value for `columnsOnly` will
trigger a PHP deprecation warning. A compatibility layer will automatically
set the field list for the required tables.
Affected installations
======================
All installations passing a comma-separated list of fields as a value for
`columnsOnly`.
Migration
=========
The fields to be rendered have to be passed as an :php:`array` under the
corresponding table name.
An example, building such link using the `UriBuilder`:
.. code-block:: php
$urlParameters = [
'edit' => [
'pages' => [
1 => 'edit',
],
],
'columnsOnly' => 'title,slug'
'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri(),
];
GeneralUtility::makeInstance(UriBuilder::class)->buildUriFromRoute('record_edit', $urlParameters);
Above example has to be migrated to:
.. code-block:: php
$urlParameters = [
'edit' => [
'pages' => [
1 => 'edit',
],
],
'columnsOnly' => [
'pages' => [
'title',
'slug'
]
],
'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri(),
];
GeneralUtility::makeInstance(UriBuilder::class)->buildUriFromRoute('record_edit', $urlParameters);
Additionally, when rendering records from many tables, a configuration
could look like the following:
.. code-block:: php
$urlParameters = [
'edit' => [
'pages' => [
1 => 'edit',
],
'tt_content' => [
2 => 'edit',
],
],
'columnsOnly' => [
'pages' => [
'title',
'slug'
],
'tt_content' => [
'header',
'subheader'
]
],
'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri(),
];
// https:://example.com/typo3/record/edit?edit[pages][1]=edit&edit[tt_content][2]=edit&columnsOnly[pages][0]=title&columnsOnly[pages][1]=slug&columnsOnly[tt_content][0]=header&columnsOnly[tt_content][1]=subheader
$link = GeneralUtility::makeInstance(UriBuilder::class)->buildUriFromRoute('record_edit', $urlParameters);
.. index:: Backend, NotScanned, ext:backend
@@ -0,0 +1,48 @@
.. include:: /Includes.rst.txt
.. _deprecation-104154-1718802119:
=====================================================================
Deprecation: #104154 - Deprecate Utility.updateQueryStringParameter()
=====================================================================
See :issue:`104154`
Description
===========
The :js:`Utility.updateQueryStringParameter()` method in the
:js:`@typo3/backend/utility.js` module was introduced in TYPO3 v8 as a bugfix
for highlighting in the old ExtJS-based page tree. Since removal of ExtJS in
TYPO3 v9 the method has been unused.
Because safe removal of the method cannot be guaranteed as this point, it is
therefore deprecated.
Impact
======
Calling :js:`Utility.updateQueryStringParameter()` will result in a JavaScript
warning.
Affected installations
======================
All 3rd party extensions using the deprecated method.
Migration
=========
Now, JavaScript supports the :js:`URL` and its related :js:`URLSearchParams`
object that can be used to achieve the same result:
.. code-block:: javascript
const url = new URL('http://localhost?baz=baz');
url.searchParams.set('baz', 'bencer');
const urlString = url.toString(); // http://localhost?baz=bencer
.. index:: JavaScript, NotScanned, ext:backend
@@ -0,0 +1,32 @@
.. include:: /Includes.rst.txt
.. _feature-102155-1717653944:
======================================================================
Feature: #102155 - User TSconfig option for default resources ViewMode
======================================================================
See :issue:`102155`
Description
===========
The listing of resources in the TYPO3 backend, e.g. in the
:guilabel:`File > Filelist` module or the `FileBrowser` can be switched
between `list` and `tiles`. TYPO3 serves `tiles` by default.
A new User TSconfig option :typoscript:`options.defaultResourcesViewMode` has
been introduced, which allows the initial display mode to be defined. Valid
values are therefore `list` and `tiles`, e.g.:
.. code-block:: typoscript
options.defaultResourcesViewMode = list
Impact
======
Integrators can now define the default display mode for resources via
User TSconfig.
.. index:: Backend, TSConfig, ext:filelist
@@ -0,0 +1,74 @@
.. include:: /Includes.rst.txt
.. _feature-102326-1699707043:
===================================================================
Feature: #102326 - Allow custom translations for Extbase validators
===================================================================
See :issue:`102326`
Description
===========
All validation messages from Extbase validators can now be overwritten
using validator options. It is possible to provide either a translation key or
a custom message as string.
Extbase validators providing only one validation message can be overwritten by a
translation key or message using the validator option :php:`message`. Validators
providing multiple validation messages (e.g. :php:`Boolean`, :php:`NotEmpty` or
:php:`NumberRange`) use different validator options keys. In general,
translation keys or messages for validators are registered in the validator
property :php:`translationOptions`.
Example with translations
-------------------------
.. code-block:: php
use TYPO3\CMS\Extbase\Annotation as Extbase;
#[Extbase\Validate([
'validator' => 'NotEmpty',
'options' => [
'nullMessage' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:validation.myProperty.notNull',
'emptyMessage' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:validation.myProperty.notEmpty',
],
])]
protected string $myProperty = '';
In this example, translation option keys for the :php:`NotEmptyValidator` are
overwritten for the property :php:`$myProperty`. The :php:`locallang.xlf`
translation file from the extension :php:`my_extension` will be used to lookup
translations for the newly provided translation key options.
Example with a custom string
----------------------------
.. code-block:: php
use TYPO3\CMS\Extbase\Annotation as Extbase;
#[Extbase\Validate([
'validator' => 'Float',
'options' => [
'message' => 'A custom, non translatable message',
],
])]
protected float $myProperty = 0.0;
In this example, translation option keys for the :php:`FloatValidator` are
overwritten for the property :php:`$myProperty`. The message string is
shown if validation fails.
Impact
======
The new validator translation option keys allow developers to define unique
validation messages for TYPO3 Extbase validators on validator usage basis. This
may result in a better user experience, since validation messages now can refer
to the current usage scope (e.g. "The field 'Title' is required" instead of
"The given subject was empty.").
.. index:: Backend, ext:extbase
@@ -0,0 +1,132 @@
.. include:: /Includes.rst.txt
.. _feature-102337-1715591178:
=====================================================================
Feature: #102337 - PSR-14 event for modifying record list export data
=====================================================================
See :issue:`102337`
Description
===========
A new PSR-14 event :php:`TYPO3\CMS\Backend\RecordList\Event\BeforeRecordDownloadIsExecutedEvent`
has been introduced to modify the result of a download / export initiated in
the :guilabel:`Web > List` module.
This replaces the
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList']['customizeCsvHeader']`
and
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList']['customizeCsvRow']`,
hooks, which have been :ref:`deprecated <deprecation-102337-1715591179>`.
The event allows body and header sections of the data dump to be modified,
so that they can e.g. be used to redact specific data for GDPR compliance,
transform / translate specific data, trigger creation of archives or web hooks,
log export access and more.
The event offers the following methods:
- :php:`getHeaderRow()`: Return the current header row of the dataset.
- :php:`setHeaderRow()`: Sets the modified header row of the dataset.
- :php:`getRecords()`: Returns the current body rows of the dataset.
- :php:`setRecords()`: Sets the modified body rows of the dataset.
- :php:`getRequest()`: Returns the PSR request context.
- :php:`getTable()`: Returns the name of the database table of the dataset.
- :php:`getFormat()`: Returns the format of the download action (CSV/JSON).
- :php:`getFilename()`: Returns the name of the download filename (for browser output).
- :php:`getId()`: Returns the page UID of the download origin.
- :php:`getModTSconfig()`: Returns the active module TSconfig of the download origin.
- :php:`getColumnsToRender()`: Returns the list of header columns for the triggered download.
- :php:`isHideTranslations()`: Returns whether translations are hidden or not.
Example
=======
The corresponding event listener class:
.. code-block:: php
<?php
declare(strict_types=1);
namespace Vendor\MyPackage\Core\EventListener;
use TYPO3\CMS\Backend\RecordList\Event\BeforeRecordDownloadIsExecutedEvent;
use TYPO3\CMS\Core\Attribute\AsEventListener;
#[AsEventListener(identifier: 'my-package/record-list-download-data')]
final readonly class DataListener
{
public function __invoke(BeforeRecordDownloadIsExecutedEvent $event): void
{
// List of redactable fields.
$gdprFields = ['title', 'author'];
$headerRow = $event->getHeaderRow();
$records = $event->getRecords();
// Iterate header to mark redacted fields...
foreach ($headerRow as $headerRowKey => $headerRowValue) {
if (in_array($headerRowKey, $gdprFields, true)) {
$headerRow[$headerRowKey] .= ' (REDACTED)';
}
}
// Redact actual content...
foreach ($records as $uid => $record) {
foreach ($gdprFields as $gdprField) {
if (isset($record[$gdprField])) {
$records[$uid][$gdprField] = '(REDACTED)';
}
}
}
$event->setHeaderRow($headerRow);
$event->setRecords($records);
}
}
Migration
=========
The functionality of both hooks :php:`customizeCsvHeader` and
:php:`customizeCsvRow` are now handled by the new PSR-14 event.
Migrating :php:`customizeCsvHeader`
-----------------------------------
The prior hook parameter/variable :php:`fields` is now available via
:php:`$event->getColumnsToRender()`. The actual record data
(previously :php:`$this->recordList`, submitted to the hook as its object
reference) is accessible via :php:`$event->getHeaderRow()`.
Migrating :php:`customizeCsvRow`
--------------------------------
The prior hook parameters/variables have the following substitutes:
- :php:`databaseRow` is now available via :php:`$event->getRecords()` (see note below).
- :php:`tableName` is now available via :php:`$event->getTable()`.
- :php:`pageId` is now available via :php:`$event->getId()`.
The actual record data
(previously :php:`$this->recordList`, submitted to the hook as its object
reference) is accessible via :php:`$event->getRecords()`.
Please note that the hook was previously executed once per row retrieved
from the database. The PSR-14 event however - due to performance reasons -
is only executed for the full record list after database retrieval,
thus allowing post-processing on the whole dataset.
Impact
======
Using the PSR-14 event :php:`BeforeRecordDownloadIsExecutedEvent` it is
now possible to modify all of the data available when downloading / exporting
a list of records via the :guilabel:`Web > List` module.
.. index:: Backend, PHP-API, ext:core
@@ -0,0 +1,105 @@
.. include:: /Includes.rst.txt
.. _feature-102337-1715591177:
==========================================================================
Feature: #102337 - PSR-14 event for modifying record list download presets
==========================================================================
See :issue:`102337`
Description
===========
A new PSR-14 event :php:`TYPO3\CMS\Backend\RecordList\Event\BeforeRecordDownloadPresetsAreDisplayedEvent`
has been introduced to manipulate the list of available download presets in
the :guilabel:`Web > List` module.
See :ref:`feature-102337-1712597691` for a detailed description of how to
utilize presets when downloading a set of records from the backend in CSV
or JSON format.
The event class offers the following methods:
- :php:`getPresets()`: Returns a list of presets set via TSconfig
- :php:`setPresets()`: Sets a modified list of presets.
- :php:`getDatabaseTable()`: Returns the database table name that a preset applies to.
- :php:`getRequest()`: Returns the PSR Request object for the context of the request.
- :php:`getId()`: Returns the page ID of the originating page.
Note that the event is dispatched for one specific database table. If
an event listener is created to attach presets to different tables, the
listener method must check for the table name, as shown in the example below.
If no download presets exist for a given table, the PSR-14 event can still
be used to modify and add presets to it via the :php:`setPresets()` method.
The array passed from :php:`getPresets()` to :php:`setPresets()` can contain
an array collection of :php:`TYPO3\CMS\Backend\RecordList\DownloadPreset`
objects with the array key using the preset label.
The existing presets can be retrieved with these getters:
- :php:`$preset->getLabel()`: Name of the preset (can utilize LLL translations), optional.
- :php:`$preset->getColumns()`: Array of database table column names.
- :php:`$preset->getIdentifier()`: Identifier of the preset (manually set or calculated based on label and columns)
The event listener can also remove array indexes or columns of existing
array entries by passing a newly constructed :php:`DownloadPreset` object with the
changed `label` and `columns` constructor properties.
Example
=======
The corresponding event listener class:
.. code-block:: php
<?php
declare(strict_types=1);
namespace Vendor\MyPackage\RecordList\EventListener;
use TYPO3\CMS\Backend\RecordList\Event\BeforeRecordDownloadPresetsAreDisplayedEvent;
use TYPO3\CMS\Backend\RecordList\DownloadPreset;
use TYPO3\CMS\Core\Attribute\AsEventListener;
#[AsEventListener(identifier: 'my-package/modify-record-list-preset')]
final readonly class PresetListener
{
public function __invoke(BeforeRecordDownloadPresetsAreDisplayedEvent $event): void
{
$presets = $event->getPresets();
switch ($event->getDatabaseTable()) {
case 'be_users':
$presets[] = new DownloadPreset('PSR-14 preset', ['uid','email']);
break;
case 'pages':
$presets[] = new DownloadPreset('PSR-14 preset', ['title']);
$presets[] = new DownloadPreset('Another PSR-14 preset', ['title', 'doktype']);
break;
case 'tx_myvendor_myextension':
$presets[] = new DownloadPreset('PSR-14 preset', ['uid', 'something']);
break;
}
$presets[] = new DownloadPreset('Available everywhere, simple UID list', ['uid']);
$presets['some-identifier'] = new DownloadPreset('Overwrite preset', ['uid, pid'], 'some-identifier');
$event->setPresets($presets);
}
}
Impact
======
Using the PSR-14 event :php:`BeforeRecordDownloadPresetsAreDisplayedEvent`
it is now possible to modify the presets of each table for
downloading / exporting a list of such records via the :guilabel:`Web > List`
module.
.. index:: Backend, PHP-API, ext:core
@@ -0,0 +1,99 @@
.. include:: /Includes.rst.txt
.. _feature-102337-1712597691:
=======================================================
Feature: #102337 - Presets for download of record lists
=======================================================
See :issue:`102337`
Description
===========
In the :guilabel:`Web > List` backend module, the data of records for each
database table (including pages and content records) can be downloaded.
This export takes the currently selected list of columns into consideration and
alternatively allows all columns to be selected.
A new feature has been introduced adding the ability to pick the exported
data columns from a list of configurable presets.
Those presets can be configured via page TSconfig, and can also be
overridden via user TSconfig (for example, to make certain presets
only available to specific users).
.. code-block:: typoscript
:caption: EXT:my_extension/Configuration/page.tsconfig
mod.web_list.downloadPresets {
pages {
10 {
label = Quick overview
columns = uid, title, crdate, slug
}
20 {
identifier = LLL:EXT:myext/Resources/Private/Language/locallang.xlf:preset2.label
label = UID and titles only
columns = uid, title
}
}
}
Each entry of :typoscript:`mod.web_list.downloadPresets`
defines the table name on the first level (in this case `pages`), followed by
any number of presets.
Each preset contains a :typoscript:`label` (the displayed name of the preset,
which can be a locallang key), a comma-separated list of each column that
should be included in the export as :typoscript:`columns` and optionally
an :typoscript:`identifier`. If :typoscript:`identifier` is not provided,
the identifier is generated as a hash of the :typoscript:`label` and
:typoscript:`columns`.
This can be manipulated with user TSConfig by adding the :typoscript:`page.`
prefix. User TSConfig is loaded after page TSConfig, so you can overwrite
existing keys or replace the whole list of keys:
.. code-block:: typoscript
:caption: EXT:my_extension/Configuration/user.tsconfig
page.mod.web_list.downloadPresets {
pages {
10 {
label = Quick overview (customized)
columns = uid, title, crdate, slug
}
30 {
label = Short with URL
columns = uid, title, slug
}
}
}
Since any table can be configured for a preset, any extension
can deliver a defined set of presets through the
:file:`EXT:my_extension/Configuration/page.tsconfig` file and
their table name(s).
Additionally, the list of presets can be manipulated via the new
:ref:`BeforeRecordDownloadPresetsAreDisplayedEvent <feature-102337-1715591177>`.
Impact
======
Editors can now export data with specific presets as required
as identified by the website maintainer or extension developer(s).
It is no longer required to pick specific columns to export over and over again,
and the list of presets is controlled by the website maintainer.
Two new PSR-14 Events have been added to allow further manipulation:
* :ref:`BeforeRecordDownloadIsExecutedEvent <feature-102337-1715591177>`
* :ref:`BeforeRecordDownloadPresetsAreDisplayedEvent <feature-102337-1715591178>`
.. index:: Backend, TSConfig
@@ -0,0 +1,26 @@
.. include:: /Includes.rst.txt
.. _feature-102869-1705661913:
================================================
Feature: #102869 - List workspaces in LiveSearch
================================================
See :issue:`102869`
Description
===========
The backend LiveSearch is now able to list workspaces a backend user has access
to, offering the possibility to switch to a workspace quickly outside the
Workspaces module.
Impact
======
Backend users now have another, quickly accessible way to access a workspace.
With proper permissions, a backend user may also switch to the edit interface of
a workspace to configure its settings.
.. index:: Backend, ext:workspaces
@@ -0,0 +1,27 @@
.. include:: /Includes.rst.txt
.. _feature-102951-1709643048:
==============================================================
Feature: #102951 - Provide PSR-7 request in Extbase validators
==============================================================
See :issue:`102951`
Description
===========
Extbase :php:`abstractValidator` now provides a getter and a setter
for the PSR-7 Request object. Validators extending :php:`AbstractValidator`
will include the PSR-7 request object, if the validator has been instantiated
by Extbase :php:`ValidationResolver`.
Impact
======
Extension developers can now create custom validators which consume data
from the PSR-7 request object (e.g. request attribute
:php:`frontend.user`).
.. index:: PHP-API, ext:extbase
@@ -0,0 +1,53 @@
.. include:: /Includes.rst.txt
.. _feature-103019-1706856586:
======================================================================
Feature: #103019 - ModifyRedirectUrlValidationResultEvent PSR-14 event
======================================================================
See :issue:`103019`
Description
===========
This feature introduces the new PSR-14 event
:php:`ModifyRedirectUrlValidationResultEvent` in the felogin extension to
provide developers the possibility and flexibility to implement custom
validation for the redirect URL. This may be useful if TYPO3 frontend login
acts as an SSO system or if users should be redirected to an external URL after
login.
Example
-------
.. code-block:: php
<?php
namespace Vendor\MyExtension\EventListener;
use TYPO3\CMS\Core\Attribute\AsEventListener;
use TYPO3\CMS\FrontendLogin\Event\ModifyRedirectUrlValidationResultEvent;
class ValidateRedirectUrl
{
#[AsEventListener('validate-custom-redirect-url')]
public function __invoke(ModifyRedirectUrlValidationResultEvent $event): void
{
$parsedUrl = parse_url($event->getRedirectUrl());
if ($parsedUrl['host'] === 'trusted-host-for-redirect.tld') {
$event->setValidationResult(true);
}
}
}
Impact
======
Developers now have the possibility to modify the validation results for the
redirect URL, allowing redirects to URLs not matching existing validation
constraints.
.. index:: Frontend, PHP-API, ext:felogin
@@ -0,0 +1,29 @@
.. include:: /Includes.rst.txt
.. _feature-103493-1711562309:
===========================================================
Feature: #103493 - Edit full record in "Check Links" module
===========================================================
See :issue:`103493`
Description
===========
Previously, the listing in the :guilabel:`Check Links` backend module
provided the possibility to edit the field of a record that has been identified
as having a broken link. However, in some cases relevant context might be missing,
e.g. when editing redirect records.
Therefore, a new button has been introduced which allows the full record of the
broken link to be edited. The new button is placed next to the
existing - single field - edit button.
Impact
======
A new button is now displayed in the :guilabel:`Check Links` backend module,
allowing the full record of a broken link to be edited.
.. index:: Backend, ext:linkvalidator
@@ -0,0 +1,44 @@
.. include:: /Includes.rst.txt
.. _feature-103706-1713883119:
=========================================================
Feature: #103706 - Default search level for record search
=========================================================
See :issue:`103706`
Description
===========
When searching for records in the :guilabel:`Web > List` module as well as
the database browser, it's possible to select the search levels (page tree
levels to respect in the search).
An editor is therefore able to select between the current page, a couple of
defined levels (e.g. 1, 2, 3) as well as the special "infinite levels".
Those options can already be extended using the TSconfig option
:typoscript:`mod.web_list.searchLevel.items`.
Next to this, a new TSconfig option :typoscript:`mod.web_list.searchLevel.default`
has been introduced, which allows to define one of the available level options
as the default level to use.
Example
-------
.. code-block:: typoscript
:caption: EXT:my_sitepackage/Configuration/page.tsconfig
# Set the default search level to "infinite levels"
mod.web_list.searchLevel.default = -1
Impact
======
It's now possible to define a default search level using the new page
TSconfig option :typoscript:`mod.web_list.searchLevel.default`.
.. index:: Backend, TSConfig, ext:backend
@@ -0,0 +1,176 @@
.. include:: /Includes.rst.txt
.. _feature-103783-1715113274:
======================================================
Feature: #103783 - RecordTransformation Data Processor
======================================================
See :issue:`103783`
Description
===========
A new TypoScript data processor for :typoscript:`FLUIDTEMPLATE` and
:typoscript:`PAGEVIEW` has been added.
The :typoscript:`record-transformation` Data Processor can typically be used in
conjunction with the DatabaseQuery Data Processor. The DatabaseQuery Data
Processor typically fetches records from the database, and the
:typoscript:`record-transformation` will take the result and transform
the objects into :php:`Record` objects, which contain relevant data from
the TCA table, which has been configured in the TCA columns fields for this
record.
This is especially useful for TCA tables, which contain "types" (such as pages
or tt_content database tables), where only relevant fields are added to the
record object. In addition, special fields from "enableColumns" or deleted
fields, as well as language and version information are extracted so they can be
dealt with in a unified way.
The "type" property contains the database table name and the actual type based
on the record, such as "tt_content.textmedia" for Content Elements.
.. note::
The Record object is available but details are still to be finalized in
the API by TYPO3 v13 LTS. Right now only the usage in Fluid is public
API.
Impact
======
Example of the data processor being used in conjunction with DatabaseQuery
processor.
.. code-block:: typoscript
page = PAGE
page {
10 = PAGEVIEW
10 {
paths.10 = EXT:my_extension/Resources/Private/Templates/
dataProcessing {
10 = database-query
10 {
as = mainContent
table = tt_content
select.where = colPos=0
dataProcessing.10 = record-transformation
}
}
}
}
Transform the current data array of :typoscript:`FLUIDTEMPLATE` to a Record
object. This can be used for Content Elements of Fluid Styled Content or
custom ones. In this example the FSC element "Text" has its data transformed for
easier and enhanced usage.
.. code-block:: typoscript
tt_content.text {
templateName = Text
dataProcessing {
10 = record-transformation
}
}
Usage in Fluid templates
------------------------
The :html:`f:debug` output of the Record object is misleading for integrators,
as most properties are accessed differently than would be expected. The debug view
is a better organized overview of all the available information. E.g.
the property `properties` lists all relevant fields for the current Content
Type.
We are dealing with an object here. You can, however, access your record
properties as you are used to with :html:`{record.title}` or
:html:`{record.uid}`. In addition, you gain special, context-aware properties
like the language :html:`{record.languageId}` or workspace
:html:`{record.versionInfo.workspaceId}`.
Overview of all possibilities:
.. code-block:: html
<!-- Any property, which is available in the Record (like normal) -->
{record.title}
{record.uid}
{record.pid}
<!-- Language related properties -->
{record.languageId}
{record.languageInfo.translationParent}
{record.languageInfo.translationSource}
<!-- The overlaid uid -->
{record.overlaidUid}
<!-- Types are a combination of the table name and the Content Type name. -->
<!-- Example for table "tt_content" and CType "textpic": -->
<!-- "tt_content" (this is basically the table name) -->
{record.mainType}
<!-- "textpic" (this is the CType) -->
{record.recordType}
<!-- "tt_content.textpic" (Combination of mainType and record type, separated by a dot) -->
{record.fullType}
<!-- System related properties -->
{record.systemProperties.deleted}
{record.systemProperties.disabled}
{record.systemProperties.lockedForEditing}
{record.systemProperties.createdAt}
{record.systemProperties.lastUpdatedAt}
{record.systemProperties.publishAt}
{record.systemProperties.publishUntil}
{record.systemProperties.userGroupRestriction}
{record.systemProperties.sorting}
{record.systemProperties.description}
<!-- Computed properties depending on the request context -->
{record.computedProperties.versionedUid}
{record.computedProperties.localizedUid}
{record.computedProperties.requestedOverlayLanguageId}
{record.computedProperties.translationSource} <!-- Only for pages, contains the Page model -->
<!-- Workspace related properties -->
{record.versionInfo.workspaceId}
{record.versionInfo.liveId}
{record.versionInfo.state.name}
{record.versionInfo.state.value}
{record.versionInfo.stageId}
.. note::
The :html:`{record}` object contains only properties relevant for
the current record type (e.g. `CType` for :php:`tt_content`). If
you need to access properties which are not defined for the record
type, which is usually the case for fields of TCA type `passthrough`,
the "raw" record can be used by accessing it via :html:`{record.rawRecord}`.
Note that those properties are not transformed (:ref:`feature-103581-1723209131`).
Available options
------------------
.. code-block:: typoscript
The variable that contains the record(s) from a previous data processor,
or from a FLUIDTEMPLATE view. Default is :typoscript:`data`.
variableName = items
# the name of the database table of the records. Leave empty to auto-resolve
# the table from context.
table = tt_content
# the target variable where the resolved record objects are contained
# if empty, "record" or "records" (if multiple records are given) is used.
as = myRecords
.. index:: Fluid, TypoScript, ext:frontend
@@ -0,0 +1,112 @@
.. include:: /Includes.rst.txt
.. _feature-103894-1716544976:
====================================================================
Feature: #103894 - Additional properties for columns in Page Layouts
====================================================================
See :issue:`103894`
Description
===========
Backend Layouts were introduced in TYPO3 v6 in order to customize the view of
the :guilabel:`Page` module in TYPO3 backend for pages, but has since grown, also in
frontend rendering, to select e.g. Fluid template files via TypoScript for a page,
commonly used via :typoscript:`data:pagelayout`.
In order to use a single source for backend and frontend representation, the
definition of a "Backend Layout" or "Page Layout" is expanded to also include
more information for a specific content area. The Content Area was previously
defined via "name" (for the label in the :guilabel:`Page` module) and "colPos",
the numeric database field in which content is grouped in.
A definition can now optionally also contain a "slideMode" property and an
"identifier" property next to each colPos, in order to simplify frontend
rendering.
Whereas "identifier" is a speaking representation for the colPos, such as
"main", "sidebar" or "footerArea", the "slideMode" can be set to one of the
three options:
* :typoscript:`slideMode = slide` - if no content is found, check the parent
pages for more content
* :typoscript:`slideMode = collect` - use all content from this page, and the
parent pages as one collection
* :typoscript:`slideMode = collectReverse`- same as "collect" but in the
opposite order
With this information added, a new DataProcessor :typoscript:`page-content`
(:php:`\TYPO3\CMS\Frontend\DataProcessing\PageContentFetchingProcessor`)
is introduced for the frontend rendering,
which fetches all content for a page and respecting the settings from the
page layout.
The new data processor allows to manipulate the fetched page content via
the PSR-14 :ref:`AfterContentHasBeenFetchedEvent <feature-105638-1732034075>`.
Impact
======
Enriching the backend layout information for each colPos enables a TYPO3
integrator to write less TypoScript in order to render content on a page.
The DataProcessor fetches all content elements from all defined columns with an
included "identifier" in the selected backend layout and makes the resolved
record objects available in the Fluid template via
:html:`{content."myIdentifier".records}`.
Example of an enriched backend layout definition:
.. code-block:: typoscript
mod.web_layout.BackendLayouts {
default {
title = Default
config {
backend_layout {
colCount = 1
rowCount = 1
rows {
1 {
columns {
1 {
name = Main Content Area
colPos = 0
identifier = main
slideMode = slide
}
}
}
}
}
}
}
}
Example of the frontend output:
.. code-block:: typoscript
page = PAGE
page.10 = PAGEVIEW
page.10.paths.10 = EXT:my_site_package/Tests/Resources/Private/Templates/
page.10.dataProcessing.10 = page-content
page.10.dataProcessing.10.as = myContent
.. code-block:: html
<main>
<f:for each="{myContent.main.records}" as="record">
<f:cObject typoscriptObjectPath="{record.mainType}" table="{record.mainType}" data="{record}"/>
</f:for>
</main>
The :html:`f:cObject` ViewHelper above uses the rendering definition of the
tt_content table :html:`{record.mainType}` to render the Content Element from
the list. The attribute :html:`data` expects the raw database record, which is
retrieved from :html:`{record}`.
.. index:: Backend, Frontend, ext:frontend
@@ -0,0 +1,183 @@
.. include:: /Includes.rst.txt
.. _feature-104002-1718273913:
=============================
Feature: #104002 - Schema API
=============================
See :issue:`104002`
Description
===========
A new Schema API is introduced to access information about TCA structures
in a unified way.
The main goal of this architecture is to reduce direct access to
:php:`$GLOBALS['TCA']` after the Bootstrap process is completed.
The Schema API implements the following design goals:
#. An object-oriented approach to access common TCA information such as if a
database table is localizable or workspace-aware, if it has a "deleted" field
("soft-delete"), or other common functionality such as "enableFields" / "enablecolumns",
which can be accessed via "Capabilities" within a Schema.
#. A unified way to access information which "types" a TCA table has available,
such as "tt_content", where the "CType" field is the divisor for types, thus,
allowing a Schema to have sub-schemata for a TCA Table.
The API in turn then handles which fields are available for a specific "CType".
An example is "tt_content" with type "textpic": The sub-schema "tt_content.textpic"
only contains the fields that are registered of that "CType", such as "bodytext",
which then knows it is a Rich Text Field (the default column does not have this information),
or "image" (a file relation field), but the sub-schema does not contain fields
that are irrelevant for this type, such as "assets" (also a file relation field).
#. An abstracted approach to available TCA field types such as "input" or "select",
which also takes information into account, if a select field is a selection of a
static list (such as "pages.layout") or if it contains a relation to another
schema or field (based on "foreign_table"). Previously, this was evaluated in
many places in TYPO3 Core, and can now be reduced.
Thus, Schema API can now be utilized to determine the :php:`RelationshipType`
of a relational field type in a unified way without having to deal with deeply
nested arrays.
#. Information about relations to other database tables or fields. This is
especially useful when dealing with Inline elements or category selection fields.
Schema API can find out, which fields of other schemata are pointing to one-self.
Schema API differentiates between an "Active Relation" and a "Passive Relation".
An Active Relation is the information that a field such as "pages.media"
(a field of type "file") contains a reference to the "sys_file_reference.uid_foreign"
field. Active Relations in consequence are connected to a specific field
(of type :php:`RelationalFieldTypeInterface`).
In turn, a "Passive Relation" is the information what other schemata/fields are
pointing to a specific table or field.
A common example of a "Passive Relation" is "sys_workspace_stage":
The information stored in :php:`$GLOBALS[TCA][sys_workspace_stage]` does not contain
the information that this table is actually used as a reference from the database
field `sys_workspace.custom_stages`, the `sys_workspace_stage` Schema now
contains this information directly via :php:`TcaSchema->getPassiveRelations()`.
This is possible as TcaSchemaFactory is evaluating all TCA information and
holistically as a graph. Passive Relations
are currently only connected to a Schema, and Active Relations to a Field or
a Schema.
As the Schema API fetches information solely based on the TCA, an Active Relation
only points to **possible** references, however, the actual reference
(does a record really have a connection to another database table) would
require an actual Record instance (a database row) to evaluate this information.
Relations do not know about the "Type" or "Quantity" (many-to-many etc) as
this information is already stored in the Field information. For this reason,
the "Relations" currently only contain a flat information structure of the table
(and possibly a field) pointing TO another schema name (Active Relation) or
FROM another schema name / field (Passive Relation).
Schema API also parses all available FlexForm data structures in order to
resolve relations. As a result, a field of type FlexFormField contains
a list of possible "FlexFormSchema" instances, which resolve all fields, sheets
and section containers within each data structure.
#. Once built, the Schema can never be changed. Whereas the TCA could be
overridden at runtime, all TCA is now evaluated once and
then cached. This is a consequence of working with an object-oriented approach.
If the TCA is changed after the Bootstrap process is completed,
the Schema needs to be rebuilt manually, which TYPO3 Core currently does, for
example, in some Functional Testing Scenarios.
All key objects (Schema, FieldType, Capabilities) are treated as immutable DTOs
and never contain cross-references to their parent objects (Sub schemata do not
know information about their parent schema, a field does not know which schema
it belongs to), so the only entry point is always the :php:`TcaSchemaFactory`
object.
This design allows the API to be fully cacheable at PHP level as a nested tree.
#. Low-level, not full-fledged but serves as a basis.
Several API decisions were made in order to let Schema API keep only its
original purpose, but can be encapsulated further in other APIs:
- Schema API is not available during Bootstrap as it needs TCA to be available
and fully finished.
- Schema API does not contain all available TCA properties for each field type.
An example is "renderType" for select fields. This information is not relevant
when querying records in the frontend, and mainly relevant for FormEngine -
it is not generic enough to justify a getter method.
- Extensibility: custom field types are currently not available
until TYPO3 Core as fully migrated to Schema API.
- User Permissions: Evaluating if a user has access to "tt_content.bodytext"
requires information about the currently logged in user, thus it is not part of the
Schema API. A "Permission API" should evaluate this information in the
future.
- Available options for a field. As an example, a common scenario is to find out
which possible options are available for "pages.backend_layout". In TYPO3 Core
an :php:`itemsProcFunc` is connected to that field in TCA. Whether there is an
:php:`itemsProcFunc` is stored, but Schema API is not designed to actually
execute the itemsProcFunc as it is dependent on various factors evaluated during
runtime, such as the page it resides on, user permissions or PageTsConfig
overrides.
Schema API is currently marked as internal, as it might be changed during
TYPO3 v13 development, because more parts of TYPO3 will be migrated towards
Schema API.
DataHandler and the Record Factory already utilize Schema API in order to reduce
direct access to :php:`$GLOBALS[TCA]`.
In the future Schema API might be used to evaluate information
for Site Configurations, like TCA and FlexForms.
Impact
======
Reading and writing :php:`$GLOBALS[TCA]` within :file:`Configuration/TCA/*`
and via TCA Overrides is untouched, as the API is meant for reading the
information there in a unified way.
Usage
-----
The API can now be used to find out information about TCA fields.
.. code-block:: php
public function __construct(
protected readonly PageRepository $pageRepository,
protected readonly TcaSchemaFactory $tcaSchemaFactory
) {}
public function myMethod(string $tableName): void
{
if (!$this->tcaSchemaFactory->has($tableName)) {
// this table is not managed via TYPO3's TCA API
return;
}
$schema = $this->tcaSchemaFactory->get($tableName);
// Find out if a table is localizable
if ($schema->isLocalizable()) {
// do something
}
// Find all registered types
$types = $schema->getSubSchemata();
}
Using the API improves handling for parts such as evaluating :php:`columnsOverrides`,
foreign field structures, FlexForm Schema parsing, and evaluating type fields
for database fields.
.. index:: PHP-API, TCA, ext:core
@@ -0,0 +1,50 @@
.. include:: /Includes.rst.txt
.. _feature-104020-1718381897:
====================================================
Feature: #104020 - ViewHelper to check feature flags
====================================================
See :issue:`104020`
Description
===========
The `<f:feature>` ViewHelper allows integrators to check for feature flags from within Fluid
templates. The ViewHelper follows the same rules as the underlying TYPO3 api, which means
that undefined flags will be treated as `false`.
Examples
========
Basic usage
-----------
::
<f:feature name="myFeatureFlag">
This is being shown if the flag is enabled
</f:feature>
feature / then / else
---------------------
::
<f:feature name="myFeatureFlag">
<f:then>
Flag is enabled
</f:then>
<f:else>
Flag is undefined or not enabled
</f:else>
</f:feature>
Impact
======
Feature flags can now be checked from within Fluid templates.
.. index:: Fluid, ext:fluid
@@ -0,0 +1,23 @@
.. include:: /Includes.rst.txt
.. _feature-104067-1718188232:
======================================================
Feature: #104067 - Sorting of forms in the form module
======================================================
See :issue:`104067`
Description
===========
The listing of existing forms in the :guilabel:`Form` backend module has
been extended to provide sorting functionality.
Impact
======
It's now possible to sort the existing forms in the :guilabel:`Form`
backend module.
.. index:: Backend, ext:form
@@ -0,0 +1,27 @@
.. include:: /Includes.rst.txt
.. _feature-104069-1718551315:
======================================================================
Feature: #104069 - Improved backend notifications display and handling
======================================================================
See :issue:`104069`
Description
===========
The notifications shown on the lower right now have a "Clear all" button to allow the
user to clear all notifications with a single click. This button is only displayed when
two or more notifications are on screen.
In case the height of the notification container exceeds the viewport, a scroll bar will
allow the user to navigate through the notifications.
Impact
======
Handling of multiple notifications has been improved by allowing to
scroll and clear all notifications at once.
.. index:: Backend, ext:backend
@@ -0,0 +1,33 @@
.. include:: /Includes.rst.txt
.. _feature-104085-1718271935:
===========================================================================
Feature: #104085 - Edit specific columns of multiple records in List module
===========================================================================
See :issue:`104085`
Description
===========
Using the "Show columns" button on a record table in the :guilabel:`Web > List`
backend module allows to select the columns to be displayed for the
corresponding table listing.
When selecting multiple records, it has already been possible to edit all
those records at once, using the "Edit" button in the table header.
Now, a new button "Edit columns" has been introduced, which additionally
allows to access the editing form for the selected records with just the
columns of the current selection (based on "Show columns"). This improves
the usability when doing mass editing of specific columns.
Impact
======
It's now possible to edit the columns of multiple records in the
:guilabel:`Web > List` backend module, using the new "Edit columns" button.
.. index:: Backend, ext:backend
@@ -0,0 +1,35 @@
.. include:: /Includes.rst.txt
.. _feature-104095-1718283782:
=============================================================================
Feature: #104095 - Edit specific columns of multiple files in Filelist module
=============================================================================
See :issue:`104095`
Description
===========
Using the "Show columns" action in the :guilabel:`File > Filelist`
backend module allows to select the columns to be displayed file and
folder listing.
When selecting multiple files, it has already been possible to edit the
metadata of all those records at once, using the "Edit Metadata" button
above the listing.
Now, a new button "Edit selected columns" has been introduced, which
additionally allows to access the editing form for the selected files
with just the columns of the current selection (based on "Show columns").
This improves the usability when doing mass editing of specific columns.
Impact
======
It's now possible to edit selected columns of multiple file metadata in the
:guilabel:`File > Filelist` backend module, using the new
"Edit selected columns" button.
.. index:: Backend, ext:filelist
@@ -0,0 +1,48 @@
.. include:: /Includes.rst.txt
.. _feature-104114-1719419341:
=========================================================
Feature: #104114 - Command to generate Fluid schema files
=========================================================
See :issue:`104114`
Description
===========
With Fluid Standalone 2.12, a new implementation of the XSD schema generator has
been introduced, which was previously a separate composer package. These XSD files
allow IDEs to provide autocompletion for ViewHelper arguments in Fluid templates,
provided that they are included in the template by using the xmlns syntax:
.. code-block:: html
<html
xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
xmlns:my="http://typo3.org/ns/Vendor/MyPackage/ViewHelpers"
data-namespace-typo3-fluid="true"
>
A new CLI command has been defined to apply Fluid's new schema generator to TYPO3's
Fluid integration. New Fluid APIs are used to find all ViewHelpers that exist in
the current project (based on the composer autoloader). Then, TYPO3's configuration
is checked for any merged Fluid namespaces (like `f:`, which consists of both
Fluid Standalone and EXT:fluid ViewHelpers which in some cases override each other).
After that consolidation, `*.xsd` files are created in `var/transient/` using another
API from Fluid Standalone. These files which will automatically get picked up by
supporting IDEs (like PhpStorm) to provide autocompletion in template files.
Impact
======
To get autocompletion for all available ViewHelpers in supporting IDEs, the following
CLI command can be executed in local development environments:
.. code-block:: bash
vendor/bin/typo3 fluid:schema:generate
.. index:: CLI, Fluid, ext:fluid
@@ -0,0 +1,68 @@
.. include:: /Includes.rst.txt
.. _feature-104220-1719409311:
=================================================================
Feature: #104220 - Make parseFunc allowTags and denyTags optional
=================================================================
See :issue:`104220`
Description
===========
Defining the TypoScript properties :typoscript:`allowTags` or
:typoscript:`denyTags` for the HTML processing via
:typoscript:`stdWrap.parseFunc` is now optional.
Besides that, it is now possible to use :typoscript:`allowTags = *`.
Impact
======
By omitting :typoscript:`allowTags` or :typoscript:`denyTags`, the
corresponding rendering instructions can be simplified.
Security aspects are considered automatically by the HTML sanitizer,
unless :typoscript:`htmlSanitize` is disabled explicitly.
Examples
--------
.. code-block:: typoscript
10 = TEXT
10.value = <p><em>Example</em> <u>underlined</u> text</p>
10.parseFunc = 1
10.parseFunc {
allowTags = *
denyTags = u
}
The example above allows any tag, except :html:`<u>` which will be encoded.
.. code-block:: typoscript
10 = TEXT
10.value = <p><em>Example</em> <u>underlined</u> text</p>
10.parseFunc = 1
10.parseFunc {
allowTags = u
}
The example above only allows :html:`<u>` and encodes any other tag.
.. code-block:: typoscript
10 = TEXT
10.value = <p><em>Example</em> <u>underlined</u> text</p>
10.parseFunc = 1
10.parseFunc {
allowTags = *
denyTags = *
}
The example above allows all tags, the new :typoscript:`allowTags = *`
takes precedence over :typoscript:`denyTags = *`.
.. index:: Frontend, TypoScript, ext:core
@@ -0,0 +1,49 @@
.. include:: /Includes.rst.txt
.. _feature-104223-1719417803:
==================================================
Feature: #104223 - Update Fluid Standalone to 2.12
==================================================
See :issue:`104223`
Description
===========
Fluid Standalone has been updated to version 2.12. This version adds new capabilities for
tab based ViewHelpers and adds the new ViewHelper :html:`f:constant`.
Also see this :ref:`deprecation document<deprecation-104223-1721383576>` for
information on deprecated functionality.
Impact
======
Arbitrary tags with tag based view helpers
------------------------------------------
Tag based view helpers (such as :html:`<f:image />` or :html:`<f:form.*>`) can now
receive arbitrary tag attributes which will be appended to the resulting HTML tag,
without dedicated registration.
.. code-block:: html
<f:form.textfield inputmode="tel" />
<f:image image="{image}" hidden="hidden" />
New f:constant ViewHelper
-------------------------
A :html:`<f:constant>` ViewHelper has been added to be able to access PHP constants from
Fluid templates:
.. code-block:: html
{f:constant(name: 'PHP_INT_MAX')}
{f:constant(name: '\Vendor\Package\Class::CONSTANT')}
{f:constant(name: '\Vendor\Package\Enum::CASE')}
.. index:: Fluid, Frontend, ext:fluid
@@ -0,0 +1,39 @@
.. include:: /Includes.rst.txt
.. _feature-91783-1712426102:
=========================================================================
Feature: #91783 - Allow system maintainer to mute disable_functions error
=========================================================================
See :issue:`91783`
Description
===========
Adds a configuration option to adapt the environment check in the Install Tool
for a list of sanctioned :php:`disable_functions`.
With the new configuration option
:php:`$GLOBALS['TYPO3_CONF_VARS']['SYS']['allowedPhpDisableFunctions']`,
a system maintainer can add native PHP function names to this list,
which are then reported as environment warnings instead of errors.
Configuration example in :file:`additional.php`:
.. code-block:: php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['allowedPhpDisableFunctions']
= ['set_time_limit', 'set_file_buffer'];
You can also define this in your :file:`settings.php` file manually
or via :guilabel:`Admin Tools > Settings > Configure options`.
Impact
======
Native php function names can be added as an array of function names, which will
not trigger an error but only a warning, if they can also be found in the php.ini
setting :php:`disable_functions`.
.. index:: Backend, ext:core
@@ -0,0 +1,23 @@
.. include:: /Includes.rst.txt
.. _feature-92009-1718182575:
=======================================================
Feature: #92009 - Provide backend modules in LiveSearch
=======================================================
See :issue:`92009`
Description
===========
The backend LiveSearch is now capable of listing backend modules, a user has
access to, offering the possibility of alternative navigation to different
parts of the backend.
Impact
======
Backend users now have another possibility to quickly access a backend module.
.. index:: Backend, ext:backend
@@ -0,0 +1,65 @@
.. include:: /Includes.rst.txt
.. _feature-99203-1704401590:
===========================================================================
Feature: #99203 - Streamline FE/versionNumberInFilename to 'EXT:' resources
===========================================================================
See :issue:`99203`
Description
===========
Local resources are currently not "cache-busted", for example, have no version
in URL. TypoScript has no possibility to add the cache buster. When replacing
them a new filename must be used (which feels little hacky).
getText "asset" to cache-bust assets in TypoScript
--------------------------------------------------
.. code-block:: typoscript
:caption: EXT:my_extension/Configuration/TypoScript/setup.typoscript
:emphasize-lines: 3
page.20 = TEXT
page.20 {
value = { asset : EXT:core/Resources/Public/Icons/Extension.svg }
insertData = 1
}
.. code-block:: text
:caption: Result
typo3/sysext/core/Resources/Public/Icons/Extension.svg?1709051481
Cache-busted assets with the :html:`<f:uri.resource>` ViewHelper
----------------------------------------------------------------
.. code-block:: html
:caption: EXT:my_extension/Resources/Private/Template/MyTemplate.html
:emphasize-lines: 3
<f:uri.resource
path="EXT:core/Resources/Public/Icons/Extension.svg"
useCacheBusting="true"
/>
.. code-block:: text
:caption: Comparison
Before: typo3/sysext/core/Resources/Public/Icons/Extension.svg
Now: typo3/sysext/core/Resources/Public/Icons/Extension.svg?1709051481
The ViewHelper argument :html:`useCacheBusting` is enabled by default.
Depending on :php:`$GLOBALS['TYPO3_CONF_VARS']['FE']['versionNumberInFilename']`
the cache buster is applied as query string or embedded in the filename.
Impact
======
Local resources now can have a cache buster to easily replace them without
changing the filename.
.. index:: Fluid, Frontend, ext:frontend
@@ -0,0 +1,30 @@
.. include:: /Includes.rst.txt
.. _important-101621-1718125029:
=================================================================
Important: #101621 - Changed default value for twitter_card field
=================================================================
See :issue:`101621`
Description
===========
The default value of the `twitter_card` field of a page is now an empty string
instead of `summary`.
Meta tag :html:`<meta name="twitter:card">` is only rendered if one of the
following fields is filled in,
- `twitter_title`
- `twitter_description`
- `twitter_image`
- `twitter_card`
- `og_title`
- `og_description`
- `og_image`
If no twitter card is selected, the fallback value is `summary`.
.. index:: Frontend, ext:seo
@@ -0,0 +1,32 @@
.. include:: /Includes.rst.txt
.. _important-103485-1718964758:
===========================================================
Important: #103485 - Provide lib.parseFunc via ext:frontend
===========================================================
See :issue:`103485`
Description
===========
The :typoscript:`lib.parseFunc` and :typoscript:`lib.parseFunc_RTE` functions
render HTML from Rich Text Fields in TYPO3. Direct interaction with these
libraries is now uncommon, but they control the output of the
:html:`<f:format.html>` ViewHelper.
Previously, the libraries were available only through content rendering definitions
like fluid_styled_content, the bootstrap_package or your own packages.
The :html:`<f:format.html>` ViewHelper requires a parseFunc to function and
will throw an exception if none is provided. With the shift towards
self-contained content elements, also known as content blocks, there is no need
to include a separate rendering definition. The frontend provides a base version
of the libraries, which are now available in the frontend context.
The libraries are loaded early in the TypoScript chain, ensuring that all
existing overrides continue to work as before, without the need for a basic
parseFunc definition.
.. index:: Frontend, TypoScript, ext:frontend
@@ -0,0 +1,48 @@
.. include:: /Includes.rst.txt
.. _important-103748-1714290385:
=====================================================
Important: #103748 - Reference index rebuild required
=====================================================
See :issue:`103748`
Description
===========
A series of new columns has been added to the reference index table
:sql:`sys_refindex`. This requires a rebuild of the table. All instances
must update the reference index when upgrading.
In TYPO3 v13 the reference index has become more important. Most notably,
it is used in the frontend for performance improvements. This requires
a valid index and keeping it up-to-date after deployments is mandatory
to avoid incorrect data during frontend and backend processing.
After deployment and initial rebuild, the index is kept up-to-date automatically
by the :php:`DataHandler` when changing records in the backend .
In general, updating the reference index is required when database
relations that are defined in TCA change - typically when adding, removing
or changing extensions, and after TYPO3 Core updates (also patch level).
It is strongly recommended to update the reference index after deployments.
Note TYPO3 v13 has optimized this operation - a full update is usually much
quicker than with previous versions.
The recommended way to rebuild and fully update the reference index is the CLI
command:
.. code-block:: bash
bin/typo3 referenceindex:update
If CLI can not be used, the reference index can be updated in the backend
using the "DB check" module in the "typo3/cms-lowlevel" extension. Since
the update process may take a while, PHP web processes may time out during
this operation, which makes this backend interface suitable for small sized
instances only.
.. index:: Database, ext:core
@@ -0,0 +1,88 @@
.. include:: /Includes.rst.txt
.. _important-103915-1716666919:
=========================================================================
Important: #103915 - Adjust database field defaults for "check" TCA types
=========================================================================
See :issue:`103915`
Description
===========
TYPO3 v13.0 has introduced automatic database field creation for TCA
fields configured as type "check" (if not explicitly defined in
:file:`ext_tables.sql`), via
`https://review.typo3.org/c/Packages/TYPO3.CMS/+/80513`__.
This conversion applied a :sql:`default 0` to all fields, and did not
evaluate the actual TCA definition for the
:php:`['config']['default']` setting.
This bug has been fixed, and the DB schema analyzer will now convert
all the following fields to their proper default settings:
* :sql:`be_users.options` (0->3)
* :sql:`sys_file_storage.is_browsable` (0->1)
* :sql:`sys_file_storage.is_writable` (0->1)
* :sql:`sys_file_storage.is_online` (0->1)
* :sql:`sys_file_storage.auto_extract_metadata` (0->1)
* :sql:`sys_file_metadata.visible` (0->1)
* :sql:`tt_content.sectionIndex` (0->1)
* :sql:`tx_styleguide_palette.palette_1_1` (0->1)
* :sql:`tx_styleguide_palette.palette_1_3` (0->1)
* :sql:`tx_styleguide_valuesdefault.checkbox_1` (0->1)
* :sql:`tx_styleguide_valuesdefault.checkbox_2` (0->1)
* :sql:`tx_styleguide_valuesdefault.checkbox_3` (0->5)
* :sql:`tx_styleguide_valuesdefault.checkbox_4` (0->5)
* :sql:`sys_workspace.edit_allow_notificaton_settings` (0->3)
* :sql:`sys_workspace.edit_notification_preselection` (0->2)
* :sql:`sys_workspace.publish_allow_notificaton_settings` (0->3)
* :sql:`sys_workspace.publish_notification_preselection` (0->1)
* :sql:`sys_workspace.execute_allow_notificaton_settings` (0->3)
* :sql:`sys_workspace.execute_notification_preselection` (0->3)
* :sql:`sys_workspace_stage.allow_notificaton_settings` (0->3)
* :sql:`sys_workspace_stage.notification_preselection` (0->8)
All these records, created via :php:`DataHandler` calls, actually
evaluate the TCA default for record insertion and do not rely
on SQL database field defaults.
Only records created using the :php:`QueryBuilder` or
other "raw" database calls would apply the wrong
values.
An example of this is
:php:`TYPO3\CMS\Core\Resource\StorageRepository->createLocalStorage()`
which creates a default :file:`fileadmin` record via the :php:`QueryBuilder`
and then sets the field :sql:`auto_extract_metadata` to :sql:`0`, instead of `1`
as would be expected in the TCA. This would mean YouTube files would not
automatically fetch metadata on creation.
This means, for all custom extension code that
* removed the column definition in :file:`ext_tables.sql`
to enforce automatic database field creation,
* *and* did not use the recommended :php:`DataHandler` for
record insertion (so, any code that is not executed in the
backend context, using :php:`QueryBuilder` or Extbase
repository methods),
* *and* expects a different default than :sql:`0` for newly
created records,
* *and* relied on the database field definition default
this code may have created incorrect database records for versions between
TYPO3 v13.0 and 13.2.
For TYPO3 Core code, this has only affected:
* Default file storage creation, field :sql:`sys_file_metadata.auto_extract_metadata`
* Default backend user creation (admin) property :sql:`be_users.options`
In these rare case, the database record integrity needs to be
checked manually, because there are no automated tools
to see if a record has used SQL default values or specifically
defined values.
.. index:: Database, ext:core
@@ -0,0 +1,19 @@
.. include:: /Includes.rst.txt
.. _important-104037-1718098487:
=====================================================================
Important: #104037 - Backend module "Access" renamed to "Permissions"
=====================================================================
See :issue:`104037`
Description
===========
The TYPO3 backend module "Access" has been renamed to "Permissions".
This accurately reflects the purpose of this module and improves consistency in the
TYPO3 backend.
.. index:: Backend, ext:core
@@ -0,0 +1,397 @@
.. include:: /Includes.rst.txt
.. _important-104153-1718790066:
==============================================================
Important: #104153 - About database error "Row size too large"
==============================================================
See :issue:`104153`
Description
===========
Introduction
------------
MySQL and MariaDB database engines sometimes generate a "Row size too large" error
when modifying the schema of tables with many columns. This document aims to
provide a detailed explanation of this error and presents solutions for TYPO3
instance maintainers to fix it.
Note that TYPO3 Core v13 has implemented measures to mitigate this error in
most scenarios. Therefore, instance maintainers typically do not need to
be aware of the specific details outlined below.
Preface
-------
Firstly, it is important to recognize that there are two different error messages
that appear similar but have distinct root causes and potentially opposite solution
strategies. This will be elaborated on later in this document.
Secondly, we will not cover all possible variations of these errors, but will
focus on a subset most relevant to TYPO3. Therefore, later sections of the
document are very specific. Correctly following the instructions may already
resolve the issue for instances running a different setup.
The issue is most likely to occur with the database table :sql:`tt_content`, as
this table is often extended with many additional columns, increasing the
likelihood of encountering the error. This document uses table :sql:`tt_content`
in code examples. However, the solution strategies are applicable to other
tables as well by adjusting the code examples below.
Ensure storage engine is 'InnoDB'
.................................
TYPO3 typically utilizes the :sql:`InnoDB` storage engine for tables in
MySQL / MariaDB databases. However, instances upgraded from older TYPO3 Core
versions might still employ different storage engines for some tables.
TYPO3 Core provides an automatic migration within
:guilabel:`Admin Tools > Maintenance > Analyze Database Structure` and will
suggest to migrate all tables to :sql:`InnoDB`.
You can manually verify the engine currently in use:
.. code-block:: sql
SELECT `TABLE_NAME`,`ENGINE`
FROM `information_schema`.`TABLES`
WHERE `TABLE_SCHEMA`='my_database'
AND `TABLE_NAME`='tt_content';
Tables *not* using :sql:`InnoDB` should be converted via
:guilabel:`Admin Tools > Maintenance > Analyze Database Structure` or manually
via SQL:
.. code-block:: sql
USE `my_database`;
ALTER TABLE `tt_content` ENGINE=InnoDB;
Ensure InnoDB row format is 'Dynamic'
.....................................
The :sql:`InnoDB` row format dictates how data is physically stored. The
:sql:`Dynamic` row format provides better support for tables with many
variable-length columns and has been the default format for some time. However,
instances upgraded from older TYPO3 Core versions and older MySQL / MariaDB
engines might still use the previous default format :sql:`Compact`.
TYPO3 Core provides an automatic migration within
:guilabel:`Admin Tools > Maintenance > Analyze Database Structure` and will
suggest to migrate all tables to :sql:`ROW_FORMAT=DYNAMIC`.
You can manually verify the row format currently in use:
.. code-block:: sql
SELECT `TABLE_NAME`,`Row_format`
FROM `information_schema`.`TABLES`
WHERE `TABLE_SCHEMA`='my_database'
AND `TABLE_NAME`='tt_content';
Tables *not* using :sql:`Dynamic` should be converted via
:guilabel:`Admin Tools > Maintenance > Analyze Database Structure` or manually
via SQL:
.. code-block:: sql
USE 'my_database`;
ALTER TABLE `tt_content` ROW_FORMAT=DYNAMIC;
Database, table and column charset
..................................
The column charset impacts length calculations. This document assumes
:sql:`utf8mb4` for columns, aligning with the default TYPO3 setup. Converting
an existing instance to :sql:`utf8mb4` can be a complex task depending on the
currently used charset and is beyond the scope of this document.
A key point about :sql:`utf8mb4` is that when dealing with the :sql:`utf8mb4`
charset for :sql:`VARCHAR()` columns, storage and index calculations need to be
multiplied by four (4). For example, a :sql:`VARCHAR(20)` can take up to eighty
(80) *bytes* since each of the twenty (20) *characters* can use up to four (4)
*bytes*. In contrast, a :sql:`VARCHAR(20)` in a :sql:`latin1` column will consume
only twenty (20) *bytes*, as each *character* is only one byte long.
The TYPO3 Core may set individual columns to a charset like :sql:`latin1` in the
future, which will optimize storage for ASCII-character only columns, but most
content-related columns should be :sql:`utf8mb4` to avoid issues with
multi-byte characters.
Note that column types that do not store characters (like :sql:`INT`) do not have
a charset. An overview of current charsets can be retrieved:
.. code-block:: sql
# Default charset of the database, new tables use this charset when no
# explicit charset is given with a "CREATE TABLE" statement:
SELECT `SCHEMA_NAME`, `DEFAULT_CHARACTER_SET_NAME` FROM `INFORMATION_SCHEMA`.`SCHEMATA`
WHERE `SCHEMA_NAME`='my_database';
# Default charset of a table, new columns use this charset when no
# explicit charset is given with a "ALTER TABLE" statement:
SELECT `table`.`table_name`,`charset`.`character_set_name`
FROM `information_schema`.`TABLES` AS `table`,`information_schema`.`COLLATION_CHARACTER_SET_APPLICABILITY` AS `charset`
WHERE `charset`.`collation_name`=`table`.`table_collation`
AND `table`.`table_schema`='my_database'
AND `table`.`table_name`='tt_content';
# List table columns, their column types with length and selected charsets:
SELECT `column_name`,`column_type`,`character_set_name`
FROM `information_schema`.`COLUMNS`
WHERE `table_schema`='my_database'
AND `table_name`='tt_content';
Ensure innodb_page_size is 16384
................................
Few instances modify the MySQL / MariaDB :sql:`innodb_page_size` system variable,
and it is advisable to keep the default value of :sql:`16384`. Verify the
current value:
.. code-block:: sql
SHOW variables WHERE `Variable_name`='innodb_page_size';
Row size too large
------------------
This document now assumes that MySQL / MariaDB is used, the table in question
uses the :sql:`InnoDB` storage engine with :sql:`Dynamic` row format (please
check :guilabel:`Admin Tools > Maintenance > Analyze Database Structure` which
provides automatic migrations), :sql:`innodb_page_size` default :sql:`16384` is
set, and that a system maintainer is aware of specific column charsets.
Error "Row size too large 65535"
--------------------------------
.. code-block:: plaintext
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type,
not counting BLOBs, is 65535. This includes storage overhead, check the manual. You
have to change some columns to TEXT or BLOBs
Explanation
...........
When altering the database schema of a table, such as adding or increasing the
size of a :sql:`VARCHAR` column, the above error might occur.
Note the statement: "The maximum row size [...] is 65535".
MySQL / MariaDB impose a global maximum size per table row of 65kB. The combined
length of all column types contribute to this limit, except for :sql:`TEXT` and
:sql:`BLOB` types, which are stored "off row" where only a "pointer" to the actual
storage location counts.
However, standard :sql:`VARCHAR` fields contribute their full maximum byte length
towards this 65kB limit. For instance, a :sql:`VARCHAR(2048)` column with the
:sql:`utf8mb4` character set (4 bytes per character) requires 4 * 2048 = 8192 bytes.
Therefore, only 65535 - 8192 = 57343 bytes remain available for the storage
of all other table columns.
As another example, consider the query below which creates a table with
a :sql:`VARCHAR(16383)` column alongside an :sql:`INT` column:
.. code-block:: sql
# ERROR 1118 (42000): Row size too large. The maximum row size [...] is 65535
CREATE TABLE test (c1 varchar(16383), c2 int) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Let's break down the calculation:
.. code-block:: plaintext
varchar 16383 characters = 16383 * 4 bytes = 65532 bytes
int = 4 bytes
Total: 65532 + 4 = 65536 bytes
This exceeds the maximum limit by one byte, causing the query to fail.
Mitigation
..........
The primary strategy to mitigate the 65kB limit is to minimize the use of
lengthy :sql:`VARCHAR` columns.
For instance, in the :sql:`tt_content` table of a default Core instance, there
are approximately a dozen :sql:`VARCHAR(255)` columns, totaling about 12kB,
alongside smaller :sql:`INT` and similar fields. This leaves ample
room for additional custom :sql:`VARCHAR()` columns.
TYPO3 v13 has introduced improvements in two key areas:
Firstly, TCA fields with :php:`type='link'` and :php:`type='slug'` have been
converted from :sql:`VARCHAR(2048)` (requiring 8kB of row space) to :sql:`TEXT`.
The :sql:`tt_content` table was affected by this change in at least one
column (:sql:`header_link`). This adjustment provides more space by default for
custom columns.
Additionally, the TYPO3 Core now defaults to using :sql:`TEXT` instead of
:sql:`VARCHAR()` for TCA fields with :php:`type='input'` when the TCA property
:php:`max` is set to a value greater than :php:`255` and extension authors utilize
the :ref:`column auto creation feature <feature-101553-1691166389>`.
Instances encountering the 65kB limit can consider adjusting fields with these
considerations in mind:
* Priority should be given to reconsidering long :sql:`VARCHAR()` columns first.
Changing a single :sql:`utf8mb4` :sql:`VARCHAR(2048)` column to :sql:`TEXT`
can free enough space for up to eight (8) :sql:`utf8mb4` :sql:`VARCHAR(255)`
columns.
* Consider reducing the length of :sql:`VARCHAR()` columns. For instance, columns
containing database table or column names can be limited to :sql:`VARCHAR(64)`,
as MySQL / MariaDB restricts table and column names to a maximum of 64 characters.
Similar considerations apply to "short" content fields, such as a column storing
an author's name or similar potentially limited length information.
However, be cautious, as setting :sql:`VARCHAR()` columns to "too short" lengths
may impose a different limit, as discussed below.
* Consider removing entries from :file:`ext_tables.sql` with TYPO3 Core v13: the
:ref:`column auto creation feature <feature-101553-1691166389>` generally provides
better-defined column definitions and ensures columns stay synchronized with TCA
definitions automatically. The TYPO3 Core aims to provide sensible default
definitions, often superior to a potentially imprecise definition by extension
authors.
* Note that individual column definitions in :file:`ext_tables.sql` always override
TYPO3 Core v13's column auto creation feature. In rare cases where TYPO3
Core's definition is inappropriate, extension authors can always override these
details.
* Note :sql:`utf8mb4` :sql:`VARCHAR(255)` and :sql:`TINYTEXT` are *not* the same:
a :sql:`VARCHAR(255)` size limit is 255 *characters*, while a :sql:`TINYTEXT`
is 255 *bytes*. The proper substitution for a (4 bytes per character) :sql:`utf8mb4`
:sql:`VARCHAR(255)` field is :sql:`TEXT`, which allows for 65535 bytes.
* :sql:`TEXT` *may* negatively impact performance as it forces additional
Input/Output operations in the database. This is typically not a significant issue
with standard TYPO3 queries, as various other operations in TYPO3 have a greater
impact on overall performance. However, indiscriminately changing all fields from
:sql:`VARCHAR()` to :sql:`TEXT` or similar is *not* advisable.
* Be mindful of indices. When :sql:`VARCHAR()` columns that are part of an index
are changed to :sql:`TEXT` or similar, these indexes may require adjustment.
Ensure they are properly restricted in length to avoid a "Specified key was too long"
error. The :sql:`InnoDB` key length limit with row format :sql:`Dynamic` is 3072
*bytes* (not *characters*). In general, indexes on :sql:`VARCHAR()` and all other
"longish" columns should be set with care and only if really needed since long
indexes can negatively impact database performance as well, especially when a
table has many write operations in production.
Error "Row size too large (> 8126)"
-----------------------------------
.. code-block:: plaintext
ERROR 1118 (42000): Row size too large (> 8126). Changing some columns to TEXT
or BLOB may help. In current row format, BLOB prefix of 0 bytes is stored inline.
Sometimes there is also an error similar to this in MySQL / MariaDB logs:
.. code-block:: plaintext
[Warning] InnoDB: Cannot add field col1 in table db1.tab because after adding it,
the row size is 8478 which is greater than maximum allowed size (8126) for a record
on index leaf page.
Explanation
...........
This error may occur when adding or updating table rows, not only when altering table
schema.
Note the statement: "Row size too large (> 8126)". This differs from the
previous error message. This error is *not* about a general row size limit of
65535 bytes, but a limit imposed by InnoDB tables.
The root cause is that InnoDB has a maximum row size equivalent to half of the
:sql:`innodb_page_size` system variable value of 16384 bytes, which is 8192 bytes.
InnoDB mitigates this by storing certain variable-length columns on "overflow pages".
The decision regarding which columns are *actually* stored on overflow pages is made
dynamically when adding or changing rows. This is why the error can be raised at
runtime and not only when altering the schema. Additionally, it makes accurately
predicting whether the error will occur challenging. Furthermore, not all variable-length
columns *can* be stored on overflow pages. This is why the error can be raised when
altering table schema.
Variable-length columns of type :sql:`TEXT` and :sql:`BLOB` can always be stored on
overflow pages, thus minimally impacting the main data page limit of 8192 bytes.
However, :sql:`VARCHAR` columns can only be stored on overflow pages if their maximum
length exceeds 255 *bytes*. Therefore, an unexpected solution to the "Row size too
large 8192" error in many cases is to increase the length of some variable-length
columns, enabling InnoDB to store them on overflow pages.
Mitigation
..........
TYPO3 Core v13 has modified several default columns to mitigate the issue for instances
with many custom columns. The TYPO3 Core maintainers expect this issue to occur
infrequently in practice.
Instances encountering the 8192 bytes limit can consider adjusting fields with these
considerations in mind:
* The calculation determining if a column can be stored on overflow pages is based
on a minimum of 256 *bytes*, not *characters*. A typical :sql:`utf8mb4`
:sql:`VARCHAR(255)` equates to 1020 bytes, which *can* be stored on overflow pages.
Changing such fields makes no difference.
* Changing a :sql:`utf8mb4` :sql:`VARCHAR(63)` (or smaller) to :sql:`VARCHAR(64)`
(64 characters utf8mb4 = 256 bytes) allows this column to be stored on overflow
pages and *does* make a difference.
* Changing a :sql:`utf8mb4` :sql:`VARCHAR(63)` (or smaller) to :sql:`TINYTEXT`
should allow this column to be stored on overflow pages as well. However, this
may not be the optimal solution due to potential performance penalties, as
discussed earlier. Similarly, indiscriminately increasing the length of
multiple variable-length columns is not advisable. Columns should ideally be
kept as small as possible, only exceeding the 255-byte limit or converting to
:sql:`TEXT` types if absolutely necessary. Also, refer to the note on indexes
above when single columns are part of indexes.
* Columns using :sql:`utf8mb4` that are smaller or equal to :sql:`VARCHAR(63)`
and only store ASCII characters can be downsized by changing the charset to
:sql:`latin1`. For instance, a :sql:`VARCHAR(60)` column occupies 4 * 60 = 240
bytes in row size, but only 60 bytes when using the :sql:`latin1` charset.
Currently, TYPO3 Core does not interpret charset definitions for individual
columns from :sql:`ext_tables.sql`. The Core Team anticipates implementing
this feature in the future.
* Note that increasing the length of :sql:`VARCHAR` columns can potentially
conflict with the 65kB limit mentioned earlier. This is another reason to
avoid indiscriminately increasing the length of variable-length columns.
Further reading
---------------
This document is based on information from database vendors and other sites
found online. The following links may provide further insights:
* `(MariaDB) InnoDB Row Formats Overview <https://mariadb.com/kb/en/innodb-row-formats-overview/>`_
* `(MariaDB) Troubleshooting Row Size Too Large Errors with InnoDB <https://mariadb.com/kb/en/troubleshooting-row-size-too-large-errors-with-innodb/>`_
* `(Contao) MySQL Row size too large <https://github.com/contao/contao/issues/4159>`_
Final words
-----------
Navigating the two limits in MySQL / MariaDB requires a deep understanding of
database engine internals to manage them effectively. The TYPO3 Core Team is
confident that version 13 has effectively mitigated the issue, ensuring that
typical instances will rarely encounter it. We trust this document remains
helpful and welcome any feedback in case something crucial has been overlooked.
.. index:: Database, ext:core
+52
View File
@@ -0,0 +1,52 @@
:template: changelogOverview.html
.. include:: /Includes.rst.txt
.. _changelog-13-2:
============
13.2 Changes
============
.. contents:: Table of contents
:local:
:depth: 1
Breaking Changes
================
None since TYPO3 v13.0 release.
.. attention::
After TYPO3 v13.0, only new functionality with a solid migration path
can be added on top, aiming for as few as possible breaking changes
after the initial v13.0 release on the way to LTS.
Features
========
.. toctree::
:maxdepth: 1
:titlesonly:
:glob:
Feature-*
Deprecation
===========
.. toctree::
:maxdepth: 1
:titlesonly:
:glob:
Deprecation-*
Important
=========
.. toctree::
:maxdepth: 1
:titlesonly:
:glob:
Important-*