The default value of the fields imagewidth and imageheight of the
tt_content table is now null. This removes the awkward UI behavior of the
fields being set to 0 if no value is entered.
Impact
Custom queries might fail if they expect the fields to be 0 instead of null.
Affected installations
TYPO3 installation relying on fields imagewidth and imageheight of the
tt_content table being always an integer.
Migration
Use the "Media fields zero to null" upgrade wizard to update the field values.
Also modify your queries to handle null values instead of 0.
Breaking: #85323 - Move GET parameters in sitemap into namespace
The names of the GET parameters used in the sitemap generated by EXT:seo have
been changed from page and sitemap to tx_seo[page] and tx_seo[sitemap]
respectively.
Impact
Applications, routing configuration and 3rd party tools that rely on the parameters being named page and sitemap break.
Affected installations
This affects installations, which use the arguments page and sitemap or
override the sitemap templates of EXT:seo.
Migration
In case the arguments are mapped in the routing configuration, the code needs to
be slightly adopted. A working example issue
The backend sub-module "Database Relations" within "DB Check" aims to provide
information about potentially broken database relations.
The information it gives is really sparse and barely helpful, also the whole
module and its code received no meaningful updates in the past.
Due to this, the module has been removed.
Impact
The module has been removed. Links and stored bookmarks will not work anymore.
When using the PHP API of File Abstraction Layer, there are several classes
involved representing a File Object.
Next to the
FileInterface there is also the
AbstractFile class,
where most classes extend from when representing a File.
However, in order to ensure proper code strictness, the Abstract class does
not implement the methods
getIdentifier() and
setIdentifier()
anymore, as this is indeed part of the subclasses' job.
They are now implemented in the respective classes inheriting from
AbstractFile.
Impact
In an unlikely case that the TYPO3's File Abstraction Layer is extended by
adding custom PHP classes extending from AbstractFile, this will result in a
fatal PHP error, as the new abstract methods
getIdentifier() and
setIdentifier() are not implemented.
Affected installations
TYPO3 installations with a custom File Abstraction Layer code extending the
actual file abstraction layer, which is highly unlikely.
Migration
Implement the two methods
getIdentifier() and
setIdentifier() in
the custom File class extending
AbstractFile.
This can also be done in previous TYPO3 versions to make the code ready for
multiple TYPO3 versions.
Breaking: #103910 - Change logout handling in ext:felogin
The logout handling has been adjusted to correctly dispatch the PSR-14 event
LogoutConfirmedEvent when a logout redirect is configured. The
actionUri variable has been removed, and the logout template has been
updated to reflect the change, including the correct use of the
noredirect functionality.
Impact
The PSR-14 event LogoutConfirmedEvent is now correctly dispatched, when a
logout redirect is configured. Additionally, the
noredirect parameter
is now evaluated on logout.
Affected installations
Websites using ext:felogin with a custom Fluid template for the logout form.
Migration
The
{actionUri} variable is not available any more and should be removed
from the template.
// Before
<f:formaction="login"actionUri="{actionUri}"target="_top"fieldNamePrefix="">
// After
<f:formaction="login"target="_top"fieldNamePrefix="">
Copied!
The evaluation of the
noRedirect variable must be added to the template.
// Before
<divclass="felogin-hidden"><f:form.hiddenname="logintype"value="logout"/></div>
// After
<divclass="felogin-hidden"><f:form.hiddenname="logintype"value="logout"/><f:ifcondition="{noRedirect}!=''"><f:form.hiddenname="noredirect"value="1" /></f:if></div>
Copied!
Breaking: #103913 - Do not perform redirect in ext:felogin logoutAction
Redirect handling for the
logoutAction has been removed.
Impact
The
logoutAction will not perform a possible configured redirect via
plugin or GET parameter.
Affected installations
TYPO3 installation relying on redirect handling in
logoutAction.
Migration
There is no migration path, since the redirect handling in the
logoutAction was wrong and possible configured redirects were already
correctly handled via loginAction and overviewAction.
The following methods changed signature according to previous deprecations in v13 at the end of the argument list:
\TYPO3\CMS\Backend\View\BackendLayout\DataProviderContext->__construct() - All arguments are now mandatory (Deprecation entry)
\TYPO3\CMS\Core\Imaging\IconFactory->getIcon() (argument 4 is now of type
\TYPO3\CMS\Core\Imaging\IconState|null) (Deprecation entry)
\TYPO3\CMS\Core\Resource\AbstractFile->copyTo() (argument 3 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\AbstractFile->moveTo() (argument 3 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\AbstractFile->rename() (argument 2 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\FileInterface->rename() (argument 2 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\FileReference->rename() (argument 2 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\Folder->addFile() (argument 3 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\Folder->addUploadedFile() (argument 2 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\Folder->copyTo() (argument 3 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\Folder->moveTo() (argument 3 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\InaccessibleFolder->addFile() (argument 3 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\InaccessibleFolder->addUploadedFile() (argument 2 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\InaccessibleFolder->copyTo() (argument 3 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\InaccessibleFolder->moveTo() (argument 3 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\ResourceStorage->addFile() (argument 4 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\ResourceStorage->addUploadedFile() (argument 4 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\ResourceStorage->copyFile() (argument 4 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\ResourceStorage->copyFolder() (argument 4 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\ResourceStorage->moveFile() (argument 4 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\ResourceStorage->moveFolder() (argument 4 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Resource\ResourceStorage->renameFile() (argument 3 is now of type
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior ) (Deprecation entry)
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPlugin() (argument 2
$type and 3
$extensionKey have been dropped) (Deprecation entry)
The following public class properties have been dropped:
$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['SecondDatabase']['driverMiddlewares']['driver-middleware-identifier']
must be an array, not a class string (Deprecation entry)
Accepting arrays returned by
readFileContent() in Indexed Search external parsers (Deprecation entry)
Allowing instantiation of
\TYPO3\CMS\Core\Imaging\IconRegistry in ext_localconf.php (Deprecation entry)
Accepting a comma-separated list of fields as value for the columnsOnly parameter (Deprecation entry)
Support for extbase repository magic
findByX(),
findOneByX() and
countByX() methods (Deprecation entry)
Fluid view helpers that extend
\TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormFieldViewHelper
should no longer register
class attribute and should rely on attribute auto registration
for the error class to be added correctly. (Deprecation entry)
The legacy backend entry point typo3/index.php has been removed along with handling of composer.json
setting extra.typo3/cms.install-deprecated-typo3-index-php(Deprecation entry)
The following upgrade wizards have been removed:
Install extension "fe_login_mode" from TER
Migrate base and path to the new identifier property of the "sys_filemounts" table
Migrate site settings to separate file
Set workspace records in table "sys_template" to deleted
Migrate backend user and groups to new module names
Migrate backend groups "explicit_allowdeny" field to simplified format
Migrate sys_log entries to a JSON formatted value
Migrate storage and folder to the new folder_identifier property of the "sys_file_collection" table
The following database table fields have been removed:
The following JavaScript method behaviours have changed:
FormEngineValidation.markFieldAsChanged() always requires
HTMLInputElement|HTMLTextAreaElement|HTMLSelectElement to be passed as first argument (Deprecation entry)
FormEngineValidation.validateField() always requires
HTMLInputElement|HTMLTextAreaElement|HTMLSelectElement to be passed as first argument (Deprecation entry)
The following JavaScript method has been removed:
updateQueryStringParameter() of
@typo3/backend/utility.js(Deprecation entry)
The following smooth migration for JavaScript modules have been removed:
@typo3/backend/page-tree/page-tree-element to
@typo3/backend/tree/page-tree-element(Deprecation entry)
The following localization XLIFF files have been removed:
The
DataHandler PHP API has been
extended to support qualified and unqualified ISO8601 date formats in order to
correctly process supplied timezone offsets, if supplied.
Qualified ISO8601: Includes an explicit timezone offset (e.g.,
1999-12-11T10:09:00+01:00 or 1999-12-11T10:09:00Z)
Previously, TYPO3 incorrectly used qualified ISO8601 with Z (UTC+00:00) to
denote "LOCALTIME" and applied the server's timezone offset, leading to
misinterpretations when any other timezone offset was given, or if real UTC-0
was intended instead of LOCALTIME. Now, timezone offsets are accurately applied
if supplied and based on server localtime if omitted.
TYPO3 will internally use unqualified ISO8601 dates for communication between
FormEngine and DataHandler API from now on, allowing to correctly process
timezone offsets – instead of shifting them – if supplied to the
DataHandler PHP API.
In essence this means that existing workarounds for the previously applied
timezone offsets need to be revised and removed.
Impact
TYPO3 now provides accurate and consistent handling of ISO8601 dates,
eliminating previous issues related to timezone interpretation and LOCALTIME
representation.
Affected installations
Installations with custom TYPO3 extensions that invoke
DataHandler API with data for
type="datetime" fields.
Migration
Qualified ISO8601 dates with intended timezone offsets, and \DateTimeInterface
objects can now be passed directly to the
DataHandler without requiring manual
timezone adjustments.
Example for a previous workaround timezone offsets for DataHandler:
Passing datetime data via DataHandler PHP API
$myDate = new \DateTime('yesterday');
$this->dataHandler->start([
'tx_myextension_mytable' => [
'NEW-1' => [
'pid' => 2,
// A previous workaround add localtime offset to supplied dates,// as it was subtracted by DataHandler persistence layer'mydatefield_1' => gmdate('c', $myDate->getTimestamp() + (int)date('Z')),
],
],
]);
Copied!
Previous timezone shifting workarounds can be removed and replaced by intuitive
formats.
Passing datetime data via DataHandler PHP API
$myDate = new \DateTime('yesterday');
$this->dataHandler->start([
'tx_myextension_mytable' => [
'NEW-1' => [
'pid' => 2,
// pass \DateTimeInterface object directly'mydatefield_1' => $myDate,
// format as LOCALTIME'mydatefield_2' => $myDate->format('Y-m-dTH:i:s'),
// format with timezone information// (offsets will be normalized to persistence timezone format,// UTC for integer fields, LOCALTIME for native DATETIME fields)'mydatefield_3' => $myDate->format('c'),
],
],
]);
Copied!
Breaking: #105686 - Avoid obsolete $charset in sanitizeFileName()
Classes implementing the interface no longer need to take care of
a second argument.
Impact
This most likely has little to no impact since the main API caller,
the core class
ResourceStorage never hands over the second
argument. Default implementing class
\TYPO3\CMS\Core\Resource\Driver\LocalDriver
thus always fell back as if handling utf-8 strings.
Affected installations
Projects with instances implementing own FAL drivers using
DriverInterface
may be affected.
Migration
Implementing classes should drop support for the second argument. It does
not collide with the interface if the second argument is kept, but core
code will never call method
sanitizeFileName() with handing over
a value for a second argument.
This removes most helper methods that implemented conversions between different
charsets from the core codebase: The vast majority of web sites is based
on utf-8 nowadays and needs no expensive conversion provided as core
framework functionality anymore.
Impact
Calling one of the above methods will raise fatal PHP errors.
Affected installations
The core does not surface any of this removed low level functionality in upper
layers like TypoScript for a while already. The removed methods should have little
to no impact to casual instances. The only use cases that may be affected are
probably import and export extensions that had to convert between nowadays rather
obscure character sets like those of the EUC family. Affected extensions could
mitigate the removal by copying the TYPO3 v13 version of class
CharsetConverter
including affected files from core/Resources/Private/Charsets/csconvtbl/ to
their own codebase. The extension scanner will find usages and classify as weak match.
Migration
Avoid calling above methods. Extensions that still need above functionality should
copy consumed functionality to their own codebase, or use some third party library.
This detail has a direct substitution:
// Before
$charsetConverter->specCharsToASCII('utf-8', $myString);
// After
$charsetConverter->utf8_char_mapping($myString);
Copied!
Breaking: #105728 - Extbase backend modules not in page context rely on global TypoScript only
Configuration of extbase based backend modules can be done using frontend TypoScript.
The standard prefix in TypoScript to do this is
module.tx_myextension, extbase backend
module controllers can typically retrieve their configuration using a call like
$configuration = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS, 'myextension');.
TypoScript itself is always bound to a page: In the frontend, there must be either some rootline page with
a sys_template record, or a page that has a site set. The frontend rendering will otherwise bail out with
an error message.
Extbase based backend modules are sometimes bound to pages as well: They can have a rendered page tree
configured by their module configuration, and then receive the selected page uid within the request as GET parameter
id.
Other extbase based backend modules however are not within page scope and do not render the page tree. Examples of such
modules within the core are the backend modules delivered by the form and beuser extension.
Such extbase based backend without page tree modules had a hard time to calculate their relevant frontend TypoScript
based configuration: Since TypoScript is bound to pages, they looked for "the first" valid page in the page
tree, and the first valid sys_template record to calculate their TypoScript configuration. This dependency
and guesswork made final configuration of extbase backend module configuration not in page context brittle,
intransparent and clumsy.
TYPO3 v14 puts an end to this: Extbase backend modules without page context compile their TypoScript configuration
from "global" TypoScript only and stop calculating TypoScript from guessing "the first valid" page.
The key call to register such "global" TypoScript is
ExtensionManagementUtility::addTypoScriptSetup() in
ext_localconf.php files.
Impact
Configuration of extbase based backend modules may change if their configuration is defined by the first
given valid page in the page tree. Configuration of such backend modules can no longer be changed by including
TypoScript on the "first valid" page.
Affected installations
Instances with extbase based backend modules without page tree may be affected.
Migration
Configuration of extbase based backend modules without page tree must be supplied programmatically
and "made global" by extending
$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup']
using
ExtensionManagementUtility::addTypoScriptSetup() within extensions
ext_localconf.php files. The backend module of the form extension is a good example.
Additional locations of extensions that deliver form yaml definitions are defined like this:
Note it is also possible to use
ExtensionManagementUtility::addTypoScriptConstants()
to declare "global" TypoScrip constants, and to use them in above TypoScript.
Breaking: #105733 - FileNameValidator no longer accepts custom regex in __construct()
Class
\TYPO3\CMS\Core\Resource\Security\FileNameValidator does not handle
a custom file deny pattern in
__construct() anymore. The service is now
stateless and can be injected without side effects.
Impact
A custom partial regex as first constructor argument when instantiating the
service is ignored. The service relies on
$GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern']
configuration, and a hard coded constant as fallback.
Affected installations
Instances with custom extensions using
GeneralUtility::makeInstance(FileNameValidator::class, 'some-custom-pattern');
are affected. This is most likely a very rare case.
Migration
Extensions that need to test with custom patterns that can not be declared
globally using
$GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern']
should probably switch to an own service implementing the test, or inline
the code. The main worker code of the service is just four lines of code.
The event
\TYPO3\CMS\Core\Mail\Event\AfterMailerInitializationEvent
has been removed. This event became useless with the introduction of the symfony
based mailer in TYPO3 v10 and was only able to influence the core handling by
calling the
@internal marked method
injectMailSettings()after the
settings have already been determined within the core mailer. The event has been
removed since it did not fit a useful use case anymore.
Impact
Event listeners registered for this event will no longer be triggered.
Affected installations
This event did not fit much purpose since the switch to the symfony based
mailer anymore and is probably not used in many instances. The extension
scanner will find usages.
Migration
Check if this event could be substituted by reconfiguring
$GLOBALS['TYPO3_CONF_VARS']['MAIL'] , or by listening on
\TYPO3\CMS\Core\Mail\Event\BeforeMailerSentMessageEvent event instead.
Breaking: #105855 - Remove file backwards compatibility for alt and link field
Back then, when FAL was introduced, the Core file fields media for table
pages as well as image and assets for table tt_content had their
so-called "overlay palettes" overridden to imageOverlayPalette, so that
additional fields like alternative, link and crop were displayed. However,
this was done for all file types, including text, application and the
fallback type unknown. For these types those additional fields serve no
meaningful purpose. For this reason they are now removed.
Impact
The Core file fields media for table pages as well as image and assets
for table tt_content will no longer display the fields alternative and
link for file types other than image.
Affected installations
This affects installations, which use one of the named Core fields for file
types other than image (for example text or application) and make use of
the fields alternative and/or link.
This should not affect that many installations, as these fields are used most
often for images.
Migration
In case you need those fields back, they can be brought back with TCA overrides.
First, register a new palette for the sys_file_reference table with the needed
set of fields.
Then, use this palette for your specific Core field and file type. This will
bring back the fields alternative and link for the media field of table
pages, when the file type is text.
The TypoScript setting
exposeNonexistentUserInForgotPasswordDialog has been
removed in ext:felogin.
Impact
Using the TypoScript setting
exposeNonexistentUserInForgotPasswordDialog has
no effect any more and the password recovery process in ext:felogin now always
shows the same message, when either a username or email address is submitted in
the password recovery form.
Affected installations
Websites using the TypoScript setting
exposeNonexistentUserInForgotPasswordDialog
for ext:felogin.
Migration
The setting has been removed without a replacement. It is possible to use the
PSR-14 event
\TYPO3\CMS\FrontendLogin\Event\SendRecoveryEmailEvent to
implement a similar functionality if really needed. From a security perspective,
it is however highly recommended to not expose the existence of email addresses
or usernames.
An exception handling detail within FAL/Resource handling has been changed: When
calling
getSubFolder('mySubFolderName') on a
\TYPO3\CMS\Core\Resource\Folder
object, and if this sub folder does not exist, the specific
\TYPO3\CMS\Core\Resource\Exception\FolderDoesNotExistException is now raised
instead of the global
\InvalidArgumentException.
Impact
The change may have impact on extensions that directly or indirectly call
Folder->getSubFolder() and expect a
\InvalidArgumentException
to be thrown.
Affected installations
FolderDoesNotExistException does not extend
\InvalidArgumentException.
Code that currently expects a
\InvalidArgumentException to be thrown, needs
adaption.
Migration
The change is breaking for code that takes an "optimistic" approach like
"get the sub folder object, and if this throws, create one". Example:
This should be changed to catch a
FolderDoesNotExistException instead:
Extensions that need to stay compatible with both TYPO3 v13 and v14 should catch
both exceptions and should later avoid catching
\InvalidArgumentException
when v13 compatibility is dropped:
Extbase had the TypoScript toggle
config.tx_extbase.persistence.updateReferenceIndex
whether the reference index shall be updated when records are persisted.
It becomes more and more important the reference index is always up to date since
an increasing number of core code relies on current reference index data. Using
the reference index at key places can improve read and rendering performance
significantly.
This toggle has been removed, reference index updating is now always enabled.
Impact
The change may increase database load slightly which may become noticeable when
Extbase changes many records at once.
Affected installations
Instances with extensions writing many records using the Extbase persistence layer
may be affected.
Migration
TypoScript toggle
config.tx_extbase.persistence.updateReferenceIndex
should be removed from any extensions codebase, it is ignored by Extbase.
Breaking: #106056 - Add setRequest and getRequest to extbase ValidatorInterface
Custom validators implementing
\TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface must now
implement the methods
setRequest() and
getRequest().
Impact
Missing implementation of the methods
setRequest() and
getRequest() will now result in a PHP fatal error.
The methods
setRequest() and
getRequest() must be implemented in
affected validators.
If no direct implementation of
\TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface is required,
it is recommended to extend
\TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator ,
where both methods already are implemented.
Public property
TYPO3\CMS\Core\DataHandling\DataHandler->storeLogMessages
has been removed without substitution. It should not be used by extensions anymore.
Impact
Setting or reading the property in extension raises a PHP warning level error.
Affected installations
Instances with extensions dealing with the property. This should be a very rare
use case, no TER extension was affected when looking this up. The extension scanner
is configured to find usages as weak match.
Migration
The property has been removed, setting or reading it from
DataHandler instances
should be removed. The
DataHandler->log() method now always writes given
$details to table
sys_log.
Breaking: #106412 - TCA interface settings for list view removed
Each TCA definition has had an optional entry named interface to define
relevant information for displaying the TCA records.
The TCA options
['interface']['maxSingleDBListItems'] and
['interface']['maxDBListItems'] are removed and not evaluated anymore.
These options have been used for defining the amount of table rows to show
within TYPO3's Web>List module.
Impact
Setting these values in custom extensions will have no effect anymore, as they
are automatically removed during build-time.
Affected installations
TYPO3 installations with custom TCA settings from third-party-extensions.
Migration
Overriding visual settings can still be done on a per - User TSconfig or
per - Page TSconfig level, which is much more flexible anyways, as it allows
for rendering different amount of values per site / pagetree or usergroup.
The TCA option
['interface']['maxSingleDBListItems'] is removed in
favor of
mod.web_list.itemsLimitSingleTable.
The TCA option php:['interface']['maxDBListItems']is removed in
favor of
mod.web_list.itemsLimitPerTable.
Breaking: #106427 - File Abstraction Layer related changes
In TYPO3 v14, the PHP code API for the File Abstraction Layer (FAL) has undergone
some major changes, which might affect extension authors:
Most PHP code from FAL is now strongly typed by PHP native typing system
Some methods have been moved from
AbstractFile to its concrete
implementation within
File as other derivatives should implement
this on their own. The moved methods are:
-
AbstractFile->rename()
-
AbstractFile->copyTo()
-
AbstractFile->moveTo()
The
FileInterface's method
rename() has been removed as it
is only necessary within the implementation of
File.
Classes implementing
FolderInterface must now implement
FolderInterface::getSubFolder(),
FolderInterface::getReadablePath()
as well as
FolderInterface::getFiles() and
FolderInterface::searchFiles()
to be interchangeable with the new
Folder class.
In previous implementations this was not possible to make Folder more
interchangeable but this is a first step towards that process.
Impact
Calling the PHP classes and methods from File Abstraction Layer directly might
result in fatal PHP errors due to specific types required as method arguments.
Affected installations
TYPO3 installations with third-party extensions that have used FAL API in a
non-documented way.
Migration
Ensure to hand in or expect proper PHP types when using or extending FAL API.
In addition, ensure to implement the new methods in your own
Folder
implementations or derivatives of
AbstractFile.
Breaking: #106503 - Removal of field from sys_file_metadata
The following database fields and TCA definitions have been removed from the DB table sys_file_metadata without substitution:
visible
fe_groups
These fields are added to the DB table when the system extension filemetadata is installed.
Both fields seemed like being fields known from any other table which restrict access to the content but they have never been
configured so, which is also depending on the use-case and not possible from TYPO3 Core usages.
Additionally, the field status has been moved from the tab Access to Metadata to avoid the notion that this field has
any restrictive behaviour.
Impact
The fields visible and fe_groups of the database table sys_file_metadata are not used anymore. After a Database Compare
in the Install Tool, the columns are removed and its content lost. When accessing the DB fields via PHP or TypoScript,
a PHP warning might exist.
Affected installations
Any TYPO3 installation using the mentioned fields by having EXT:filemetadata installed.
Migration
No migration is available.
If the fields are in use, it is recommended to re-add the TCA definitions in a custom extension.
Feature: #92760 - Configurable timezone for DateViewHelper
A new PSR-14 event
\TYPO3\CMS\Backend\Search\Event\BeforeLiveSearchFormIsBuiltEvent
has been added.
To modify the live search form data, the following methods are available:
addHint(): Add a single hint.
addHints(): Add one or multiple hints.
setHints(): Allows to set hints. Can be used to reset or overwrite current hints.
getHints(): Returns all hints.
getRequest(): Returns the current PSR-7 Request.
getSearchDemand(): Returns the
SearchDemand, used by the live search.
setSearchDemand(): Allows to set a custom
SearchDemand object.
:php:`getAdditionalViewData(): Returns the additional view data set to be used in the template.
:php:`setAdditionalViewData(): Set the additional view data to be used in the template.
Note
setAdditionalViewData() becomes handy to provide additional data to
the template without the need to cross class ("xclass") the controller. The
additional view data can be used in a overridden backend template of the
live search form.
A new TCA field type called
country has been added to TYPO3 Core. Its main
purpose is to use the newly introduced
Country API to provide
a country selection in the backend and use the stored representation in Extbase
or TypoScript output.
TCA Configuration
The new TCA type displays all filtered countries including the configurable name and the corresponding flag.
Configuration/TCA/tx_myextension_mymodel.php
'country' => [
'label' => 'Country',
'config' => [
'type' => 'country',
// available options: name, localizedName, officialName, localizedOfficialName, iso2, iso3'labelField' => 'localizedName',
// countries which are listed before all others'prioritizedCountries' => ['AT', 'CH'],
// sort by the label'sortItems' => [
'label' => 'asc'
],
'filter' => [
// restrict to the given country ISO2 or ISO3 codes'onlyCountries' => ['DE', 'AT', 'CH', 'FR', 'IT', 'HU', 'US', 'GR', 'ES'],
// exclude by the given country ISO2 or ISO3 codes'excludeCountries' => ['DE', 'ES'],
],
'default' => 'HU',
// When required=false, an empty selection ('') is possible'required' => false,
],
],
required (bool) - whether an empty selection can be made or not
Extbase usage
When using Extbase Controllers to fetch Domain Models containing
properties declared with the
Country type, these models
can be used with their usual getters, and passed along to Fluid
templates as usual.
usePsr\Http\Message\ResponseInterface;
useTYPO3\CMS\Extbase\Mvc\Controller\ActionController;
useTYPO3\CMS\Core\Country\Country;
classItemControllerextendsActionController{
// ...publicfunction__construct(
private readonly CountryProvider $countryProvider,
){}
publicfunctionsingleAction(SomeDomainModel $model): ResponseInterface{
// Do something in PHP, using the Country APIif ($model->getCountry()->getAlpha2IsoCode() == 'DE') {
$this->loadGermanLanguage();
}
$this->view->assign('model', $model);
// You can access the `CountryProvider` API for additional country-related// operations, too (ideally use Dependency Injection for this):$this->view->assign('countries', $this->countryProvider->getAll());
return$this->htmlResponse();
}
}
You can use any of the
getXXX() methods available from
the Country API via
the Fluid
{model.country.XXX} accessors.
If you use common Extbase CRUD (Create/Read/Update/Delete) with models using
a Country type, you can utilize the existing
ViewHelper f:form.countrySelect within
your <f:form> logic.
Please keep in mind that Extbase by default has no coupling (in terms of validation)
to definitions made in the TCA for the properties, as with other types like
file uploads or select items.
That means, if you restrict the allowed countries via filter.onlyCountries on
the backend (TCA) side, you also need to enforce this in the frontend.
It is recommended to use
Extbase Validators
for this task. If you want to share frontend-based validation and TCA-based
validation non-redundantly, you could use data objects (DO/DTO) or ENUMs for returning
the list of allowed countries:
The type
Country does not point to a real Extbase model, and thus has no inherent
localization or query-logic based on real records. It is just a pure
PHP data object with some getters, and a magic
__toString() method
returning a LLL:... translation key for the name of the country
(
Country->getLocalizedNameLabel()).
Here are some examples how to access them and provide localization:
<f:comment>Will show something like "AT" or "DE"</f:comment>
Country ISO2:
{item.country.alpha2IsoCode}
<f:comment>Will show something like "CHE"</f:comment>
Country ISO3:
{item.country.alpha3IsoCode}
<f:comment>Will show something a flag (UTF-8 character)</f:comment>
Country flag:
{item.country.flag}
<f:comment>Will show something like "LLL:EXT:core/Resources/Private/Language/Iso/countries.xlf:AT.name"</f:comment>
Country LLL label:
{item.country}
Actual localized country:
<f:translatekey="{item.country}" /><f:comment>Will show something like "LLL:EXT:core/Resources/Private/Language/Iso/countries.xlf:AT.official_name"</f:comment>
Country LLL label:
{item.country.localizedOfficialNameLabel}
Actual localized official country name:
<f:translatekey="{item.country.localizedOfficialNameLabel}" /><f:comment>Will show something like "Germany" (always english)</f:comment>
{item.country.name}
Copied!
You can use the Extbase
\TYPO3\CMS\Extbase\Utility\LocalizationUtility
in PHP-scope (Controllers, Domain Model)
to create a custom getter in your Domain Model to create a shorthand method:
As mentioned above, since Country has no database-record relations.
The single-country relation always uses the 2-letter ISO alpha2 key
(respectively custom country keys, when added via the PSR-14 event
BeforeCountriesEvaluatedEvent). Thus, queries need to utilize them
as string comparisons:
The default Extbase repository magic method
$repository->findBy(['country' => 'DE']) will work, too.
TypoScript rendering usage via record-transformation
Database records using 'country' type fields can be rendered
with the TypoScript-based record-transformation rendering
(data processor).
You can specify how a field containing a country is rendered in the output
(using the name, the flag icon, specific ISO keys) with regular fluid
logic then:
Step 1: TypoScript utilizing record-transformation, defining a Homepage.html Fluid template
page = PAGE
page {
# Just an example basic template for your site. The important section starts with `dataProcessing`!100 = FLUIDTEMPLATE100 {
templateName = Homepage
templateRootPaths {
0 = EXT:myextension/Resources/Private/Templates/
}
dataProcessing {
10 = database-query
10 {
as = mainContent
# This table holds for example a TCA type=country definition for a field "country"
table = tx_myextension_domain_model_mycountries
# An extra boolean field "show_on_home_page" would indicate whether these# records are fetched and displayed on the home page
where = show_on_home_page=1
# Depending on your table storage you may need to set a proper pidInList constraint.#pidInList = 4711
dataProcessing {
# Makes all records available as `{mainContent.[0..].myRecord}` in the# Fluid file EXT:myextension/Resources/Private/Templates/Homepage.html10 = record-transformation
10 {
as = myRecord
}
}
}
}
}
}
<f:ifcondition="{mainContent}"><f:foreach="{mainContent}"as="element"><!-- given that your 'tx_myextension_domain_model_mycountries' has a TCA field called "storeCountry":
Selected Country:
<f:translate key="{element.myRecord.storeCountry.localizedOfficialNameLabel}" />
</f:for>
<!-- note that you can access any transformed record type object via 'element', also multiple country
elements could be contained in 'element.myRecord'. --></f:if>
Copied!
Hint
Instead of adding the data processor to the PAGE definition, you could create
an own country Content Element type and set it for tt_content.country, and
utilize a Content-Element specific Fluid template accessing this data, providing
something like a "Store" Content Element associated with a country.
Impact
It is now possible to use a dedicated TCA type for storing a relation
to a country in a record.
Using the new TCA type, corresponding database columns are added automatically.
Country-annotated properties of Extbase Domain Models can be evaluated
in Extbase and via TypoScript.
Feature: #103740 - Language selection for backend module "Info - Pagetree Overview"
The backend module Web > Info > Pagetree Overview is enriched by
a language selection.
This allows to switch the displayed Pagetree to the selected language, and adjust
all labels, edit and view links accordingly.
The language selection dropdown is right next to the other filter possibilities
(recursion depth, information type) and compliments the
Web > Info > Localization Overview with a page/record-focussed view.
Impact
The Web > Info backend module is more useful on sites with multiple
languages, to have a quick overview about information of the selected page and
its subpages.
Feature: #104047 - Option to report redirects in link validator
A new Page TSconfig option
mod.linkvalidator.linktypesConfig.external.allowRedirects
has been added to the link validator to report HTTP redirects
with external links as problems.
The
DataHandler PHP API has been
extended to support qualified and unqualified ISO8601 date formats in order to
correctly process supplied timezone offsets, if supplied.
Qualified ISO8601: Includes an explicit timezone offset (e.g.,
1999-12-11T10:09:00+01:00 or 1999-12-11T10:09:00Z)
TYPO3
DataHandler now accepts five
different formats:
Format
Examples
Unqualified ISO8601
(LOCALTIME)
'Y-m-d\\TH:i:s'
1999-11-11T11:11:11
Qualified ISO8601
'Y-m-d\\TH:i:sP'
1999-11-11T10:11:11Z
1999-11-11T11:11:11+01:00
DateTime objects
\DateTimeInterface
new \DateTime('yesterday')
new \DateTimeImmutable()
SQL flavored dates(internal)
'Y-m-d H:i:s'
1999-11-11 11:11:11
Unix timestamps(internal)
'U'
942315071
The ISO8601 variants and
\DateTimeInterface objects are intended to be
used as API. The SQL flavored variant and unix timestamps are mainly targeted
for copy and import operations of native datetime and unix timestamp database
fields and are considered internal API.
Passing datetime data via DataHandler PHP API
$myDate = new \DateTime('yesterday');
$this->dataHandler->start([
'tx_myextension_mytable' => [
'NEW-1' => [
'pid' => 2,
// Format as LOCALTIME'mydatefield_1' => $myDate->format('Y-m-dTH:i:s'),
// Format with timezone information// (offsets will be normalized to persistence timezone format,// UTC for integer fields, LOCALTIME for native DATETIME fields)'mydatefield_2' => $myDate->format('c'),
// Pass \DateTimeInterface objects directly'mydatefield_3' => $myDate,
],
],
]);
Copied!
Impact
TYPO3 now provides accurate and consistent handling of ISO8601 dates,
eliminating previous issues related to timezone interpretation and LOCALTIME
representation.
Feature: #105624 - PSR-14 event after a Backend user password has been reset
A new PSR-14 event
\TYPO3\CMS\Backend\Authentication\Event\PasswordHasBeenResetEvent
has been introduced which is raised right after a Backend user reset their password
and it has been hashed and persisted to the database.
The event contains the corresponding Backend user UID.
Example
The corresponding event listener class:
<?phpnamespaceVendor\MyPackage\Backend\EventListener;
useTYPO3\CMS\Backend\Authentication\Event\PasswordHasBeenResetEvent;
useTYPO3\CMS\Core\Attribute\AsEventListener;
finalclassPasswordHasBeenResetEventListener{
#[AsEventListener('my-package/backend/password-has-been-reset')]publicfunction__invoke(PasswordHasBeenResetEvent $event): void{
$userUid = $event->userUid;
// Do something with the be_user UID
}
}
Copied!
Impact
It's now possible to add custom business logic after a Backend user reset their
password using the new PSR-14 event
PasswordHasBeenResetEvent.
Feature: #105783 - Notify backend user on failed MFA verification attempts
TYPO3 now notifies backend users via email when a failed MFA (Multi-Factor
Authentication) verification attempt occurs. The notification is sent only if
an MFA provider is configured and the user has a valid email address in their
profile.
Impact
TYPO3 backend users benefit from enhanced security awareness through immediate
email notifications about failed MFA verification attempts. This is especially
useful in scenarios where backend accounts with active MFA setup are targeted
by unauthorized access attempts.
Feature: #105833 - Extended page tree filter functionality
The page tree is one of the central components in the TYPO3 backend,
particularly for editors. However, in large installations, the page tree can
quickly become overwhelming and difficult to navigate. To maintain a clear
overview, the page tree can be filtered using basic terms, such as the page
title or ID.
To enhance the filtering capabilities, the new PSR-14
\TYPO3\CMS\Backend\Tree\Repository\BeforePageTreeIsFilteredEvent
has been introduced. This event allows developers to extend the filter's
functionality and process the given search phrase in more advanced ways.
Using the Event, it is for example possible to evaluate a given URL or to
add additional field matchings, like filter pages by their
doktype
or their configured backend layout.
The event provides the following member properties:
$searchParts:
The search parts to be used for filtering
$searchUids:
The uids to be used for filtering by a special search part, which
is added by Core always after listener evaluation
$searchPhrase
The complete search phrase, as entered by the user
$queryBuilder:
The current
QueryBuilder
instance to provide context and to be used to create search parts
Important
The
QueryBuilder instance is provided solely
for context and to simplify the creation of
search parts by using the
ExpressionBuilder
via
QueryBuilder->expr(). The instance itself must not be modified by listeners and
is not considered part of the public API. TYPO3 reserves the right to change the instance at
any time without prior notice.
Example
The event listener class, using the PHP attribute
#[AsEventListener] for
registration, adds additional conditions to the filter.
useTYPO3\CMS\Backend\Tree\Repository\BeforePageTreeIsFilteredEvent;
useTYPO3\CMS\Core\Attribute\AsEventListener;
useTYPO3\CMS\Core\Database\Connection;
finalclassMyEventListener{
#[AsEventListener]publicfunctionremoveFetchedPageContent(BeforePageTreeIsFilteredEvent $event): void{
// Adds an additional UID to the filter
$event->searchUids[] = 123;
// Adds evaluation of doktypes to the filterif (preg_match('/doktype:([0-9]+)/i', $event->searchPhrase, $match)) {
$doktype = $match[1];
$event->searchParts = $event->searchParts->with(
$event->queryBuilder->expr()->eq('doktype', $event->queryBuilder->createNamedParameter($doktype, Connection::PARAM_INT))
);
}
}
}
Copied!
Impact
With the new PSR-14 event
\BeforePageTreeIsFilteredEvent, custom
functionality and advanced evaluations can now be added to enhance the page
tree filter.
Feature: #106072 - Introduce regex based replacements for slugs
Adds a second replacement config array to provide regex based
definitions. This way it's possible to define case-insensitive
or wildcard replacements.
Note
The regexp based replacement operates on the original field values,
which are not sanitized yet. That means, not lowercased or otherwise
processed and only on field level for the record configured with the
['generatorOptions']['fields'] option. Additional, not automatic
character detection and escaping is processed and needs to be taken care
when configure patterns. Keep these points in mind.
Impact
Slug fields have now a new regexReplacements configuration array inside generatorOptions.
'generatorOptions' => [
'regexReplacements' => [
'/foo/i' => 'bar', // case-insensitive replace of Foo, foo, FOO,... with "bar", ignoring casing'/\(.*\)/' => '', // Remove string wrapped in parentheses'@\(.*\)@' => '', // Remove string wrapped in parentheses with custom regex delimiter
],
],
Copied!
Feature: #106092 - Associative array keys for TCA valuePicker items
It is now possible to define associative array keys for the
items
configuration of TCA configuration
valuePicker. The
new keys are called:
label and
value.
This follows the change done already to the
items configuratio of the TCA types
select,
radio and
check. See forge#99739
Impact
It is now much easier and clearer to define the TCA
items configuration
with associative array keys. The struggle to remember which option is first,
label or value, is now over. In addition, optional keys like
icon and
group can be omitted, for example, when one desires to set the
description option.
Feature: #106232 - Provide SEO record title provider
The class
\TYPO3\CMS\Seo\PageTitle\RecordTitleProvider
is a new page title provider with the identifier recordTitle which is called before
\TYPO3\CMS\Seo\PageTitle\SeoTitlePageTitleProvider with the TypoScript
identifier seo.
This provider can be used by 3rd party extensions to set the page title.
A new PSR-14 event
\AfterPageUrlsForSiteForRedirectIntegrityHaveBeenCollectedEvent
is added which allows TYPO3 Extensions to register event listeners to modify
the list of URLs that are being processed by the CLI command
redirects:checkintegrity.
Example
The event listener class, using the PHP attribute
#[AsEventListener] for
registration, adds the URLs found in a sites XML sitemap to the list of URLs.
The class
\TYPO3\CMS\Extbase\Persistence\Generic\Backend is the covering entity
to retrieve data from the database within the Extbase persistence framework.
Already in 2013 the
getObjectDataByQuery method got equipped with signals
(later migrated to events) in order to modify data retrieval.
Especially when used in combination with Extbase's
QueryResult there is also
a second important method
getObjectCountByQuery, which is often used in combination
with Fluid.
Extensions, or any other code using the existing events for data retrieval, have not been able
to consistently modify queries, such that results returned by
QueryResult were consistent.
The
getObjectCountByQuery method is now enhanced with events as well. This finally
allows extensions to modify all parts of query usage within Extbase's generic
Backend
to achieve consistent results.
The new events are:
\TYPO3\CMS\Extbase\Event\Persistence\ModifyQueryBeforeFetchingObjectCountEvent
may be used to modify the query before being passed on to the actual storage backend.
\TYPO3\CMS\Extbase\Event\Persistence\ModifyResultAfterFetchingObjectCountEvent
may be used to adjust the result.
Typically, an extension will want to implement events pair-wise:
ModifyQueryBeforeFetchingObjectCountEvent together with
ModifyQueryBeforeFetchingObjectDataEvent, and
ModifyResultAfterFetchingObjectCountEvent together with
ModifyResultAfterFetchingObjectDataEvent
Deprecation: #106393 - Various methods in BackendUtility
Due to the use of the Schema API the following methods of
\TYPO3\CMS\Backend\Utility\BackendUtility which are
related to retrieving information from :php:$GLOBALS['TCA']` have
been deprecated:
Calling one of the following methods raises deprecation level
log errors and will stop working in TYPO3 v15.0.
Affected installations
Instances using the mentioned methods directly.
Migration
isWebMountRestrictionIgnored
// Beforereturn BackendUtility::isWebMountRestrictionIgnored($table);
// After// Retrieve in instance of tcaSchemaFactory with Dependency Injection of TYPO3\CMS\Core\Schema\TcaSchemaFactory
$schema = $this->tcaSchemaFactory->get('pages');
return $schema->hasCapability(TcaSchemaCapability::RestrictionWebMount);
Copied!
resolveFileReferences
No substitution is available. Please copy the method to your own codebase and
adjust it to your needs.
Deprecation: #106527 - markFieldAsChanged() moved to FormEngine main module
The static method
markFieldAsChanged() in the module
@typo3/backend/form-engine-validation is used to modify the markup in the
DOM to mark a field as changed. Technically, this is unrelated to validation at
all, therefore the method has been moved to
@typo3/backend/form-engine.
Impact
Calling
markFieldAsChanged() from
@typo3/backend/form-engine-validation will trigger a deprecation notice in
the browser console.
Affected installations
All extensions using the deprecated code are affected.
Migration
If not already done, import the main FormEngine module and call
markFieldAsChanged() from that.
Example:
- import FormEngineValidation from '@typo3/backend/form-engine-validation.js';+ import FormEngine from '@typo3/backend/form-engine.js';- FormEngineValidation.markFieldAsChanged(fieldReference);+ FormEngine.markFieldAsChanged(fieldReference);
The method
GeneralUtility::resolveBackPath has been marked as deprecated
and will be removed in TYPO3 v15.0.
It served as a possibility to remove any relative path segments such as ".."
when referencing files or directories, and was especially important before
TYPO3 v7, where every TYPO3 Backend had their own route and entrypoint PHP file,
but nowadays has been a relict from the past.
Since TYPO3 v13, this method has been even more unrelated as the main
entrypoint file for TYPO3 Backend is now the same as the frontend
("htdocs/index.php").
Impact
TYPO3 does not resolve the back path of a reference to a resource and does not
"normalize" the path anymore when rendering or referencing the resource
in the HTML output - neither in the frontend or backend. It will however
continue to work.
Affected installations
TYPO3 installations with custom inclusions in TypoScript, or backend modules
referencing files with relative paths, which is very uncommon in the current web
era.
Migration
Referencing resources should now be done with the EXT prefix, or relative
to the public web path of the TYPO3 installation.
Referencing JavaScript modules (ES6 modules) should be handled via import maps
and the module names.
When installing TYPO3 for the first time, a .htaccess file is added to the
htdocs / public path, when running TYPO3 via Apache webserver.
Next to some TYPO3 optimizations, this file mainly contains rules (via the
"mod_rewrite" Apache2 module) for pointing all URL requests to non-existent
files within a TYPO3 project to the main index.php entry point file.
For new installations, this file has some changed configuration, which can be
adapted to existing TYPO3 installations reflecting a default setup:
URL requests within /_assets/ and /fileadmin/ are not redirected,
as they contain resources either managed by editors or TYPO3 itself.
The directory /_assets/ is added now, as it has been in place since TYPO3 v12 for
Composer-based installations.
The folder /uploads/ is officially not needed anymore since TYPO3 v11, and
not maintained by TYPO3 anymore. This folder is now removed from the .htaccess
configuration as well, so TYPO3 pages can officially have the URL path /uploads
now.
It is recommended to change this in existing TYPO3 installations as well - also
with other server configurations such as nginx or IIS - in case no
custom usage of /_assets/ or "/uploads/ is in effect, like via a PSR-15
middleware, custom extensions, or custom routing.
TYPO3 parses ext_tables.sql files into a Doctrine DBAL object schema to define
a virtual database scheme, enriched with
DefaultTcaSchema information for
TCA-managed tables and fields.
Fixed and variable length variants have been parsed already in the past, but missed
to flag the column as
$fixed = true for the fixed-length database field types
CHAR and
BINARY. This resulted in the wrong creation of these columns as
VARCHAR and
VARBINARY, which is now corrected.
ext_tables.sql
created as (before)
created as (now)
CHAR(10)
VARCHAR(10)
CHAR(10)
VARCHAR(10)
VARCHAR(10)
VARCHAR(10)
BINARY(10)
VARBINARY(10)
BINARY(10)
VARBINARY(10)
VARBINARY(10)
VARBINARY(10)
Not all database systems (RDBMS) act the same way for fixed-length columns. Implementation
differences need to be respected to ensure the same query/data behaviour across all supported
database systems.
Warning
Using fixed-length
CHAR and
BINARY column types requires to carefully work
with data being persisted and retrieved from the database due to differently
behaviour specifically of PostgreSQL.
Fixed-length
CHAR
Key Difference Between CHAR and VARCHAR
The main difference between
CHAR and
VARCHAR is how the database
stores character data in a database.
CHAR, which stands for character,
is a fixed-length data type, meaning it always reserves a specific amount of
storage space for each value, regardless of whether the actual data occupies
that space entirely. For example, if a column is defined as
CHAR(10) and
the word apple is stored inside of it, it will still occupy 10 characters worth of
space (not just 5). Unusued characters are padded with extra spaces.
On the other hand,
VARCHAR, short for variable character, is a
variable-length data type. It only uses as much storage space as needed
to store the actual data without padding. So, storing the word apple in a
VARCHAR(10) column will only occupy 5 characters worth of
space, leaving the remaining table row space available for other data.
The main difference from PostgreSQL to MySQL/MariaDB/SQLite is:
PostgreSQL also returns the filler-spaces for a value not having the
column length (returning apple[space][space][space][space][space]).
On top of that, the filled-up spaces are also respected for query conditions, sorting
or data calculations (
concat() for example). These two facts makes a huge
difference and must be carefully taken into account when using
CHAR
field.
Rule of thumb for fixed-length
CHARcolumns
Only use with ensured fixed-length values (so that no padding occurs).
For 255 or more characters
VARCHAR or
TEXT must be used.
More hints for fixed-length
CHARcolumns
Ensure to write fixed-length values for
CHAR (non-space characters),
for example use hash algorithms which produce fixed-length hash identifier
values.
Ensure to use query statements to trim OR rightPad the value within
WHERE,
HAVING or
SELECT operations, when values are
not guaranteed to contain fixed-length values.
Tip
Helper
\TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
expressions can be used, for example
\TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder->trim() or
\TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder->rightPad() to.
Usage of
CHARmust be avoided when using the column with the
Extbase ORM, because fixed-value length cannot be ensured due to the
lack of using trim/rightPad within the ORM generated queries. Only with ensured
fixed-length values, it is usable with Extbase ORM.
Cover custom queries extensively with functional tests executed against
all supported database platforms. Code within public extensions should ensure to test
queries and their operations against all officially TYPO3-supported database platforms.
Example of difference in behaviour of fixed-length
CHAR types
Example ext_tables.sql defining a fixed-length tt_content field
Because of this, retrieved values need to be trimmed OR padded AFTER
the query results are fetched, to ensure the same retrieved value across all
supported database systems. Another option is to ensure that the persisted
data always has a fixed-value length, like by using the aforementioned hashing
algorithms (making results not human-readable).
To raise the awareness for problems on this topic, using the trimmed value inside
a
WHERE condition will match the record, but the returned value will be different
from the value used in the condition:
CHAR and
BINARY fields can be used (for storage or performance adjustments),
but only when composed data and queries take care of database-system differences.
Otherwise, the "safe bet" is to consistently utilize
VARCHAR and
VARBINARY
columns types.
Due to the removal of the plugin content element (
list) and the corresponding
plugin subtype field
list_type the fifth parameter
$pluginType
of
ExtensionUtility::configurePlugin() is now unused and can be omitted.
It is only kept for backwards compatibility. However, be aware that passing any
value other than
CType will trigger a
\InvalidArgumentException.
Please also note that due to the removal of the
list_type field in
tt_content, passing list_type as second parameter
$field to
ExtensionManagementUtility::addTcaSelectItemGroup() will now - as for
any other non-existent field - trigger a
\RuntimeException.
Important: #106192 - Add 'center' and 'font' to YAML processing removeTags
The default YAML processing configuration file
EXT:rte_ckeditor/Configuration/RTE/Processing.yaml
has been changed to remove these HTML tags
<font> and
<center> by default when saving a RTE field content
to the database.
This new default is adjusted with the option processing.HTMLparser_db.removeTags,
which now also lists these two tags.
A stored input like
<p><font face="Arial">My text</font></p>
will - when saved - be changed to
<p>My text</p>.
Affected installations
All installations having
<font> and :html<center>
stored in their database fields, and where no custom RTE
YAML configuration is in place that allows these tags.
Please note that due issue forge#104839, this
removeTags option was never properly applied previously, so the chances
are that an installation never had output for font and
center properly working anyways.
Also take note that the CKEditor by default uses
<span style="...">
tags to apply font formatting when using the Full preset.
Thus, real-life impact should be low, but for legacy installations
you may want to convert existing data to replace font/html tags
with their appropriate modern counterparts.
Migration
Either accept the removal of these tags, and use specific
HTML tags like
<span> and
<div> to apply formatting.
Or adapt the RTE Processing via TypoScript/YAML configuration
to not have center and font to the processing.HTMLparser_db.removeTags
list.
If the tags center and font have been configured via the editor.conf.style.definitions
YAML option (not set by default), CKEditor would allow to use these tags,
but they will now be removed both when saving, or when being rendered in the
frontend. So these style definitions should be removed and/or adapted to
<span style="..."> configurations.
Important: #106532 - Changed database storage format for Scheduler Tasks
TYPO3's system extension scheduler has stored its tasks to be executed with PHP-serialized
storage format in the database since its inception.
This has led to many problems, e.g. when changing a class property to be fully typed,
or when a class name has changed to use PHP 5 namespaces back then, or when
renaming a class or a class property.
This has now changed, where as the task object now stores the "tasktype" (typically
the class name) and its options in a "parameters" as JSON-encoded value as well as
the execution details (DB field execution_details) in separate fields of the database
table
tx_scheduler_task. This way, the task object can be re-constituted with a
properly defined API, avoiding pains in the future.
All existing tasks are compatible with the new internal format. An upgrade wizard
ensures that the previously serialized objects are now transferred into the new
format. If this wizard does not disappear after being executed, it means there
are tasks that failed to be migrated and may need manual inspection or re-creation.
Inspect all tasks of
tx_scheduler_task where the "tasktype" column is empty.
The old serialized data format is somewhat human-readable (or can be inspected with PHP
deserializers), so re-creating a task with its former configuration options should be
possible.
Please note that this upgrade step needs to be performed in the context of TYPO3 v14;
performing the wizard in future TYPO3 versions may not succeed due to changes in the Task objects.
Important: #106649 - Default Language Binding in page module
The Page module now always uses default language binding
(
mod.web_layout.defLangBinding) when displaying
localized content in the language comparion mode.
Default language binding makes editing translations easier: Editors can see
what they’re translating next to the default language. It additionally prevents
confusion when localizations are incomplete. Editors directly see which content
is not translated yet. This improves UX in the backend for multilingual sites,
which was also a result of recent JTBD interviews.
Impact
Editors will now always see the content elements next to each other within
the page module, when in language comparison mode.
Migration
Because default language binding is now always enabled, the previous Page
TSconfig setting
mod.web_layout.defLangBinding is not evaluated
and can therefore be removed
Important: #106656 - Allow DEFAULT NULL for varchar fields
In TCA, if an input field is configured to be nullable via
'nullable' => true, the database migration now respects this and creates
new or updates existing fields with DEFAULT NULL.
In Extbase, this may cause issues if properties and their accessor methods are
not properly declared to be nullable, therefore this change is introduced to
TYPO3 v14 only.
As stated above, this automatic detection is not provided in TYPO3 versions
older than 14.0. Using DEFAULT NULL can be enforced via an extension's
ext_tables.sql instead:
CREATETABLE tx_myextension_table (
title varchar(255) DEFAULTNULL
);
Copied!
14.x Changes by type
This lists all changes to the TYPO3 Core of minor versions grouped by their type.
With forge#103894 the new data processor PageContentFetchingProcessor
has been introduced, to allow fetching page content based on the current page
layout, taking the configured
SlideMode into account.
Fetching content has previously mostly been done via the Content content
object. A common example looked like this:
As mentioned in the linked changelog, using the page-content data processor,
this can be simplified to:
page.20 = page-content
Copied!
This however reduces the possibility to modify the select configuration
(SQL statement), used to define which content should be fetched, as this
is automatically handled by the data processor. However, there might be some
use cases in which the result needs to be adjusted, e.g. to hide specific
page content, like it's done by EXT:content_blocks
for child elements. For such use cases, the new PSR-14
AfterContentHasBeenFetchedEvent
has been introduced, which allows to manipulate the list of fetched page
content.
The following member properties of the event object are provided:
$groupedContent: The fetched page content, grouped by their column - as defined in the page layout
$request: The current request, which can be used to e.g. access the page layout in question
Example
The event listener class, using the PHP attribute
#[AsEventListener] for
registration, removes some of the fetched page content elements based on
specific field values.
Using the new PSR-14
AfterContentHasBeenFetchedEvent, it's possible
to manipulate the page content, which has been fetched by the
PageContentFetchingProcessor, based on the page layout and
corresponding columns configuration.
Important: #92187 - Evaluation of incoming HTTP Header X-Forwarded-Proto
At this point it is not known if the request between the client (the actual
web browser for example) and the reverse proxy was made via HTTP or HTTPS,
mainly because TYPO3 only evaluated the information from the reverse proxy
to TYPO3 - which was typically faked on the TYPO3's webserver by setting
"HTTPS=on" (e.g. via .htaccess file). In a typical setup, the communication
between the reverse proxy and TYPO3's webserver is done via HTTP and irrelevant
for TYPO3.
When the site owner knows that the reverse proxy acts as a SSL termination point
and only communicates via https to the client, the
$GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxySSL'] option
can be set, to identify all reverse proxy IPs that ensure a secure connection
between client and reverse proxy.
In case, it is not known, and reverseProxySSL is not in use, but
reverseProxyIP is in use, the incoming HTTP header X-Forwarded-Proto is
now evaluated to determine if the request was made, if the header is sent.
If it is NOT sent, TYPO3 will assume to detect a secure connection between
SSL information as before via various other HTTP Headers or server configuration
settintgs.
Important: #103140 - Allow to configure rate limiters in Message consumer (Symfony Messenger)
This change introduces missing configuration options for Symfony Messenger-based
rate limiters.
A rate limiter controls how frequently a specific event (e.g., HTTP request
or login attempt) is allowed to occur. It acts as a safeguard to prevent services from
being overwhelmed — either accidentally or intentionally — thus helping
to maintain their availability.
Rate limiters are also useful for controlling internal or outbound
processes, such as limiting the simultaneous processing of messages.
Rate limiters can be defined in your service configuration
EXT:yourext/Configuration/Services.yaml. The name specified
in the settings is resolved to a service tagged with messenger.rate_limiter
and the corresponding identifier.
The
\TYPO3\CMS\Core\Log\Writer\DatabaseWriter is used to write logs into
the database table sys_log. Additional log information data is persisted
in the field data and has been prefixed with a - until now.
As this makes it harder to parse the data, which is JSON-encoded anyway,
the prefix has been removed.
Beware that existing log entries are not migrated automatically.
This leads to a mixed structure in the database table until old records are cleaned.
(TYPO3 itself does not interpret the content of the field.)
Important: #105007 - Manipulation of final search query in EXT:indexed_search
By removing the
searchSkipExtendToSubpagesChecking option in
forge#97530, there might have been performance implications for installations
with a lot of sites. This could be circumvented by adjusting the search query
manually, using available hooks. Since those hooks have also been removed with
forge#102937, developers were no longer be able to handle the query
behaviour.
Therefore, the PSR-14
BeforeFinalSearchQueryIsExecutedEvent has been
introduced which allows developers to manipulate the
QueryBuilder
instance again, just before the query gets executed.
Additional context information, provided by the new event:
searchWords - The corresponding search words list
freeIndexUid - Pointer to which indexing configuration should be searched in.
-1 means no filtering. 0 means only regular indexed content.
Important
The provided query (the
QueryBuilder instance) is controlled by
TYPO3 and is not considered public API. Therefore, developers using this
event need to keep track of underlying changes by TYPO3. Such changes might
be further performance improvements to the query or changes to the
database schema in general.
TYPO3 parses ext_tables.sql files into a Doctrine DBAL object schema to define
a virtual database scheme, enriched with
DefaultTcaSchema information for
TCA-managed tables and fields.
Fixed and variable length variants have been parsed already in the past, but missed
to flag the column as
$fixed = true for the fixed-length database field types
CHAR and
BINARY. This resulted in the wrong creation of these columns as
VARCHAR and
VARBINARY, which is now corrected.
ext_tables.sql
created as (before)
created as (now)
CHAR(10)
VARCHAR(10)
CHAR(10)
VARCHAR(10)
VARCHAR(10)
VARCHAR(10)
BINARY(10)
VARBINARY(10)
BINARY(10)
VARBINARY(10)
VARBINARY(10)
VARBINARY(10)
Not all database systems (RDBMS) act the same way for fixed-length columns. Implementation
differences need to be respected to ensure the same query/data behaviour across all supported
database systems.
Warning
Using fixed-length
CHAR and
BINARY column types requires to carefully work
with data being persisted and retrieved from the database due to differently
behaviour specifically of PostgreSQL.
Fixed-length
CHAR
Key Difference Between CHAR and VARCHAR
The main difference between
CHAR and
VARCHAR is how the database
stores character data in a database.
CHAR, which stands for character,
is a fixed-length data type, meaning it always reserves a specific amount of
storage space for each value, regardless of whether the actual data occupies
that space entirely. For example, if a column is defined as
CHAR(10) and
the word apple is stored inside of it, it will still occupy 10 characters worth of
space (not just 5). Unusued characters are padded with extra spaces.
On the other hand,
VARCHAR, short for variable character, is a
variable-length data type. It only uses as much storage space as needed
to store the actual data without padding. So, storing the word apple in a
VARCHAR(10) column will only occupy 5 characters worth of
space, leaving the remaining table row space available for other data.
The main difference from PostgreSQL to MySQL/MariaDB/SQLite is:
PostgreSQL also returns the filler-spaces for a value not having the
column length (returning apple[space][space][space][space][space]).
On top of that, the filled-up spaces are also respected for query conditions, sorting
or data calculations (
concat() for example). These two facts makes a huge
difference and must be carefully taken into account when using
CHAR
field.
Rule of thumb for fixed-length
CHARcolumns
Only use with ensured fixed-length values (so that no padding occurs).
For 255 or more characters
VARCHAR or
TEXT must be used.
More hints for fixed-length
CHARcolumns
Ensure to write fixed-length values for
CHAR (non-space characters),
for example use hash algorithms which produce fixed-length hash identifier
values.
Ensure to use query statements to trim OR rightPad the value within
WHERE,
HAVING or
SELECT operations, when values are
not guaranteed to contain fixed-length values.
Tip
Helper
\TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
expressions can be used, for example
\TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder->trim() or
\TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder->rightPad() to.
Usage of
CHARmust be avoided when using the column with the
Extbase ORM, because fixed-value length cannot be ensured due to the
lack of using trim/rightPad within the ORM generated queries. Only with ensured
fixed-length values, it is usable with Extbase ORM.
Cover custom queries extensively with functional tests executed against
all supported database platforms. Code within public extensions should ensure to test
queries and their operations against all officially TYPO3-supported database platforms.
Example of difference in behaviour of fixed-length
CHAR types
Example ext_tables.sql defining a fixed-length tt_content field
Because of this, retrieved values need to be trimmed OR padded AFTER
the query results are fetched, to ensure the same retrieved value across all
supported database systems. Another option is to ensure that the persisted
data always has a fixed-value length, like by using the aforementioned hashing
algorithms (making results not human-readable).
To raise the awareness for problems on this topic, using the trimmed value inside
a
WHERE condition will match the record, but the returned value will be different
from the value used in the condition:
CHAR and
BINARY fields can be used (for storage or performance adjustments),
but only when composed data and queries take care of database-system differences.
Otherwise, the "safe bet" is to consistently utilize
VARCHAR and
VARBINARY
columns types.
Important: #105653 - Require a template filename in extbase module template rendering
With the introduction of the FluidAdapter in TYPO3 v13, the dependency between
Fluid and Extbase has been decoupled. As part of this change, the behavior of
the
ModuleTemplate::renderResponse() and
ModuleTemplate::render()
methods has been adjusted.
The
$templateFileName argument is now mandatory for the
ModuleTemplate::renderResponse() and
ModuleTemplate::render()
methods. Previously, if this argument was not provided, the template was
automatically resolved based on the controller and action names. Starting from
TYPO3 13.4, calling these methods with an empty string or without a valid
$templateFileName will result in an
InvalidArgumentException.
Extensions using Extbase backend modules must explicitly provide the
$templateFileName when calling these methods. Existing implementations
relying on automatic template resolution need to be updated to prevent
runtime errors.
Note, that it is already possible to explicitly provide the
$templateFileName in TYPO3 12.4. It is therefore recommended to
implement the new requirement for websites using TYPO3 12.4.
Important: #105703 - Premature end of script headers due to X-TYPO3-Cache-Tags
The X-TYPO3-Cache-Tags header is now split into multiple lines if it exceeds the maximum
of 8000 characters. This change prevents premature end of script headers and ensures
that the header is sent correctly, even if it contains a large number of cache tags.
Affected installations
This change affects all TYPO3 installations that have $GLOBALS['TYPO3_CONF_VARS']['FE']['debug']
enabled and misusing the X-TYPO3-Cache-Tags header for anything else then debugging.
If you have a large number of cache tags, the header is now split into multiple
lines to avoid exceeding the maximum header size limit imposed by some web servers.
As this header is for debugging purposes only, this does not effect any production
environments.
Important: #106401 - Treat 0 as a defined value for nullable datetime fields
For nullable integer-based datetime fields, the value 0 now explicitly
represents the Unix epoch time (1970-01-01T00:00:00Z) instead of being
interpreted as an empty value by FormEngine.
Only an explicit null database value will be considered an empty value.
The default database schema that is generated from TCA has been adapted
to generate datetime columns with
DEFAULT NULL instead of
DEFAULT 0 if they have been configured to be nullable.
When dealing with relations to multilingual Extbase entities, these relations should always store
their reference to the "original" (sys_language_uid=0) entity, so that later on,
language record overlays can be properly applied.
For this to work in areas like persistence, internally an "identifier" is established that references
these multilingual objects like [defaultLanguageRecordUid]_[localizedRecordUid].
Internally, this identifier should be converted back to only contain/reference the defaultLanguageRecordUid.
A bug has been fixed with #106494 to deal with this inside the <f:form.select> ViewHelper, which utilized
an <option value="11_42"> (defaultLanguageRecordUid=11, localizedRecordUid=42), and when using an <f:form>
to edit existing records, the currently attached records would NOT get pre-selected.
When such objects with relations were persisted (in frontend management interfaces with Extbase), if the proper
option had not been selected again, the relation would get lost.
Important: Adapt custom ViewHelpers extended from AbstractFormFieldViewHelper or using persistenceManager->getIdentifierByObject()
The bug has been fixed, but it is important that if third-party code created custom ViewHelpers based on
\TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormFieldViewHelper , these may need adoption too.
Instead of using code like this:
Example ViewHelper code utilizing persistenceManager->getIdentifierByObject()
if ($this->persistenceManager->getIdentifierByObject($valueElement) !== null) {
return$this->persistenceManager->getIdentifierByObject($valueElement);
}
Copied!
the code should be adopted to not rely on getIdentifierByObject() but instead:
Refactored ViewHelper code preferring an object's getUid() method instead
if ($this->persistenceManager->getIdentifierByObject($valueElement) !== null) {
if ($valueElement instanceof DomainObjectInterface) {
return $valueElement->getUid() ?? $this->persistenceManager->getIdentifierByObject($valueElement);
}
return$this->persistenceManager->getIdentifierByObject($valueElement);
}
Copied!
This code ensures that retrieving the relational object's UID is done with the overlaid record,
and only falls back to the full identifier, if it's not set, or not an object implementing the Extbase
DomainObjectInterface.
Also note that the abstract's method
convertToPlainValue() has been fixed to no longer return
a value of format [defaultLanguageRecordUid]_[localizedRecordUid] but instead always use the
original record's ->getUid() return value (=defaultLanguageRecordUid).
If this method
convertToPlainValue() is used in 3rd-party code, make sure this is the
expected result, too.
Important: #106508 - Respect column CHARACTER SET and COLLATE in ext_tables.sql
TYPO3 now reads column based CHARACTER SET and COLLATION from extension
ext_tables.sql files and applies them on column level. This allows
CHARACTER SET and COLLATION column settings different than defaults defined
on table or schema level. This is limited to MySQL and MariaDB DBMS.
Note
Setting different charset and collation comes with some technical impact
during query time and requires for some queries special handling, for instance
when joining field that have different charsets or collations. Setting special
charsets and collations for single columns should only be used in rare
cases. The support is @internal and should be used with care if at all.
For now,
CHARACTER SET ascii COLLATE ascii_bin is used for
sys_refindex.hash to reduce required space for the index using
single bytes instead of multiple bytes per character.
The introduced database change is considerable non-breaking, because:
Not applying the database changes still keeps a fully working state.
Applying database schema change does not require data migrations.
After TYPO3 v13.0, only new functionality with a solid migration path
can be added on top, with aiming for as little as possible breaking changes
after the initial v13.0 release on the way to LTS.
Historically, plugins have been registered using the list content
element and the plugin subtype list_type field. This functionality
has been kept for backwards compatibility reasons. However, since the release
of TYPO3 v12.4, the recommended way to create a plugin is by using a dedicated
content type (CType) for each plugin.
This old "General Plugin" approach has always been ugly from a UX perspective point
of view since it hides plugin selection behind "General plugin" content element,
forcing a second selection step and making such plugins something special.
Therefore, the plugin content element (list) and the plugin sub types
field (
list_type) have been marked as deprecated in TYPO3 v13.4 and will
be removed in TYPO3 v14.0.
Additionally, the related PHP constant
TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_PLUGIN has been
deprecated as well.
Impact
Plugins added using
TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPlugin() where
the second parameter is
list_type (which is still the default) will
trigger a deprecation level log entry in TYPO3 v13 and will fail in v14.
Therefore, the same applies on using
TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin() (to
configure the plugin for frontend rendering), where no fifth parameter is
provided or where the fifth parameter is
list_type
(
ExtensionUtility::PLUGIN_TYPE_PLUGIN), which is still the default.
The extension scanner will report any usage of
configurePlugin(),
where less than the required five arguments are provided. Actually, the
only valid value for the fifth parameter
$pluginType is
CType,
for which the
ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT constant
can be used.
Note
addPlugin() is also internally called when registering a plugin
via
TYPO3\CMS\Core\Utility\ExtensionManagementUtility::registerPlugin().
In that case the plugin type to use is either the one defined via
TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin()
or also falls back to
list_type.
Affected installations
Extensions registering plugins as list_type plugin sub type.
Migration
Existing plugins must be migrated to use the CType record type.
Extension authors must implement the following changes:
Register plugins using the CType record type
Create update wizard which extends
\TYPO3\CMS\Install\Updates\AbstractListTypeToCTypeUpdate
and add list_type to CType mapping for each plugin to migrate.
The migration wizard for indexed_search in class
IndexedSearchCTypeMigration
can be used as reference example.
Migrate possible FlexForm registration and add dedicated showitem TCA
configuration
Migrate possible PreviewRenderer registration in TCA
Adapt possible content element wizard items in Page TSConfig, where
list_type is used
Adapt possible content element restrictions in backend layouts or container
elements defined by third-party extensions like
ichhabrecht/content-defender
.
Common example
// Before
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['my_plugin'] = 'pi_flexform';
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_excludelist']['my_plugin'] = 'pages,layout,recursive';
// After
$GLOBALS['TCA']['tt_content']['types']['my_plugin']['showitem'] = '<Some Fields>,pi_flexform,<Other Fields>';
The old TypoScript syntax to import external TypoScript files based on
<INCLUDE_TYPOSCRIPT: has been marked as deprecated
with TYPO3 v13 and will be removed in v14.
Integrators should switch to
@import.
There are multiple reasons to finally phase out this old construct:
The
<INCLUDE_TYPOSCRIPT: syntax is clumsy and hard to grasp,
especially when combining multiple options. It is hard to learn for integrators
new to the project.
The implementation has a high level of complexity, is only partially tested
and consists of edge cases that are hard to decide on and even harder to change
since that may break existing usages in hard to debug ways.
The syntax can have negative security impact when not used wisely by loading
TypoScript from editor related folders like fileadmin/. The syntax
based on
@import has been designed more thoughtful in this regard.
Loading TypoScript files from folders relative to the public web folder is
unfortunate and can have negative side effects when switching "legacy" based
instances to composer.
The syntax based on
@import has been introduced in TYPO3 v9 already
and has been designed to stay at this point in time. With TYPO3 v12, the
last missing feature of
<INCLUDE_TYPOSCRIPT: has been made possible
for
@import as well:
@import can be loaded conditionally
by putting them into the body of a casual TypoScript condition.
TYPO3 v12 discouraged using
<INCLUDE_TYPOSCRIPT: within the documentation
and already anticipated a future deprecation and removal.
Impact
When using TypoScript
<INCLUDE_TYPOSCRIPT: syntax a deprecation level
log entry in TYPO3 v13 is emitted. The syntax will stop working with TYPO3 v14 and
will be detected as an "invalid line" in the TypoScript related Backend modules.
Affected installations
Instances TypoScript syntax based on
<INCLUDE_TYPOSCRIPT:.
Migration
Most usages of
<INCLUDE_TYPOSCRIPT: can be turned into
@import
easily. A few examples:
# Before<INCLUDE_TYPOSCRIPT: source="FILE:EXT:my_extension/Configuration/TypoScript/myMenu.typoscript"># After@import 'EXT:my_extension/Configuration/TypoScript/myMenu.typoscript'# Before# Including .typoscript files in a single (non recursive!) directory<INCLUDE_TYPOSCRIPT: source="DIR:EXT:my_extension/Configuration/TypoScript/" extensions="typoscript"># After@import 'EXT:my_extension/Configuration/TypoScript/*.typoscript'# Before# Including .typoscript and .ts files in a single (non recursive!) directory<INCLUDE_TYPOSCRIPT: source="DIR:EXT:my_extension/Configuration/TypoScript/" extensions="typoscript,ts"># After@import 'EXT:my_extension/Configuration/TypoScript/*.typoscript'# Rename all files ending on .ts to .typoscript# Before# Including a file conditionally<INCLUDE_TYPOSCRIPT: source="FILE:EXT:my_extension/Configuration/TypoScript/user.typoscript" condition="[frontend.user.isLoggedIn]"># After[frontend.user.isLoggedIn]@import 'EXT:my_extension/Configuration/TypoScript/user.typoscript'[END]
Copied!
There are a few more use cases that cannot be transitioned so easily since
@import is
a bit more restrictive.
As one restriction
@import cannot include files from arbitrary directories
like fileadmin/, but only from extensions by using the
EXT:
prefix. Instances that use
<INCLUDE_TYPOSCRIPT: with
source="FILE:./someDirectory/..."
should move this TypoScript into a project or site extension. Such instances are also encouraged to
look into the TYPO3 v13 "Site sets" feature and eventually transition towards it along the way.
@import allows to import files with the file ending .typoscript
and .tsconfig. If you used any of the outdated file endings like .ts or
.txt rename those files before switching to the
@import syntax.
The
@import feature does not support recursive directory inclusion, as it does
not allow wildcards in directory paths. Having directories like TypoScript/foo and
TypoScript/bar, each having .typoscript files, could be included using
<INCLUDE_TYPOSCRIPT: source=DIR:EXT:my_extension/Configuration/TypoScript extensions="typoscript">,
which would find such files in foo and bar, and any other directory. This level of complexity
was not wished to allow in the
@import syntax since it can make file includes more intransparent
with too much attached magic. Instances using this should either reorganize their files, or have multiple dedicated
@import statements. The need for recursive includes may also be mitigated by restructuring
TypoScript based functionality using "Site sets".
The transition from
<INCLUDE_TYPOSCRIPT: can be often further relaxed with these features in mind:
TypoScript provider for sites and sets automatically loads TypoScript
per site when located next to site config.yaml files as constants.typoscript and setup.typoscript,
which is a good alternative to files in fileadmin and similar. Note that configured site sets TypoScript
are loaded before, so constants.typoscript and setup.typoscript are designed to adapt site set
TypoScript to specific site needs.
One of the main features of TCA are the record types. This allows to use
a single table for different purposes and in different contexts. The most
known examples of using record types are the "Page Types" of
pages
and the "Content Types" of
tt_content. For every specific type of
such table, it's possible to define the fields to be used and even
manipulate them e.g. change their label.
A special case since ever has been the plugin registration. This for
a long time has been done using the so called "sub types" feature of TCA.
This is another layer below record types and allows to further customize
the behaviour of a record type using another select field, defined via
subtype_value_field as well as defining fields to be added
-
subtypes_addlist - or excluded -
subtypes_excludelist - for
the record type, depending on the selected sub type.
For a couple of version now, it's encouraged to register plugins just
as standard content elements via the
tt_content type field
CType.
Therefore, the special registration via the combination of the
list
record type and the selection of a sub type via the
list_type field
has already been deprecated with Deprecation: #105076 - Plugin content element and plugin sub types.
Since the "sub types" feature was mainly used for this scenario only, it has
now been deprecated as well. Registration of custom types should therefore
always be done by using record types. This makes configuration much cleaner
and more comprehensible.
Impact
Using
subtype_value_field in a TCA types configurations will
lead to a deprecation log entry containing information about where
adaptations need to take place.
Affected installations
All installations using the sub types feature by defining a
subtype_value_field in a TCA types configuration, which
is really uncommon as the feature was mainly used for plugin
registration in the
tt_content table only.
Migration
Replace any
subtype_value_field configuration with dedicated record
types. Please also consider migrating corresponding
subtypes_addlist
and
subtypes_excludelist definitions accordingly.
Class
\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController and
its global instance
$GLOBALS['TSFE'] have been marked as deprecated.
The class will be removed with TYPO3 v14.
Impact
Calling
TypoScriptFrontendController methods, or accessing state from
$GLOBALS['TSFE'] is considered deprecated.
Affected installations
Various instances may still retrieve information from
$GLOBALS['TSFE'] .
Remaining uses should be adapted. The extension scanner will find possible
matches.
To keep backwards compatibility in TYPO3 v13, some calls can not raise
deprecation level log messages.
The backend layout related data object class
\TYPO3\CMS\Backend\View\BackendLayout\DataProviderContext
has been turned into a data object using public constructor property promotion (PCPP).
All
setX() and
getX() methods have been marked as deprecated in TYPO3 v13.4 and
will be removed with TYPO3 v14.0. The class will be declared
readonly in TYPO3 v14.0
which will enforce instantiation using PCPP. The class has been declared final since it is
an API contract that must never be changed or extended. The constructor arguments will be
declared non-optional in TYPO3 v14.0.
Calling the getters or setters raises deprecation level log errors and will stop working
in TYPO3 v14.0.
Affected installations
This data object is only relevant for instances with extensions that add custom backend layout
data providers using
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['BackendLayoutDataProvider'] .
There are few known extensions that do this. The extension scanner is not configured to find
possible usages since the method names are too generic and would lead to too many false positives.
Migration
Create new objects using PCPP with named arguments instead of the setters.
Instances should be created using
new():
// Before
$dataProviderContext = GeneralUtility::makeInstance(DataProviderContext::class);
$dataProviderContext
->setPageId($pageId)
->setData($parameters['row'])
->setTableName($parameters['table'])
->setFieldName($parameters['field'])
->setPageTsConfig($pageTsConfig);
// After
$dataProviderContext = new DataProviderContext(
pageId: $pageId,
tableName: $parameters['table'],
fieldName: $parameters['field'],
data: $parameters['row'],
pageTsConfig: $pageTsConfig,
);
Copied!
Use the properties instead of the getters, example:
// Before
$pageId = $dataProviderContext->getPageId()
// After
$pageId = $dataProviderContext->pageId
Copied!
Deprecation: #105279 - Replace TYPO3 EnumType with Doctrine DBAL EnumType
TYPO3 did provide a custom Doctrine DBAL column type implementation for the native
SQL type
ENUM that was only compatible with MySQL and MariaDB connections.
The Doctrine DBAL Team implemented
ENUM support with
Release 4.2.0 in
class
\Doctrine\DBAL\Types\EnumType, only supporting MySQL and MariaDB
as well.
TYPO3 removed its custom implementation with TYPO3 v13.4.0.
Class
\TYPO3\CMS\Core\Database\Schema\Types\EnumType has been marked as deprecated
and is replaced with an class alias of
\EnumType.
The alias will be removed with TYPO3 v14.
doctrine/dbal
>= 4.2.0 is incompatible with TYPO3 versions before v13.4.0.
Composer-based instances using TYPO3 v13.3 or older should add an according
conflict to their composer.json.
Affected installations
Instances using the the
ENUM type directly or by any third party
extension using TYPO3 13.0 to 13.3 in Composer mode will break, when
the
doctrine/dbal
Composer packages is updated to version 4.2.0
or newer.
Migration
Upgrade (directly) to TYPO3 v13.4 or ensure to avoid updating
Doctrine DBAL to 4.2.x or newer versions in Composer-based instances.
Replace
\TYPO3\CMS\Core\Database\Schema\Types\EnumType type
declarations with
\Doctrine\DBAL\Types\EnumType.
Deprecation: #105297 - tableoptions and collate connection configuration
The possibility to configure default table options like charset and collation for the database
analyzer has been introduced using the array
$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['tableoptions'] with
sub-array keys
charset and
collate. These were only used for MySQL and MariaDB
connections.
Since TYPO3 v11 the
tableoptions keys were silently migrated to
defaultTableOptions, which is the proper Doctrine DBAL connection option for
for MariaDB and MySQL.
Furthermore, Doctrine DBAL 3.x switched from using they array key
collate to
collation, ignoring the old array key with Doctrine DBAL 4.x. This was silently
migrated by TYPO3, too.
These options and migration are now deprecated in favor of using the final array
keys and will be removed with TYPO3 v15 (or later) as breaking change.
Note
When migrating, make sure to remove the old
tableoptions array key, otherwise
it will take precedence over setting the new
defaultTableOptions key in TYPO3 v13.
Impact
Instances using the database connection options in
$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['tableoptions']
array, or using the
collate key will trigger a
E_USER_DEPRECATED
notification.
Affected installations
All instances using the mentioned options.
Migration
Review
settings.php and
additional.php and adapt the deprecated
configuration by renaming affected array keys.
The internal
\TYPO3\CMS\Frontend\Authentication\FrontendBackendUserAuthentication
class, used for frontend requests while being logged in the backend has been
moved from EXT:backend to EXT:frontend, since its dependencies are limited
to EXT:core and EXT:frontend.
While for v13 a class alias mapping and a legacy notation for IDE's is
available, the class is marked as @internal and therefore does not fall
under TYPO3's Core API deprecation policy.
After TYPO3 v13.0, only new functionality with a solid migration path
can be added on top, with aiming for as little as possible breaking changes
after the initial v13.0 release on the way to LTS.
Some additional fields were added to Page TSconfig
mod.linkvalidator.searchFields:
pages = canonical_link
sys_redirect = target
sys_file_reference = link
Two special fields are currently defined, but are
not checked yet due to their TCA configuration. For forward
compatibility, these are kept in the field configuration:
pages = media has TCA type="file"
tt_content = records has TCA type="group"
The following fields could theoretically be included in
custom configurations, as their type / softref is available,
but they are specifically not added in the default configuration:
sys_webhook = url (webhook should not be invoked)
tt_content = subheader (has softref email[subst]
which is not a supported link type)
Instead of having to use custom route aspect mappers, implementing
\TYPO3\CMS\Core\Routing\Aspect\StaticMappableAspectInterface ,
to avoid having &cHash= signatures
being applied to the generated URL, variables now can be simply declared
static in the corresponding route enhancer configuration.
Impact
By using the new static route configuration directive, custom aspect
mapper implementations can be avoided. However, static route variables
are only applied for a particular variable name if
there is no aspect mapper configured - aspect mappers are
considered more specific and will take precedence
there is a companion requirements definition which narrows the
set of possible values, and should be as restrictive as possible
to avoid potential cache flooding - static routes variables are
ignored, if there is no corresponding requirements definition
Example
routeEnhancers:Verification:type:SimpleroutePath:'/verify/{code}'static:code:truerequirements:# only allows SHA1-like hex values - which still allows lots# of possible combinations - thus, for this particular example# the handling frontend controller should be uncached as well## hint: if `static` is set, `requirements` must be set as wellcode:'[a-f0-9]{40}'
Copied!
As a result, using the URI query parameters &code=11f6ad8ec52a2984abaafd7c3b516503785c2072
would generate the URL https://example.org/verify/11f6ad8ec52a2984abaafd7c3b516503785c2072.
The TYPO3 system extension
typo3/cms-recycler
is now enabled by default for new TYPO3 installations.
Impact
New composer-based TYPO3 installations based on the TYPO3 CMS Base Distribution,
and new legacy installations (tarball / zip download) have the system extension recycler
enabled by default.
Feature: #99510 - Add file embedding option to asset ViewHelpers
The ViewHelpers <f:asset.css>
and <f:asset.script> have
been extended with a new argument
inline. If this argument is set,
the referenced asset file is rendered inline.
Setting the argument will therefore load the file content of the defined
href /
src as inline style or script. This is especially
useful for content elements which are used as first element on a page and
need some custom CSS to improve the Cumulative Layout Shift (CLS).
Impact
To add inline styles and scripts from a referenced file, the new
inline
argument can be set. For example, to add above-the-fold styles, the
priority option can be set, which will put the file contents of
EXT:sitepackage/Resources/Public/Css/my-hero.css as inline styles
to the
<head> section.
The new error handler
\TYPO3\CMS\Core\Error\PageErrorHandler\RedirectLoginErrorHandler
has been added, which makes it possible to redirect the user to a configurable page.
Requesting a login-protected URL would usually return a generic HTTP 403 error
in case of a missing fulfilled access permissions and the configuration
typolinkLinkAccessRestrictedPages = NONE (default)
is set.
By enabling this new handler via the site settings, the 403 response
can be handled and a custom redirect can be performed.
The
RedirectLoginErrorHandler
allows to define a
loginRedirectTarget, which must be configured to the page, where the
login process is handled. Additionally, the
loginRedirectParameter
must be set to the URL parameter that will be used to hand over the original
URL to the target page.
The redirect ensures that the original URL is added to the configured GET
parameter
loginRedirectParameter, so that the user can be redirected
back to the original page after a successful login.
The error handler allows
return_url or
redirect_url as values
for
loginRedirectParameter. Those values are used in extensions like
EXT:felogin or EXT:oidc.
Important
Redirection to the originating URL via URI arguments requires that
extensions like EXT:felogin are configured to allow these redirect modes
(for example via
plugin.tx_felogin_login.settings.redirectMode=getpost,loginError)
The new error handler works (with some minor exceptions) similar to the
"Forbidden (HTTP Status 403)" handler in TYPO3 extension
plan2net/sierrha
.
It will still emit generic 403 HTTP error messages in certain scenarios,
like when a user is already logged in, but the permissions are not
satisfied.
Impact
It is now possible to configure a login redirection process when a user has no
access to a page and a 403 error is thrown, so that after login the
originating URL is requested again. Previously, this required custom
Middlewares or implementations of
PageErrorHandlerInterface .
Feature: #101391 - Add base64 attribute to ImageViewHelper
The ViewHelpers <f:image> and
<f:uri.image> now
support the attribute
base64="true" that will provide
a possibility to return the value of the image's
src attribute
encoded in base64.
It is now possible to configure static routes with the type asset to link to
resources which are typically located in the directory
EXT:my_extension/Resources/Public/.
The
\TYPO3\CMS\Core\Page\AssetCollector options have been extended to
include an external
flag. When set for asset files using
$assetCollector->addStyleSheet()
or
$assetCollector->addJavaScript(), all processing of the asset
URI (like the addition of the cache busting parameter) is skipped and the input
path will be used as-is in the resulting HTML tag.
Example
The following code skips the cache busting parameter ?1726090820 for the
supplied CSS file:
GIFBUILDER, the image manipulation library for TypoScript based on GDlib, a PHP
extension bundled into PHP, now also supports generating resulting files of
type "avif".
AVIF is an image format, that is supported by most modern browsers, and usually
has a better compression (= smaller file size) than jpg files.
Important
Before using this feature, please check whether the used operating system
actually supports de/encoding AVIF files. Especially Debian 11 (Bullseye)
and older or systems forked from that may lack AVIF support.
Impact
If defined via format=avif within a GifBuilder setup, the generated files are
now AVIF files instead of png (the default).
It is possible to define the quality of a AVIF image similar to jpg images
globally via
$TYPO3_CONF_VARS['GFX']['avif_quality'] or via TypoScript's
"quality" property on a per-image basis. Via TypoScript it is also possible
to use the new property "speed" - see https://www.php.net/manual/en/function.imageavif.php
for more details.
A new test in the Environment module / Install Tool can be used to check if the
bundled GDlib extension of your PHP version supports the AVIF image format.
Feature: #102422 - Introduce CacheDataCollector Api
A new API has been introduced to collect cache tags and their corresponding
lifetime. This API is used in TYPO3 to accumulate cache tags from page cache and
content object cache.
The API is implemented as a new PSR-7 request attribute
'frontend.cache.collector', which makes this API independent from TSFE.
Every cache tag has a lifetime. The minimum lifetime is calculated
from all given cache tags. By default, the lifetime of a cache tag is set to
PHP_INT_MAX, so it expires many years in the future. API users must
therefore define the lifetime of a cache tag individually.
The current TSFE API is deprecated in favor of the new API, as the
current cache tag API implementation does not allow to set lifetime and
extension authors had to work around it.
Example
Add a single cache tag with 24 hours lifetime
useTYPO3\CMS\Core\Cache\CacheTag;
$cacheDataCollector = $request->getAttribute('frontend.cache.collector');
$cacheDataCollector->addCacheTags(
new CacheTag('tx_myextension_mytable', 86400)
);
Copied!
Add multiple cache tags with different lifetimes
useTYPO3\CMS\Core\Cache\CacheTag;
$cacheDataCollector = $request->getAttribute('frontend.cache.collector');
$cacheDataCollector->addCacheTags(
new CacheTag('tx_myextension_mytable_123', 3600),
new CacheTag('tx_myextension_mytable_456', 2592000)
);
Copied!
Remove a cache tag
useTYPO3\CMS\Core\Cache\CacheTag;
$cacheDataCollector = $request->getAttribute('frontend.cache.collector');
$cacheDataCollector->removeCacheTags(
new CacheTag('tx_myextension_mytable_123')
);
Copied!
Remove multiple cache tags
useTYPO3\CMS\Core\Cache\CacheTag;
$cacheDataCollector = $request->getAttribute('frontend.cache.collector');
$cacheDataCollector->removeCacheTags(
new CacheTag('tx_myextension_mytable_123'),
new CacheTag('tx_myextension_mytable_456')
);
Copied!
Get minimum lifetime, calculated from all cache tags
The following event should only be used in code that has no access to the
request attribute
'frontend.cache.collector', it is marked
@internal
and may vanish: It designed to allow passive cache-data signaling, without
exactly knowing the current context and not having the current request at hand.
It is not meant to allow for cache tag interception or extension.
Add cache tag without access to the request object
$this->eventDispatcher->dispatch(
new AddCacheTagEvent(
new CacheTag('tx_myextension_mytable_123', 3600)
)
);
Copied!
Feature: #103090 - Make link type label configurable
It is now possible to provide a translated label for custom link types.
For this, a new interface
\TYPO3\CMS\Linkvalidator\Linktype\LabelledLinktypeInterface has been
created, which offers the method
getReadableName for implementation.
That method can return the translated label.
The default abstract implementation
\TYPO3\CMS\Linkvalidator\Linktype\AbstractLinktype has been enhanced
to implement that interface. Any custom class extending this abstract is
able to override the method
getReadableName to provide the
custom translation.
Custom linktype classes should now configure a label by implementing the method
LabelledLinktypeInterface::getReadableName().
All existing custom implementations of the
AbstractLinktype class or the
LabelledLinktypeInterface
will continue to work as before, and will just continue to use the internal name of
the link type, instead of a translated label.
Feature: #103511 - Introduce Extbase file upload and deletion handling
TYPO3 now provides an API for file upload- and deletion-handling in Extbase
extensions, which allows extension developers to implement file uploads
more easily into Extbase Domain Models.
The scope of this API is to cover some of the most common use cases and to
keep the internal file upload and deletion process in Extbase as simple as
possible.
The API supports mapping and handling of file uploads and deletions for the
following scenarios:
Property of type
FileReference
in a domain model
Property of type
\TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
in a domain model
File uploads can be validated by the following rules:
minimum and maximum file count
minimum and maximum file size
allowed MIME types
image dimensions (for image uploads)
Additionally, it is ensured, that the filename given by the client is valid,
meaning that no invalid characters (null-bytes) are added and that the file
does not contain an invalid file extension. The API has support for custom
validators, which can be created on demand.
To avoid complexity and maintain data integrity, a file upload is only
processed if the validation of all properties of a domain model is successful.
In this first implementation, file uploads are not persisted/cached temporarily,
so this means in any case of a validation failure ("normal" validators and file upload
validation) a file upload must be performed again by users.
Possible future enhancements of this functionality could enhance the existing
#[FileUpload] attribute/annotation with configuration like a temporary storage
location, or specifying additional custom validators (which can be done via the PHP-API as
described below)
Nesting of domain models
File upload handling for nested domain models (e.g. modelA.modelB.fileReference)
is not supported.
File upload configuration with the FileUpload attribute
File upload for a property of a domain model can be configured using the
newly introduced
\TYPO3\CMS\Extbase\Annotation\FileUpload attribute.
All configuration settings of the
\TYPO3\CMS\Extbase\Mvc\Controller\FileUploadConfiguration object can
be defined using the
FileUpload
attribute. It is however not possible
to add custom validators using the
FileUpload attribute, which you
can achieve with a manual configuration as shown below.
The currently available configuration array keys are:
validation (
array with keys required, maxFiles, minFiles,
fileSize, allowedMimeTypes, mimeType, imageDimensions, see
File upload validation)
uploadFolder (
string, destination folder)
duplicationBehavior (
object, behaviour when file exists)
addRandomSuffix (
bool, suffixing files)
createUploadFolderIfNotExist (
bool, whether to create missing
directories)
It is also possible to use the
FileUpload annotation to configure
file upload properties, but it is recommended to use the
FileUpload attribute due to better readability.
Manual file upload configuration
A file upload configuration can also be created manually and should be
done in the
initialize*Action.
The configuration for a file upload is defined in a
FileUploadConfiguration object.
This object contains the following configuration options.
Hint
The appropriate setter methods or configuration
keys can best be inspected inside that class definition.
Property name:
Defines the name of the property of a domain model to which the file upload
configuration applies. The value is automatically retrieved when using
the
FileUpload attribute. If the
FileUploadConfiguration object
is created manually, it must be set using the
$propertyName
constructor argument.
Validation:
File upload validation is defined in an array of validators in the
FileUploadConfiguration object. The validator
\TYPO3\CMS\Extbase\Validation\Validator\FileNameValidator ,
which ensures that no executable PHP files can
be uploaded, is added by default if the file upload configuration object
is created using the
FileUpload attribute.
In addition, Extbase includes the following validators to validate an
UploadedFile object:
Those validators can either be configured with the
FileUpload attribute or added
manually to the configuration object
with the
addValidator method.
Required:
Defines whether a file must be uploaded. If it is set to true, the
minFiles configuration is set to 1.
Minimum files:
Defines the minimum amount of files to be uploaded.
Maximum files:
Defines the maximum amount of files to be uploaded.
Upload folder:
Defines the upload path for the file upload. This configuration expects a
storage identifier (e.g.
1:/user_upload/folder/). If the given target
folder in the storage does not exist, it is created automatically.
Upload folder creation, when missing:
The default creation of a missing storage folder can be disabled via the
configuration attribute
createUploadFolderIfNotExist
(
bool, default
true).
Add random suffix:
When enabled, the filename of an uploaded and persisted file will contain a
random 16 char suffix. As an example, an uploaded file named
job-application.pdf will be persisted as
job-application-<random-hash>.pdf in the upload folder.
The default value for this configuration is
true and it is recommended
to keep this configuration active.
This configuration only has an effect when uploaded files are persisted.
Duplication behavior:
Defines the FAL behavior, when a file with the same name exists in the target
folder. Possible values are
DuplicationBehavior::RENAME (default),
DuplicationBehavior::REPLACE and
DuplicationBehavior::CANCEL.
Modifying existing configuration
File upload configuration defined by the
FileUpload attribute can be
changed in the
initialize*Action.
The example shows how to modify the file upload configuration for the argument
item and the property
file. The minimum amount of files to be
uploaded is set to
2 and a custom validator is added.
To remove all defined validators except the
DenyPhpUploadValidator, use
the
resetValidators() method.
Using TypoScript configuration for file uploads configuration
When a file upload configuration for a property has been added using the
FileUpload attribute, it may be
required make the upload folder or
other configuration options configurable with TypoScript.
Extension authors should use the
initialize*Action to apply settings
from TypoScript to a file upload configuration.
Each uploaded file can be validated against a configurable set of validators.
The
validation section of the
FileUpload attribute allows to
configure commonly used validators using a configuration shorthand.
The following validation rules can be configured in the
validation
section of the
FileUpload attribute:
Extbase will internally use the Extbase file upload validators for
fileSize,
mimeType and
imageDimensions validation.
Custom validators can be created according to project requirements and must
extend the Extbase
AbstractValidator .
The value to be validated is
always a PSR-7
UploadedFile object.
Custom validators can however not
be used in the
FileUpload attribute
and must be configured manually.
Shorthand notation for allowedMimeTypes
Using the
mimeType configuration array, all options of the MimeTypeValidator
can be set as sub-keys (since TYPO3 13.4.1):
The shorthand notation via
'allowedMimeTypes' continues to
exist, in case only the mime type validation is needed. However, it is recommended
to utilize the full
'mimeType' configuration array.
Example for an object with an
TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
property, containing multiple files and allowing to delete the first one
(iteration is possible within Fluid, to do that for every object of the collection):
Extbase will then handle file deletion(s) before persisting a validated
object. It will:
validate that minimum and maximum file upload configuration for the affected
property is fulfilled (only if the property has a
FileUpload )
delete the affected
sys_file_reference record
delete the affected file
Internally, Extbase uses
FileUploadDeletionConfiguration objects to track
file deletions for properties of arguments. Files are deleted directly without
checking whether the current file is referenced by other objects.
Apart from using this ViewHelper, it is of course still possible to manipulate
FileReference properties with custom logic before persistence.
New PSR-14 events
The following new PSR-14 event has been added to allow customization
of file upload related tasks:
ModifyUploadedFileTargetFilenameEvent
The
ModifyUploadedFileTargetFilenameEvent
allows event listeners to
alter a filename of an uploaded file before it is persisted.
Event listeners can use the method getTargetFilename() to retrieve the filename
used for persistence of a configured uploaded file. The filename can then be
adjusted via setTargetFilename(). The relevant configuration can be retrieved
via getConfiguration().
Impact
Extension developers can use the new feature to implement file uploads and
file deletions in Extbase extensions easily with commonly known Extbase
property attributes/annotations.
Feature: #103521 - Change table restrictions UI to combine read and write permissions
The tables_select and tables_modify fields of the be_groups table store
information about permissions to read and write into selected database tables.
Due to TYPO3's internal behavior, when write permissions are granted for some
tables, those tables are also automatically available for reading.
To make managing table permissions much easier and more efficient for
integrators, the separate form fields for Tables (listing) [tables_select] and
Tables (modify) [tables_modify] have been combined into a single UI element.
This field now offers separate radio buttons to define which tables the backend
user group should have permission to read and / or write. This is done by
selecting one of the "No Access", "Read" or "Read & Write" options.
To further improve the user experience, it is also possible to use the
"Check All", "Uncheck All" and "Toggle Selection" options for each permission.
Under the hood, when these permissions are processed, they are still saved
separately in the tables_select and tables_modify columns in the
be_groups table, as they were before.
To render this new table view and handle its behavior, a dedicated form
renderType tablePermission has been introduced, which is now set for
the tables_modify column. The tables_select column has been changed
to TCA type passthrough.
The new form element is defined through:
\TYPO3\CMS\Backend\Form\Element\TablePermissionElement .
It uses a dedicated data provider defined in:
\TYPO3\CMS\Backend\Form\FormDataProvider\TcaTablePermission .
The JavaScript code is handled by a new web component:
@typo3/backend/form-engine/element/table-permission-element.js.
When the
TcaTablePermission
data provider handles the configuration, it
reads table lists from both the tables_select and tables_modify
columns and combines them into a single array with unique table names.
Impact
Managing table permissions for backend user groups has been improved by
visually combining the Tables (listing) [tables_select] and
Tables (modify) [tables_modify] options, as well as by adding the
multi record selection functionality.
Note
These changes might affect custom integrations and modifications made to
the tables_select or tables_modify columns in the be_groups TCA.
Integrators who have modified the configuration for these fields should
verify if their code works and adapt it if needed.
Feature: #103576 - Allow defining opacity in TCA type=color element
A new boolean property opacity has been added to the TCA configuration of
a TCA type color element to allow defining colors with an opacity using
the RRGGBBAA color notation.
With forge#103783 the new
\TYPO3\CMS\Core\Domain\Record object has been
introduced. It is an
object representing a raw database record, based on TCA and is usually used in
the frontend (via Fluid Templates), when fetching records with the
RecordTransformationProcessor
(
record-transformation) or by collecting content elements with the
PageContentFetchingProcessor
(
page-content).
The Records API - introduced together with the Schema API in forge#104002 -
now expands the record's values for most common field types (known
from the TCA Schema) from their raw database value into "rich-flavored" values,
which might be
Record ,
FileReference ,
\TYPO3\CMS\Core\Resource Folder or
\DateTimeImmutable objects.
This works for the following "relation" TCA types:
category
file
folder
group
inline
select with
MM and
foreign_table
In addition, the values of following TCA types are also resolved and
expanded automatically:
datetime
flex
json
link
select with a static list of entries
Each of the fields receives a full-fledged resolved value, based on the field
configuration from TCA.
In case of relations (
category,
group,
inline,
select with
MM and
foreign_table), a collection
(
LazyRecordCollection) of new
Record objects is attached as
value. In case of
file, a collection (
LazyFileReferenceCollection)
of
FileReference objects and in case of type
folder, a collection
(
LazyFolderCollection) of
Folder objects are attached.
Note
The relations are only resolved once they are accessed - also known as
"lazy loading". This allows for recursion and circular dependencies to be
managed automatically. It is therefore also possible that the collection
is actually empty.
In order to define cardinality on TCA level, the option
relationship is
introduced for all "relation" TCA types listed above. If this option is set to
oneToOne or
manyToOne, then relations are resolved directly
without being wrapped into collection objects. In case the relation can
not be resolved,
NULL is returned.
The TCA option
maxitems does not influence this behavior. This means
it is possible to have a
oneToMany relation with maximum one value
allowed. This way, overrides of this value will not break functionality.
Field expansion
For TCA type
flex, the corresponding FlexForm is resolved and therefore
all values within this FlexForm are processed and expanded as well.
Fields of TCA type
datetime will be transformed into a full
\DateTimeInterface object.
Fields of TCA type
json will provide the decoded JSON value.
Fields of TCA type
link will provide the
\TYPO3\CMS\Core\LinkHandling\TypolinkParameter object,
which is an object oriented representation of the corresponding TypoLink
parameter configuration.
Fields of TCA type
select without a
relationship will always provide
an array of static values.
Note
TYPO3 tries to automatically resolve the
relationship for type
select fields, which use
renderType=selectSingle and
having a
foreign_table set. This means, in case no
relationship has been defined yet, it is set to either
manyToOne
as the default or
manyToMany for fields with option
MM.
Impact
When using
Record objects through the
\TYPO3\CMS\Core\Domain\RecordFactory API, e.g. via
RecordTransformationProcessor
(
record-transformation) or
PageContentFetchingProcessor
(page-content), the corresponding
Record
objects are now automatically processed and enriched.
Those can not only be used in the frontend but also for Backend Previews in
the page module. This is possible by configuring a Fluid Template via Page
TSconfig to be used for the page preview rendering:
In such template the newly available variable
{record} can be used to
access the resolved field values. It is advised to migrate existing preview
templates to this new object, as the former values will probably vanish in the
next major version.
By utilizing the new API for fetching records and content elements, the need
for further data processors, e.g.
FilesProcessor (
files),
becomes superfluous since all relations are resolved automatically when
requested.
Feature: #103789 - Add "close"-button to page layout, if returnUrl is set
A "close"-button is now displayed in the page module, if the returnUrl
argument is set. When this button is clicked, the previous module
leading to the page module (or a custom link defined in returnUrl) will be displayed
again.
In order to utilize this, backend module links set in extensions must pass the returnUrl
argument. If returnUrl is not set, the "close"-button will not be displayed.
Examples
Here is an example, using the Fluid
<be:moduleLink> ViewHelper:
The behaviour is similar to the
<be:uri.editRecord> ViewHelper,
where setting the returnUrl argument will also cause a "close"-button to
be displayed.
Important
When using the
<be:uri.editRecord> ViewHelper, returnUrl is
passed directly as argument. However, using
<be:moduleLink>, the
returnUrl argument must be passed as an additional parameter via the Fluid
ViewHelper's argument
arguments or
query.
The returnUrl should usually return to the calling (originating) module.
You can build the returnUrl with the Fluid ViewHelper
be:uri:
Fluid example for building returnUrl to module "linkvalidator"
The change has no impact, unless the functionality is being used. Extension
authors can make use of the new functionality to also conveniently link back to an originating
or custom module for a streamlined linear backend user-experience.
Feature: #104126 - Add configuration setting to define backend-locking file
TYPO3 supports the ability to lock the backend for maintenance reasons. This
is controlled with a LOCK_BACKEND file that was previously stored in
typo3conf/.
When empty, it falls back to a file LOCK_BACKEND, which is now stored
by default in:
var/lock/ for Composer Mode
config/ for Legacy Mode
If you previously manually maintained the LOCK_BACKEND file (for example via
deployment or other maintenance automation), please either adjust
your automations to the new file location, or change the setting to the desired file location,
or at best use the CLI commands
vendor/bin/typo3 backend:lock and
vendor/bin/typo3 backend:unlock.
The backend locking functionality is now contained in a distinct service class
\TYPO3\CMS\Backend\Authentication\BackendLocker to allow future flexibility.
When upgrading an installation to Composer Mode with a locked backend in effect,
please ensure your backend can remain locked by moving (or copying) the file to the new
location var/lock/.
Remember, if you want locked backend state to persist between deployments, ensure that the
used directory (var/lock by default) is shared between deployment releases.
Impact
The location for LOCK_BACKEND to lock (and unlock) the backend can now be controlled
by maintainers of a TYPO3 installation, and has moved outside of typo3conf/ by default
to either var/lock/ (Composer) or config/ (Legacy).
Feature: #104168 - PSR-14 event for modifying countries
A new PSR-14 event
\TYPO3\CMS\Core\Country\Event\BeforeCountriesEvaluatedEvent
has been introduced to modify the list of countries provided by
\TYPO3\CMS\Core\Country\CountryProvider .
This event allows to add, remove and alter countries from the list used by the
provider class itself and ViewHelpers like
<f:form.countrySelect />.
Note
The DTO
\TYPO3\CMS\Core\Country\Country
uses EXT:core/Resources/Private/Language/Iso/countries.xlf for translating
the country names.
If additional countries are added, add translations to countries.xlf
via locallangXMLOverride.
Example
An example corresponding event listener class:
<?phpdeclare(strict_types=1);
namespaceMyVendor\MyExtension\EventListener;
useTYPO3\CMS\Core\Attribute\AsEventListener;
useTYPO3\CMS\Core\Country\Country;
useTYPO3\CMS\Core\Country\Event\BeforeCountriesEvaluatedEvent;
final readonly classEventListener{
#[AsEventListener(identifier: 'my-extension/before-countries-evaluated')]publicfunction__invoke(BeforeCountriesEvaluatedEvent $event): void{
$countries = $event->getCountries();
unset($countries['BS']);
$countries['XX'] = new Country(
'XX',
'XYZ',
'Magic Kingdom',
'987',
'🔮',
'Kingdom of Magic and Wonders'
);
$event->setCountries($countries);
}
}
<?xml version="1.0" encoding="utf-8" standalone="yes" ?><xliffversion="1.0"><filesource-language="en"datatype="plaintext"date="2024-01-08T18:44:59Z"product-name="my_extension"><body><trans-unitid="XX.name"approved="yes"><source>Magic Kingdom</source></trans-unit><trans-unitid="XX.official_name"approved="yes"><source>Kingdom of Magic and Wonders</source></trans-unit></body></file></xliff>
Copied!
Impact
Using the PSR-14 event
BeforeCountriesEvaluatedEvent allows
modification of countries provided by
CountryProvider .
Feature: #104221 - PSR-14 events for RTE <-> Persistence transformations
When using an RTE HTML content element, two transformations
take place within the TYPO3 backend:
From database: Fetching the current content from the database (persistence) and
preparing it to be displayed inside the RTE HTML component.
To database: Retrieving the data returned by the RTE and preparing it to
be persisted into the database.
This takes place in the
\TYPO3\CMS\Core\Html\RteHtmlParser class, by utilizing the
methods
transformTextForRichTextEditor and
transformTextForPersistence.
With forge#96107 and forge#92992, the former hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_parsehtml_proc.php']['transformation']
was removed, which took care of applying custom user-transformations. The suggested replacement
for this was to use the actual RTE YAML configuration and API like
allowAttributes.
Now, four PSR-14 Events are introduced to allow more granular control over data for
persistence -> RTE and RTE -> persistence. This allows developers to apply
more customized transformations, apart from the internal and API ones:
Modify data when saving RTE content to the database (persistence):
The event is meant to be used so that developers can change the HTML content
either before the internal TYPO3 modifications, or after those.
The before events are executed before TYPO3 applied any kind of internal transformations,
like for links. Event Listeners that want to modify output so that
TYPO3 additionally operates on that, should listen to those before-Events.
When Event Listeners want to perform on the final result, the corresponding after-Events
should be utilized.
Event listeners can use
$value = $event->getHtmlContent() to get the current contents,
apply changes to $value and then store the manipulated data via $event->setHtmlContent($value),
see example:
Example
An event listener class is constructed which will take an RTE input TYPO3 and internally
store it in the database as [tag:typo3]. This could allow a content element data processor
in the frontend to handle this part of the content with for example internal glossary operations.
The workflow would be:
Editor enters "TYPO3" in the RTE instance.
When saving, this gets stored as "[tag:typo3]".
When the editor sees the RTE instance again, "[tag:typo3]" gets replaced to "TYPO3" again.
So: The editor will always only see "TYPO3" and not know how it is internally handled.
The frontend output receives "[tag:typo3]" and could do its own content element magic,
other services accessing the database could also use the parseable representation.
<?phpdeclare(strict_types=1);
namespaceMyVendor\MyExtension\EventListener;
useTYPO3\CMS\Core\Attribute\AsEventListener;
classTransformListener{
/**
* Transforms the current value the RTE delivered into a value that is stored (persisted) in the database.
*/#[AsEventListener('rtehtmlparser/modify-data-for-persistence')]publicfunctionmodifyPersistence(AfterTransformTextForPersistenceEvent $event): void{
$value = $event->getHtmlContent();
$value = str_replace('TYPO3', '[tag:typo3]', $value);
$event->setHtmlContent($value);
}
/**
* Transforms the current persisted value into something the RTE can display
*/#[AsEventListener('rtehtmlparser/modify-data-for-richtexteditor')]publicfunctionmodifyRichTextEditor(AfterTransformTextForRichTextEditorEvent $event): void{
$value = $event->getHtmlContent();
$value = str_replace('[tag:typo3]', 'TYPO3', $value);
$event->setHtmlContent($value);
}
}
There are various
TCA table
ctrl settings that define fields used
to enable certain TYPO3 table capabilities and to specify the database column
to store this row state.
An example is
$GLOBALS['TCA']['ctrl']['enablecolumns']['starttime'] = 'starttime' , which
makes the table "start time aware", resulting in the automatic exclusion of a record
if the given start time is in the future, when rendered in the frontend.
Such
ctrl settings require TCA
columns definitions. Default definitions
of such
columns are now automatically added to
TCA if not manually
configured. Extension developers can now remove and avoid a significant amount
of boilerplate field definitions in
columns and rely on TYPO3 Core to create
them automatically. Note the Core does not automatically add such columns to TCA
types or
palettes definitions: Developers still need to place them,
to show the columns when editing record rows, and need to add according access
permissions.
Let us have a quick look on what happened within TCA and its surrounding code lately,
to see how this feature embeds within the general TYPO3 Core strategy in this area
and why the above feature has been implemented at this point in time:
TCA has always been a central cornerstone of TYPO3. The TYPO3 Core strives to maintain
this central part while simplifying and streamlining less desirable details.
TYPO3 version v12 aimed to simplify single column definitions by implementing new
column types like
file,
category,
email, and more. These are
much easier to understand and require far fewer single property definitions than
previous solutions. With this in place, auto-creation of database column
definitions derived from TCA has been established with TYPO3 v13, making the
manual definition of database table schemas in ext_tables.sql largely
unnecessary. Additionally, an object-oriented approach called
TcaSchema has
been introduced to harmonize and simplify information retrieval from TCA.
With the step described in this document - the auto-creation of TCA columns from
ctrl properties - the amount of manual boilerplate definitions is
significantly reduced, and the TYPO3 Core gains more control over these columns to
harmonize these fields throughout the system. Note that the TYPO3 Core has not yet
altered the structure of TCA
types and
palettes. This will be one of
the next steps in this area, but details have not been decided upon yet.
All these steps streamline TCA and its surrounding areas, simplify the system,
and reduce the amount of details developers need to be aware of when defining
their own tables and fields.
This document details the "column auto-creation from 'ctrl' fields" feature: It
first lists all affected settings with their derived default definitions. It
concludes with a section relevant for instances that still need to override
certain defaults of these columns by explaining the order of files and classes
involved in building TCA and the available options to change defaults and where
to place these changes.
Auto-created columns from 'ctrl'
The configuration settings below enable single table capabilities. Their values
are a database column name responsible for storing the row data of the capability.
If a setting is defined in a "base" TCA table file (Configuration/TCA, not
in Configuration/TCA/Overrides), the TYPO3 Core will add default
columns
definition for this field name if no definition exists in a base file.
This setting makes database table rows "frontend group aware": A row can be defined
to be shown only to frontend users who are a member of selected groups.
$GLOBALS['TCA']['ctrl']['languageField'] and transOrigPointerField`
These setting make database table rows "localization aware": Backend editors
can create localized versions of a record. Note when
languageField is
set, and
transOrigPointerField is not, the TYPO3 Core will automatically set
transOrigPointerField to
l10n_parent since both fields must be
always set in combination.
This setting makes database table rows "parent language record change aware": Backend
editors can have an indicator when the parent column has been changed.
To understand if and when TCA column auto-creation from
ctrl definitions
kicks in, it is important to have an overview of the order of the single loading
steps:
Load single files from extension Configuration/TCA files
NEW - Enrich
columns from
ctrl settings
Load single files from extension Configuration/TCA/Overrides files
Apply TCA migrations
Apply TCA preparations
As a result of this strategy,
columns fields are not auto-created, when
a
ctrl capability is added in a Configuration/TCA/Overrides
file, and not in a Configuration/TCA "base" file. In general, such
capabilities should be set in base files only: Adding them at a later point - for
example in a different extension - is brittle and there is a risk the main
extension can not deal with such an added capability properly.
Overriding definitions from auto-created TCA columns
I most cases, developers do not need to change definitions of
columns
auto-created by the TYPO3 Core. In general, it is advisable to not actively do this.
Developers who still want to change detail properties of such columns should
generally stick to "display" related details only.
There are two options to have own definitions: When a column is already defined
in a "base" TCA file (Configuration/TCA), the TYPO3 Core will not override it.
Alternatively, a developer can decide to let the TYPO3 Core auto-create a column, to
then override single properties in Configuration/TCA/Overrides files.
As example, "base"
pages file defines this (step 1 above):
When an editor creates a new page, it should be "disabled" by default to
avoid having a new page online in the website before it is set up completely.
A Configuration/TCA/Overrides/pages.php file does this:
<?php// New pages are disabled by default
$GLOBALS['TCA']['pages']['columns']['hidden']['config']['default'] = 1;
Copied!
Impact
Extension developers can typically remove
columns definitions of all the
above fields and rely on TYPO3 Core creating them with a good default
definition.
It is only required to define the desired table capabilities in
ctrl with
its field names, and the system will create the according
columns
definitions automatically.
Feature: #104321 - Allow handling of argument mapping exceptions in ActionController
A new method
handleArgumentMappingExceptions has been introduced in
Extbase
\TYPO3\CMS\Extbase\Mvc\Controller\ActionController to improve
handling of exceptions that occur during argument mapping.
The new method supports optional handling of the following exceptions:
\TYPO3\CMS\Extbase\Property\Exception\TargetNotFoundException ,
which occurs, when a given object UID can not be resolved to an existing record.
\TYPO3\CMS\Extbase\Mvc\Controller\Exception\RequiredArgumentMissingException ,
which occurs, when a required action argument is missing.
Handling of the exceptions can be enabled globally with the following TypoScript
configuration.
By default, these options are set to 0, which will lead to exceptions
being thrown (and would lead to errors, if not caught). This is the current
behavior of TYPO3.
When setting one of these values to 1, the configured exceptions will not be thrown.
Instead, a
pageNotFound response is propagated, resulting in a 404 error being
shown.
Additionally, extension authors can extend or override the method
handleArgumentMappingExceptions in relevant Controllers in order
to implement custom argument mapping exception handling.
Impact
Extension authors can now handle exceptions in implementations of a
ActionController ,
which are thrown during argument mapping.
Feature: #104451 - Redis backends support for key prefixing
It is now possible to add a dedicated key prefix for all invocations of a Redis
cache or session backend. This allows to use the same Redis database for multiple
caches or even for multiple TYPO3 instances if the provided prefix is unique.
Possible use cases are:
Using Redis caching for multiple caches, if only one Redis database is available
Pre-fill caches upon deployments using a new prefix (zero downtime deployments)
additional.php example for using Redis as session backend
The new feature allows to use the same Redis database for multiple caches or even
for multiple TYPO3 instances while having no impact on existing configuration.
Attention
If you start using the same Redis database for multiple caches or
using the same database also for session storage, make sure any involved
cache configuration uses a unique key prefix.
If only one of the caches does not use a key prefix, any cache flush
operation will always flush the whole database, hence also all other caches/sessions.
Feature: #104482 - Add if() support to ExpressionBuilder
The TYPO3
\TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
provides a new method to phrase "if-then-else" expressions. Those are translated
into
IF or
CASE statements depending on the used database engine.
ExpressionBuilder::if()
Creates an IF-THEN-ELSE expression.
Method signature
/**
* Creates IF-THEN-ELSE expression construct compatible with all supported database vendors.
* No automatic quoting or escaping is done, which allows to build up nested expression statements.
*
* **Example:**
* ```
* $queryBuilder
* ->selectLiteral(
* $queryBuilder->expr()->if(
* $queryBuilder->expr()->eq('hidden', $queryBuilder->createNamedParameter(0, Connection::PARAM_INT)),
* $queryBuilder->quote('page-is-visible'),
* $queryBuilder->quote('page-is-not-visible'),
* 'result_field_name'
* ),
* )
* ->from('pages');
* ```
*
* **Result with MySQL:**
* ```
* SELECT (IF(`hidden` = 0, 'page-is-visible', 'page-is-not-visible')) AS `result_field_name` FROM `pages`
* ```
*/publicfunctionif(
CompositeExpression|\Doctrine\DBAL\Query\Expression\CompositeExpression|\Stringable|string $condition,
\Stringable|string $truePart,
\Stringable|string $falsePart,
\Stringable|string|null $as = null
): string{
$platform = $this->connection->getDatabasePlatform();
$pattern = match (true) {
$platform instanceof DoctrineSQLitePlatform => 'IIF(%s, %s, %s)',
$platform instanceof DoctrinePostgreSQLPlatform => 'CASE WHEN %s THEN %s ELSE %s END',
$platform instanceof DoctrineMariaDBPlatform,
$platform instanceof DoctrineMySQLPlatform => 'IF(%s, %s, %s)',
default => thrownew \RuntimeException(
sprintf('Platform "%s" not supported for "%s"', $platform::class, __METHOD__),
1721806463
)
};
$expression = sprintf($pattern, $condition, $truePart, $falsePart);
if ($as !== null) {
$expression = $this->as(sprintf('(%s)', $expression), $as);
}
return $expression;
}
Copied!
Impact
Extension authors can use the new expression method to build more advanced
queries without the requirement to deal with the correct implementation for
all supported database vendors.
Note
No automatic quoting or escaping is done for the condition and true/false
part. Extension authors need to ensure proper quoting for each part or use
API calls doing the quoting, for example the TYPO3 CompositeExpression or
ExpressionBuilder calls.
Feature: #104493 - Add castText() expression support to ExpressionBuilder
The TYPO3
\TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
provides a new method to cast expression results to text like datatypes. This
is done to large
VARCHAR/CHAR types using the
CAST/CONVERT or similar
methods based on the used database engine.
Note
This should not be mixed with
TEXT,
CHAR or
VARCHAR
data types for column (fields) definition used to describe the structure
of a table.
ExpressionBuilder::castText()
Creates a
CAST expression.
Method signature
/**
* Creates a cast for the `$expression` result to a text datatype depending on the database management system.
*
* Note that for MySQL/MariaDB the corresponding CHAR/VARCHAR types are used with a length of `16383` reflecting
* 65554 bytes with `utf8mb4` and working with default `max_packet_size=16KB`. For SQLite and PostgreSQL the text
* type conversion is used.
*
* Main purpose of this expression is to use it in a expression chain to convert non-text values to text in chain
* with other expressions, for example to {@see self::concat()} multiple values or to ensure the type, within
* `UNION/UNION ALL` query parts for example in recursive `Common Table Expressions` parts.
*
* This is a replacement for {@see QueryBuilder::castFieldToTextType()} with minor adjustments like enforcing and
* limiting the size to a fixed variant to be more usable in sensible areas like `Common Table Expressions`.
*
* Alternatively the {@see self::castVarchar()} can be used which allows for dynamic length setting per expression
* call.
*
* **Example:**
* ```
* $queryBuilder->expr()->castText(
* '(' . '1 * 10' . ')',
* 'virtual_field'
* );
* ```
*
* **Result with MySQL:**
* ```
* CAST((1 * 10) AS CHAR(16383) AS `virtual_field`
* ```
*
* @throws \RuntimeException when used with a unsupported platform.
*/publicfunctioncastText(CompositeExpression|\Stringable|string $expression, string $asIdentifier = ''): string{
$platform = $this->connection->getDatabasePlatform();
if ($platform instanceof DoctrinePostgreSQLPlatform) {
return$this->as(sprintf('((%s)::%s)', $expression, 'text'), $asIdentifier);
}
if ($platform instanceof DoctrineSQLitePlatform) {
return$this->as(sprintf('(CAST((%s) AS %s))', $expression, 'TEXT'), $asIdentifier);
}
if ($platform instanceof DoctrineMariaDBPlatform) {
// 16383 is the maximum for a VARCHAR field with `utf8mb4`return$this->as(sprintf('(CAST((%s) AS %s(%s)))', $expression, 'VARCHAR', '16383'), $asIdentifier);
}
if ($platform instanceof DoctrineMySQLPlatform) {
// 16383 is the maximum for a VARCHAR field with `utf8mb4`return$this->as(sprintf('(CAST((%s) AS %s(%s)))', $expression, 'CHAR', '16383'), $asIdentifier);
}
thrownew \RuntimeException(
sprintf(
'%s is not implemented for the used database platform "%s", yet!',
__METHOD__,
get_class($this->connection->getDatabasePlatform())
),
1722105672
);
}
Copied!
Impact
Extension authors can use the new expression method to build more advanced
queries without the requirement to deal with the correct implementation
for all supported database vendors - at least to some grade.
Feature: #104526 - Provide validators for PSR-7 UploadedFile objects in Extbase
4 new Extbase validators have been added to allow common validation tasks of a
PSR-7
\TYPO3\CMS\Core\Http\UploadedFile object or an
\TYPO3\CMS\Extbase\Persistence\ObjectStorage containing PSR-7
UploadedFile objects.
Note, that the new validators can only be applied to the TYPO3 implementation
of the PSR-7
\Psr\Http\Message\UploadedFileInterface because they validate the uploaded
files before it has been moved.
Custom implementations of the
\UploadedFileInterface must continue to
implement their own validators.
FileNameValidator
This validator ensures, that files with PHP executable file extensions can not
be uploaded. The validator has no options.
FileSizeValidator
This validator can be used to validate an uploaded file against a given minimum
and maximum file size.
Validator options:
minimum - The minimum size as string (e.g. 100K)
maximum - The maximum size as string (e.g. 100K)
MimeTypeValidator
This validator can be used to validate an uploaded file against a given set
of accepted MIME types. The validator additionally verifies, that the given
file extension of the uploaded file matches allowed file extensions for the
detected mime type.
Validator options:
allowedMimeTypes - An array of allowed MIME types
ignoreFileExtensionCheck - If set to "true", it is checked, the file
extension check is disabled
ImageDimensionsValidator
This validator can be used to validate an uploaded image for given image
dimensions. The validator must only be used, when it is ensured, that the
uploaded file is an image (e.g. by validating the MIME type).
Validator options:
width - Fixed width of the image as integer
height - Fixed height of the image as integer
minWidth - Minimum width of the image as integer. Default is 0
maxWidth - Maximum width of the image as integer. Default is PHP_INT_MAX
minHeight - Minimum height of the image as integer. Default is 0
maxHeight - Maximum height of the image as integer. Default is PHP_INT_MAX
Impact
TYPO3 extension autors can now use the new validators to validate a given
UploadedFile object.
Feature: #104631 - Add UNION Clause support to the QueryBuilder
The
UNION clause is used to combine the result sets of two or more
SELECT statements, which all database vendors support, each with their
own specific variations.
However, there is a commonly shared subset that works across all of them:
SELECT column_name(s) FROM table1
WHERE ...
UNION <ALL | DISTINCT>
SELECT column_name(s) FROM table2
WHERE ...
ORDERBY ...
LIMIT x OFFSET y
Copied!
with shared requirements:
Each SELECT must return the same fields in number, naming and order.
Each SELECT must not have ORDER BY, expect MySQL allowing it to be used as sub
query expression encapsulated in parentheses.
Generic
UNION clause support has been contributed to Doctrine DBAL and
is included since Release 4.1.0
which introduces two new API method on the
\QueryBuilder:
union(string|QueryBuilder $part) to create first UNION query part
addUnion(string|QueryBuilder $part, UnionType $type = UnionType::DISTINCT)
to add additional
UNION (ALL|DISTINCT) query parts with the selected union
query type.
TYPO3 decorates the Doctrine DBAL
\QueryBuilder
to provide for most API methods automatic
quoting of identifiers and values and to apply database restrictions automatically
for
SELECT queries.
The Doctrine DBAL API has been adopted now to provide the same surface for the
TYPO3
\TYPO3\CMS\Core\Database\Query\QueryBuilder and the intermediate
\TYPO3\CMS\Core\Database\Query\ConcreteQueryBuilder to make it easier to
create
UNION clause queries. The API on both methods allows to provide
dedicated
QueryBuilder instances
or direct queries as strings in case it is needed.
Note
Providing
UNION parts as plain string requires the developer to take
care of proper quoting and escaping within the query part.
In queries containing subqueries, only named placeholders (such as :username)
can be used and must be registered on the outermost
QueryBuilder object,
similar to advanced query creation with
SUB QUERIES.
Warning
QueryBuilder can be used create
UNION clause queries not compatible with all database providers,
for example using
LIMIT/OFFSET in each part query or other stuff.
UnionType::DISTINCT and UnionType::ALL
Each subsequent part needs to be defined either as
UNION DISTINCT or
UNION ALL which could have not so obvious effects.
For example, using
UNION ALL for all parts in between except for the last
one would generate larger result sets first, but discards duplicates when adding
the last result set. On the other side, using
UNION ALL tells the query
optimizer not to scan for duplicates and remove them at all which can be a
performance improvement - if you can deal with duplicates it can be ensured that
each part does not produce same outputs.
Example: Compose a
UNION clause query
Custom service class using a UNION query to retrieve data.
useDoctrine\DBAL\Query\UnionType;
useTYPO3\CMS\Core\Database\Connection;
useTYPO3\CMS\Core\Database\ConnectionPool;
final readonly classMyService{
publicfunction__construct(
private ConnectionPool $connectionPool,
){}
publicfunctionexecuteUnionQuery(
int $pageIdOne,
int $pageIdTwo,
): ?array{
$connection = $this->connectionPool->getConnectionForTable('pages');
$unionQueryBuilder = $connection->createQueryBuilder();
$firstPartQueryBuilder = $connection->createQueryBuilder();
$secondPartQueryBuilder = $connection->createQueryBuilder();
// removing automatic TYPO3 restriction for the sake of the example// to match the PLAIN SQL example when executed. Not removing them// will generate corresponding restriction SQL code for each part.
$firstPartQueryBuilder->getRestrictions()->removeAll();
$secondPartQueryBuilder->getRestrictions()->removeAll();
$expr = $unionQueryBuilder->expr();
$firstPartQueryBuilder
// The query parts **must** have the same column counts, and these// columns **must** have compatible types
->select('uid', 'pid', 'title')
->from('pages')
->where(
$expr->eq(
'pages.uid',
// !!! Ensure to use most outer / top / main QueryBuilder// instance for creating parameters and the complete// query can be executed in the end.
$unionQueryBuilder->createNamedParameter($pageIdOne, Connection::PARAM_INT),
)
);
$secondPartQueryBuilder
->select('uid', 'pid', 'title')
->from('pages')
->where(
$expr->eq(
'pages.uid',
// !!! Ensure to use most outer / top / main QueryBuilder instance
$unionQueryBuilder->createNamedParameter($pageIdTwo, Connection::PARAM_INT),
)
);
// Set first and second union part to the main (union)// QueryBuilder and return the retrieved rows.return $unionQueryBuilder
->union($firstPartQueryBuilder)
->addUnion($secondPartQueryBuilder, UnionType::DISTINCT)
->orderBy('uid', 'ASC')
->executeQuery()
->fetchAllAssociative();
}
}
Copied!
This would create the following query for MySQL with
$pageIdOne = 100 and
$pageIdTwo = 10:
A new CLI command
typo3 upgrade:mark:undone has been
introduced. It allows to mark a previously executed upgrade wizard as "undone",
so it can be run again.
This makes the existing functionality from the install tool also available on
CLI.
Note
Bear in mind that wizards theoretically can cause data inconsistencies when
being run again. Also, a wizard may not run properly again when its
pre-requisites no longer apply after its first run.
Impact
You can now mark an already executed upgrade wizard as "undone" with
typo3 upgrade:mark:undone <wizardIdentifier>
Class
\TYPO3\CMS\Core\View\ViewFactoryInterface has been added as a
generic view interface to create views that return an instance of
\TYPO3\CMS\Core\View\ViewInterface . This implements the "V" of "MVC"
in a generic way and is used throughout the TYPO3 Core.
This obsoletes all custom view instance creation approaches within the TYPO3 Core
and within TYPO3 extensions. Extensions should retrieve view instances based
on this
ViewFactoryInterface .
Impact
Instances of this interface should be injected using dependency injection. The
default injected implementation is a Fluid view, and can be reconfigured using
dependency injection configuration, typically in a Services.yaml file.
A casual example to create and render a view looks like this.
ContentArgumentName has been a feature on Fluid ViewHelpers for some time now.
It allows ViewHelpers to link a ViewHelper argument to the children of the
ViewHelper name. As a result, an input value can either be specified as an
argument or as the ViewHelper's children, leading to the same result.
Previously, this feature was only available to ViewHelpers using the trait
\CompileWithContentArgumentAndRenderStatic .
It is now available to all ViewHelpers since it has been integrated into the
\AbstractViewHelper . The
trait is no longer necessary.
To use the new feature, all the ViewHelper implementation needs to do is to define
a method getContentArgumentName() which returns the name of the argument to be
linked to the ViewHelper's children:
ViewHelpers using the trait
\CompileWithContentArgumentAndRenderStatic
should be migrated to the new feature.
\CompileWithContentArgumentAndRenderStatic
will continue to work in Fluid v4, but will log a deprecation level error message.
It will be removed in Fluid v5.
A new Site Settings editor has been introduced that allows to configure per-site
settings in file:config/sites/*/settings.yaml.
The new backend module Site Management > Settings
provides an overview of sites which offer configurable settings and makes
them editable based on
Site Set provided Settings Definitions.
The editor shows a list of settings categories and respective settings. It will
persist all settings into config/sites/*/settings.yaml. The module will
only persist settings that deviate from the site-scoped default value. That
means it will only change the minimal difference to the settings set defined
by the active sets for the respective site.
The backend module is currently available for administrators only, but will
likely be extended to be made available for editors in future.
Anonymous (undefined) site settings – as supported since TYPO3 v10 –
will not be made editable, but will be preserved as-is when persisting changes
through the settings editor.
Categorization
Sets can define categories and settings definitions can reference the category
by ID in order to assign a setting to a specific category.
These definitions are placed in settings.definitions.yaml
next to the site set file config.yaml.
categories:myCategory:label:'My Category'settings:my.example.setting:label:'My example setting'category:myCategorytype:stringdefault:''my.seoRelevantSetting:label:'My SEO relevant setting'# show in EXT:seo provided category "seo"category:seotype:intdefault:5
Copied!
The settings ordering is defined through the loading order of extensions and by
the order of categories. Uncategorized settings will be grouped into a virtual
"Other" category and shown at the end of the list of available settings.
Readonly
Site settings can be made readonly. They can be overridden only by editing
the config/sites/my-site/settings.yaml but not from within the editor.
The value of the field is displayed in a readonly field in the settings editor.
settings:my.enumSetting:label:'My setting with options'type:stringenum:valueA:'Label of value A'valueB:'Label of value B'
Copied!
Impact
Site-scoped settings will most likely be the place to configure site-wide
configuration, which was previously only possible to modify via Constant Editor,
modifying TypoScript constants.
It is recommended to use site-sets and their UI configuration in favor of
TypoScript Constants in the future.
Feature: #104814 - Automatically add system fields to content types
All content elements types (
CType) are usually equipped with the same
system fields (language, hidden, etc.) - see also Feature: #104311 - Auto created system TCA columns.
Adding them to the editor form has previously been done by adding those fields
to each content types'
showitem definition.
In the effort to simplify content element creation, to unify the available
fields and position for the editor and to finally reduce configuration effort
for integrators, those system fields are now added automatically based
on the
ctrl definition.
Note
The fields are added to the
showitem through their corresponding
palettes. In case such palette has been changed by extensions, the required
system fields are added individually to corresponding tabs.
The following tabs / palettes are now added automatically:
The General tab with the general palette at the very beginning
The Language tab with the language palette after custom fields
The Access tab with the hidden and access palettes
The Notes tab with the rowDescription field
As mentioned, in case one of those palettes has been changed to no longer
include the corresponding system fields, those fields are added individually
depending on their definition in the table's
ctrl section:
The
ctrl[type] field (usually
CType)
The
colPos field
The
ctrl[languageField] (usually
sys_language_uid)
The
ctrl[editlock] field (usually
editlock)
The
ctrl[enablecolumns][disabled] field (usually
hidden)
The
ctrl[enablecolumns][starttime] field (usually
starttime)
The
ctrl[enablecolumns][endtime] field (usually
endtime)
The
ctrl[enablecolumns][fe_group] field (usually
fe_group)
The
ctrl[descriptionColumn] field (usually
rowDescription)
By default, all custom fields - the ones still defined in
showitem - are
added after the general palette and are therefore added to the
General tab, unless a custom tab (e.g. Plugin,
or Categories) is defined in between. It is also possible to start
with a custom tab by defining a --div-- as the first item in the
showitem. In this case, the General tab will be omitted.
All those system fields, which are added based on the
ctrl section are
also automatically removed from any custom palette and from the customized
type's
showitem definition.
If the content element defines the Extended tab, it will be
inserted at the end, including all fields added to the type via API methods,
without specifying a position, e.g. via
ExtensionManagementUtility::addToAllTcaTypes().
Impact
Creating content elements has been simplified by removing the need to
define the system fields for each element again and again. This shrinks
down a content element's
showitem to just the element specific fields.
A usual migration will therefore look like the following:
Since all fields, palettes and tabs, which are defined in the
showitem
are added after the
general palette, also the Categories tab
- if defined - is displayed before the system tabs / fields. The only special
case is the Extended tab, which is always added at the end.
Important
For consistency reasons, custom labels for system fields are no
longer preserved.
Feature: #104832 - PSR-14 Event to alter the results of PageTreeRepository
Until TYPO3 v9, it was possible to alter the rendering of one of TYPO3's
superpowers — the page tree in the TYPO3 Backend User Interface.
This was done via a "Hook", but was removed due to the migration towards an
SVG-based tree rendering.
As the Page Tree Rendering has evolved, and the hook system has been replaced
in favor of PSR-14 Events, a new event
\TYPO3\CMS\Backend\Tree\Repository\AfterRawPageRowPreparedEvent
has been introduced.
Example
The event listener class, using the PHP attribute
#[AsEventListener] for
registration, will remove any children for displaying for the page with the
UID 123:
To make it easier for TYPO3 users to view all the internal notes (EXT:sys_note) in
their TYPO3 system, TYPO3 now offers dashboard widgets for each internal note type.
The backend user must have access to the sys_note table and view permission to the
page where the record is located.
Impact
TYPO3 users who have access to the Dashboard module and are
granted access to the new widgets can now add and use these widgets.
Feature: #104846 - Custom field transformations for new records
With forge#103783 the new
\TYPO3\CMS\Core\Domain\Record object has been introduced, which
is an object representing a raw database record based on TCA and is usually
used in the frontend (via Fluid Templates).
Since Feature: #103581 - Automatically transform TCA field values for record objects the properties of those
Record
objects are transformed / expanded from their raw database value into
"rich-flavored" values. Those values might be relations to e.g.
Record ,
FileReference ,
Folder or
\DateTimeImmutable objects.
However, TYPO3 does not know about custom field meanings, e.g. latitude and
longitude information, stored in an input field or user settings stored as
JSON in an TCA type json field. For such custom needs, the new
PSR-14
\TYPO3\CMS\Core\Domain\Event\RecordCreationEvent has been
introduced. It is dispatched right before a
Record is created and
therefore allows to fully manipulate any property, even the ones already
transformed by TYPO3.
The new event is stoppable (implementing
\StoppableEventInterface ), which
allows listeners to actually create a
Record object completely on their
own.
Important
The event operates on the
RecordInterface instead of an actual
implementation. This way, extension authors are able to set custom records,
implementing the interface.
The new event features the following methods:
setRecord() - Manually adds a
RecordInterface
object (stops the event propagation)
hasProperty() - Whether a property exists
setProperty() - Add or overwrite a property
setProperties() - Set properties for the
RecordInterface
unsetProperty() - Unset a single property
getProperty() - Get the value for a single property
getProperties() - Get all properties
getRawRecord() - Get the
RawRecord object
getSystemProperties() - Get the calculated
SystemProperties
getContext() - Get the current
Context (used to fetch the raw database row)
isPropagationStopped() - Whether the event propagation is stopped
Example
The event listener class, using the PHP attribute
#[AsEventListener] for
registration, creates a
Coordinates object based on the field value of
the
coordinates field for the custom
maps content type.
Options have been added to switch between the available color schemes in TYPO3. A set of buttons
for each available color scheme in the user dropdown at the top right and a setting in User Settings.
As the dark color scheme is currently regarded experimental until further notice, color scheme switching logic is
currently hidden behind the UserTS setting
setup.fields.colorScheme.disabled.
Impact
Warning
If you don't want the automatic switching and don't include the setup core extension in your environment,
you need to manually disable the feature yourself using the UserTS configuration
setup.fields.colorScheme.disabled = 1!
It is now possible to switch to an automatic, light or dark color scheme for use in the backend.
Feature: #104878 - Introduce dashboard widget for pages with latest changes
To make it easier for TYPO3 users to view the latest changed pages in their
TYPO3 system, TYPO3 now offers a dashboard widget that lists the latest
changed pages.
Widget Options:
- limit The limit of pages, displayed in the widget, default is 10
- historyLimit The maximum number of history records to check, default 1000
Impact
TYPO3 users who have access to the Dashboard module and are
granted access to the new widgets can now add and use this widget.
TYPO3 13 now uses Fluid 4 as the new base version. Old TYPO3 versions
will keep using Fluid 2, which will still receive bugfixes if necessary.
For detailed information about this release, please refer to the
dedicated release notes on GitHub.
With the update to Fluid 4, tag-based ViewHelpers now have proper
support for boolean attributes. Before this change, it was very
cumbersome to generate these with Fluid, now it is implemented similar
to popular JavaScript frameworks by using the newly introduced
boolean literals:
Of course, any variable containing a boolean can be supplied as well:
<my:viewhelperasync="{isAsync}" />
Copied!
This can also be used in combination with variable casting:
<my:viewhelperasync="{myString as boolean}" />
Copied!
For compatibility reasons empty strings still lead to the attribute
being omitted from the tag.
Impact
For existing installations, negative consequences of this update should be
minimal as deprecated features will still work. Users are however advised
to look into the already announced deprecations and to update their code
accordingly. This update helps with this by now writing log messages to the
deprecation log (if activated) if any deprecated feature is used in the
TYPO3 instance.
Feature: #104904 - Ignore Fluid syntax error in <f:comment>
Fluid 4 brings a new template processor
\TYPO3Fluid\Fluid\Core\Parser\TemplateProcessor\RemoveCommentsTemplateProcessor
which removes Fluid comments created with the
Debug ViewHelper <f:debug> from the template source
string before the parsing process starts. It retains the original line breaks to ensure
that error messages still refer to the correct line in the template.
By applying this template processor to all Fluid instances in the Core, it is now
possible to use invalid Fluid code inside
<f:comment> without triggering a Fluid error.
Impact
This feature is helpful during template development because developers don't need to
take care for commented-out code being valid Fluid code.
Feature: #104914 - Updated HTTP headers for frontend rendering and new TypoScript setting for proxies
In a typical frontend rendering scenario, TYPO3 sends HTTP response headers to
deny caching to clients (= browsers) when e.g. a frontend user is logged in,
a backend user is previewing a page, or a non-cacheable plugin is on a page.
When a frontend page is "client-cacheable", TYPO3 does not send any HTTP headers
by default, but only when
config.sendCacheHeaders = 1 is set
via TypoScript.
In this case, TYPO3 sends the following HTTP Headers (example):
Expires: Thu, 26 Aug 2024 08:52:00 GMT
ETag: "d41d8cd98f00b204ecs00998ecf8427e"
Cache-Control: max-age=86400
Pragma: public
Copied!
However, in the past, this could lead to problems, because recurring website
users might see outdated content for up to 24 hours (by default) or even longer,
even if other website visitors already see new content, depending on various
cache_timeout settings.
Thus,
config.sendCacheHeaders = 1 should be used with extreme care.
However, this option was also used when a proxy / CDN / shared cache such as
Varnish was put in between TYPO3 / the webserver and the client. The reverse
proxy can then evaluate the HTTP Response Headers sent by TYPO3 frontend, put
the TYPO3 response from the actual webserver into its "shared cache" and send
a manipulated / adapted response to the client.
However, when working with proxies, it is much more helpful to take load
off of TYPO3 / the webserver by keeping a cached version for a period of
time and answering requests from the client, while still telling the
client to not cache the response inside the browser cache.
This is now achieved with a new option
config.sendCacheHeadersForSharedCaches = auto.
With this option enabled, TYPO3 now evaluates if the current TYPO3 frontend
request is executed behind a Reverse Proxy, and if so, TYPO3 sends the following
HTTP Response Headers at a cached response:
Expires: Thu, 26 Aug 2024 08:52:00 GMT
ETag: "d41d8cd98f00b204ecs00998ecf8427e"
Cache-Control: max-age=0, s-maxage=86400
Pragma: public
With
config.sendCacheHeadersForSharedCaches = force the reverse
proxy evaluation can be omitted, which can be used for local webserver internal
caches.
"s-maxage" is a directive to tell shared caches - CDNs and reverse proxies - to keep
a cached version of the HTTP response for a period of time (based on various
cache settings) in their shared cache, while max-age=0 is evaluated at the
client level. See
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control for more
details and if your reverse proxy supports this directive.
The new option takes precedence over
config.sendCacheHeaders = 1
if running behind a reverse proxy.
Impact
By utilizing the new TypoScript setting, TYPO3 caches cacheable contents,
and also instructs shared caches such as reverse proxies or CDNs to cache
the HTTP Response, while always delivering fresh content to the client,
if certain routines for cache invalidation are in place. The latter is
typically handled by TYPO3 extensions which hook into the cache invalidation
process of TYPO3 to also invalidate cache entries in the reverse proxies.
In addition, compared to previous TYPO3 versions, client-cacheable HTTP Responses
now send "Cache-Control: private, no-store" if no option applies.
Feature: #104935 - Allow moving content elements via page tree
To make managing content across pages easier, a backend user may now drag
content elements from the Web > Page module into a page in the page tree.
Once dropped, a modal window opens, allowing the backend user to select the
position for placing the content element and to change the target page if needed.
Impact
Content elements can be moved from the Web > Page module into the
page tree to initiate the moving process.
Feature: #104973 - Activate the shipped LintYaml executable for TYPO3
The
typo3 executable received a new command lint:yaml to ease and encourage
linting of YAML files before deploying to production and therefore avoid failures.
Usage as follows:
# Validates a single file
bin/typo3 lint:yaml path/to/file.yaml
# Validates multiple files
bin/typo3 lint:yaml path/to/file1.yaml path/to/file2.yaml
# Validates all files in a directory (also in sub-directories)
bin/typo3 lint:yaml path/to/directory
# Validates all files in multiple directories (also in sub-directories)
bin/typo3 lint:yaml path/to/directory1 path/to/directory2
# Exclude one or more files from linting
bin/typo3 lint:yaml path/to/directory --exclude=path/to/directory/foo.yaml --exclude=path/to/directory/bar.yaml
# Show help
bin/typo3 lint:yaml --help
Copied!
The help argument will list possible usage elements.
Impact
Integrate easy made linting of YAML files from Core, custom extensions or
any other source into your quality assurance workflow in the known format
of the
typo3 executable.
When database records are used in the frontend, and the rendered result is put
into caches like the page cache, the TYPO3 frontend now automatically tags cache
entries with lists of used records.
When changing such records in the backend, affected cache entries are dropped,
leading to automatic cache eviction.
This is a huge improvement to previous TYPO3 versions where tagging and cache
eviction had to configured manually.
This feature - automatically tagging cache entries - is the final solution to
consistent caches at any point in time. It is however a bit tricky to get right
in a performant way: There are still details to rule out, and the core will
continue to improve in this area. The basic implementation in TYPO3 v13 however
already resolves many use cases. Core development now goes ahead to see how this
features behaves in the wild.
This feature is encapsulated in the feature toggle
frontend.cache.autoTagging:
It is enabled by default with new instances based on TYPO3 v13, and needs to be
manually enabled for instances being upgrades from previous versions.
Impact
Instances configured with the feature toggle automatically tag caches. Affected
cache entries will be removed when changing records.
The default view of ext:extbase now returns a view that implements
\TYPO3\CMS\Core\View\ViewInterface and not only
\TYPO3Fluid\Fluid\View\ViewInterface anymore. This allows
implementing any view that implements
ViewInterface ,
and frees the direct dependency to Fluid.
The default return object is an instance of
\TYPO3\CMS\Fluid\View\FluidViewAdapter which implements all
special methods tailored for Fluid. Extbase controllers should
check for instance of this object before calling these methods,
especially:
getRenderingContext()
setRenderingContext()
renderSection()
renderPartial()
Method calls not being part of
ViewInterface or the above
listed method names have been marked as deprecated and will be removed in TYPO3 v14.
Impact
Extbase controllers that extend
ActionController
and call methods not part of
ViewInterface , should
test for
$view instanceof FluidViewAdapter before calling
getRenderingContext(),
setRenderingContext(), php:renderSection()
and
renderPartial().
All other Fluid related methods called on
$view have been marked as
deprecated and will log a deprecation level error message.
Affected installations
Instances with Extbase based extensions that call
$view methods without
testing for
FluidViewAdapter .
Migration
Methods on "old" Fluid instances were wrapper methods for
RenderingContext . Controllers
should call
$view->getRenderingContext()
to perform operations instead.
Deprecation: #102422 - TypoScriptFrontendController->addCacheTags() and ->getPageCacheTags()
The methods
\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->addCacheTags() and
\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->getPageCacheTags()
have been marked as deprecated.
Impact
Calling the methods
\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->addCacheTags()
and
\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->getPageCacheTags()
will trigger a PHP deprecation warning.
Affected installations
TYPO3 installations calling
\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->addCacheTags()
or
\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->getPageCacheTags().
Migration
// Before
$GLOBALS['TSFE']->addCacheTags([
'tx_myextension_mytable_123',
'tx_myextension_mytable_456'
]);
// AfteruseTYPO3\CMS\Core\Cache\CacheTag;
$request->getAttribute('frontend.cache.collector')->addCacheTags(
new CacheTag('tx_myextension_mytable_123', 3600),
new CacheTag('tx_myextension_mytable_456', 3600)
);
Copied!
// Before
$GLOBALS['TSFE']->getPageCacheTags();
// After
$request->getAttribute('frontend.cache.collector')->getCacheTags();
The method
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPItoST43()
has been marked as deprecated in TYPO3 v13 and will be removed with TYPO3 v14.
Impact
Using the
ExtensionManagementUtility::addPItoST43() will raise a deprecation
level log entry and a fatal error in TYPO3 v14.
Affected installations
Extensions using
ExtensionManagementUtility::addPItoST43() are affected:
Using
ExtensionManagementUtility::addPItoST43() triggers a deprecation level log message.
The extension scanner will find usages of
ExtensionManagementUtility::addPItoST43() as strong match.
Calling these methods is discouraged. They will log a deprecation level
error when used with Fluid standalone v4.
Affected installations
Instances with extensions calling above methods.
Migration
registerUniversalTagAttributes()
Within tag based ViewHelpers, calls to
registerUniversalTagAttributes() should be removed.
This method has been marked as
@deprecated with Fluid standalone 2.12, will
log a deprecation level error with Fluid standalone v4, and will be removed with v5.
When removing the call, attributes registered by the call are now available in
$this->additionalArguments, and no longer in
$this->arguments. This may need
adaption within single ViewHelpers, if they handle such attributes on their own. For example,
the common ViewHelper
f:image was affected within the TYPO3 Core. The following attributes
may need attention when removing
registerUniversalTagAttributes():
class,
dir,
id,
lang,
style,
title,
accesskey,
tabindex,
onclick.
registerTagAttribute()
Within tag based ViewHelpers, calls to
registerTagAttribute() should be removed.
This method has been marked as
@deprecated with Fluid standalone 2.12, will
log a deprecation level error with Fluid standalone v4, and will be removed with v5.
The call be often simply removed since arbitrary attributes not specifically registered
are just added as-is by
\TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper .
This only needs attention
if single view helpers deal with such attributes within the
render() method:
When removing the call, those arguments are no longer available in
$this->arguments,
but in
$this->additionalArguments. Additional attention is needed with
attributes registered with type
boolean: Those usually have some handling
within
render(). To stay compatible, it can be helpful to not simply
remove the
registerTagAttribute() call, but to turn it into a call to
registerArgument().
The method
\TYPO3\CMS\Backend\Utility\BackendUtility::getTcaFieldConfiguration was introduced back
in 2010 to add a simple abstraction to access "TCA" definitions of a field.
However, apart from the set up that it is not part of a flexible API without
knowing the context, it was used seldom in TYPO3 Core.
The method has now been deprecated, as one could and can easily write the same
PHP code with
$GLOBALS['TCA'] in mind already (which the TYPO3 Core already did
in several other places).
Now that Schema API was introduced, the last parts have been migrated to use
the new API.
Impact
Calling the PHP method
BackendUtility::getTcaFieldConfiguration will
trigger a PHP deprecation warning.
Affected installations
TYPO3 installations with custom extensions using this method.
Migration
Either access
$GLOBALS['TCA'] directly (in order to support TYPO3 v12 and TYPO3 v13),
or migrate to the new Schema API:
Method
\TYPO3\CMS\Core\Utility\DiffUtility->makeDiffDisplay()
and class property
DiffUtility->stripTags have been
deprecated in favor of new method
DiffUtility->diff().
The new method no longer applies
strip_tags() to the input strings.
This change makes class
DiffUtility stateless: Property
$stripTags will vanish in v14.
Impact
Using method
DiffUtility->makeDiffDisplay() will trigger a
deprecation level error message.
Affected installations
Instances with extensions calling
DiffUtility->makeDiffDisplay().
Migration
If
DiffUtility->stripTagsis not explicitly set to false, a typical
migration looks like this:
// before
$diffUtility->DiffUtility->makeDiffDisplay($from, $to);
// after
$diffUtility->DiffUtility->diff(strip_tags($from), stripTags($to));
Copied!
If
DiffUtility->stripTags = false is set before calling
DiffUtility->makeDiffDisplay(), method
diff() can be called
as before, and
DiffUtility->stripTags = false can be removed.
Fluid standalone method
\TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper->overrideArgument()
has been marked as deprecated.
Impact
Using
overrideArgument() in ViewHelpers logs a deprecation level error message in Fluid standalone v4,
and will be removed with Fluid standalone v5. The method continues to work without deprecation level
error message in Fluid standalone v2.
With Fluid standalone v2.14,
registerArgument() no longer throws an exception if an
argument is already registered. This allows to override existing arguments transparently
without using
overrideArgument().
Affected installations
Instances with custom ViewHelpers using
overrideArgument() are affected.
Migration
Update typo3fluid/fluid to at least 2.14 and use
registerArgument().
Method
\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::returnWebmounts() has
been marked as deprecated and will be removed with TYPO3 v14.
Method
BackendUserAuthentication::getWebmounts() was
introduced as substitution. It returns a unique list of integer uids
instead of a list of strings, which is more type safe.
Superfluous calls to array_unique() can be removed since the uniqueness
is now guaranteed by BackendUserAuthentication::getWebmounts().
Impact
Calling
BackendUserAuthentication::returnWebmounts() will trigger a PHP
deprecation warning.
Affected installations
All installations using
BackendUserAuthentication::returnWebmounts()
are affected.
Migration
Existing calls to
BackendUserAuthentication::returnWebmounts() should
be replaced by
BackendUserAuthentication::getWebmounts().
If third party extensions convert the previous result array from an array of
strings to an array of integers, this can be skipped. In addition
superfluous calls to array_unique() can be removed since the uniqueness
is now guaranteed by BackendUserAuthentication::getWebmounts().
The method
\TYPO3\CMS\Backend\Utility\BackendUtility::thumbCode() has been deprecated since the
method is no longer used in TYPO3 anymore. Additionally, due to multiple changes
to file processing over the years, e.g. introducing of FAL, the method's
signature changed a couple of times leading to a couple of method arguments
are being unused, which is quite a bad API.
Impact
Calling the PHP method
BackendUtility::thumbCode() will
trigger a PHP deprecation warning.
Affected installations
TYPO3 installations with custom extensions using this method. The extension
scanner will report any usage as strong match.
Migration
Remove any usage of this method. In case you currently rely on the
functionality, you can copy it to your custom extension. However, you might
want to consider refactoring the corresponding code places.
The method basically resolved given
FileReference objects. In case
a file could not be resolved, a special icon has been rendered. Otherwise,
the cropping configuration has been applied and the file's
process()
has been called to get the thumbnail, which has been wrapped in corresponding
thumbnail markup. This might has been extended to also open the information
modal on click.
This means the relevant parts are:
// Get file references
$fileReferences = BackendUtility:resolveFileReferences($table, $field, $row);
// Check for existence of the file
$fileReference->getOriginalFile()->isMissing()
// Render special icon if missing
$iconFactory
->getIcon('mimetypes-other-other', IconSize::MEDIUM, 'overlay-missing')
->setTitle(static::getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:warning.file_missing') . ' ' . $fileObject->getName())
->render()
// Process file with cropping configuration if not missing
$fileReference->getOriginalFile()->process(
ProcessedFile::CONTEXT_IMAGEPREVIEW,// ProcessedFile::CONTEXT_IMAGECROPSCALEMASK if cropArea is defiend
[
'width' => '...',
'height' => '...',
'crop'// If cropArea is defined
]
)
// Use cropped file and create <img> tag
<img src="' . $fileReference->getOriginalFile()->process()->getPublicUrl() . '"/>
// Wrap the info popup via <a> around the thumbnail
<a href="#" data-dispatch-action="TYPO3.InfoWindow.showItem" data-dispatch-args-list="_FILE,' . (int)$fileReference->getOriginalFile()->getUid() . '">
Calling above methods triggers a deprecation level log entry in TYPO3 v13 and
will trigger a fatal PHP error with TYPO3 v14.
Affected installations
RenderingContext->getRequest() is a relatively common call in custom
view helpers. Instances with extensions that deliver custom view helpers may
be affected. The extension scanner is not configured to find potential
places since the method names are common and would lead to too many false
positives.
Migration
Class
\TYPO3\CMS\Fluid\Core\Rendering\RenderingContext of the Core
extension Fluid extends class
\TYPO3Fluid\Fluid\Core\Rendering\RenderingContext
of Fluid standalone and adds the methods
setRequest() and
getRequest().
These methods are however not part of
\TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface .
Fluid standalone will not add these methods, since the view of this library should
stay free from direct PSR-7
\ServerRequestInterface
dependencies. Having those
methods in ext:fluid
RenderingContext
however collides with
\RenderingContextInterface ,
which is type hinted in Fluid view helper method signatures.
Fluid standalone instead added three methods to handle arbitrary additional data
in
\RenderingContextInterface :
setAttribute(),
hasAttribute()
and
getAttribute(). Those should be used instead.
Method
\TYPO3\CMS\Fluid\View\TemplatePaths->fillDefaultsByPackageName()
has been marked as deprecated in TYPO3 v13 and will be removed in TYPO3 v14.
Fluid template paths should be set directly using the methods
setTemplateRootPaths(),
setLayoutRootPaths() and
setPartialRootPaths(), or - even better - be handled by
ViewFactoryInterface, which comes as new feature in TYPO3 v13.
Calling
fillDefaultsByPackageName() triggers a deprecation level
log level entry in TYPO3 v13 and will be removed in TYPO3 v14.
Affected installations
The method is relatively rarely used by extensions directly, a usage in
Extbase
ActionController has been refactored away. The extension
scanner will find candidates.
Note class
TemplatePaths is marked @internal and should not be
used by extensions at all.
Migration
Use
\TYPO3\CMS\Core\View\ViewFactoryInterface to create views with
proper template paths instead. The TYPO3 system extensions come with plenty
of examples on how to do this.
Deprecation: #104773 - Custom Fluid views and Extbase
Using one of the above classes triggers a deprecation level log entry.
Affected installations
Instances with extensions that create view instances of
\StandaloneView or
\TemplateView are affected. The extension
scanner will find possible candidates.
Migration
Extensions should no longer directly instantiate own views, but should get
\TYPO3\CMS\Core\View\ViewFactoryInterface injected and use
create()
to retrieve a view.
Within Extbase,
ActionController->defaultViewObjectName should only be
set to Extbase
JsonView if needed, or not set at all. Custom view implementations
should implement an own
ViewFactoryInterface and configure
controllers to inject an instance, or can set
$this->defaultViewObjectName = JsonView::class
in a custom
__construct().
Method
\TYPO3\CMS\Backend\LoginProvider\LoginProviderInterface->render() has been marked as deprecated
and is substituted by
LoginProviderInterface->modifyView() that will
be added to the interface in TYPO3 v14, removing
render() from the
interface in v14.
Related to this, event
\TYPO3\CMS\Backend\LoginProvider\Event\ModifyPageLayoutOnLoginProviderSelectionEvent
has been changed to deprecate
getController() and
getPageRenderer(),
while
getRequest() has been added.
getView() now typically returns
an instance of
ViewInterface.
The default
LoginProviderInterface
implementation is
UsernamePasswordLoginProvider
provided by ext:core. This consumer has been adapted.
Using
LoginProviderInterface->render() in TYPO3 v13 will trigger a
deprecation level log entry and will fail in v14.
Affected installations
Instances with custom login providers that change the TYPO3 backend login
field rendering may be affected. The extension scanner is not configured to
find usages, since method name
render() is too common. A deprecation
level log message is triggered upon use of the old method.
Migration
Consumers of
LoginProviderInterface
should implement
modifyView() instead, the transition should be smooth.
Consumers that need the
PageRenderer
for JavaScript magic, should use dependency injection
to receive an instance.
The default implementation in
UsernamePasswordLoginProvider
is a good example. Extensions that need to configure additional template, layout or
partial lookup paths can extend them:
Consumers of
ModifyPageLayoutOnLoginProviderSelectionEvent
should use the request instead, and/or should get an instance of
PageRenderer injected as well.
Deprecation: #104778 - Instantiation of IconRegistry in ext_localconf.php
Since TYPO3 v11 it is possible to automatically register own icons via
Configuration/Icons.php. Prior to this, extension authors used to register
icons manually via instantiating the php:\TYPO3\CMS\Core\Imaging\IconRegistry
in their ext_localconf.php
files. This method has now been deprecated. It is recommended to switch to
the newer method introduced with forge#94692.
Impact
Instantiating
IconRegistry inside
ext_localconf.php files will trigger a deprecation-level log entry.
Affected installations
All installations, which instantiate
IconRegistry
before the
\TYPO3\CMS\Core\Core\Event\BootCompletedEvent . This includes
ext_localconf.php files as well as TCA/Overrides.
Migration
The most common use-cases can be accomplished via the Configuration/Icons.php
file.
For more complex tasks, it is recommended to register an event listener for the
BootCompletedEvent . At this stage the system
is fully booted and you have a completely configured IconRegistry at hand.
In case the registry was used in TCA/Overrides files to retrieve icon
identifiers, then this should be replaced completely with static identifiers.
The reason behind this is, that the registry isn't even fully usable at this
stage. TCA isn't fully built yet and icons can still be registered at a later
point.
Fluid standalone will add proper language syntax for booleans and null
with Fluid v4, which will be used in TYPO3 v13. Thus, user-defined variables
named true, false and null are no longer allowed.
Impact
Assigning variables with name true, false or null will throw
an exception in Fluid v4. In preparation of this change, Fluid v2.15 logs a
deprecation level error message if any of these variable names are used.
Affected installations
Instances with Fluid templates using true, false or null as user-defined variable names.
This should rarely happen, as it would involve using
$view->assign('true', $someVar).
Migration
Template code using these variables should be adjusted to use different variable names.
In Fluid v4, the variables will contain their matching PHP counterparts.
Deprecation: #104789 - renderStatic() for Fluid ViewHelpers
The usage of
renderStatic() for Fluid ViewHelpers has been deprecated.
Also, Fluid standalone traits
\TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithContentArgumentAndRenderStatic
and
\TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic
have been marked as deprecated.
Impact
Using one of the mentioned traits or
renderStatic() in ViewHelpers
logs a deprecation level error message in Fluid standalone v4.
renderStatic()
will no longer be called in Fluid standalone v5.
renderStatic() and both
traits continue to work without deprecation level error message in
Fluid standalone v2.
Affected installations
Instances with custom ViewHelpers using any variant of
renderStatic() are affected.
Migration
ViewHelpers should always use
render() as their primary rendering method.
ViewHelpers using just
renderStatic() without any trait or with the trait
\CompileWithRenderStatic
can be migrated by converting the static rendering method to a non-static method:
ViewHelpers using
\TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithContentArgumentAndRenderStatic
can use the new contentArgumentName feature added with Fluid v2.15:
The database table tt_content contains all necessary fields for rendering
content elements.
Back with TYPO3 v4.7, a major feature to render certain Content Types in a more
accessible way, funded by the German Government (BLE_) with the
"Konjunkturpaket II" was merged into CSS Styled Content.
In this procedure, certain Content Types received new fields and rendering definitions, which
were stored in the database fields accessibility_title, accessibility_bypass
and accessibility_bypass_text.
When CSS Styled Content was removed in favor of Fluid Styled Content in TYPO3 v8, the DB
fields continued to exist in TYPO3 Core, so a migration from CSS Styled Content was possible.
However, the DB fields are not evaluated anymore since then, and are removed, along with
their TCA definition in tt_content.
If these fields are still relevant for a custom legacy installation, these DB fields need to be
re-created via TCA for further use in a third-party extension.
Important: #104126 - Drop "typo3conf" directory from system status check and backend locking
The directory typo3conf is no longer needed in Composer Mode.
Checking for the existence of this directory is no longer performed in the
Environment and Install Tool.
Previously it contained:
extensions (which are now Composer packages stored in vendor/),
the configuration files (which are now part of the config/ tree)
language labels and some artifact states (now part of var/)
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.
Adds a configuration option to adapt the environment check in the Install Tool
for a list of sanctioned
disable_functions.
With the new configuration option
$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.
You can also define this in your settings.php file manually
or via 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
disable_functions.
Feature: #92009 - Provide backend modules in LiveSearch
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.
Feature: #99203 - Streamline FE/versionNumberInFilename to 'EXT:' resources
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
The listing of resources in the TYPO3 backend, e.g. in the
File > Filelist module or the FileBrowser can be switched
between list and tiles. TYPO3 serves tiles by default.
A new User TSconfig option
options.defaultResourcesViewMode has
been introduced, which allows the initial display mode to be defined. Valid
values are therefore list and tiles, e.g.:
options.defaultResourcesViewMode = list
Copied!
Impact
Integrators can now define the default display mode for resources via
User TSconfig.
Feature: #102326 - Allow custom translations for Extbase validators
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
message. Validators
providing multiple validation messages (e.g.
Boolean,
NotEmpty or
NumberRange) use different validator options keys. In general,
translation keys or messages for validators are registered in the validator
property
translationOptions.
In this example, translation option keys for the
NotEmptyValidator are
overwritten for the property
$myProperty. The
locallang.xlf
translation file from the extension
my_extension will be used to lookup
translations for the newly provided translation key options.
In this example, translation option keys for the
FloatValidator are
overwritten for the property
$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.").
Feature: #102337 - PSR-14 event for modifying record list export data
A new PSR-14 event
\TYPO3\CMS\Backend\RecordList\Event\BeforeRecordDownloadIsExecutedEvent
has been introduced to modify the result of a download / export initiated in
the Web > List module.
This replaces the
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList']['customizeCsvHeader']
and
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList']['customizeCsvRow'] ,
hooks, which have been deprecated.
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:
getHeaderRow(): Return the current header row of the dataset.
setHeaderRow(): Sets the modified header row of the dataset.
getRecords(): Returns the current body rows of the dataset.
setRecords(): Sets the modified body rows of the dataset.
getRequest(): Returns the PSR request context.
getTable(): Returns the name of the database table of the dataset.
getFormat(): Returns the format of the download action (CSV/JSON).
getFilename(): Returns the name of the download filename (for browser output).
getId(): Returns the page UID of the download origin.
getModTSconfig(): Returns the active module TSconfig of the download origin.
getColumnsToRender(): Returns the list of header columns for the triggered download.
isHideTranslations(): Returns whether translations are hidden or not.
Example
The corresponding event listener class:
<?phpdeclare(strict_types=1);
namespaceVendor\MyPackage\Core\EventListener;
useTYPO3\CMS\Backend\RecordList\Event\BeforeRecordDownloadIsExecutedEvent;
useTYPO3\CMS\Core\Attribute\AsEventListener;
#[AsEventListener(identifier: 'my-package/record-list-download-data')]final readonly classDataListener{
publicfunction__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);
}
}
Copied!
Migration
The functionality of both hooks
customizeCsvHeader and
customizeCsvRow are now handled by the new PSR-14 event.
Migrating
customizeCsvHeader
The prior hook parameter/variable
fields is now available via
$event->getColumnsToRender(). The actual record data
(previously
$this->recordList, submitted to the hook as its object
reference) is accessible via
$event->getHeaderRow().
Migrating
customizeCsvRow
The prior hook parameters/variables have the following substitutes:
databaseRow is now available via
$event->getRecords() (see note below).
tableName is now available via
$event->getTable().
pageId is now available via
$event->getId().
The actual record data
(previously
$this->recordList, submitted to the hook as its object
reference) is accessible via
$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
BeforeRecordDownloadIsExecutedEvent it is
now possible to modify all of the data available when downloading / exporting
a list of records via the Web > List module.
Feature: #102337 - PSR-14 event for modifying record list download presets
A new PSR-14 event
\TYPO3\CMS\Backend\RecordList\Event\BeforeRecordDownloadPresetsAreDisplayedEvent
has been introduced to manipulate the list of available download presets in
the Web > List module.
getPresets(): Returns a list of presets set via TSconfig
setPresets(): Sets a modified list of presets.
getDatabaseTable(): Returns the database table name that a preset applies to.
getRequest(): Returns the PSR Request object for the context of the request.
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
setPresets() method.
The array passed from
getPresets() to
setPresets() can contain
an array collection of
\TYPO3\CMS\Backend\RecordList\DownloadPreset
objects with the array key using the preset label.
The existing presets can be retrieved with these getters:
$preset->getLabel(): Name of the preset (can utilize LLL translations), optional.
$preset->getColumns(): Array of database table column names.
$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
DownloadPreset object with the
changed label and columns constructor properties.
Using the PSR-14 event
BeforeRecordDownloadPresetsAreDisplayedEvent
it is now possible to modify the presets of each table for
downloading / exporting a list of such records via the Web > List
module.
Feature: #102337 - Presets for download of record lists
In the 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).
Each entry of
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
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
columns and optionally
an
identifier. If
identifier is not provided,
the identifier is generated as a hash of the
label and
columns.
This can be manipulated with user TSConfig by adding the
page.
prefix. User TSConfig is loaded after page TSConfig, so you can overwrite
existing keys or replace the whole list of keys:
Since any table can be configured for a preset, any extension
can deliver a defined set of presets through the
EXT:my_extension/Configuration/page.tsconfig file and
their table name(s).
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.
Feature: #102951 - Provide PSR-7 request in Extbase validators
Extbase
abstractValidator now provides a getter and a setter
for the PSR-7 Request object. Validators extending
AbstractValidator
will include the PSR-7 request object, if the validator has been instantiated
by Extbase
ValidationResolver.
Impact
Extension developers can now create custom validators which consume data
from the PSR-7 request object (e.g. request attribute
frontend.user).
This feature introduces the new PSR-14 event
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.
Developers now have the possibility to modify the validation results for the
redirect URL, allowing redirects to URLs not matching existing validation
constraints.
Feature: #103493 - Edit full record in "Check Links" module
Previously, the listing in the 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 Check Links backend module,
allowing the full record of a broken link to be edited.
Feature: #103706 - Default search level for record search
When searching for records in the 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
mod.web_list.searchLevel.items.
Next to this, a new TSconfig option
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
EXT:my_sitepackage/Configuration/page.tsconfig
# Set the default search level to "infinite levels"
mod.web_list.searchLevel.default = -1
Copied!
Impact
It's now possible to define a default search level using the new page
TSconfig option
mod.web_list.searchLevel.default.
Feature: #103783 - RecordTransformation Data Processor
A new TypoScript data processor for
FLUIDTEMPLATE and
PAGEVIEW has been added.
The
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
record-transformation will take the result and transform
the objects into
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.
Transform the current data array of
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.
tt_content.text {
templateName = Text
dataProcessing {
10 = record-transformation
10 {
as = data
}
}
}
Copied!
Usage in Fluid templates
The
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
{record.title} or
{record.uid}. In addition, you gain special, context-aware properties
like the language
{record.languageId} or workspace
{data.versionInfo.workspaceId}.
Overview of all possibilities:
<!-- 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 -->
{data.systemProperties.isDeleted}
{data.systemProperties.isDisabled}
{data.systemProperties.isLockedForEditing}
{data.systemProperties.createdAt}
{data.systemProperties.lastUpdatedAt}
{data.systemProperties.publishAt}
{data.systemProperties.publishUntil}
{data.systemProperties.userGroupRestriction}
{data.systemProperties.sorting}
{data.systemProperties.description}
<!-- Computed properties depending on the request context -->
{data.computedProperties.versionedUid}
{data.computedProperties.localizedUid}
{data.computedProperties.requestedOverlayLanguageId}
{data.computedProperties.translationSource} <!-- Only for pages, contains the Page model --><!-- Workspace related properties -->
{data.versionInfo.workspaceId}
{data.versionInfo.liveId}
{data.versionInfo.state.name}
{data.versionInfo.state.value}
{data.versionInfo.stageId}
Copied!
Note
The
{record} object contains only properties relevant for
the current record type (e.g. CType for
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
{record.rawRecord}.
Note that those properties are not transformed (Feature: #103581 - Automatically transform TCA field values for record objects).
Available options
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
Copied!
Feature: #103894 - Additional properties for columns in Page Layouts
Backend Layouts were introduced in TYPO3 v6 in order to customize the view of
the 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
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 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:
slideMode = slide - if no content is found, check the parent
pages for more content
slideMode = collect - use all content from this page, and the
parent pages as one collection
slideMode = collectReverse- same as "collect" but in the
opposite order
With this information added, a new DataProcessor
page-content
(
\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.
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
{content."myIdentifier".records}.
Example of an enriched backend layout definition:
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
}
}
}
}
}
}
}
}
The
f:cObject ViewHelper above uses the rendering definition of the
tt_content table
{record.mainType} to render the Content Element from
the list. The attribute
data expects the raw database record, which is
retrieved from
{record}.
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
$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
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
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
$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
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
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
itemsProcFunc is connected to that field in TCA. Whether there is an
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
$GLOBALS[TCA].
In the future Schema API might be used to evaluate information
for Site Configurations, like TCA and FlexForms.
Impact
Reading and writing
$GLOBALS[TCA] within 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.
publicfunction__construct(
protected readonly PageRepository $pageRepository,
protected readonly TcaSchemaFactory $tcaSchemaFactory
){}
publicfunctionmyMethod(string $tableName): void{
if (!$this->tcaSchemaFactory->has($tableName)) {
// this table is not managed via TYPO3's TCA APIreturn;
}
$schema = $this->tcaSchemaFactory->get($tableName);
// Find out if a table is localizableif ($schema->isLocalizable()) {
// do something
}
// Find all registered types
$types = $schema->getSubSchemata();
}
Copied!
Using the API improves handling for parts such as evaluating
columnsOverrides,
foreign field structures, FlexForm Schema parsing, and evaluating type fields
for database fields.
Feature: #104020 - ViewHelper to check feature flags
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>
Copied!
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>
Copied!
Impact
Feature flags can now be checked from within Fluid templates.
Feature: #104067 - Sorting of forms in the form module
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.
Feature: #104085 - Edit specific columns of multiple records in List module
Using the "Show columns" button on a record table in the 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
Web > List backend module, using the new "Edit columns" button.
Feature: #104095 - Edit specific columns of multiple files in Filelist module
Using the "Show columns" action in the 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
File > Filelist backend module, using the new
"Edit selected columns" button.
Feature: #104114 - Command to generate Fluid schema files
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:
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:
vendor/bin/typo3 fluid:schema:generate
Copied!
Feature: #104220 - Make parseFunc allowTags and denyTags optional
Defining the TypoScript properties
allowTags or
denyTags for the HTML processing via
stdWrap.parseFunc is now optional.
Besides that, it is now possible to use
allowTags = *.
Impact
By omitting
allowTags or
denyTags, the
corresponding rendering instructions can be simplified.
Security aspects are considered automatically by the HTML sanitizer,
unless
htmlSanitize is disabled explicitly.
Fluid Standalone has been updated to version 2.12. This version adds new capabilities for
tab based ViewHelpers and adds the new ViewHelper
f:constant.
Tag based view helpers (such as
<f:image /> or
<f:form.*>) can now
receive arbitrary tag attributes which will be appended to the resulting HTML tag,
without dedicated registration.
The
errorMessage validator option provides a custom string
as error message for validation failures of the
RegularExpressionValidator.
In order to streamline error message translation keys with other validators,
the
errorMessage validator option has been marked as deprecated in
TYPO3 v13 and will be removed in TYPO3 v14.
Impact
Using the
errorMessage validator option with the
RegularExpressionValidator
will trigger a PHP deprecation warning.
Affected installations
TYPO3 installations using the validator option
errorMessage with the
RegularExpressionValidator.
Migration
The new
message validator option should be used to provide a custom
translatable error message for failed validation.
The previously used hooks
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList']['customizeCsvHeader']
and
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList']['customizeCsvRow'] ,
used to manipulate the download / export configuration of records, triggered
in the Web > List backend module, have been deprecated in favor of a
new PSR-14 event
\TYPO3\CMS\Backend\RecordList\Event\BeforeRecordDownloadIsExecutedEvent .
When the hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList']['customizeCsvHeader']
or
$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
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList']['customizeCsvHeader']
or
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList']['customizeCsvRow']
are affected.
Migration
The new PSR-14 event
\TYPO3\CMS\Backend\RecordList\Event\BeforeRecordDownloadIsExecutedEvent
can be used as a near drop-in replacement.
Configuration option
$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
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
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
pages table then add
this field in
addRootLineFields. This option is no longer evaluated.
Relation fields attached to
pages are always resolved in frontend.
There should be hardly any extensions using this option, since it was
an internal option of class
RootlineUtility. Extensions using
$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
settings.php during upgrade, if given.
TYPO3 has the method
MathUtility::convertToPositiveInteger() to ensure
that an integer is always positive. However, the method is rather
"heavy" as it calls
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
max() call, the method is therefore deprecated.
Impact
Calling
MathUtility::convertToPositiveInteger() will trigger a PHP
deprecation warning.
Affected installations
All installations using
MathUtility::convertToPositiveInteger().
Migration
To recover the original behavior of the deprecated method, its call can be
replaced with
max(0, $number). To actually convert negative numbers to
their positive counterpart, call
abs($number).
Deprecation: #103965 - Deprecate namespaced shorthand validator usage in Extbase
It is possible to use undocumented namespaced shorthand notation in Extbase
to add validators to properties or arguments. For example,
TYPO3.CMS.Extbase:NotEmpty will be resolved as
\TYPO3\CMS\Extbase\Validation\Validator\NotEmptyValidator and
Vendor.Extension:Custom will be resolved as
\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.
When linking to the edit form it's possible to instruct the
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
array under the
corresponding table name.
An example, building such link using the UriBuilder:
The
Utility.updateQueryStringParameter() method in the
@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
Utility.updateQueryStringParameter() will result in a JavaScript
warning.
Affected installations
All 3rd party extensions using the deprecated method.
Migration
Now, JavaScript supports the
URL and its related
URLSearchParams
object that can be used to achieve the same result:
The
lib.parseFunc and
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
<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
<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.
Important: #103748 - Reference index rebuild required
A series of new columns has been added to the reference index table
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
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:
bin/typo3 referenceindex:update
Copied!
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.
Important: #103915 - Adjust database field defaults for "check" TCA types
All these records, created via
DataHandler calls, actually
evaluate the TCA default for record insertion and do not rely
on SQL database field defaults.
Only records created using the
QueryBuilder or
other "raw" database calls would apply the wrong
values.
An example of this is
TYPO3\CMS\Core\Resource\StorageRepository->createLocalStorage()
which creates a default fileadmin record via the
QueryBuilder
and then sets the field
auto_extract_metadata to
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 ext_tables.sql
to enforce automatic database field creation,
and did not use the recommended
DataHandler for
record insertion (so, any code that is not executed in the
backend context, using
QueryBuilder or Extbase
repository methods),
and expects a different default than
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
sys_file_metadata.auto_extract_metadata
Default backend user creation (admin) property
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.
Important: #104037 - Backend module "Access" renamed to "Permissions"
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
tt_content, as
this table is often extended with many additional columns, increasing the
likelihood of encountering the error. This document uses table
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
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
Admin Tools > Maintenance > Analyze Database Structure and will
suggest to migrate all tables to
InnoDB.
You can manually verify the engine currently in use:
The
InnoDB row format dictates how data is physically stored. The
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
Compact.
TYPO3 Core provides an automatic migration within
Admin Tools > Maintenance > Analyze Database Structure and will
suggest to migrate all tables to
ROW_FORMAT=DYNAMIC.
You can manually verify the row format currently in use:
Tables not using
Dynamic should be converted via
Admin Tools > Maintenance > Analyze Database Structure or manually
via SQL:
USE'my_database`;
ALTER TABLE `tt_content` ROW_FORMAT=DYNAMIC;
Copied!
Database, table and column charset
The column charset impacts length calculations. This document assumes
utf8mb4 for columns, aligning with the default TYPO3 setup. Converting
an existing instance to
utf8mb4 can be a complex task depending on the
currently used charset and is beyond the scope of this document.
A key point about
utf8mb4 is that when dealing with the
utf8mb4
charset for
VARCHAR() columns, storage and index calculations need to be
multiplied by four (4). For example, a
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
VARCHAR(20) in a
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
latin1 in the
future, which will optimize storage for ASCII-character only columns, but most
content-related columns should be
utf8mb4 to avoid issues with
multi-byte characters.
Note that column types that do not store characters (like
INT) do not have
a charset. An overview of current charsets can be retrieved:
# 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';
Copied!
Ensure innodb_page_size is 16384
Few instances modify the MySQL / MariaDB
innodb_page_size system variable,
and it is advisable to keep the default value of
16384. Verify the
current value:
This document now assumes that MySQL / MariaDB is used, the table in question
uses the
InnoDB storage engine with
Dynamic row format (please
check Admin Tools > Maintenance > Analyze Database Structure which
provides automatic migrations),
innodb_page_size default
16384 is
set, and that a system maintainer is aware of specific column charsets.
Error "Row size too large 65535"
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
Copied!
Explanation
When altering the database schema of a table, such as adding or increasing the
size of a
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
TEXT and
BLOB types, which are stored "off row" where only a "pointer" to the actual
storage location counts.
However, standard
VARCHAR fields contribute their full maximum byte length
towards this 65kB limit. For instance, a
VARCHAR(2048) column with the
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
VARCHAR(16383) column alongside an
INT column:
# ERROR 1118 (42000): Row size too large. The maximum row size [...] is 65535CREATETABLEtest (c1 varchar(16383), c2 int) ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;
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
VARCHAR columns.
For instance, in the
tt_content table of a default Core instance, there
are approximately a dozen
VARCHAR(255) columns, totaling about 12kB,
alongside smaller
INT and similar fields. This leaves ample
room for additional custom
VARCHAR() columns.
TYPO3 v13 has introduced improvements in two key areas:
Firstly, TCA fields with
type='link' and
type='slug' have been
converted from
VARCHAR(2048) (requiring 8kB of row space) to
TEXT.
The
tt_content table was affected by this change in at least one
column (
header_link). This adjustment provides more space by default for
custom columns.
Additionally, the TYPO3 Core now defaults to using
TEXT instead of
VARCHAR() for TCA fields with
type='input' when the TCA property
max is set to a value greater than
255 and extension authors utilize
the column auto creation feature.
Instances encountering the 65kB limit can consider adjusting fields with these
considerations in mind:
Priority should be given to reconsidering long
VARCHAR() columns first.
Changing a single
utf8mb4
VARCHAR(2048) column to
TEXT
can free enough space for up to eight (8)
utf8mb4
VARCHAR(255)
columns.
Consider reducing the length of
VARCHAR() columns. For instance, columns
containing database table or column names can be limited to
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
VARCHAR() columns to "too short" lengths
may impose a different limit, as discussed below.
Consider removing entries from ext_tables.sql with TYPO3 Core v13: the
column auto creation feature 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 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
utf8mb4
VARCHAR(255) and
TINYTEXT are not the same:
a
VARCHAR(255) size limit is 255 characters, while a
TINYTEXT
is 255 bytes. The proper substitution for a (4 bytes per character)
utf8mb4
VARCHAR(255) field is
TEXT, which allows for 65535 bytes.
TEXTmay 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
VARCHAR() to
TEXT or similar is not advisable.
Be mindful of indices. When
VARCHAR() columns that are part of an index
are changed to
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
InnoDB key length limit with row format
Dynamic is 3072
bytes (not characters). In general, indexes on
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)"
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.
Copied!
Sometimes there is also an error similar to this in MySQL / MariaDB logs:
[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.
Copied!
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
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
TEXT and
BLOB can always be stored on
overflow pages, thus minimally impacting the main data page limit of 8192 bytes.
However,
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
utf8mb4
VARCHAR(255) equates to 1020 bytes, which can be stored on overflow pages.
Changing such fields makes no difference.
Changing a
utf8mb4
VARCHAR(63) (or smaller) to
VARCHAR(64)
(64 characters utf8mb4 = 256 bytes) allows this column to be stored on overflow
pages and does make a difference.
Changing a
utf8mb4
VARCHAR(63) (or smaller) to
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
TEXT types if absolutely necessary. Also, refer to the note on indexes
above when single columns are part of indexes.
Columns using
utf8mb4 that are smaller or equal to
VARCHAR(63)
and only store ASCII characters can be downsized by changing the charset to
latin1. For instance, a
VARCHAR(60) column occupies 4 * 60 = 240
bytes in row size, but only 60 bytes when using the
latin1 charset.
Currently, TYPO3 Core does not interpret charset definitions for individual
columns from
ext_tables.sql. The Core Team anticipates implementing
this feature in the future.
Note that increasing the length of
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:
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.
After TYPO3 v13.0, only new functionality with a solid migration path
can be added on top, with aiming for as little as possible breaking changes
after the initial v13.0 release on the way to LTS.
Cropping SVG images via backend image editing or specific Fluid ViewHelper via
<f:image> or
<f:uri.image> (via
crop attribute) now
outputs native SVG files by default - which are processed but again stored
as SVG, instead of rasterized PNG/JPG images like before.
Impact
Editors and integrators can now crop SVG assets without an impact to their
output quality.
Forced rasterization of cropped SVG assets can still be performed by setting the
fileExtension="png" Fluid ViewHelper attribute or the TypoScript
file.ext = png property.
<f:image> ViewHelper example:
<f:imageimage="{image}"fileExtension="png" />
Copied!
This keeps forcing images to be generated as PNG image.
To invoke a deletion on items in FormEngine's Inline Relation container
API-wise, a new message identifier
typo3:foreignRelation:delete has been
introduced.
The Tree feature in TYPO3 stands as one of its most iconic and widely used
components, offering a visual representation of site structures to editors
globally. Serving various purposes, such as file management, category/record
selection, navigation, and more, the Tree has been a cornerstone for content
handling.
Originally introduced in Version 8 with a performance-oriented approach, the
SVG tree, powered by d3js, has faithfully served the community for the past
seven years. While it excelled in providing a fast and efficient experience,
it had its share of challenges, particularly due to its reliance on SVG and
d3js.
Challenges with the SVG tree:
Limited functionality due to SVG constraints
Maintenance complexities with code-built SVG
Accessibility challenges
Difficulty in extension and innovation
Lack of native drag and drop
Complexity hindering understanding for many
Recognizing these challenges, we embarked on a journey to reimagine the Tree
component, paving the way for a more adaptable and user-friendly experience.
Introducing the Modern Reactive Tree:
The new Tree, built on contemporary web standards, bids farewell to the
SVG tree's limitations. Embracing native drag and drop APIs, standard HTML
markup, and CSS for styling, the Modern Reactive Tree promises improved
maintainability and accessibility.
Key enhancements:
Unified experience: All features are now consolidated into the base tree,
ensuring a seamless and consistent user experience. This encompasses data
loading and processing, selection, keyboard navigation, drag and drop, and
basic node editing.
User preferences: The tree now dynamically adjusts to user preferences,
supporting both light/dark mode and left-to-right (LTR) or right-to-left
(RTL) writing modes.
Reactive rendering: Adopting a modern reactive rendering approach, the tree
and its nodes now autonomously redraw themselves based on property changes,
ensuring a smoother and more responsive interface.
Native drag and drop: Leveraging native drag and drop functionality opens
up avenues for future enhancements, such as dragging content directly onto
a page or seamlessly moving elements between browser windows.
Improved API endpoints: All endpoints delivering data for the tree now adhere
to a defined API definition, enhancing consistency and compatibility with
existing integrations.
Unified dragging tooltip handling: The dragging tooltip handling has been
adjusted to a unified component that can be utilized across all components,
ensuring synchronization across browser windows.
Dynamic tree status storage: The Pagetree status is no longer stored in the
database. Instead, it is now stored in the local storage of the user's
browser. This change empowers the browser to control the tree status, making
it more convenient for users to transition between multiple browsers or
machines.
Enhanced virtual scroll: The virtual scroll of the tree has been improved,
ensuring that only nodes currently visible to the user are rendered to the
DOM. Additionally, the focus on selected nodes is maintained even when
scrolled out of view, providing a smoother and more user-friendly experience.
As we transition to this Modern Reactive Tree, we anticipate a renewed era of
flexibility, ease of use, and potential for exciting future features.
Impact
The TYPO3 CMS Tree modernization brings:
Personalization:
Adapts to user preferences for a tailored interface.
Reactive design:
Ensures smoother interactions.
Efficient integration:
Improved API endpoints for seamless data exchange.
Consistency across devices:
Unified dragging and dynamic storage for a consistent experience.
Enhanced performance:
Optimal rendering during navigation.
These changes collectively enhance usability, adaptability, and performance,
elevating the TYPO3 CMS Tree experience.
Feature: #103147 - Provide full userdata in password recovery email in ext:backend
A new array variable
{userData} has been added to the password
recovery FluidEmail object. It contains the values of all fields from
the
be_users table belonging to the affected backend user.
Impact
It is now possible to use the
{userData} variable in the password
recovery FluidEmail to access data from the affected backend user.
Feature: #103186 - Introduce tree node status information
We've enhanced the backend tree component by extending tree nodes to
incorporate status information. These details serve to indicate the
status of nodes and provide supplementary information.
For instance, if a page undergoes changes within a workspace, it will
now display an indicator on the respective tree node. Additionally,
the status is appended to the node's title. This enhancement not only
improves visual clarity but also enhances information accessibility.
Each node can accommodate multiple status information, prioritized by
severity and urgency. Critical messages take precedence over other
status notifications.
For example, status information can be added by using the event
\TYPO3\CMS\Backend\Controller\Event\AfterPageTreeItemsPreparedEvent :
A new CLI command
./bin/typo3 setup:begroups:default has been
introduced as an alternative to the existing backend module. This command
automates the creation of backend user groups, enabling the creation of
two pre-configured backend user groups with permission presets applied.
Note
The pre-configured backend user group permissions are subject to be
further changed and adjusted and defines a first set. It is also possible
that additional groups may be added or made configurable. That means,
that the
./bin/typo3 setup:begroups:default command and the
pre-defined permissions are considerable experimental during the
TYPO3 v13 development cycle.
Impact
You can now use
./bin/typo3 setup:begroups:default to create
pre-configured backend user groups without touching the GUI.
Example
Interactive / guided setup (questions/answers):
Basic command
./bin/typo3 setup:begroups:default
Copied!
The backend user group can be set via the
--groups|-g option. Allowed
values for groups are
Both,
Editor and
Advanced Editor:
When using the
--no-interaction option, this defaults to
Both.
Note
At the moment, the command does not support the creation of backend user
groups with custom names or permissions (they can be modified later through
the backend module). It is limited to creating two pre-configured backend
user groups with permission presets applied.
We've upgraded the backend tree component by extending tree nodes to
incorporate labels, offering enhanced functionality and additional
information.
Before the implementation of labels, developers and integrators
relied on
pageTree.backgroundColor.<pageid> for visual cues,
which has been deprecated with TYPO3 v13.
However, these background colors lacked accessibility and meaningful context,
catering only to users with perfect eyesight and excluding those
dependent on screen readers or contrast modes.
With labels, we now cater to all editors. These labels not only offer
customizable color markings for tree nodes but also require an
associated label for improved accessibility.
Each node can support multiple labels, sorted by priority, with the
highest priority label taking precedence over others. Users can
assign a label to a node via user TSconfig, noting that only one label
can be set through this method.
EXT:my_extension/Configuration/user.tsconfig
options.pageTree.label.<pageid> {
label = Campaign A
color = #ff8700
}
Copied!
The labels can also be added by using the event
\TYPO3\CMS\Backend\Controller\Event\AfterPageTreeItemsPreparedEvent .
<?phpdeclare(strict_types=1);
namespaceMyVendor\MyExtension\Backend\EventListener;
useTYPO3\CMS\Backend\Controller\Event\AfterPageTreeItemsPreparedEvent;
useTYPO3\CMS\Backend\Dto\Tree\Label\Label;
useTYPO3\CMS\Core\Attribute\AsEventListener;
#[AsEventListener(
identifier: 'my-extension/backend/modify-page-tree-items',
)]
final readonly classModifyPageTreeItems{
publicfunction__invoke(AfterPageTreeItemsPreparedEvent $event): void{
$items = $event->getItems();
foreach ($items as &$item) {
// Add special label for all pages with parent page ID 123if (($item['_page']['pid'] ?? null) === 123) {
$item['labels'][] = new Label( label: 'Campaign B', color: '#00658f', priority: 1, );
}
}
$event->setItems($items);
}
}
Copied!
Please note that only the marker for the label with the highest priority is
rendered. All additional labels will only be added to the title of the node.
Impact
Labels are now added to the node and their children, significantly
improving the clarity and accessibility of the tree component.
Feature: #103220 - Support comma-separated lists in page tree filter
The page tree has been enhanced to enable the user to not only search for
strings and single page IDs, but for comma-separated lists of page IDs as well.
Feature: #103255 - Native support for language Scottish Gaelic added
The TYPO3
\TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
provides a relatively conservative set of database query expressions since a
couple of TYPO3 and Doctrine DBAL versions now.
Additional expression methods are now available to build more advanced database
queries that ensure compatibility across supported database vendors.
Creates a statement to append a field alias to a value, identifier or sub-expression.
Note
Some
ExpressionBuilder methods provides a argument to directly add
the expression alias to reduce some nesting. This method can be used for
custom expressions and avoids recurring conditional quoting and alias appending.
Method signature
/**
* @param string $expression Value, identifier or expression which
* should be aliased.
* @param string $asIdentifier Used to add a field identifier alias
* (`AS`) if non-empty string (optional).
*
* @return string Returns aliased expression.
*/publicfunctionas(
string $expression,
string $asIdentifier = '',
): string{}
// use TYPO3\CMS\Core\Database\Connection;// use TYPO3\CMS\Core\Database\ConnectionPool;// use TYPO3\CMS\Core\Utility\GeneralUtility;
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('some_table');
$expressionBuilder = $queryBuilder->expr();
$queryBuilder->selectLiteral(
$queryBuilder->quoteIdentifier('uid'),
$expressionBuilder->as('(1 + 1 + 1)', 'calculated_field'),
);
$queryBuilder->selectLiteral(
$queryBuilder->quoteIdentifier('uid'),
$expressionBuilder->as(
$expressionBuilder->concat(
$expressionBuilder->literal('1'),
$expressionBuilder->literal(' '),
$expressionBuilder->literal('1'),
),
'concatenated_value'
),
);
Copied!
ExpressionBuilder::concat()
Can be used to concatenate values, row field values or expression results into
a single string value.
Note
The created expression is built on the proper platform specific and preferred
concatenation method, for example
string || string || string || ...
for SQLite and
CONCAT(...string) for other database vendors.
Method signature
/**
* @param string ...$parts Unquoted value or expression parts to
* concatenate with each other
* @return string Returns the concatenation expression compatible with
* the database connection platform.
*/publicfunctionconcat(string ...$parts): string{}
Be aware to properly quote values, identifiers and sub-expressions.
No automatic quoting will be applied.
ExpressionBuilder::castVarchar()
Can be used to create an expression which converts a value, row field value or
the result of an expression to varchar type with dynamic length.
Note
Use the platform specific preferred way for casting to dynamic length
character type, which means
CAST("value" AS VARCHAR(<LENGTH>))
or
CAST("value" AS CHAR(<LENGTH>)) is used, except PostgreSQL.
For PostgreSQL the
"value"::INTEGER cast notation is used.
Method signature
/**
* @param string $value Unquoted value or expression,
* which should be casted.
* @param int $length Dynamic varchar field length.
* @param string $asIdentifier Used to add a field identifier alias
* (`AS`) if non-empty string (optional).
* @return string Returns the cast expression compatible for the database platform.
*/publicfunctioncastVarchar(
string $value,
int $length = 255,
string $asIdentifier = '',
): string{}
Copied!
Usage example
// use TYPO3\CMS\Core\Database\ConnectionPool;// use TYPO3\CMS\Core\Utility\GeneralUtility;
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('some_table');
$fieldVarcharCastExpression = $queryBuilder->expr()->castVarchar(
$queryBuilder->quote('123'), // integer as string255, // convert to varchar(255) field - dynamic length'new_field_identifier',
);
$fieldExpressionCastExpression = $queryBuilder->expr()->castVarchar(
'(100 + 200)', // calculate a integer value100, // dynamic varchar(100) field'new_field_identifier',
);
Copied!
Warning
Be aware to properly quote values, identifiers and sub-expressions.
No automatic quoting will be applied.
ExpressionBuilder::castInt()
Can be used to create an expression which converts a value, row field value or
the result of an expression to signed integer type.
Note
Use the platform specific preferred way for casting to dynamic length
character type, which means
CAST("value" AS INTEGER) for most database vendors
except PostgreSQL. For PostgreSQL the
"value"::INTEGER cast notation
is used.
Method signature
/**
* @param string $value Quoted value or expression result which
* should be casted to integer type.
* @param string $asIdentifier Used to add a field identifier alias
* (`AS`) if non-empty string (optional).
* @return string Returns the integer cast expression compatible with the
* connection database platform.
*/publicfunctioncastInt(string $value, string $asIdentifier = ''): string{}
Copied!
Usage example
// use TYPO3\CMS\Core\Database\ConnectionPool;// use TYPO3\CMS\Core\Utility\GeneralUtility;
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('pages');
$queryBuilder
->select('uid')
->from('pages');
// simple value (quoted) to be used as sub-expression
$expression1 = $queryBuilder->expr()->castInt(
$queryBuilder->quote('123'),
);
// simple value (quoted) to return as select field
$queryBuilder->addSelectLiteral(
$queryBuilder->expr()->castInt(
$queryBuilder->quote('123'),
'virtual_field',
),
);
$expression3 = queryBuilder->expr()->castInt(
$queryBuilder->quoteIdentifier('uid'),
);
// expression to be used as sub-expression
$expression4 = $queryBuilder->expr()->castInt(
$queryBuilder->expr()->castVarchar('(1 * 10)'),
);
// expression to return as select field
$queryBuilder->addSelectLiteral(
$queryBuilder->expr()->castInt(
$queryBuilder->expr()->castVarchar('(1 * 10)'),
'virtual_field',
),
);
Copied!
Warning
Be aware to properly quote values, identifiers and sub-expressions.
No automatic quoting will be applied.
ExpressionBuilder::repeat()
Create a statement to generate a value repeating defined
$value for
$numberOfRepeats times. This method can be used to provide the
repeat number as a sub-expression or calculation.
Note
REPEAT(string, number) is used to build this expression for all database
vendors except SQLite for which the compatible replacement construct expression
REPLACE(PRINTF('%.' || <valueOrStatement> || 'c', '/'),'/', <repeatValue>)
is used, based on
REPLACE() and the built-in
printf().
Method signature
/**
* @param int|string $numberOfRepeats Statement or value defining
* how often the $value should
* be repeated. Proper quoting
* must be ensured.
* @param string $value Value which should be repeated.
* Proper quoting must be ensured.
* @param string $asIdentifier Provide `AS` identifier if not
* empty.
* @return string Returns the platform compatible statement to create the
* x-times repeated value.
*/publicfunctionrepeat(
int|string $numberOfRepeats,
string $value,
string $asIdentifier = '',
): string{}
The
SPACE(number) expression is used for MariaDB and MySQL and
ExpressionBuilder::repeat() expression as fallback for PostgreSQL
and SQLite.
Method signature
/**
* @param int|string $numberOfSpaces Expression or value defining how
* many spaces should be created.
* @param string $asIdentifier Provide result as identifier field
* (AS), not added if empty string.
* @return string Returns the platform compatible statement to create the
* x-times repeated space(s).
*/publicfunctionspace(
string $numberOfSpaces,
string $asIdentifier = '',
): string{}
Be aware to properly quote values, identifiers and sub-expressions.
No automatic quoting will be applied.
ExpressionBuilder::left()
Extract
$length character of
$value from the left side.
Note
Creates a
LEFT(string, number_of_chars) expression for all supported
database vendors except SQLite, where
substring(string, integer[, integer])
is used to provide a compatible expression.
Method signature
/**
* @param int|string $length Integer value or expression
* providing the length as integer.
* @param string $value Value, identifier or expression
* defining the value to extract from
* the left.
* @param string $asIdentifier Provide `AS` identifier if not empty.
* @return string Return the expression to extract defined substring
* from the right side.
*/publicfunctionleft(
int|string $length,
string $value,
string $asIdentifier = '',
): string{}
For other sub string operations,
\Doctrine\DBAL\Platforms\AbstractPlatform::getSubstringExpression()
can be used. Synopsis:
getSubstringExpression(string $string, string $start, ?string $length = null): string.
ExpressionBuilder::right()
Extract
$length character of
$value from the right side.
Note
Creates a
RIGHT(string, number_of_chars) expression for all supported
database vendors except SQLite, where
substring(string, integer[, integer])
is used to provide a compatible expression.
Method signature
/**
* @param int|string $length Integer value or expression
* providing the length as integer.
* @param string $value Value, identifier or expression
* defining the value to extract from
* the right.
* @param string $asIdentifier Provide `AS` identifier if not empty.
*
* @return string Return the expression to extract defined substring
* from the right side.
*/publicfunctionright(
int|string $length,
string $value,
string $asIdentifier = '',
): string{}
Be aware to properly quote values, identifiers and sub-expressions.
No automatic quoting will be applied.
ExpressionBuilder::leftPad()
Left-pad the value or sub-expression result with $paddingValue, to a total
length of $length.
Note
SQLite does not support
LPAD(string, integer, string), therefore a
more complex compatible replacement expression construct is created.
Method signature
/**
* @param string $value Value, identifier or expression
* defining the value which should
* be left padded.
* @param int|string $length Value, identifier or expression
* defining the padding length to
* fill up on the left or crop.
* @param string $paddingValue Padding character used to fill
* up if characters are missing on
* the left side.
* @param string $asIdentifier Used to add a field identifier alias
* (`AS`) if non-empty string (optional).
* @return string Returns database connection platform compatible
* left-pad expression.
*/publicfunctionleftPad(
string $value,
int|string $length,
string $paddingValue,
string $asIdentifier = '',
): string{}
Be aware to properly quote values, identifiers and sub-expressions.
No automatic quoting will be applied.
ExpressionBuilder::rightPad()
Right-pad the value or sub-expression result with
$paddingValue, to a
total length of
$length.
Note
SQLite does not support
RPAD(string, integer, string), therefore a
complexer compatible replacement expression construct is created.
Method signature
/**
* @param string $value Value, identifier or expression
* defining the value which should be
* right padded.
* @param int|string $length Value, identifier or expression
* defining the padding length to
* fill up on the right or crop.
* @param string $paddingValue Padding character used to fill up
* if characters are missing on the
* right side.
* @param string $asIdentifier Used to add a field identifier alias
* (`AS`) if non-empty string (optional).
* @return string Returns database connection platform compatible
* right-pad expression.
*/publicfunctionrightPad(
string $value,
int|string $length,
string $paddingValue,
string $asIdentifier = '',
): string{}
Be aware to properly quote values, identifiers and sub-expressions.
No automatic quoting will be applied.
Impact
Extension authors can use the new expression methods to build more advanced
queries without the requirement to deal with the correct implementation for
all supported database vendors.
Feature: #103331 - Native support for language Maltese added
Site sets ship parts of site configuration as composable pieces. They are
intended to deliver settings, TypoScript, TSconfig and reference enabled content
blocks for the scope of a site.
Extensions can provide multiple sets in order to ship presets for different
sites or subsets (think of frameworks) where selected features are exposed
as a subset (example: typo3/seo-xml-sitemap).
A set is defined in an extension's subfolder in Configuration/Sets/, for
example EXT:my_extension/Configuration/Sets/MySet/config.yaml.
The folder name in Configuration/Sets/ is arbitrary, significant
is the name defined in config.yaml. The name uses a vendor/name
scheme by convention, and should use the same vendor as the containing
extension. It may differ if needed for compatibility reasons (e.g. when sets are
moved to other extensions). If an extension provides exactly one set that should
have the same name as defined in composer.json.
The config.yaml for a set that is composed of three subsets looks as
follows:
name:my-vendor/my-setlabel:MySet# Load TypoScript, TSconfig and settings from dependenciesdependencies:-some-namespace/slider-other-namespace/fancy-carousel
Copied!
Sets are applied to sites via dependencies array in site configuration:
Site sets can also be edited via the backend module
Site Management > Sites.
A list of available site sets can be retrieved with the console command
bin/typo3 site:sets:list.
Settings definitions
Sets can define settings definitions which contain more metadata than just a
value: They contain UI-relevant options like label, description, category
and tags and types like int, bool, string, stringlist, text or
color. These definitions are placed in settings.definitions.yaml
next to the site set file config.yaml.
The description can make use of markdown syntax for richtext formatting.
settings:foo.bar.baz:label:'My example baz setting'description:'Configure `baz` to be used in `bar`.'type:intdefault:5
Copied!
Settings for subsets
Settings for subsets (e.g. to configure settings in declared dependencies)
can be shipped via settings.yaml when placed next to the set file
config.yaml.
Note that default values for settings provided by the set do not need to be
defined here, as defaults are to be provided within
settings.definitions.yaml.
Here is an example where the setting styles.content.defaultHeaderType — as
provided by typo3/fluid-styled-content — is configured via
settings.yaml:
This setting will be exposed as site setting whenever the set
my-vendor/my-set is applied to a site configuration.
Hidden sets
Sets may be hidden from the backend set selection in
Site Management > Sites and the console command
bin/typo3 site:sets:list by adding a hidden flag to the
config.yaml definition:
Integrators may choose to hide existing sets from the list of available
sets for backend users via User TSConfig, in case only a curated list of sets
shall be selectable:
The Site Management > Sites GUI will not show hidden sets,
but makes one exception if a hidden set has already been applied to a site
(e.g. by manual modification of config.yaml). In this case a set
marked as hidden will be shown in the list of currently activated sets (that means
it can be introspected and removed via backend UI).
Impact
Sites can be composed of sets where relevant configuration, templates, assets
and setting definitions are combined in a central place and applied to sites as
one logical volume.
Sets have dependency management and therefore allow sharing code between
multiple TYPO3 sites and extensions in a flexible way.
Feature: #103439 - TypoScript provider for sites and sets
TYPO3 sites have been enhanced to be able to operate as TypoScript template
provider. They act similar to
sys_template records with "clear" and "root"
flags set. By design a site TypoScript provider always defines a new scope
("root" flag) and does not inherit from parent sites (for example, sites up in the
root line). That means it behaves as if the "clear" flag is set in a sys_template
record. This behavior is not configurable by design, as TypoScript code sharing
is intended to be implemented via sharable sets (Feature: #103437 - Introduce site sets).
Note that
sys_template records will still be loaded, but they are optional
now, and applied after TypoScript provided by the site.
TypoScript dependencies can be included via set dependencies. This mechanism is
much more effective than the previous static_file_include's or manual
@import
statements (they are still fine for local includes, but should be avoided for
cross-set/extensions dependencies), as sets are automatically ordered and
deduplicated.
Site TypoScript
The files setup.typoscript and constants.typoscript (placed next
to the site's config.yaml file) will be loaded as TypoScript setup and
constants, if available.
Site dependencies (sets) will be loaded first, that means setup and constants
can be overridden on a per-site basis.
Set TypoScript
Set-defined TypoScript can be shipped within a set. The files
setup.typoscript and constants.typoscript (placed next to the
config.yaml file) will be loaded, if available.
They are inserted (similar to static_file_include) into the TypoScript chain
of the site TypoScript that will be defined by a site that is using sets.
Set constants will always be overruled by site settings. Since site settings
always provide a default value, a constant will always be overruled by a defined
setting. This can be used to provide backward compatibility with TYPO3 v12
in extensions, where constants shall be used in v12, while v13 will always
prefer defined site settings.
In contrast to static_file_include, dependencies are to be included via
sets. Dependencies are included recursively. This mechanism supersedes the
previous include via static_file_include or manual
@import statements as
sets are automatically ordered and deduplicated. That means TypoScript will not
be loaded multiple times, if a shared dependency is required by multiple sets.
Note that
@import statements are still fine to be used for local
includes, but should be avoided for cross-set/extensions dependencies.
Global TypoScript
Site sets introduce reliable dependencies in order to replace the need for
globally provided TypoScript. It is therefore generally discouraged to use
global TypoScript in an environment using TypoScript provided by site sets.
TypoScript should only be provided globally if absolutely needed.
It has therefore been decided that ext_typoscript_setup.typoscript and
ext_typoscript_constants.typoscript are not autoloaded in site set
provided TypoScript.
These files can still be used to provide global TypoScript for traditional
sys_template setups. Existing setups do not need to be adapted and
extensions can still ship globally defined TypoScript via
ext_typoscript_setup.typoscript for these cases, but should provide
explicitly dependable sets for newer site set setups.
If global TypoScript is still needed and is unavoidable, it can be provided
for site sets and
sys_template setups in ext_localconf.php via:
There are some cases where globally defined TypoScript configurations are needed
because backend modules rely on their availability. One such case is the form
framework backend module which uses
module.tx_form.settings.yamlConfigurations as a registry for
extension-provided form configuration. Global form configuration can be loaded
via
ExtensionManagementUtility as described
in
YAML registration for the backend via addTypoScriptSetup()
Please make sure to only load backend-related form TypoScript globally and to
provide TypoScript related to frontend rendering via site sets.
Impact
Sites and sets can ship TypoScript without the need for
sys_template
records in database, and dependencies can be expressed via sets, allowing for
automatic ordering and deduplication.
Feature: #103441 - Request ID as public visible error reference in error handlers output
The
ProductionExceptionHandler in EXT:core outputs error details, but not
for everyone. As a normal visitor you don't see any traceable error information.
The
ProductionExceptionHandler in EXT:frontend outputs "Oops, an error
occurred!" followed by a timestamp and a hash. This is part of log messages.
Whenever an error/exception is logged, the log message contains the request ID.
With this the request ID is also shown in web output of error/exception handlers
as public visible error reference.
Impact
Everyone sees a request id as traceable error information.
A new content object for TypoScript
PAGEVIEW has been added.
This cObject is mainly intended for rendering a full page in the TYPO3 frontend
with fewer configuration options over the generic
FLUIDTEMPLATE
cObject.
A basic usage of the
PAGEVIEW cObject is as follows:
The name of the used page layout (backend layout) is resolved automatically.
If a page has a layout named "with_sidebar", the template file is then resolved
to EXT:mysite/Resources/Private/Templates/Pages/With_sidebar.html.
Fluid features for layouts and partials are wired automatically. They
can be placed into EXT:mysite/Resources/Private/Templates/Layouts/
and EXT:mysite/Resources/Private/Templates/Partials/ with above example.
Default variables are available in the Fluid template:
settings - contains all TypoScript settings (= constants)
site - the current
Site object
language - the current
SiteLanguage object
page - the current page record as object
Note
The
PageInformation object contains all relevant information about
the current page. Those are, for example, the corresponding page record, the
root line, and many more. Worth mentioning is also the
PageLayout
object, which provides all the information about the selected backend layout.
This includes the identifier, the title, the available content areas
with their corresponding name and colPos. Additionally, the full (raw)
backend layout configuration is available.
There is no special Extbase resolving done for the templates.
Migration
Before
page = PAGE
page {
10 = FLUIDTEMPLATE10 {
templateName = TEXT
templateName {
stdWrap {
cObject = TEXT
cObject {
data = levelfield:-2, backend_layout_next_level, slide
override {
field = backend_layout
}
split {
token = pagets__
1 {
current = 1
wrap = |
}
}
}
ifEmpty = Standard
}
}
templateRootPaths {
100 = {$plugin.tx_mysite.templateRootPaths}
}
partialRootPaths {
100 = {$plugin.tx_mysite.partialRootPaths}
}
layoutRootPaths {
100 = {$plugin.tx_mysite.layoutRootPaths}
}
variables {
pageUid = TEXT
pageUid.data = page:uid
pageTitle = TEXT
pageTitle.data = page:title
pageSubtitle = TEXT
pageSubtitle.data = page:subtitle
parentPageTitle = TEXT
parentPageTitle.data = levelfield:-1:title
}
dataProcessing {
10 = menu
10.as = mainMenu
}
}
}
In Fluid, the pageUid is available as
{page.uid} and pageTitle
as
{page.title}. The page layout identifier can be accessed
using
{page.pageLayout.identifier}.
Impact
Creating new page templates based on Fluid follows conventions in order to
reduce the amount of TypoScript needed to render a page in the TYPO3 frontend.
Sane defaults are applied, variables and settings are available at any time.
Note
This cObject is marked as experimental until TYPO3 v13 LTS as some
functionality will be added.
Note
Default variable names cannot be set or overridden and trying to do
will throw an exception.
Feature: #103522 - Page TSconfig provider for sites and sets
TYPO3 sites have been enhanced to be able to provide page TSconfig on a per-site
basis.
Site page TSconfig is loaded from page.tsconfig, if placed next to the
site configuration file config.yaml and is scoped to pages within that
site.
Impact
Sites and sets can ship page TSconfig without the need for database entries or
by polluting global scope when registering page TSconfig globally via
ext_localconf.php or Configuration/page.tsconfig.
Dependencies can be expressed via sets, allowing for automatic ordering and
deduplication.
Feature: #103529 - Introduce hotkey for "Save and Close"
Fluid Standalone has been updated to version 2.11. This version includes new
ViewHelpers that cover common tasks in Fluid templates. More ViewHelpers will
be added with future minor releases.
Similar to editing regular content elements, it is now possible to save
scheduler tasks being edited via keyboard shortcuts as well.
Impact
It is possible to invoke the Ctrl/Cmd + s hotkey to save a
scheduler task, altogether with the hotkey Ctrl/Cmd + Shift + S
to save and close a scheduler task.
Feature: #103578 - Add database default value support for TEXT, BLOB and JSON field types
Database default values for
TEXT,
JSON and
BLOB fields
could not be used in a cross-database, vendor-compatible manner, for
example in ext_tables.sql, or as default database scheme generation
for TCA-managed tables and types.
Direct default values are still unsupported, but since
MySQL 8.0.13+
this is possible by using default value expressions, albeit in a slightly
differing syntax.
CREATETABLE a_textfield_test_table
(
# JSON object default value containing single quote in json field
field1 JSONNOTNULLDEFAULT'{"key1": "value1", "key2": 123, "key3": "value with a '' single quote"}',
# JSON object default value containing double-quote in json field
field2 JSONNOTNULLDEFAULT'{"key1": "value1", "key2": 123, "key3": "value with a \" double quote"}',
);
Copied!
Impact
Database
INSERT queries that do not provide values for fields with
defined default values, and that do not use TCA-powered TYPO3
APIs, can now be used, and will receive default values defined at databaselevel.
This also accounts for dedicated applications operating directly
on the database table.
Note
TCA-unaware API will not consider different TCA or FormEngine default
value overrides and settings. So it's good to provide the basic default
both in TCA and at database level, if added manually.
Feature: #103671 - Provide null coalescing operator for TypoScript constants
TypoScript constants expressions have been extended to support a null coalescing
operator (??) as a way for providing a migration path from a legacy constant
name to a newer name, while providing full backwards compatibility for the
legacy constant name, if still defined.
Example that evaluates to $config.oldThing if set, otherwise the newer setting
$myext.thing would be used:
Since Feature: #103439 - TypoScript provider for sites and sets it is suggested to define site settings
via settings.definitions.yaml in site sets instead of TypoScript
constants. Migration of TYPO3 Core extensions revealed that such migration is a
good time to revisit constant names and the null coalescing operator helps to
switch to a new setting identifier without breaking backwards-compatibility with
previous constant names.
Usage of the method will raise a deprecation level log entry in
TYPO3 v13 and a fatal error in TYPO3 v14.
Affected installations
All third-party extensions using
\TYPO3\CMS\Core\Utility\GeneralUtility::hmac().
Migration
All usages of
\TYPO3\CMS\Core\Utility\GeneralUtility::hmac()
must be migrated to use the
hmac() method in the class
\TYPO3\CMS\Core\Crypto\HashService .
The user TSconfig option
options.pageTree.backgroundColor
has been deprecated and will be removed in TYPO3 v14 due to its
lack of accessibility. It is being replaced with a
new label system for tree nodes.
Impact
During v13,
options.pageTree.backgroundColor will be
migrated to the new label system. Since the use case is unknown,
the generated label will be "Color: <value>". This information
will be displayed on all affected nodes.
Affected installations
All installations that use the user TSconfig option
options.pageTree.backgroundColor are affected.
The TYPO3 backend module
@typo3/backend/wizard.js that offers simple
wizards has been marked as deprecated in favor of the richer
@typo3/backend/multi-step-wizard.js module.
Impact
Using the deprecated module will trigger a browser console warning.
Affected installations
All installations using
@typo3/backend/wizard.js are affected.
Migration
Migrate to the module
@typo3/backend/multi-step-wizard.js. There are two
major differences:
The class name changes to
MultiStepWizard.
The method
addSlide() receives an additional argument for the step title
in the progress bar.
Example
-import Wizard from '@typo3/backend/wizard.js';+import MultiStepWizard from '@typo3/backend/multi-step-wizard.js';-Wizard.addSlide(+MultiStepWizard.addSlide(
'my-slide-identifier',
'Slide title',
'Content of my slide',
SeverityEnum.notice,
+ 'My step',
function () {
// callback executed after displaying the slide
}
);
Class
\TYPO3\CMS\Core\DataHandling\SlugEnricher has been marked as
deprecated in TYPO3 v13 and will be removed with v14.
The class was used as a helper for
\TYPO3\CMS\Core\DataHandling\DataHandler ,
which now inlines the code in a simplified variant.
Impact
Using the class will raise a deprecation level log entry and a fatal error in TYPO3 v14.
Affected installations
There is little to no reason to use this class in custom extensions, very few
instances should be affected by this. The extension scanner will find usages
with a strong match.
The JavaScript module
@typo3/backend/document-save-actions.js was
introduced in TYPO3 v7 to add some interactivity in FormEngine context.
At first it was only used to disable the submit button and render a
spinner icon instead. Over the course of some years, the module got more
functionality, for example to prevent saving when validation fails.
Since some refactorings within FormEngine, the module rather became a
burden. This became visible with the introduction of the
Hotkeys API, as
the
@typo3/backend/document-save-actions.js reacts on explicit
click
events on the save icon, that is not triggered when FormEngine invokes a
save action via keyboard shortcuts.
Adjusting
document-save-actions.js's
behavior is necessary, but would become a breaking change, which is
unacceptable after the 13.0 release. For this reason, said module has
been marked as deprecated and its usages are replaced by its successor
@typo3/backend/form/submit-interceptor.js.
Impact
Using the JavaScript module
@typo3/backend/document-save-actions.js will
render a deprecation warning in the browser's console.
Affected installations
All installations relying on
@typo3/backend/document-save-actions.js are
affected.
Migration
To migrate the interception of submit events, the successor module
@typo3/backend/form/submit-interceptor.js shall be used instead.
The usage is similar to
@typo3/backend/document-save-actions.js, but
requires the form HTML element in its constructor.
Example
import'@typo3/backend/form/submit-interceptor.js';
// ...const formElement = document.querySelector('form');
const submitInterceptor = new SubmitInterceptor(formElement);
submitInterceptor.addPreSubmitCallback(function() {
// the same handling as in @typo3/backend/document-save-actions.js
});
Copied!
Deprecation: #103850 - Renamed Page Tree Navigation Component ID
When registering a module in the TYPO3 Backend, using the page tree as navigation component,
the name of the page tree navigation component has been renamed in TYPO3 v13.
Previously, the navigation component was called
@typo3/backend/page-tree/page-tree-element, now it is named
@typo3/backend/tree/page-tree-element.
Impact
Using the old navigation ID will trigger a PHP deprecation warning.
Affected installations
TYPO3 installations with custom backend modules utilizing the page tree navigation component.
Migration
Instead of writing this snippet in your Configuration/Backend/Modules.php:
When editing records in the backend, the
FormEngine class structure located
within EXT:backend/Classes/Form/ handles the generation of the editing view.
A change has been applied related to the rendering of single field labels, which
is no longer done automatically by "container" classes: Single elements have to
create the label themselves.
Extension that add own elements to FormEngine must be adapted, otherwise the
element label is no longer rendered.
Impact
When the required changes are not applied to custom FormEngine element classes,
the value of the TCA "label" property is not rendered.
Affected installations
Instances with custom FormEngine elements are affected. Custom elements need to be
registered to the FormEngine's
NodeFactory, candidates are found by looking at
the
$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine'] array (for instance
using the System > Configuration backend module provided by
EXT:lowlevel). Classes registered using the sub keys
nodeRegistry and
nodeResolver may be affected. The extension scanner does not find
affected classes.
Migration
Custom elements must take care of creating a
<label> or
<legend>
tag on their own: If the element creates an
<input>, or
<select> tag,
the
<label> should have a
for attribute that points to a field having
an
id attribute. This is important especially for accessibility. When no such
target element exists, a
<legend> embedded in a
<fieldset> can be used.
There are two helper methods in
\TYPO3\CMS\Backend\Form\Element\AbstractFormElement to help with this:
renderLabel() and
wrapWithFieldsetAndLegend().
In practice, an element having an
<input>, or
<select> field should
essentially look like this:
$resultArray = $this->initializeResultArray();
// Next line is only needed for extensions that need to keep TYPO3 v12 compatibility
$resultArray['labelHasBeenHandled'] = true;
$fieldId = StringUtility::getUniqueId('formengine-input-');
$html = [];
$html[] = $this->renderLabel($fieldId);
$html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
$html[] = '<div class="form-wizards-wrap">';
$html[] = '<div class="form-wizards-element">';
$html[] = '<div class="form-control-wrap">';
$html[] = '<input class="form-control" id="' . htmlspecialchars($fieldId) . '" value="..." type="text">';
$html[] = '</div>';
$html[] = '</div>';
$html[] = '</div>';
$html[] = '</div>';
$resultArray['html'] = implode(LF, $html);
return $resultArray;
Copied!
The
renderLabel() is a helper method to generate a
<label> tag with a
for attribute, and the same fieldId is used as
id attribute in the
<input> field to connect
<label> and
<input> with each other.
If there is no such field, a
<legend> tag should be used:
$resultArray = $this->initializeResultArray();
// Next line is only needed for extensions that need to keep TYPO3 v12 compatibility
$resultArray['labelHasBeenHandled'] = true;
$html = [];
$html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
$html[] = '<div class="form-wizards-wrap">';
$html[] = '<div class="form-wizards-element">';
$html[] = '<div class="form-control-wrap">';
$html[] = Some custom element html
$html[] = '</div>';
$html[] = '</div>';
$html[] = '</div>';
$html[] = '</div>';
$resultArray['html'] = $this->wrapWithFieldsetAndLegend(implode(LF, $html));
return $resultArray;
The PHP interface
\TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManagerInterface
now requires PHP classes to implement an additional method
hasForms() in
order to fulfill the API.
Impact
TYPO3 projects with extensions using implementations of the
\TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManagerInterface will now
break with a fatal PHP error.
Affected installations
Extensions using implementations of the
\TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManagerInterface .
Migration
Add the new method to your extension's implementation of this interface,
which also makes it compatible with TYPO3 v12 and TYPO3 v13 at the same time.
Breaking: #99323 - Removed hook for modifying records after fetching content
The hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content_content.php']['modifyDBRow']
has been removed in favor of the more powerful PSR-14
\TYPO3\CMS\Frontend\ContentObject\Event\ModifyRecordsAfterFetchingContentEvent .
Impact
Any hook implementation registered is not executed anymore
in TYPO3 v13.0+.
Affected installations
TYPO3 installations with custom extensions using this hook.
Migration
The hook is removed without deprecation in order to allow extensions
to work with TYPO3 v12 (using the hook) and v13+ (using the new event)
when implementing the event as well without any further deprecations.
Use the PSR-14 event
to allow greater influence in the functionality.
The
\TYPO3\CMS\Seo\Event\ModifyUrlForCanonicalTagEvent has been
improved.
Therefore, the event is now always dispatched after the standard functionality
has been executed, such as fetching the URL from the page properties.
The event is furthermore also dispatched in case the canonical tag generation
has been disabled via TypoScript or the page properties. This allows greater
influence in the generation process, but might break existing setups, which
rely on listeners are being called before standard functionality has been
executed or only in case generation is enabled.
Effectively, this also means that
getUrl() might already return a
non-empty
string.
Impact
The
\TYPO3\CMS\Seo\Event\ModifyUrlForCanonicalTagEvent is now always
dispatched when generating canonical tags, just before the final tag markup
is being built.
Affected installations
TYPO3 installations with custom extensions, whose event listeners rely on the
event being dispatched before standard functionality has been executed or
only in case generation has not been disabled.
Migration
Adjust your listeners by respecting the new execution order. Therefore, the
event contains the new
getCanonicalGenerationDisabledException() method,
which can be used to determine whether generation is disabled and the reason
for it.
Breaking: #99898 - Continuous array keys from GeneralUtility::intExplode
When the method
\TYPO3\CMS\Core\Utility\GeneralUtility::intExplode()
is called with the parameter
$removeEmptyEntries set to
true, the
array keys are now continuous.
Previously, the array had gaps in the keys in the places where empty values were
removed. This behavior had been an undocumented side-effect of the
implementation. It is now changed to always return an array with continuous
integer array keys (i.e., a list) to reduce surprising behavior.
Calling
GeneralUtility::intExplode() with the parameter
$removeEmptyEntries set to
true and relying on gaps in the keys of
the resulting array keys may lead to unexpected results.
Affected installations
Custom extensions that rely on the array keys of the result of
GeneralUtility::intExplode() to have gaps in the keys.
Migration
Adapt your code to not rely on gaps in the keys anymore.
Breaking: #99937 - Utilize BIGINT database column type for datetime TCA
The TCA
'type' => 'datetime' attribute previously created
integer signed types as per the new auto-creation of table columns,
if not specified differently via ext_tables.sql or listed as an exception
(
starttime,
endtime,
tstamp,
crdate).
A
datetime field created without an exception would allow date ranges
from 1901 to 2038. While that allows dates before 1970 (usual birthdays),
sadly this field would "end" in 2038.
Because of this, the exceptions (
starttime,
endtime,
tstamp,
crdate) already are created as
integer unsigned, which puts them
from 1970 to 2106. Dates before 1970 are not needed, because you will not publish
or create anything in the past, but maybe after 2038.
However, there are many use cases where
datetime TCA fields should have
a much broader time span, or at least past 2038.
Now, all these fields are changed to use the
bigint signed data type.
This allows to define ranges far into the future and past. It uses a few
more bytes within the database, for the benefit of being a unified solution
that can apply to every use case.
Impact
All extensions that previously declared
datetime columns should
remove the column definition from ext_tables.sql to utilize the
type
bigint signed. This will allow to store timestamps after
2038 (and before 1970).
A future implementation may change from integer-based columns completely
to a native
datetime database field.
When executing the database compare utility, the column definitions for a few
Core fields are changed and their storable range increases.
These fields are now able to hold a timestamp beyond 2038 (and also before
1970):
The class
\TYPO3\CMS\Core\Authentication\Mfa\MfaViewType has been
migrated to a native PHP backed enum.
Impact
Since
MfaViewType is no longer a class, the existing class constants
are no longer available, but are enum instances instead.
In addition, it's not possible to instantiate the class anymore or call
the
equals() method.
The
\TYPO3\CMS\Core\Authentication\Mfa\MfaProviderInterface , which
all MFA providers need to implement, does now require the third argument
$type of the
handleRequest() method to be a
MfaViewType
instead of a
string.
Affected installations
All installations directly using the class constants, instantiating the
class or calling the
equals() method.
All extensions with custom MFA providers, which therefore implement the
handleRequest() method.
Migration
To access the string representation of a
MfaViewType, use the
corresponding
value property, e.g.
\TYPO3\CMS\Core\Authentication\Mfa\MfaViewType::SETUP->value or on a
variable, use
$type->value.
Replace class instantiation by
\TYPO3\CMS\Core\Authentication\Mfa\MfaViewType::tryFrom('setup').
Adjust your MFA providers
handleRequest() method to match the interface:
The class
\TYPO3\CMS\Core\Type\Bitmask\JSConfirmation is replaced by
\TYPO3\CMS\Core\Authentication\JsConfirmation . The new class is
extending the
\TYPO3\CMS\Core\Type\BitSet class instead of
\TYPO3\CMS\Core\TypeEnumeration\Enumeration.
Impact
Since
JSConfirmation is now extending the class
\TYPO3\CMS\Core\Type\BitSet
it's no longer possible to call the following public methods:
matches()
setValue()
isValid()
The only static method left is:
compare()
Affected installations
Custom TYPO3 extensions calling public methods:
matches()
setValue()
isValid()
Custom TYPO3 extensions calling static methods in
\TYPO3\CMS\Core\Type\Bitmask\JSConfirmation
except for the method
\TYPO3\CMS\Core\Type\Bitmask\JSConfirmation::compare().
Custom TYPO3 extensions calling
\TYPO3\CMS\Core\Authentication\BackendUserAuthentication->jsConfirmation(),
if first argument passed is not an
int.
Migration
Replace existing usages of
\TYPO3\CMS\Core\Type\Bitmask\JSConfirmation
with
\TYPO3\CMS\Core\Authentication\JsConfirmation .
There is no migration for the methods:
matches()
setValue()
isValid()
Remove existing calls to static methods
\TYPO3\CMS\Core\Type\Bitmask\JSConfirmation::method()
and where
JSConfirmation::compare() is used, replace the namespace from
\TYPO3\CMS\Core\Type\Bitmask\JSConfirmation to
\TYPO3\CMS\Core\Authentication\JsConfirmation .
Usage of the ext_icon.* file locations for extension icons
Usage of the result property
additionalJavaScriptPost of the form engine result array
Using chart.js v3 compatible widgets in ext:dashboard
Usage of
.t3js-contextmenutrigger to trigger and configure context menus
Usage of the jsonArray property
scriptCall for AjaxController's
Binding the selected menu items to callback actions in context menus
Checking for
\TYPO3\CMS\Core\Site\SiteLanguageAwareTrait is removed in
\TYPO3\CMS\Core\Routing\Aspect\AspectFactory
f:format.html ViewHelper no longer works in BE context
Usage of
JScode containing inline JavaScript for handing custom signals
Usage property
$resultArray['requireJsModules'] of the form engine result array
Using backend FormEngine, the current ServerRequestInterface request must be provided in key "request" as
initialData to FormDataCompiler, the fallback to
$GLOBALS['TYPO3_REQUEST'] has been removed.
Compatibility layer for "TCEforms" key in FlexFormTools has been removed
Compatibility layer for using array parameters for files in extbase (use UploadedFile instead)
The following upgrade wizards have been removed:
Wizard for migrating backend user languages
Wizard for installing the extension "legacy_collections" from TER
Wizard for migrating the
transOrigDiffSourceField field to a json encoded string
Wizard for cleaning up workspace new placeholders
Wizard for cleaning up workspace move placeholders
Wizard for migrating shortcut records
Wizard for sanitizing existing SVG files in the fileadmin folder
Wizard for populating a new channel column of the sys_log table
The following features are now always enabled:
security.backend.enforceContentSecurityPolicy
The following feature has been removed:
Regular expression based validators in ext:form backend UI
The following database table fields have been removed:
fe_users.TSconfig
fe_groups.TSconfig
The following backend route identifier has been removed:
ajax_core_requirejs
The following global JavaScript variable has been removed:
TYPO3.Tooltip
The following global JavaScript function has been removed:
Global_JavaScript_Function_Name
The following JavaScript module has been removed:
tooltip
The following JavaScript method behaviour has changed:
ColorPicker.initialize() always requires an
HTMLInputElement to be passed as first argument
The following JavaScript method has been removed:
getParameterFromUrl() of
@typo3/backend/utility
The following CKEditor plugin has been removed:
SoftHyphen
The following dependency injection service aliase has been removed:
@dashboard.views.widget
Impact
Using above removed functionality will most likely raise PHP fatal level errors,
may change website output or crashes browser JavaScript.
The NPM package jquery-ui has
been removed completely for TYPO3 v13 without any substitute.
According to the TYPO3 Deprecation Policy,
JavaScript code and packages used only in the TYPO3 backend are not
considered to be part of that policy:
The deprecation policy does not cover the deprecations of backend components
such as JavaScript code, CSS code, HTML code, and backend templates.
Impact
TYPO3 does not ship the NPM package jquery-ui any longer. Third-party
extensions that rely on this package will be broken and need to be adjusted.
Since TYPO3 exposed only parts of jquery-ui, only the components core,
draggable, droppable, mouse, resizable, selectable, sortable and
widget are affected - other components simply did not exist.
Affected installations
Those having custom or third-party extensions using jquery-ui from
typo3/sysext/core/Resources/Public/JavaScript/Contrib/jquery-ui/.
Migration
TYPO3 does not provide any substitute. In TYPO3 the draggable and resizable
features of jquery-ui have been reimplemented in the new custom element
<typo3-backend-draggable-resizable>.
Breaking: #101129 - Convert Action to native backed enum
The class
\TYPO3\CMS\Scheduler\Task\Enumeration\Action is now
converted to a native backed enum. In addition the class is moved to
the namespace
\TYPO3\CMS\Scheduler and renamed to
SchedulerManagementAction.
Impact
Since
\TYPO3\CMS\Scheduler\Task\Enumeration\Action is no longer
a class, the existing class constants are no longer available.
In addition it's not possible to instantiate it anymore.
Affected installations
Third-party extensions using the following class constants:
The class
\TYPO3\CMS\Core\Authentication\LoginType is now
converted to a native backed enum.
Impact
Since
\TYPO3\CMS\Core\Authentication\LoginType is no longer
a class, the existing class constants are no longer available.
Affected installations
Custom authenticators using the following class constants:
\TYPO3\CMS\Core\Authentication\LoginType::LOGIN
\TYPO3\CMS\Core\Authentication\LoginType::LOGOUT
Migration
Use the new syntax:
\TYPO3\CMS\Core\Authentication\LoginType::LOGIN->value
\TYPO3\CMS\Core\Authentication\LoginType::LOGOUT->value
Alternatively, use the enum method
tryFrom to convert a
value to an enum. For direct comparison of two enums, the null-coalescing
operator shall be used to ensure that the parameter is a string:
<?phpuseTYPO3\CMS\Core\Authentication\LoginType;
if (LoginType::tryFrom($value ?? '') === LoginType::LOGIN) {
// Do login stuff
}
if (LoginType::tryFrom($value ?? '') === LoginType::LOGOUT) {
// Do logout stuff
}
The public method
getIcon() in
\TYPO3\CMS\Core\Imaging\IconFactory
has changed its 4th parameter, in order to prepare the removal
of class
\TYPO3\CMS\Core\Type\Icon\IconState.
Impact
Custom extensions extending the
getIcon() method of class
\TYPO3\CMS\Core\Imaging\IconFactory not having the same signature
will fail with a PHP fatal error.
Affected installations
Custom extensions extending the
getIcon() method from class
\TYPO3\CMS\Core\Imaging\IconFactory .
Migration
Adapt the 4th parameter of
getIcon() to be of type
\TYPO3\CMS\Core\Type\Icon\IconState|IconState $state = null
In addition, adapt the code in the body of the method.
The protected property
\TYPO3\CMS\Core\Imaging\Icon->state holds now a native
enum
\TYPO3\CMS\Core\Imaging\IconState instead of an instance of
\TYPO3\CMS\Core\Type\Icon\IconState.
Impact
Custom extensions calling
\TYPO3\CMS\Core\Imaging\Icon->getState() will
receive an enum now, which will most probably lead to PHP errors in the runtime.
Custom extensions calling
\TYPO3\CMS\Core\Imaging\Icon->setState() with an
instance of
\TYPO3\CMS\Core\Type\Icon\IconState will receive a PHP
TypeError.
Affected installations
Custom extensions calling
\TYPO3\CMS\Core\Imaging\Icon->getState() or
\TYPO3\CMS\Core\Imaging\Icon->setState().
Migration
Adapt your code to handle the native enum
\TYPO3\CMS\Core\Imaging\IconState .
TYPO3 had multiple concepts of a recycler / trash bin. One of the oldest
concepts was the ability to create a manual page of the type "Recycler"
(page records with doktype=255 set) where editors could manually move content
to such a page instead of deleting it. One other option is to use the
Web > Recycler backend module (available with the shipped recycler
system extension). This process is much more user-friendly: Any kind of record
which has been (soft-)deleted can be viewed and re-added via this module, no
manual process during the deletion process is needed.
For reasons of consistency and de-cluttering the UI, the former functionality
has been removed from TYPO3 Core, along with the PHP class
constant
\TYPO3\CMS\Domain\Repository\PageRepository::DOKTYPE_RECYCLER.
Impact
The recycler doktype has been removed and cannot be selected or used anymore. Any
existing recycler pages are migrated to a page of type "Backend User Section"
which is also not accessible, if there is no valid backend user with permission
to see this page.
Affected installations
TYPO3 installations using this special page doktype "Recycler".
Migration
A migration is in place, it is recommended to use the Recycler
module with soft-deleting records.
Breaking: #101143 - Strict typing in LinktypeInterface
Instead of extending the data provider, it is recommended to register a custom
DataProvider for backend layouts, which can already be used since TYPO3 v7.
Breaking: #101175 - Convert VersionState to native backed enum
The class
\TYPO3\CMS\Core\Versioning\VersionState is now
converted to a native PHP backed enum.
Impact
Since
\TYPO3\CMS\Core\Versioning\VersionState is no longer
a class, the existing class constants are no longer available, but are
enum instances instead.
In addition it's not possible to instantiate it anymore or call
the
equals() method.
The class constructor in
\TYPO3\CMS\Frontend\Exception\UnableToLinkException
is now strictly typed. In addition, the variable
$linkText has type
string.
Impact
The class constructor is now strictly typed.
Affected installations
TYPO3 sites using the
\TYPO3\CMS\Frontend\Exception\UnableToLinkException exception.
Migration
Ensure that the class constructor is called properly, according to the changed signature:
The RequireJS project has been discontinued and was therefore
deprecated in TYPO3 v12 with forge#96510 in favor of native ECMAScript
v6/v11 modules (added in forge#96510).
The infrastructure for configuration and loading of RequireJS
modules is now removed.
Impact
Registering FormEngine JavaScript modules via
'requireJsModules' will
have no effect. The PageRenderer endpoints
\TYPO3\CMS\Core\Page\PageRenderer->loadRequireJs() and
\TYPO3\CMS\Core\Page\PageRenderer->loadRequireJsModule()
have been removed and must no longer be called.
The respective
includeJavaScriptModules property of the ViewHelper
<f:be.pageRenderer> ViewHelper has also been removed.
Affected installations
TYPO3 installations using RequireJS modules to provide JavaScript in the TYPO3
backend, or – less common – use PageRenderer RequireJS infrastructure for
frontend JavaScript module loading.
Migration
Migrate your JavaScript from the AMD module format to native ES6 modules and
register your configuration in
Configuration/JavaScriptModules.php,
also see forge#96510 and ES6 in the TYPO3 Backend
for more information:
Then use
\TYPO3\CMS\Core\Page\PageRenderer->loadJavaScriptModule() instead
of
\TYPO3\CMS\Core\Page\PageRenderer->loadRequireJsModule() to load the ES6 module:
// via PageRenderer$this->pageRenderer->loadJavaScriptModule('@vendor/my-extension/example.js');
Copied!
In Fluid templates includeJavaScriptModules is to be used instead of
includeRequireJsModules:
In Fluid template the includeJavaScriptModules property of the
<f:be.pageRenderer> ViewHelper may be used:
This affects many classes due to the following implementation
rules:
\TYPO3\CMS\Core\Resource\Folder , because it implements
\TYPO3\CMS\Core\Resource\FolderInterface which extends
\TYPO3\CMS\Core\Resource\ResourceInterface
\TYPO3\CMS\Core\Resource\FileReference , and
\TYPO3\CMS\Core\Resource\AbstractFile because both implement
\TYPO3\CMS\Core\Resource\FileInterface which extends
\TYPO3\CMS\Core\Resource\ResourceInterface
\TYPO3\CMS\Core\Resource\File and
\TYPO3\CMS\Core\Resource\ProcessedFile
because both extend
\TYPO3\CMS\Core\Resource\AbstractFile
In consequence, the following methods are affected:
Affected installations are those which either implement the
ResourceInterface
directly (very unlikely) or those that extend any of mentioned implementations
(Core classes).
The usage (the API) of those implementation itself has not changed!
Migration
Use the same return type declarations as
ResourceInterface does.
Breaking: #101291 - Introduce capabilities bit set
The capabilities property of the
ResourceStorage and drivers
(
LocalDriver/
AbstractDriver) have been converted from an integer
(holding a bit value) to an instance of a new
BitSet class
\TYPO3\CMS\Core\Resource\Capabilities .
This affects the public API of the following interface methods:
The type of the parameter
$capabilities of the method
mergeConfigurationCapabilities() has been changed from
int to
\TYPO3\CMS\Core\Resource\Capabilities .
The usage of the mentioned, removed constants of
\TYPO3\CMS\Core\Resource\ResourceStorageInterface will lead to errors.
Affected installations
Installations that implement custom drivers and therefore directly implement
\TYPO3\CMS\Core\Resource\Driver\DriverInterface or extend
\TYPO3\CMS\Core\Resource\Driver\AbstractDriver .
Also, installations that use the removed constants of
\TYPO3\CMS\Core\Resource\ResourceStorageInterface .
Migration
When using mentioned methods that formerly returned the bit value as integer or
expected the bit value as integer parameter need to use the
Capabilities
class instead. It behaves exactly the same as the plain integer. If the plain
integer value needs to be retrieved,
__toInt() can be called on
Capabilities instances.
Return and param type declarations have been introduced for all methods stubs
of
\TYPO3\CMS\Core\Resource\FileInterface .
Impact
In consequence, all implementations of
\TYPO3\CMS\Core\Resource\FileInterface need
to reflect those changes and add the same return and param type declarations.
In case, any of the Core implementations are extended, overridden methods might need
to be adjusted. The Core classes, implementing
\TYPO3\CMS\Core\Resource\FileInterface , are:
\TYPO3\CMS\Core\Resource\AbstractFile
\TYPO3\CMS\Core\Resource\File
\TYPO3\CMS\Core\Resource\FileReference
\TYPO3\CMS\Core\Resource\ProcessedFile
Affected installations
Only those installations that implement
\TYPO3\CMS\Core\Resource\FileInterface directly
or that extend any of those mentioned core implementations.
Migration
Return and param type declarations have to be synced with the ones of the interface.
Breaking: #101305 - Introduce type declarations for some methods in GeneralUtility
Return and param type declarations have been introduced for all methods stubs
of
\TYPO3\CMS\Core\Resource\Driver\DriverInterface .
Also, method
\TYPO3\CMS\Core\Resource\Driver\AbstractDriver::sanitizeFileName()
has been removed.
Impact
In consequence, all implementations of
\TYPO3\CMS\Core\Resource\Driver\DriverInterface need
to reflect those changes and add the same return and param type declarations.
In case, any of the Core implementations are extended, overridden methods might need to be adjusted.
The Core classes, implementing
\TYPO3\CMS\Core\Resource\DriverInterface, are:
Said method didn't sanitize at all, it didn't respect the given
$charset param and simply
returned the input string. Abstract classes MAY fulfill the interface contract but if they do so,
they MUST do it right. There is no benefit in fulfilling it just signature wise, it MUST fulfill
it functional wise and in this case it didn't. That's why
LocalDriver
reimplements
sanitizeFileName() completely.
As a consequence of this removal, all classes that extend either
\TYPO3\CMS\Core\Resource\Driver\AbstractDriver or
\TYPO3\CMS\Core\Resource\Driver\AbstractHierarchicalFilesystemDriver , need to
implement method
sanitizeFileName().
Affected installations
All installations that implement
\TYPO3\CMS\Core\Resource\DriverInterface or that
extend either
\TYPO3\CMS\Core\Resource\Driver\AbstractDriver or
\TYPO3\CMS\Core\Resource\Driver\AbstractHierarchicalFilesystemDriver .
Migration
As for the type declarations:
Add the same param and return type declarations the interface does.
As for the removed method
\TYPO3\CMS\Core\Resource\Driver\AbstractDriver::sanitizeFileName():
Implement the method according to your driver capabilities.
Breaking: #101311 - Make the parameter for GeneralUtility::sanitizeLocalUrl required
A return type declaration has been added to the method stub
\TYPO3\CMS\Core\Resource\FileInterface::getSize().
As a consequence, implementations of said method,
\TYPO3\CMS\Core\Resource\AbstractFile::getSize()
and
\TYPO3\CMS\Core\Resource\FileReference::getSize() received return type declarations as well.
Also,
\TYPO3\CMS\Core\Resource\AbstractFile::getSize() has been adjusted to actually just
return an integer. Previously, it returned
null, if the actual size could not be gathered. It now returns
0 in that case.
Impact
Code, that calls
\TYPO3\CMS\Core\Resource\AbstractFile::getSize() through derivatives like
\TYPO3\CMS\Core\Resource\File::getSize() might be adjusted to not respect
null any more.
Implementations (classes) that implement
\TYPO3\CMS\Core\Resource\FileInterface , have to
adjust the return type of the method
getSize() to match the contract.
Affected installations
Installations that implement
\TYPO3\CMS\Core\Resource\FileInterface or that call
\TYPO3\CMS\Core\Resource\FileInterface::getSize() via derivatives.
Migration
Adjust the return type and possible
null checks.
Breaking: #101398 - Remove leftover $fetchAllFields in RelationHandler
The
\TYPO3\CMS\Core\Database\RelationHandler had an unused property
$fetchAllFields since TYPO3 v11.5.0. The related method
setFetchAllFields() has been removed with it.
Impact
Custom extensions calling
\TYPO3\CMS\Core\Database\RelationHandler->setFetchAllFields()
will result in a PHP Fatal error.
Affected installations
All installations with custom extensions calling
\TYPO3\CMS\Core\Database\RelationHandler->setFetchAllFields().
Migration
Remove the affected line of code. This method has had no effect since
TYPO3 v11.5.0.
Breaking: #101469 - Introduce type declarations in FolderInterface
Return and param type declarations have been introduced for all methods stubs
of
\TYPO3\CMS\Core\Resource\FolderInterface .
Impact
In consequence, all implementations of
\TYPO3\CMS\Core\Resource\FolderInterface
need to reflect those changes and add the same return and param type declarations.
In case, any of the Core implementations are extended, overridden methods might need to
be adjusted. The Core classes, implementing
\TYPO3\CMS\Core\Resource\FolderInterface
are:
\TYPO3\CMS\Core\Resource\Folder
\TYPO3\CMS\Core\Resource\InaccessibleFolder
Affected installations
All installations that implement
\TYPO3\CMS\Core\Resource\FolderInterface
or that extend either
\TYPO3\CMS\Core\Resource\Folder or
\TYPO3\CMS\Core\Resource\InaccessibleFolder .
Migration
Add the same param and return type declarations the interface does.
Breaking: #101471 - Introduce type declarations in AbstractDriver
Return and param type declarations have been introduced for all methods and method
stubs of
\TYPO3\CMS\Core\Resource\Driver\AbstractDriver and
\TYPO3\CMS\Core\Resource\Driver\AbstractHierarchicalFilesystemDriver
Impact
In consequence, all classes, extending any of those abstract classes and overriding
any of those affected methods need to reflect those changes and add the same return
and param type declarations.
With the introduction in TYPO3 v10, the
DebounceEvent module had the
possibility to shift the event handler execution to the beginning of the
debounce sequence, enabled via the optional
immediate parameter.
The parameter is unused in TYPO3 and using this feature has a negative impact
on UX. If used, the event handler is directly executed
and the user has to wait a specific time after the last event was triggered,
before any further execution is possible.
The flag
immediate has been therefore removed.
Impact
The
DebounceEvent module now always waits until a certain time has passed
after the last trigger of the event happened before executing the event handler.
This is mostly used in potential heavy tasks, for example, an Ajax request that
is sent depending on the content of a search field.
Affected installations
All extensions using the removed flag are affected.
Migration
There is no direct migration possible. An extension author either may
re-implement the removed behavior manually, or use the
ThrottleEvent
module, providing a similar behavior.
Breaking: #101603 - Removed hook for overriding icon overlay identifier
The hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Core\Imaging\IconFactory']['overrideIconOverlay']
has been removed in favor of a new PSR-14 event
\TYPO3\CMS\Core\Imaging\Event\ModifyRecordOverlayIconIdentifierEvent .
Impact
Any hook implementation registered is not executed anymore in TYPO3 v13.0+.
Affected Installations
TYPO3 installations with custom extensions using this hook. The extension
scanner will report usages as strong match.
Migration
The hook is removed without deprecation in order to allow extensions
to work with TYPO3 v12 (using the hook) and v13+ (using the new event)
when implementing the event as well without any further deprecations.
The PHP interface
\TYPO3\CMS\Backend\Tree\View\LinkParameterProviderInterface
has changed. The interface is used to generate URLs with query parameters for links
within element browsers or link browsers in the TYPO3 backend.
The methods
getScriptUrl() and
isCurrentlySelectedItem() have been removed
from the interface, as the implementing link browsers do not need this information anymore
due to simplification in routing.
The method
getUrlParameters() now has a native return type
array, whereas
previously this was only type-hinted.
Impact
When accessing implementing PHP objects, it should be noted that these methods do not
exist anymore. When called this might result in fatal PHP errors.
When implementing the PHP interface, the implementing code will fail due to missing return
types.
Affected installations
TYPO3 installations with custom implementations of this interface.
Migration
For extensions implementing the interface, the return type for
getUrlParameters()
can be added in order to be TYPO3 v12+ compatible. For v13-only compatibility,
it is recommended to remove the superfluous methods.
Breaking: #101647 - Unused graphical assets removed from EXT:backend
The TYPO3 system extension "backend" accumulated many graphical assets over the
years that became unused piece by piece.
The following icons have been removed from the Icon Registry:
status-edit-read-only
warning-in-use
warning-lock
The following assets have been removed from the directory EXT:backend/Resources/Public/Images/:
FormFieldWizard/wizard_forms.gif
clear.gif
filetree-folder-default.png
filetree-folder-opened.png
Logo.png
pages.gif
tt_content.gif
Impact
Calling any of the removed icons from the Icon Registry will render the default
icon. Accessing any of the removed files directly will lead to a 404 error.
Affected installations
All extensions using the removed icons and assets are affected.
Migration
No direct migration is available.
Breaking: #101671 - Disable external linktypes by default in EXT:linkvalidator
There are several known problems with external link checking in Linkvalidator,
such as:
"False positives": Some links are reported broken, but are not broken, see
forge#101670.
External sites are checked without rate limit which may cause sites which
perform link checking to be blocked, see forge#89287.
No caching of results (except for a runtime cache during link checking which
will be invalid on next run)
These issues are currently not easily solvable and should also be addressed
specifically for the site concerned.
We now deactivate checking external link types by default in the configuration:
TSconfig Reference.
The "external" link types checking still works but must be enabled explicitly.
This will make administrators more aware of problems and the specific problems
can be addressed, for example, by providing a custom class to replace
\TYPO3\CMS\Linkvalidator\Linktype\ExternalLinktype . Additionally, a page
Known Problems was
already added to the documentation in a previous patch.
Impact
External links will no longer be checked by default in EXT:linkvalidator
unless
mod.linkvalidator.linktypes is specifically set via page
TSconfig.
Affected installations
Installations using EXT:linkvalidator.
Migration
Either leave external link checking deactivated or find ways to mitigate the
problems with external link checking.
Solutions:
do not use external link checking
or, create a custom linktype class to replace
ExternalLinktype
the custom link type should rate limit when checking external links,
for example, by adding a crawl delay in the link targets with the same domain
the custom link type should find a way to handle possible false positives
alternatively the external link type should restrict link checking to known
domains without problems
alternatively, there should be a method to exclude specific URLs or domains
from link checking
excessive checking of external links should be avoided, for example, by
using a link target cache
More information is available in the Linkvalidator documentation:
The bootstrap jQuery interfaces required a global
window.jQuery variable
to be set. The jquery drop-in is dropped in order to remove this non-optional
jQuery dependency.
As a side effect the
window.jQuery global is removed as well.
Note that global jQuery usage has already been deprecated in forge#86438 and
removed in forge#97243 with the suggestion to use JavaScript modules instead.
window.jQuery was basically left in place for bootstrap to operate and
therefore only
window.$ was removed back then.
Impact
Loading the ES6 'bootstrap' module no longer has side effects, as the global
scope
window is no longer polluted by writing to the property
jQuery.
This also means jQuery will no longer be loaded when it is not actually needed.
Affected Installations
All installations that use bootstrap's jQuery interface or applications that
use window.jQuery to invoke jQuery.
Following method calls are affected:
$(…).alert()
$(…).button()
$(…).carousel()
$(…).collapse()
$(…).dropdown()
$(…).tab()
$(…).modal()
$(…).offcanvas()
$(…).popover()
$(…).scrollspy()
$(…).toast()
$(…).tooltip()
Migration
Use bootstrap's ES6 exports
import { Carousel } from 'bootstrap'; instead.
Breaking: #101822 - Change callback interruption in @typo3/backend/document-save-actions
The JavaScript module
@typo3/backend/document-save-actions is used in
FormEngine and Scheduler context mainly to disable the submit button in the
according forms, where also a spinner is rendered within the button to visualize
a running action.
Over the time, the module took over some tasks that logically belong to
FormEngine, which lead to slimming down the module. In a further effort, jQuery
has been removed from said module, leading to a change in behavior how the
callback chain can be aborted.
Native JavaScript events cannot get asked whether event propagation has been
stopped, making changes in the callbacks necessary. All callbacks registered via
DocumentSaveActions.getInstance().addPreSubmitCallback() now need to
return a boolean value.
Impact
Using
stop[Immediate]Propagation() on events passed into registered
callbacks is now unsupported and may lead to undefined behavior.
Affected installations
All extensions using
DocumentSaveActions.getInstance().addPreSubmitCallback()
are affected.
Migration
Callbacks now need to return a boolean value, where returning
false will
abort the callback execution chain.
Breaking: #101933 - Dispatch AfterUserLoggedInEvent for frontend user login
The
\TYPO3\CMS\Core\Authentication\Event\AfterUserLoggedInEvent PSR-14
event is now also dispatched for a successful frontend user login.
Impact
Listeners to the
AfterUserLoggedInEvent event should evaluate the
implementation type of the
$user property, if custom functionality
after a user login should be executed for backend login only.
Affected installations
Installations with an event listener to the php:AfterUserLoggedInEvent PSR-14
event.
Migration
If custom functionality in a listener to the
AfterUserLoggedInEvent
event should be executed for the backend user login only, a type check for the
$user property must be added.
// Beforepublicfunction__invoke(AfterUserLoggedInEvent $afterUserLoggedInEvent): void{
// custom logic after backend user login
}
// Afterpublicfunction__invoke(AfterUserLoggedInEvent $afterUserLoggedInEvent): void{
if ($afterUserLoggedInEvent->getUser() instanceof BackendUserAuthentication) {
// custom logic after backend user login
}
}
Copied!
Breaking: #101941 - Various GFX-related legacy options removed
TYPO3's powerful image manipulation suite has legacy options which were used
20 years ago where it was more important to deliver GIF files instead of PNG
files due to the size of the file.
However, PNG supports transparency and 24 bit, and is supported widely nowadays
and the preferred option.
For this reason, TYPO3's default behavior is now to generate PNG files instead
of GIF files when creating thumbnails.
In addition, the GIFBUILDER option "reduceColors" has been removed, along with
the option to additionally compress GIF files via ImageMagick or GDLib.
When generating thumbnail images or images via GIFBUILDER from various sources which
aren't supported by TYPO3's graphical processing, a PNG is now created instead of a GIF.
This can happen, for instance, when previewing PDF files. JPG files are still kept the same.
Affected installations
TYPO3 installations which used these settings or customized GifBuilder code.
Migration
For 99% of the installations, these options have been activated already, so there is no change
necessary when upgrading and also no visual change.
Breaking: #101948 - File-based AbstractRepository class removed
When the base architecture of File Abstraction Layer (FAL) was introduced in
TYPO3 v6.0, various functionality was based on concepts based on Extbase's
architecture. Some concepts never flourished. One of them being the
\TYPO3\CMS\Core\Resource\AbstractRepository class from FAL.
This PHP class served as a basis for 2 PHP classes,
\TYPO3\CMS\Core\Resource\FileRepository and
\TYPO3\CMS\Core\Resource\ProcessedFileRepository .
Nowadays, it is obvious that some decisions in this area were not useful:
1. The coupling to Extbase's repository architecture does not work out, as the
manual database queries that return objects should not be bound to Extbase's
QueryRestrictions.
These never worked and were never implemented in the mentioned repository
classes from FAL.
It becomes abundantly clear that the concepts do not match by looking at the
AbstractRepository class which even had exceptions for methods that were
not compatible with Extbase.
2. The concept of inheritance did not work out for Dependency Injection
introduced in TYPO3 v10, and with PHP 8.x which reveals various typing problems
that arose around
AbstractRepository.
AbstractRepository is thus removed, and the implementing classes do not
extend from this class anymore, as they only include the methods required for
their purpose, and are now completely strictly typed.
Additionally,
FileRepository has been cleaned up by removing
findFileReferenceByUid() as it is only a wrapper to
ResourceFactory::getFileReferenceObject()
Impact
Code that uses the three classes in a third-party extension might fail as the
implementing PHP repositories
FileRepository and
ProcessedFileRepository have only necessary methods available.
PHP extensions that derive from the
AbstractRepository will stop working.
Code that used
FileRepository::findFileReferenceByUid() will break.
Affected installations
As all three PHP classes are low-level in the FAL API, the impact for regular
installations will be rather low. Third-party extensions that extend from the
AbstractRepository of FAL, which is a wild use-case will stop working. It is
safe to say, that only edge-case extensions that worked with the FAL API might
be affected, but regular installations will see no difference.
Migration
Only extension authors working with the low-level API of File Abstraction Layer
would need to adapt their code to be type-safe. Extensions that extend from the
AbstractRepository class of FAL should implement the necessary methods
themselves and remove the dependency from
AbstractRepository.
It is highly recommended to not use any of these classes, but rather stick
to high-level API of FAL, such as
ResourceFactory,
File
or
ResourceStorage.
Replace former calls to
FileRepository::findFileReferenceByUid() like:
GFX/processor_allowTemporaryMasksAsPng is a setting that stems from an even older
setting called im_mask_temp_ext_gif. This setting was added because generally PNG
generation of Image/GraphicsMagick is always faster than generating GIF files, but
there were issues with PNG files in earlier versions of ImageMagick 5.
TYPO3 requires newer versions of GraphicsMagick and at least ImageMagick version 6,
in which the above reported behaviours couldn't be replicated anymore, obsoleting
the need for a non-PNG setting entirely.
The following global settings have no effect anymore and are automatically removed
if still in use:
For historical reasons, there is a PHP API class
\TYPO3\CMS\Core\Imaging\GraphicalFunctions which deals with general
imaging functionality such as converting, scaling or cropping images - mainly
with ImageMagick / GraphicsMagick as a basis. In addition, the PHP class
\TYPO3\CMS\Frontend\Imaging\GifBuilder which works with instructions
originally built for use with TypoScript and image manipulation such as masking,
combining text with images based mainly on the PHP extension GDLib.
Even though TYPO3 works best having both GDLib and ImageMagick installed and
properly configured, the inter-dependency within the TYPO3 Core API when to
use what class has always been unclear - mostly because this
functionality has not been cleaned up in the past 20 years.
For this reason,
GifBuilder now contains all functionality related to
GDLib, and all related methods from GraphicalFunctions have been removed.
GraphicalFunctions thus is only contains ImageMagick/GraphicsMagick
functionality.
In addition,
GifBuilder and
GraphicalFunctions are now two separate classes
without inheritance, but utilizes the Composition pattern.
The following public methods from
GraphicalFunctions have been removed:
When using the classes directly in PHP code of extensions, calling any of the
methods or accessing / setting the affected properties will result in a PHP
error.
Affected installations
TYPO3 installations with custom extensions utilizing the PHP API of these two
classes directly.
For any usages of these classes via TypoScript or the File Abstraction Layer API
will continue to work and are not affected by this breaking change.
Migration
Use static analysis tools such as PHPStan or Psalm to detect if PHP code of
custom extensions is affected, and make use of
GifBuilder class instead of
GraphicalFunctions when needing GDLib functionality.
A cache layer called "imagesizes" was added in 2004 (= TYPO3 3.x) to cache
width and height of any kind of images - mostly generated by GifBuilder or
ImageMagick. It was using the PHP function
getimagesizes() or, if this
failed, ImageMagick identify command, which is costly.
In 2012, the new processing layer for File Abstraction Layer (FAL - via
sys_file_processedfile) was introduced with a more modern API, which persists
final information about processed images in a separate database table.
Any kind of information processing then is first checked in FAL and then stored
again in cache_imagesizes. Some more files, which do not use FAL still utilize
this functionality, but the second level cache layer (by default in the database),
is unneeded nowadays.
For this reason, the lowlevel cache "imagesizes" is removed along with some
methods which were not marked as internal, but marked public:
The main entry point
\TYPO3\CMS\Core\Imaging\GraphicalFunctions->getImageDimensions()
is still available but does not use a cache layer anymore.
Impact
Calling the removed public methods will result in a fatal PHP error. In addition,
accessing the database table directly or via TYPO3's CacheManager is not possible
anymore, as the "imagesizes" cache is removed.
Affected installations
TYPO3 installations which use the cache directly or access these methods
directly, which is very very unlikely.
Migration
The now unused database tables are automatically removed when using the database
compare update is called. When trying to retrieve image dimensions,
the
\TYPO3\CMS\Core\Type\File\Imageinfo PHP class should be used instead in
favor of the main
GraphicalFunctions method.
The removed methods should be moved also towards the
Imageinfo PHP class.
GFX/gdlib_png is a setting that adjusted rendering of temporary images
used by GDLib to be PNG files instead of GIF files.
PNG files offer many benefits over GIF files, one of them being faster
processing times using Image/GraphicsMagick.
In line with this change, the property
GraphicalFunctions::$gifExtension has
been removed, as it mainly was used by this class and
GifBuilder to determine
if a temporary PNG or GIF image should be rendered.
GFX/processor_colorspace now defaults to an empty value and is migrated to one if
you use the recommended colorspace for the given processor (sRGB for ImageMagick,
RGB for GraphicsMagick). Image processing now will pick the recommended colorspace
unless you configure it to be another one.
Additionally, all GIF assets that are now not shown anymore due to those changes have been
removed as well:
Temporary layers/masks are now saved as PNG files instead of GIF files.
Affected installations
Every instance that already didn't set gdlib_png to true. Output differences may
only occur on instances that use
GIFBUILDER functionality (see Migration
section for more information).
Migration
The configuration value has been removed without replacement. GFX/processor_colorspace is
automatically migrated to the recommended value for setups using the default configuration.
GraphicalFunctions::$gifExtension has been removed without replacement. If this has been
used to determine what type of file should be rendered using
GraphicalFunctions::imageMagickConvert,
please specify the filetype manually now.
The feature toggle
security.usePasswordPolicyForFrontendUsers has been
removed, because TypoScript-based password validation in ext:felogin has been
removed, too.
Impact
The password policy configured in
$GLOBALS['TYPO3_CONF_VARS']['FE']['passwordPolicy'] is now always active
for frontend user records in DataHandler and for the password recovery
functionality in ext:felogin.
Affected installations
Installations, where
security.usePasswordPolicyForFrontendUsers is
deactivated.
Migration
To disable the password policy for frontend users,
$GLOBALS['TYPO3_CONF_VARS']['FE']['passwordPolicy'] must be set to an
empty string. Note, that it is not recommended to disable the password policy
on production websites.
These two fields allowed to set record "sub types" based on a record
bitmask field, typically
'type' => 'check' or
'type' => 'radio'.
This has been removed, the settings are not considered anymore when
rendering records in the backend record editing interface.
Affected installations
Both settings have been used very rarely: Neither Core nor published TER extensions
revealed a single usage. The extension scanner will find affected extensions.
Migration
In case extensions still use these two rather obscure settings, they should
switch to casual
$GLOBALS['TCA']['someTable']['ctrl']['type'] fields instead,
which can be powered by columns based on string values.
Note the overall "subtype" record logic of TCA is within an ongoing process to
be removed in TYPO3 v13, so the basic thinking should be: There is a record, and its
details can be configured using
$GLOBALS['TCA']['someTable']['ctrl']['type'] ,
and that's it. Extensions using "sub types" or this bitmask detail need to simplify
and eventually deliver according upgrade wizards to adapt existing records.
'GFX/gdlib' is a setting that enables or disables image manipulation
using GDLib, functionality used in
GIFBUILDER, depending if
the host system did not provide GDLib functionality.
With this change, the configuration value 'GFX/gdlib' has been removed, and
TYPO3 will simply check for the
GdImage PHP class being available to
determine if it can be used.
Impact
TYPO3 now always enables GDLib functionality as soon as relevant GDLib classes
are found.
Migration
The configuration value has been removed without replacement.
Custom code that relied on
$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib']
should instead adopt the simpler check
if (class_exists(\GdImage::class)).
The TYPO3 configuration option
$GLOBALS['TYPO3_CONF_VARS']['BE']['flexformForceCDATA']
has been removed without substitution.
This setting was an ancient workaround for an issue in libxml in old PHP versions that has
been resolved long ago.
This was the last usage of
useCDATA option in FlexForm-related XML methods in
the Core, so that option is removed along the way. Values of XML data should still be
encoded properly when dealing with related methods like
GeneralUtility::array2xml().
Impact
There should be no impact on casual instances, except if single extensions tamper with
the
useCDATA options when dealing with XML data.
Affected installations
Instances with extensions that explicitly call XML-related transformations methods
provided by the Core that tamper with
useCDATA may need a look. Chances are
everything is ok, though.
Migration
No direct migration possible.
Breaking: #102151 - XML prologue always added in flexArray2Xml()
The second argument
$addPrologue = false on
\TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools->flexArray2Xml()
has been dropped: When imploding a FlexForm array to an XML string using
this method, the "XML prologue" is always added.
Impact
This should have no impact for consumers of this method. The counterpart method
\TYPO3\CMS\Core\Utility\GeneralUtility::xml2array() happily deals with this.
Affected installations
Instances with extensions using
FlexFormTools->flexArray2Xml() can drop
the second argument. The extension scanner will find usages with a weak match.
Since this is a detail method of the TYPO3 Core FlexForm handling, not often
handled by extensions themselves, few instances will be affected in the first place.
Migration
No data migration needed, PHP consumers should drop the second argument
when calling the method.
The Task API for processing files (mainly images) in the File Abstraction Layer
(FAL) has been reworked. This mainly accommodates to the fact, that the API was
revisited, the functionality has been updated to be up-to-date with PHP
standards and further adaptions.
The PHP interface
\TYPO3\CMS\Core\Resource\Processing\TaskInterface has
lost the
__construct() method as part of the interface, as the
constructor is an implementation detail and should not be part of an interface
definition. In addition, the method
sanitizeConfiguration() has been added
to clean and sort the properties required for a task. All other methods have
been fully typed.
The PHP class
\TYPO3\CMS\Core\Resource\Processing\AbstractGraphicalTask
has been removed in order to reduce complexity, as all of the methods have
been moved into the respective subclasses.
The PHP class
\TYPO3\CMS\Core\Resource\Processing\Task now has two
abstract methods
getName() and
getType() in favor of the protected
properties
$name and
$type.
The PHP class
\TYPO3\CMS\Core\Resource\ProcessedFile is now fully typed.
Impact
Custom FAL processing tasks will result in a fatal error if not adapted to the
new interface.
If an extension was depending on
AbstractGraphicalTask, calling this
code will now result in a PHP fatal error.
Affected installations
TYPO3 installations working with the internals of the processing part of the
File Abstraction Layer, e.g. when extensions add custom FAL processors or
custom tasks.
Migration
Implementing a custom FAL processing task will require the extension author to
adapt to the new interface requirements.
When a custom task was built on top of the
AbstractGraphicalTask, this
now needs to be removed and be compliant with the
TaskInterface, optionally
inheriting from the
AbstractTask class. This can already be achieved for
TYPO3 v12 to make an implementation compatible with TYPO3 v12 and TYPO3 v13.
Breaking: #102181 - Removed CLI options using bin/typo3 cleanup:flexforms
The CLI command
bin/typo3 cleanup:flexforms of extension
lowlevel
can be used to clean up database record
type="flex" fields that contain values
not reflected in the current FlexForm data structure anymore.
The command has been changed slightly: The CLI options
-p /
--pid
and
-d /
--depth have been removed.
The "dry run" CLI option
--dry-run is kept.
The command implementation has been rewritten in TYPO3 v13 and is some orders
of magnitudes quicker than before: While the command could easily run hours for
a seasoned instance, it is now usually a matter of seconds. The "pid" and
"depth" options were a hindrance to this drastic performance improvement and
have been removed.
Impact
The command exits with an error when called with one of
-p,
--pid,
-d or
--depth option. It is no longer possible to restrict the
command to single page tree sections, the command always checks all (not soft-deleted)
records.
Affected installations
The command is not very well known and - if ever - often only used when deploying
major upgrades of TYPO3 instances. Instances using one of the above options should
remove them from their deployment scripts, and enjoy the massive speed improvement.
Migration
No migration, remove the above mentioned options.
Breaking: #102224 - TemplaVoila related FlexForm dataStructure lookups
When dealing with TCA type
flex fields, there needs to be a "data structure" that
defines which fields are rendered when editing the record. The default is looking up
the data structure using the
['ds']['default'] value.
Multiple different data structures can be defined, so there is a strategy to find the
data structure relevant for current record. For table
tt_content, this is
defined using
ds_pointerField, which determines the specific data structure based
on the combination of the fields
CType and
list_type.
There have been more sophisticated lookup mechanisms based on the TCA config options
ds_pointerField_searchParent,
ds_pointerField_searchParent_subField
and
ds_tableField. Those lookup mechanisms have been removed with TYPO3 v13.
Affected installations
Instances with extensions having
flex fields using one of the TCA options
ds_pointerField_searchParent,
ds_pointerField_searchParent_subField
or
ds_tableField will fail to retrieve their data structure. Most likely,
an exception will be thrown when editing such records.
Those three fields have been implemented long ago for heavily flex form driven
instances based on "TemplaVoila" (TV). This detail never found broader acceptance in
not-TV driven instances.
Instances not driven by one of the TemplaVoila forks are most likely not affected
by this change. Instances actively using TemplaVoila forks may be affected, but
those forks seem to implement the data structure lookup on their own already,
affected instances should wait for their templavoila maintainers to catch up.
Migration
There are appropriate events that allow manipulating the data structure
lookup logic in class
\TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools .
Those can be used to re-implement the logic that has been removed from TYPO3
Core if needed.
Class
\TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools got a series
of cleanup and removal patches.
The following public class properties have been removed:
$reNumberIndexesOfSectionData
$flexArray2Xml_options
$callBackObj
$cleanFlexFormXML
The following public methods have been removed:
traverseFlexFormXMLData()
traverseFlexFormXMLData_recurse()
cleanFlexFormXML_callBackFunction()
The following public methods have been marked @internal:
cleanFlexFormXML()
flexArray2Xml()
migrateFlexFormTcaRecursive()
The class is now a stateless service and can be injected as shared service
without any risk of triggering side effects.
Impact
In general, these changes should have relatively low impact on extensions, if they
don't build additional low level functionality on top of the general TYPO3 Core
FlexForm related features. Extensions like the TemplaVoila forks may need to have
a look for required adaptions, though.
Using the removed methods or properties in TYPO3 v13 will of course trigger PHP
fatal errors.
Affected installations
Instances that extend functionality of FlexForm handling may be affected if they
use methods of class
FlexFormTools. This is a relatively rare case, most
instances will not be affected when they just provide and use casual FlexForm
definitions in extensions.
The extension scanner will find possible extensions that consume the methods or
properties as a weak match.
Migration
If at all, method
traverseFlexFormXMLData() is probably the one used in
extensions. The easiest way is to copy the method and it's recursive worker method
to an own class.
Extension developers are however encouraged to refactor their code since
traverseFlexFormXMLData() with its callback logic was ugly, hard to follow
and maintain. The Core switched away from the method by implementing own traversers
that match the specific use cases. Method
cleanFlexFormXML() is an
example of such an implementation. Note FlexForms are not recursive since
section containers can not be nested since TYPO3 v8 anymore. The Core thus
uses some nested foreach loops instead of a recursive approach.
TCA columns type fields like
input and
text obey the
config key
softref. One of the allowed soft reference parsers is
notify implemented
by class
\TYPO3\CMS\Core\DataHandling\SoftReference\NotifySoftReferenceParser.
This soft reference parser fits no apparent use case and has been removed.
Impact
Involving the
notify key in the comma-separated list of TCA columns config
softref or a flex form data structure column definition does not trigger
any action anymore and may log a warning this parser hasn't been found.
Affected installations
There was little reason to activate this soft reference parser in the first place
since it essentially did nothing. Instances with extensions having TCA column config
softref set to a value including
notify will be affected. That's a very
rare use case. The extension scanner will not notify about this, but the
SoftReferenceParserFactory will add a log entry this parser was not found upon
using an affected record.
Migration
Remove key
notify from TCA columns
softref list.
Breaking: #102440 - EXT:t3editor merged into EXT:backend
TYPO3 comes with a code editor extension called "t3editor" for a long time.
Since then, the extension was always optional. When the extension is installed,
selected text areas are converted to code editors based on CodeMirror.
The optional extension has been merged into EXT:backend, making the code
editor always available.
Impact
An integrator cannot optionally install the code editor anymore as it's part of
the mandatory "backend" extension now.
By default, this affects the following occurrences:
TCA: be_groups.TSconfig
TCA: be_users.TSconfig
TCA: pages.TSconfig
TCA: sys_template.constants
TCA: sys_template.config
TCA: tt_content.bodytext, if the content element is of type "HTML"
EXT:filelist: edit file content
Composer status view in Extension Manager
Also, checks whether the extension is installed via
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('t3editor')
are now obsolete.
Affected installations
All installations are affected.
Migration
Extension checks using
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('t3editor')
don't have an effect anymore and must get removed.
The user TSconfig setting
options.overridePageModule has been
removed.
This option allowed to change links within some modules to be redirected to an
alternative page module, mainly introduced in TYPO3 4.x to allow to link to
the TemplaVoila page module.
However, as this has never been applied consistently across all modules
provided by TYPO3 Core, it has been removed. The only few places within TYPO3
Core where this option was still evaluated was within the Workspaces
Administration and the Info module.
The alternative, using a different routing endpoint and support for module
aliases via the introduced Module API in TYPO3 v12, is much more robust and
consistent.
Impact
Setting the user TSconfig option
options.overridePageModule has
no effect anymore.
Affected installations
TYPO3 installations using this setting in user TSconfig, mainly when used in
conjunction with TemplaVoila and having mixed installations where both
TemplaVoila page module and the default Page module are used for different
editors.
Migration
In order to replace the Page module within a third-party extension such as
TemplaVoila, it is possible to create a custom module entry in an
extensions' Configuration/Backend/Modules.php with the following entry:
TYPO3 v13 supports these database products and versions:
MySQL 8.0.17 or higher
MariaDB 10.4.3 or higher
PostgresSQL 10.0 or higher
SQLite 3.8.3 or higher
Impact
Environments with older MariaDB or MySQL database engines will report an unsupported
database version and stop working properly with the upcoming Doctrine DBAL v4 upgrade.
Affected installations
Hosting a TYPO3 instance based on version 13 may require an update of the MariaDB or
MySQL database engine.
Migration
TYPO3 v12 supports MariaDB 10.4.3 or MySQL 8.0.17 and higher database engines required by v13.
This allows upgrading the platform in a first step and upgrading to TYPO3 v13 in a second step.
Breaking: #102581 - Removed hook for manipulating ContentObjectRenderer
The hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['postInit']
has been removed in favor of the new PSR-14 event
\TYPO3\CMS\Frontend\ContentObject\Event\AfterContentObjectRendererInitializedEvent .
Impact
Any hook implementation registered is not executed anymore
in TYPO3 v13+.
Affected installations
TYPO3 installations with custom extensions using this hook.
Migration
The hook is removed without deprecation in order to allow extensions
to work with TYPO3 v12 (using the hook) and v13+ (using the new event)
when implementing the event as well without any further deprecations.
Use the PSR-14 event
to allow greater influence in the functionality.
The
\TYPO3\CMS\Core\Context\Context aspect
typoscript has been
removed without direct substitution. This aspect was implemented by now removed
class
\TYPO3\CMS\Core\Context\TypoScriptAspect, handling the
EXT:adminpanel-related property
forcedTemplateParsing.
Frontend-related method
TypoScriptFrontendController->generatePage_preProcessing()
has been removed without substitution.
Impact
Calling the methods will raise a fatal PHP error.
Affected installations
There is little to no need for extensions to call or override this method and it
should have been marked as
@internal already. It was part of a removed
"safety net" when extensions did set
TypoScriptFrontendController->no_cache
to
false after it has been set to
true already, which is not allowed.
Frontend-related property
TypoScriptFrontendController->applicationData
has been removed without substitution.
This property has been used by a few rather old-school extensions to park and
communicate state using this global "extension-specific state array".
When looking at the TYPO3 frontend rendering chain, class
TypoScriptFrontendController
is by far the biggest technical debt: It mixes a lot of concerns and carries tons of state
and functionality that should be modeled differently, which leads to easier to understand
and more flexible code. The class is shrinking since various major versions already and will
ultimately dissolve entirely at some point. Changes in this area are becoming more aggressive
with TYPO3 v13. Any code using the class will need adaptions at some point, single patches
will continue to communicate alternatives.
In case of the
applicationData property, this is simply a misuse of the
class instance to park arbitrary state in a global object. This is why it needs to
fall and why there is no direct substitution.
Impact
Using
TypoScriptFrontendController->applicationData (or
$GLOBALS['TSFE']->applicationData ) will raise a PHP fatal error.
Affected installations
Instances with extensions that use
applicationData to store and communicate
state.
Migration
There are various solutions to communicate state to avoid
applicationData:
In some cases, an extension could establish a frontend middleware and attach a
request attribute that carries the state.
In other cases an event could be fired to gather information from other extensions.
One example is the indexed_search extension which dispatches the new event
EnableIndexingEvent to get know if indexing should be performed. The
third-party crawler extension should use this instead of setting that information
on
$GLOBALS['TSFE'] .
Frontend-related property
TypoScriptFrontendController->fe_user has been removed.
When looking at the TYPO3 frontend rendering chain, class
TypoScriptFrontendController
is by far the biggest technical debt: It mixes a lot of concerns and carries tons of state
and functionality that should be modeled differently, which leads to easier to understand
and more flexible code. The class is shrinking since various major versions already and will
ultimately dissolve entirely at some point. Changes in this area are becoming more aggressive
with TYPO3 v13. Any code using the class will need adaptions at some point, single patches
will continue to communicate alternatives.
In case of the
fe_user property, two alternatives exist: The frontend user
can be retrieved from the PSR-7 request attribute
frontend.user, and basic frontend user
information is available using the
Context aspect
frontend.user.
Note accessing TypoScript
TSFE:fe_user details continues to work for now, using
for example
lib.foo.data = TSFE:fe_user|user|username to retrieve the username of a
logged in user is still ok.
Impact
Using
TypoScriptFrontendController->fe_user (or
$GLOBALS['TSFE']->fe_user ) will raise a PHP fatal error.
Affected installations
Instances with extensions dealing with frontend user details may be affected, typically
custom login extensions or extensions consuming detail data of logged in users.
Migration
There are two possible migrations.
First, a limited information list of frontend user details can be retrieved using the
Context
aspect
frontend.user in frontend calls. See class
\TYPO3\CMS\Core\Context\UserAspect for a
full list. The current context can retrieved using dependency injection. Example:
Additionally, the full
\TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication object is
available as request attribute
frontend.user in the frontend. Note some details of that object
are marked
@internal, using the context aspect is thus the preferred way. Example of an extension
using Extbase's
ActionController:
finalclassMyExtensionControllerextendsActionController{
publicfunctionmyAction(){
// Note the 'user' property is marked @internal.
$frontendUserUsername = $this->request->getAttribute('frontend.user')->user['username'];
}
}
Copied!
Breaking: #102614 - Removed Hook for manipulating GetData result
The hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getData']
has been removed in favor of the new PSR-14 event
\TYPO3\CMS\Frontend\ContentObject\Event\AfterGetDataResolvedEvent .
Impact
Any hook implementation registered is not executed anymore
in TYPO3 v13.0+.
Affected installations
TYPO3 installations with custom extensions using this hook.
Migration
The hook is removed without deprecation in order to allow extensions
to work with TYPO3 v12 (using the hook) and v13+ (using the new event)
when implementing the event as well without any further deprecations.
Use the PSR-14 event
to allow greater influence in the functionality.
Note
The new event is no longer executed for every "section" of the provided
parameter string, but only once, before the final result of
getData()
is about to be returned. This therefore means, the former
$secVal
is no longer available in the new event. Please adjust your implementation
accordingly.
Breaking: #102621 - Most TSFE members marked internal or read-only
Most properties and methods of class
TypoScriptFrontendController have
been marked
@internal or "read-only".
TypoScriptFrontendController ("TSFE") is a god object within the TYPO3 frontend
rendering chain: It is used by multiple middlewares that call TSFE methods to create
state in it, it is used within
ContentObjectRenderer and various other
classes to update and retrieve state. It is also registered as
$GLOBALS['TSFE']
at some point and thus available as global state object.
This makes the class the biggest anti-pattern we have within the frontend - class
ContentObjectRenderer is problematic as well, but that is a different story.
The current role of
TypoScriptFrontendController leads to very complex and
opaque state handling within the frontend rendering, is the true source of many
hard to fix issues and prevents Core development from implementing cool new features.
The TYPO3 Core strives to resolve large parts of this with TYPO3 v13: State needed
by lower level code is being modeled as request attributes or handled locally in
middlewares, methods are moved out of the class into middlewares to improve
encapsulation and code flow.
To do that within continued TYPO3 v13 development, the Core needs to mark various
methods and properties
@internal, and needs to mark more strict access patterns
on others.
The solution is to look at public properties of
TypoScriptFrontendController,
and to declare those as
@internal, which extensions typically should not need to
deal with at all. Others (like for instance
id) are actively used by extensions and
will be substituted by something different later, and are thus marked as "allowed to read,
but never write" for extensions. This allows implementation of a deprecation layer for those
"read-only" properties later, while those marked
@internal can vanish without
further notice. A similar strategy is added for methods, leaving only a few not
marked
@internal, which the Core will deprecate with a compatibility layer later.
TypoScriptFrontendController->id - Use
$request->getAttribute('frontend.page.information')->getId() instead
TypoScriptFrontendController->rootLine - Use
$request->getAttribute('frontend.page.information')->getRootLine() instead
TypoScriptFrontendController->page - Use
$request->getAttribute('frontend.page.information')->getPageRecord() instead
TypoScriptFrontendController->contentPid - Avoid usages altogether, available as
@internal call using
$request->getAttribute('frontend.page.information')->getContentFromPid()
TypoScriptFrontendController->sys_page - Avoid altogether, create own instance using
GeneralUtility::makeInstance(PageRepository::class)
TypoScriptFrontendController->config - Use
$request->getAttribute('frontend.typoscript')->getConfigArray() instead of
config['config']
TypoScriptFrontendController->cObj - Create an own
ContentObjectRenderer instance, call
setRequest($request)
and
start($request->getAttribute('frontend.page.information')->getPageRecord(), 'pages')
TypoScriptFrontendController->config['rootLine'] - Use
$request->getAttribute('frontend.page.information')->getLocalRootLine() instead
The following public class properties have been marked
@internal - in general
all properties not listed above. They contain information usually not relevant within
extensions. The TYPO3 core will model them differently.
TypoScriptFrontendController->absRefPrefix
TypoScriptFrontendController->no_cache - Use request attribute
frontend.cache.instruction instead
TypoScriptFrontendController->set_no_cache() - Use
$request->getAttribute('frontend.cache.instruction')->disableCache() instead
TypoScriptFrontendController->sL() - Use
GeneralUtility::makeInstance(LanguageServiceFactory::class)->createFromSiteLanguage($request->getAttribute('language'))->sL()` instead
TypoScriptFrontendController->get_cache_timeout()
TypoScriptFrontendController->getRequestedId() - Use
$request->getAttribute('routing')->getPageId() instead
TypoScriptFrontendController->getLanguage() - Use
$request->getAttribute('site')->getDefaultLanguage() instead
TypoScriptFrontendController->getSite() - Use
$request->getAttribute('site') instead
TypoScriptFrontendController->getContext() - Use dependency injection or
GeneralUtility::makeInstance() instead
TypoScriptFrontendController->getPageArguments() - Use
$request->getAttribute('routing') instead
Impact
Writing to the listed read-only properties may break the frontend rendering,
using the properties or methods marked as
@internal may raise fatal PHP errors.
Affected installations
The majority of extensions should already use the above properties that are marked read-only
for reading only: Updating their state can easily lead to unexpected behavior. Most
extensions also don't consume the properties or methods marked as
@internal.
Extension developers should watch out for usages of
TypoScriptFrontendController in
general and reduce usages as much as possible.
Migration
The migration strategy depends on the specific use case. The frontend rendering chain
continues to add state that is needed by extensions as PSR-7 request attributes. Debugging
the incoming request within an extension often reveals a proper alternative.
Breaking: #102624 - PSR-14 Event for modifying image source collection
The hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImageSourceCollection']
has been removed in favor of the new PSR-14 event
\TYPO3\CMS\Frontend\ContentObject\Event\ModifyImageSourceCollectionEvent .
Impact
Any hook implementation registered is not executed anymore
in TYPO3 v13.0+.
Affected installations
TYPO3 installations with custom extensions using this hook.
Migration
The hook is removed without deprecation in order to allow extensions
to work with TYPO3 v12 (using the hook) and v13+ (using the new event)
when implementing the event as well without any further deprecations.
Use the PSR-14 event
to allow greater influence in the functionality.
Breaking: #102627 - Removed special properties of page arrays in PageRepository
When requesting a page with a translation, the following special properties of
an overlaid page have been removed:
_PAGES_OVERLAY_UID: The property denounced the UID of the overlaid
database record entry, keeping "uid" as the original uid field.
_PAGES_OVERLAY: A boolean flag being set to true if a page was actually
overlaid with a found record.
_PAGES_OVERLAY_LANGUAGE: The value of the database record's
"sys_language" field value (the "language ID" of the overlaid record)
_PAGES_OVERLAY_REQUESTEDLANGUAGE: A special property used to set the
actual requested language when having multi-level fallbacks while overlaying a
record. When a requested overlay of language=5 is not available, but its
fallback to language=2 is available, this property is set to "5" even though
the page records' "sys_language_uid" field is set to 2.
These special properties have been relevant especially when generating menus,
or when fetching overlays for Extbase domain models, and have been used due
to historical reasons, because translations of pages have been set in
"pages_language_overlay" instead of the database table "pages" until TYPO3 v9.0.
Any other record, where translations have been stored in the database,
received the special property "_LOCALIZED_UID".
Impact
When calling
PageRepository->getPage() or
PageRepository->getLanguageOverlay() these special page-related
properties are not set anymore when overlaying a page.
Affected installations
TYPO3 installations with custom extensions working on the low-level API
using these properties.
Migration
The value of the previous
_PAGES_OVERLAY_UID property is now available
in
_LOCALIZED_UID making it consistent with all database record overlays
across the system.
The property
_PAGES_OVERLAY is removed in favor of a
isset($page['_LOCALIZED_UID') check instead.
The property
_PAGES_OVERLAY_LANGUAGE is removed in favor of the property
$page['sys_language_uid'] which holds the same value.
The property
_PAGES_OVERLAY_REQUESTEDLANGUAGE is moved to a new property
called
_REQUESTED_OVERLAY_LANGUAGE which is available now for any kind
of overlaid record, and not just pages.
All properties, except the
$view property, in
\TYPO3\CMS\Extbase\Mvc\Controller\ActionController are now strictly typed.
In addition, all function arguments and function return types are now strictly
typed.
Also, the properties in the
\TYPO3\CMS\Extbase\Annotation\Annotation
namespace now have native PHP types for their properties.
In summary, the following classes have received strict types:
Classes extending the changed classes must now ensure that overwritten
properties and methods are all are strictly typed.
Affected installations
Custom classes extending the changed classes.
Migration
Ensure classes that extend the changed classes use strict types for overwritten
properties, function arguments and return types.
Extensions supporting multiple TYPO3 versions (for example, v12 and v13) must not
overwrite properties of the changed classes.
Instead, it is recommended to set values of overwritten properties in the
constructor of the extending class.
Before
<?phpnamespaceMyVendor\MyExtension\Controller;
useTYPO3\CMS\Extbase\Mvc\Controller\ActionController;
classMyControllerextendsActionController{
public string $errorMethodName = 'myAction';
}
Class
\TYPO3\CMS\Core\Context\Context is a stateful singleton class set up
pretty early by the frontend or backend application after the request object has been created.
Its state is then further changed by various frontend and backend middlewares. It can
be retrieved using dependency injection or
GeneralUtility::makeInstance() in consuming
classes.
To clean up Context-related code a bit, the following changes have been made:
Method
__construct() removed from
\TYPO3\CMS\Core\Context\Context
Class
\TYPO3\CMS\Core\Context\ContextAwareInterface removed
Handing over manual arguments to the constructor of
__construct() does not have
an effect anymore, and using the interface or the trait will raise a fatal PHP error.
Affected installations
Most likely, not too many instances are affected: An instance of
Context is
typically created by Core bootstrap and retrieved using dependency injection, extensions
usually do not need to create own instances.
There are also not many routing aspects with context dependencies that may use the
interface or the trait. If so, they can adapt easily and stay compatible with older
versions.
Migration
The constructor of the Context class was bogus. Since the class is an injectable singleton
that should be available through the container, it must not have manual constructor arguments
since this would shut down the container registration. Extensions typically did not create
own instances of
Context, using the constructor argument was - if at all - only done
in tests. Unit tests should typically create own instances using
new and hand them
over to classes that get the context injected.
Adaption to the interface and trait removal is straight forward as well: Get the
context injected into the aspect, or retrieve the instance using
GeneralUtility::makeInstance().
Breaking: #102715 - Frontend "determineId()" related events changed
The three events no longer retrieve an instance of
TypoScriptFrontendController, the
getter methods
getController() have been removed: The controller is instantiated
after the events have been dispatched, event listeners can no longer work with this
object.
Instead, the events now contain an instance of the new :abbr:DTO (Data Transfer Object)
:php:TYPO3CMSFrontendPagePageInformation`, which can be retrieved and
manipulated by event listeners if necessary.
Impact
Calling
getController() by consumers of above events will raise a fatal
PHP error.
Also note the events may not be dispatched anymore when the middleware
\TYPO3\CMS\Frontend\Middleware\TypoScriptFrontendInitialization creates
early responses.
Affected installations
Those events are in place for a couple of special cases during early frontend rendering.
Most instances will not be affected, but some extensions may register event listeners.
Migration
Use method
getPageInformation() instead to retrieve calculated page state at
this point in the frontend rendering chain. Event listeners that manipulate that
object should set it again within the event using
setPageInformation().
In case middleware
TypoScriptFrontendInitialization no longer dispatches an event
when it created an early response on its own, an own middleware can be added around
that middleware to retrieve and further manipulate a response if needed.
Breaking: #102731 - Removed TypoScript setting showForgotPasswordLink in ext:felogin
The
showForgotPasswordLink setting in ext:felogin has never been used in
default Fluid templates and was only been kept for backward compatibility
reasons. The setting has been deprecated with forge#98122, but it has been forgotten
to be removed in TYPO3 v12.
Impact
The
showForgotPasswordLink setting has been removed from default
TypoScript.
Affected installations
Instances using
showForgotPasswordLink setting in Fluid templates.
Migration
Use
showForgotPassword instead of
showForgotPasswordLink, which is
available since TYPO3 v11.
The ContentObject stdWrap hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['stdWrap']
has been removed in favor of the more powerful PSR-14 events:
Any hook implementation registered is not executed anymore
in TYPO3 v13.0+. The extension scanner will report usages.
Affected installations
TYPO3 installations with custom extensions using the hook.
Migration
The hook is removed without deprecation in order to allow extensions
to work with TYPO3 v12 (using the hook) and v13+ (using the new events)
when implementing the events as well without any further deprecations.
Use the PSR-14 events
to allow greater influence in the functionality.
The hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImgResource']
has been removed in favor of the new PSR-14 event
\TYPO3\CMS\Frontend\ContentObject\Event\AfterImageResourceResolvedEvent .
The new event is using the new
\TYPO3\CMS\Core\Imaging\ImageResource DTO,
which allows an improved API as developers do no longer have to deal with
unnamed array keys but benefit from the object-oriented approach, using
corresponding getter and setter. Therefore, the return types of the following
methods have been changed to
?ImageResource:
Any registered hook implementation is not executed anymore
in TYPO3 v13.0+.
Calling the mentioned methods do now return either
null or an instance
of the
ImageResource DTO.
The new Event is also using the new DTO instead of an array.
Affected Installations
TYPO3 installations with custom extensions using this hook or calling
mentioned methods directly.
Migration
The hook is removed without deprecation in order to allow extensions
to work with TYPO3 v12 (using the hook) and v13+ (using the new event)
when implementing the event as well without any further deprecations.
Use the PSR-14 event
to allow greater influence in the functionality.
Additionally, adjust your code to handle the new return types appropriately.
Breaking: #102763 - Extbase HashService usage replaced with Core HashService
All usages of the
@internal class
\TYPO3\CMS\Extbase\Security\Cryptography\HashService in TYPO3 have been
removed and replaced by
\TYPO3\CMS\Core\Crypto\HashService .
Impact
Custom extensions expecting
\TYPO3\CMS\Extbase\Security\Cryptography\HashService
as type of the property
'$hashService of various
@internal classes
will result in a PHP Fatal error.
Affected installations
TYPO3 installations with custom extensions using one of the following:
Property
$hashService of
\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper
@internal property
$hashService of class
\TYPO3\CMS\Extbase\Mvc\Controller\ActionController
Property
$hashService of
internal class
\TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfigurationService
Property
$hashService of
internal class
\TYPO3\CMS\FrontendLogin\Configuration\RecoveryConfiguration
Property
$hashService of
internal class
\TYPO3\CMS\FrontendLogin\Configuration\RecoveryConfiguration
Property
$hashService of
internal class
\TYPO3\CMS\FrontendLogin\Controller\PasswordRecoveryController
Property
$hashService of
internal class
\TYPO3\CMS\Form\Domain\Runtime\FormRuntime
Property
$hashService of
internal class
\TYPO3\CMS\Form\Mvc\Property\TypeConverter\UploadedFileReferenceConverter
Migration
Custom extensions must be adapted to use methods of class
\TYPO3\CMS\Core\Crypto\HashService .
Breaking: #102763 - Frontend user password recovery hashes invalidated
The replacement of deprecated class
\TYPO3\CMS\Extbase\Security\Cryptography\HashService results in existing
password recovery hashes of frontend users being invalid.
Impact
A frontend user with a valid and unexpired password recovery link created with
a TYPO3 version < 13 can not use the password recovery link to reset the
password.
These hashes have a limited lifetime already (12 hours). On large installations
that require hashes to survive a major update, you could write a small CLI task
that re-adds missing hashes created in the maintenance time window of the upgrade.
Affected installations
TYPO3 installations which use the "Display Password Recovery Link" option of
ext:fe_login.
Migration
Frontend users need to request a new password recovery link to reset the
password.
Breaking: #102775 - PageRepository methods with native PHP types
Various methods in of the main TYPO3 Core classes
\TYPO3\CMS\Core\Domain\Repository\PageRepository
now have native PHP types in their method signature, requiring the caller code
to use exactly the required PHP types for the corresponding method arguments.
The following methods are affected:
PageRepository->getPage()
PageRepository->getPage_noCheck()
PageRepository->getPageOverlay()
PageRepository->getPagesOverlay()
PageRepository->checkRecord()
PageRepository->getRawRecord()
PageRepository->enableFields()
PageRepository->getMultipleGroupsWhereClause()
PageRepository->versionOL()
Impact
Calling the affected methods now requires the passed arguments to be
of the specified PHP type. Otherwise a PHP TypeError is triggered.
Affected installations
TYPO3 installations with third-party extensions utilizing the
PageRepository PHP class.
Migration
Extension authors need to adapt their PHP code to use ensure passed
arguments are of the required PHP type when calling corresponding methods
of the
PageRepository PHP class. Using proper type casts would is
a possible migration strategy.
The minimum PHP version required to run TYPO3 version v13 has been defined as 8.2.
TYPO3 v13 supports these database products and versions:
MySQL 8.0.17 or higher
MariaDB 10.4.3 or higher
PostgresSQL 10.0 or higher
SQLite 3.8.3 or higher
Impact
The TYPO3 Core codebase and extensions tailored for v13 and above can use
features implemented with PHP up to and including 8.2. Running TYPO3 v13 with
older PHP versions or database engines will trigger fatal errors.
Affected installations
Hosting a TYPO3 instance based on version 13 may require an update of the
PHP platform and the database engine.
Migration
TYPO3 v11 / v12 supports PHP 8.2 and database engines required by v13. This
allows upgrading the platform in a first step and upgrading to TYPO3 v13 in a
second step.
One of the common PHP APIs used in TYPO3 Core for fetching records is
\TYPO3\CMS\Core\Domain\Repository\PageRepository . The method
enableFields() is marked as deprecated, and the according hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['addEnableColumns']
has been removed.
Impact
Hook listeners will not be executed anymore.
Affected installations
TYPO3 installations with custom extensions using the mentioned hook.
Migration
The hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['addEnableColumns']
can be replaced by a listener to the newly introduced
PSR-14 event.
Breaking: #102806 - Hooks in PageRepository removed
Later hook has been replaced by the new PSR-14 event
\TYPO3\CMS\Core\Domain\Event\BeforePageIsRetrievedEvent .
Impact
Any hook implementation registered is not executed anymore in TYPO3 v13.0+.
Affected installations
TYPO3 installations with custom extensions using these hooks.
Migration
The hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][\TYPO3\CMS\Core\Domain\PageRepository::class]['init']
is removed without substitution. Back in TYPO3 v4.x this hook was useful to modify
public properties after everything was initialized. Nowadays, this is not
necessary anymore, as the properties are not public anymore and calculated
based on the Context API when instantiated.
The hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPage']
is removed without deprecation in order to allow extensions to work with TYPO3
v12 (using the hook) and v13+ (using the new Event) when implementing the event
as well without any further deprecations. Use the
PSR-14 event
to allow greater influence in the functionality.
Breaking: #102834 - Remove items from New Content Element Wizard
The configuration of the New Content Element Wizard has been
improved
by automatically registering the groups and elements from the TCA configuration.
The previously used option to show / hide elements
mod.wizards.newContentElement.wizardItems.<group>.show is
therefore not evaluated anymore.
All configured groups and elements are automatically shown. Removing these
groups and elements from the New Content Element Wizard has to be done via
the new
mod.wizards.newContentElement.wizardItems.removeItems and
mod.wizards.newContentElement.wizardItems.<group>.removeItems
options.
Impact
Using the page TSconfig option
mod.wizards.newContentElement.wizardItems.<group>.show
to show / hide elements is not evaluated anymore.
Affected installations
TYPO3 installations with custom extensions using the page TSconfig
option
mod.wizards.newContentElement.wizardItems.<group>.show to
show / hide elements in the New Content Element Wizard.
Migration
To hide elements, migrate your page TSconfig from
mod.wizards.newContentElement.wizardItems.<group>.show := removeFromList(html) to
mod.wizards.newContentElement.wizardItems.<group>.removeItems := addToList(html).
Breaking: #102835 - Strict typing in final TypoLinkCodecService
The
\TYPO3\CMS\Core\LinkHandling\TypoLinkCodecService , used to encode
and decode TypoLinks, has been declared readonly and set final.
Additionally, the class does now use strict typing and the
decode()
method's first parameter
$typoLink is now a type hinted
string.
This has been done in combination with the introduction of the two new PSR-14
events
BeforeTypoLinkEncodedEvent and
AfterTypoLinkDecodedEvent,
which allow to fully influence the encode and decode functionality, making
any cross classing superfluous.
Impact
Extending / cross classing
TypoLinkCodecService does no longer work
and will lead to PHP errors.
Calling
decode() with the first parameter
$typolink being not
a
string will lead to a PHP TypeError.
Affected installations
All installations extending / cross classing
TypoLinkCodecService or
calling
decode() with the first parameter
$typolink not being
a
string.
Migration
Instead of extending / cross classing
TypoLinkCodecService use the
new PSR-14 events
to modify the functionality.
Ensure to always provide a
string as first parameter
$typolink,
when calling
decode() in your extension code.
The hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['stdWrap_cacheStore']
has been removed in favor of the new PSR-14 event
\TYPO3\CMS\Frontend\ContentObject\Event\BeforeStdWrapContentStoredInCacheEvent .
Impact
Any hook implementation registered is not executed anymore
in TYPO3 v13.0+.
Affected installations
TYPO3 installations with custom extensions using this hook.
Migration
The hook is removed without deprecation in order to allow extensions
to work with TYPO3 v12 (using the hook) and v13+ (using the new event)
when implementing the event as well without any further deprecations.
Use the PSR-14 event
to allow greater influence in the functionality.
The hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['Link']['resolveByStringRepresentation']
has been removed in favor of the new PSR-14 event
\TYPO3\CMS\Core\LinkHandling\Event\AfterLinkResolvedByStringRepresentationEvent
event.
Impact
Any hook implementation registered is not executed anymore
in TYPO3 v13.0+.
Affected installations
TYPO3 installations with custom extensions using this hook.
Migration
The hook is removed without deprecation in order to allow extensions
to work with TYPO3 v12 (using the hook) and v13+ (using the new event)
when implementing the event as well without any further deprecations.
Use the PSR-14 event
to allow greater influence in the functionality.
Breaking: #102875 - Changed Connection method signatures and behaviour
Signature and behaviour of following methods has been changed:
lastInsertId() no longer accepts the sequence and field name.
quote() no longer has a type argument and the value must be a string.
Public
Connection::PARAM_* class constants has been replaced with the
Doctrine DBAL 4
ParameterType and
ArrayParameterType enum definitions.
Note
Doctrine DBAL dropped the support for using the
\PDO::PARAM_* constants in
favour of the enum types on several methods. Be aware of this and use the
\TYPO3\CMS\Core\Database\Connection::PARAM_* constants to reduce
required work on upgrading.
Impact
Calling
quote() with a non-string as first argument will result in a
PHP error. Still providing the second argument will not emit an error, but
may be detected by static code analysers.
Calling
lastInsertId() not directly after the record insert or inserting
records in another table in between will return the incorrect value.
Affected installations
Only installations calling
quote() with a non-string as first argument
or not using
lastInsertId() directly after the record insert.
Migration
lastInsertId()
Returns the last inserted ID (auto-created) on the connection.
Note
That means, that the last inserted id needs to be retrieved directly before
inserting a record to another table. That should be the usual workflow used
in the wild - but be aware of this.
useDoctrine\DBAL\Platforms\TrimMode;
useTYPO3\CMS\Core\Database\ConnectionuseTYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder;
// before
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('tt_content');
$queryBuilder->expr()->comparison(
$queryBuilder->expr()->trim($fieldName, 1),
ExpressionBuilder::EQ,
$queryBuilder->createNamedParameter('', Connection::PARAM_STR)
);
// after
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('tt_content');
$queryBuilder->expr()->comparison(
$queryBuilder->expr()->trim($fieldName, TrimMode::LEADING),
ExpressionBuilder::EQ,
$queryBuilder->createNamedParameter('', Connection::PARAM_STR)
);
// example for dual version compatible code
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('tt_content');
$queryBuilder->expr()->comparison(
$queryBuilder->expr()->trim($fieldName, TrimMode::LEADING),
ExpressionBuilder::EQ,
$queryBuilder->createNamedParameter('', Connection::PARAM_STR)
);
Copied!
Tip
With Doctrine DBAL 3.x the
TrimMode was a class with class constants. Using
these no code changes are needed for TYPO3 v12 and v13 compatible code. Only
method call type hinting needs to be adjusted to use the enum instead of
int.
Doctrine DBAL 4 removed methods from the
QueryBuilder which has been
adopted to the extended
\TYPO3\CMS\Core\Database\Query\QueryBuilder .
Removed methods:
QueryBuilder::add(): Use new reset methods and normal set methods
instead.
QueryBuilder::getQueryPart($partName): No replacement, internal state.
QueryBuilder::getQueryParts(): No replacement, internal state.
QueryBuilder::resetQueryPart($partName): Replacement methods has been added,
see list.
QueryBuilder::resetQueryParts(): Replacement methods has been added,
see list.
QueryBuilder::execute(): Use
QueryBuilder::executeQuery() or
QueryBuilder::executeStatement() directly.
QueryBuilder::setMaxResults(): Using (int)0 as max result will
no longer work and retrieve no records. Use NULL instead to allow all
results.
Signature changes:
QueryBuilder::quote(string $value): Second argument has been dropped
and the value must now be of type
string.
Impact
Calling any of the mentioned removed methods will result in a PHP error. Also
signature changes introducing type hint will result in a PHP error if called
with an invalid type.
Affected installations
Only those installations that use the mentioned methods.
Migration
Extension author need to replace the removed methods with the alternatives which
This can be done already in TYPO3 v12 with at least Doctrine DBAL 3.8.
QueryBuilder::resetQueryParts() and
QueryBuilder::resetQueryPart()
However, several replacements have been put in place depending on the
$queryPartName parameter:
before
after
'select'
Call
->select() with a new set of columns
'distinct'
->distinct(false)
'where'
->resetWhere()
'having'
->resetHaving()
'groupBy'
->resetGroupBy()
'orderBy
->resetOrderBy()
'values'
Call
->values() with a new set of values.
Note
This can be done already in TYPO3 v12 with at least Doctrine DBAL 3.8.
QueryBuilder::execute()
Doctrine DBAL 4 removed
QueryBuilder::execute() in favour of the two
methods
QueryBuilder::executeQuery() for select/count and
QueryBuilder::executeStatement()
for insert, delete and update queries.
The PHP interface
\TYPO3\CMS\Core\Package\PackageInterface has been
modified.
All methods of the interface now have proper types in the method signature.
In addition, the method
getPackageIcon(): ?string is added to define
whether the package has an icon which is shipped with the package.
Impact
Although the interface exists primarily because of the original implementation
from Flow Framework in TYPO3 v6.0 in order to differentiate between TYPO3
extensions and Flow packages, the interface only has one implementation:
\TYPO3\CMS\Core\Package\Package .
Thus, it does not impact any extension or installation directly.
However, projects might be affected if there is a custom implementation
of the
PackageInterface, which is highly unlikely.
Affected installations
TYPO3 installations in very rare cases where there is a custom implementation
of the interface, which is unknown at the time of writing.
Migration
Extend the custom implementation to reflect the updated
PackageInterface.
Breaking: #102900 - Metaphone search removed from indexed_search
The indexed_search based frontend functionality had a feature called "metaphone"
to look for matches that "sound similar" to the given search word. This was available
using the "Advanced search" interface, if it has not been disabled by an
integrator. This feature has been removed.
This feature had so many issues that it was deemed unfixable:
Most importantly, search results were bad. Even during dedicated testing, it
was hard to retrieve any "similar sounding" results.
The implementation was tailored for English language only, lacking support for
any non-ASCII characters like umlauts. Sites with languages not based on
single byte characters got even worse results.
The code has been not maintained for about 15 years.
The feature seems to be used so seldom, there does not seem to be a single
extension that tries to fix at least the most important issues.
There has been no issues reported about this broken feature over the years,
except when it triggered crashes.
All in all it seems as if that feature was used extremely seldom, most likely
because the results are so bad.
On a code level, the removal affects these areas:
Class
\TYPO3\CMS\IndexedSearch\Utility\DoubleMetaPhoneUtility has been
removed.
The "hook"
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['metaphone']
to register an own "metaphone" solution has been removed.
The extension configuration option
enableMetaphoneSearch has been removed.
The database columns
index_fulltext.metaphonedata and
index_words.metaphone
have been removed.
A couple of methods and properties in the
@internal marked indexed_search
classes have been removed and simplified.
Impact
Frontend users can no longer select the "Sounds like" option when searching the
website. Backend users do not see statistics about this search variant in the
backend module.
Affected installations
Websites with a search solution based on indexed_search with "metaphone" search
being active in the extension configuration, and with users actively using
the "metaphone" search feature.
Migration
No migration available. Sites that really need this feature should switch to
a more sophisticated search solution.
Breaking: #102902 - Search rules removed from Indexed Search
The "Rules" section in Indexed Search stems from a time when today's knowledge
how a search works was considered "advanced". By today's standards, it can be
considered common sense and therefore the rules and its related TypoScript
configuration have been removed.
Impact
The Indexed Search plugin doesn't show the rules anymore. The Fluid partial file
Resources/Private/Partials/Rules.html and the related TypoScript
configuration :typoscript:plugin.tx_indexedsearch.settings.displayRules`
have been removed.
Affected installations
All installations displaying the Indexed Search search rules are affected.
Migration
Fluid
Remove any overrides for the partial file Resources/Private/Partials/Rules.html,
as well as the
<f:render partial="Rules" /> invocation from a potentially
overridden Resources/Private/Partials/Form.html partial file.
TypoScript
If configured, remove the :typoscript:plugin.tx_indexedsearch.settings.displayRules`
configuration.
Indexed Search previously used a custom link building to generate links and their targets
for linking to search results that are of type "page", instead of the native "typolink" (
LinkFactory)
system, automatically detecting links to other sites of the same installation and using
the proper
extTarget setting in TypoScript for creating the target attribute for the link.
For this reason, the two TypoScript settings are removed:
TYPO3 installations using indexed search using these options.
Migration
Remove the lines, and adapt config.extTarget accordingly if needed in such cases, as
the links are now generated through TYPO3's native link building APIs.
Breaking: #102921 - Remove several outdated indexed search features
The internal search of TYPO3, Indexed Search exists since over 20 years. Some
functionality that is shipped with the search form is not considered up-to-date
anymore, in regard to templating, as Indexed Search has an Extbase and
Fluid-based plugin since TYPO3 v6.2 (10 years).
Some functionality was never removed, which is now the case:
The ability to customize the styling of a specific page via
plugin.tx_indexedsearch.settings.specialConfiguration
The ability to customize a result icon (used as Gif images) based on the type
via
plugin.tx_indexedsearch.settings.iconRendering
The ability to customize a result language symbol icon (used as Gif images)
based on the page language via
plugin.tx_indexedsearch.settings.flagRendering
In addition, the possibility for visitors to change only search for results in
a language other than the current language is removed. It proved little sense
to search for e.g. Japanese content on a French websites.
Impact
All of the TypoScript settings are not evaluated anymore. The Fluid variables
{allLanguageUids},
{row.language} and
{row.icon} are not
filled anymore.
Search only shows results in the language of the currently active language
of the website.
Affected installations
TYPO3 installations using these options or features with Indexed Search.
Migration
Adapt your TypoScript settings, and remove the TypoScript settings and Fluid
variables.
If you still need specific rendering of icons for pages, or customized CSS for
result pages, it is recommended to use Fluid conditions adapted in your custom
template, which is usually not necessary.
Breaking: #102924 - Single Table Inheritance from fe_groups removed
Extbase ships with a feature called "Single Table Inheritance", to allow
multiple Extbase domain models reflecting one database table depending on a
specific value of a database field.
TYPO3 has the functionality enabled for the database tables
fe_users and
fe_groups.
The respective default models, which do not make a lot of sense as models
depend on a specific domain, have been removed in previous TYPO3 versions.
For frontend user groups, the usage and the usefulness for TYPO3 to ship this out
of the box, has shown little impact. For this reason, the functionality has been
removed. Along with that, the database field
fe_groups.tx_extbase_type and its
TCA definition as well as the Extbase configuration as a single table inheritance
option, has been removed.
The functionality for Single Table Inheritance in Extbase and also for frontend
users is working as before without any changes.
Impact
Using the database field in custom code, or using Single Table Inheritance in
Extbase for frontend user groups will result in SQL and PHP errors.
Affected installations
TYPO3 installations with custom extensions using Single Table Inheritance in
Extbase with frontend usergroups.
Migration
If necessary, extension authors can add Single Table Inheritance in their own
extension for fe_groups by themselves.
Add a database field
fe_groups.tx_extbase_type in ext_tables.sql
Add TCA information in Configuration/TCA/Overrides/fe_groups.php for the database field
Breaking: #102925 - Template changes in Indexed Search
Due to some major refactorings within EXT:indexed_search, Fluid templates in the
frontend plugins were adapted.
Impact
In case Fluid templates of EXT:indexed_search are overridden, the rendered output
may look different and behave unpleasant.
Affected installations
All installations overriding Fluid templates of EXT:indexed_search are affected.
Migration
Pagination
The pagination ViewHelpers have been removed in favor of native pagination API
shipped with TYPO3. Usages of the ViewHelpers is:pageBrowsingResults and
is:pageBrowsing have been removed.
The Fluid template file Private/Templates/Search/Search.html loads a new
JavaScript via
<f:asset.script>:
Remove any overrides for the partial file Resources/Private/Partials/Rules.html,
as well as the
<f:render partial="Rules" /> invocation from a potentially
overridden Resources/Private/Partials/Form.html partial file.
The following frontend TypoScript and page rendering related hooks
have been removed:
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['configArrayPostProc'] ,
substituted by event
ModifyTypoScriptConfigEvent.
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageLoadedFromCache'] ,
no direct substitution, use event
AfterTypoScriptDeterminedEvent or an own middleware
after
typo3/cms-frontend/prepare-tsfe-rendering instead.
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['createHashBase']',
substituted by event :php: BeforePageCacheIdentifierIsHashedEvent`.
Impact
Any such hook implementation registered is not executed anymore
with TYPO3 v13.0+.
Affected installations
TYPO3 installations with custom extensions using above listed hooks.
Migration
See PSR-14 event
for substitutions. The new events are tailored for more restricted use cases and can
be used when existing hook usages have not been "side" usages. Any "off label" hook
usages should be converted to custom middlewares instead.
Breaking: #102935 - Overhauled extension installation in Extension Manager
Installing extensions via the extension manager is only used for non-Composer-based
installations. However, there have been a couple of dependencies to
the EXT:extensionmanager, which required even Composer-based installations
to have this extension installed. This has now been resolved. The
EXT:extensionmanager extension is now optional.
The public
\TYPO3\CMS\Extensionmanager\Utility\InstallUtility->processExtensionSetup()
method has therefore been removed. It has previously been used to execute a
couple of "import" tasks, such as import site configurations or media assets to
the fileadmin/. However those tasks had dependencies to other optional core
extensions, such as EXT:impexp. Therefore the new PSR-14 event
PackageInitializationEvent has been introduced and the functionality
has been split into corresponding event listeners, which are added to their
associated Core extensions.
The PSR-14 events, dispatched by those "tasks" have been removed:
The information, provided by those events can now be accessed by fetching the
corresponding storage entry from the new
\TYPO3\CMS\Core\Package\Event\PackageInitializationEvent .
Using
before and
after keywords in the listener registration,
custom extensions can ensure to be executed, once the corresponding information
is available.
It's even possible to manually execute those "tasks" by dispatching the
PackageInitializationEvent in custom extension code. This can be
used as replacement for the
InstallUtility->processExtensionSetup() call.
Impact
Using one of the removed PSR-14 events or calling the removed method will
lead to a PHP error. The extension scanner will report any usages.
Affected installations
TYPO3 installations with extensions registering listeners to the removed events
or calling the removed method in their extension code.
Migration
Instead of registering listeners for the removed events, developers can now
just register a listener to the new
PackageInitializationEvent, which
contains the listeners result as storage entry:
Indexed Search provided the possibility to manipulate the search behavior via
hooks with
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['pi1_hooks'] .
There are no public extensions supporting TYPO3 v12 using this hooking mechanism,
therefore it has been removed without replacement. In case there are private consumers
of these hooks, we will allow to add a dedicated event at appropriate places later.
Impact
If implemented, hooks in
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['pi1_hooks']
are not called anymore.
Affected installations
All extensions using this hook are affected.
Migration
No migration available.
Breaking: #102945 - Pagination of Indexed Search replaced
Indexed Search used a custom crafted pagination, implemented with several
ViewHelpers known as is:pageBrowsingResults and is:pageBrowsing.
These ViewHelpers have been removed in favor of the existing Pagination API,
leading to template changes.
Impact
In case Fluid templates of EXT:indexed_search are overridden, the frontend will
render an exception due to the missing ViewHelpers.
Affected installations
All installations overriding the Fluid template Templates/Search/Search.html
of EXT:indexed_search are affected.
Migration
is:pageBrowsingResults has been replaced with a short HTML snippet:
When dealing with custom FormEngine elements in the backend record editing
interface, the infrastructure prepares a huge data array and hands it over
to single element classes for rendering.
The specific data key
$this->data['parameterArray']['itemFormElID']
has been removed. The intention of that key was to prepare some unique id
to be used as
id attribute. This never made a lot of sense, single
element classes can easily take care of this on their own if needed.
Since the Core can't actively deprecate and log access to members of the main
data array as such, there is no point in declaring a deprecation for it, and
the array entry has been removed directly.
Impact
Extensions with custom backend FormEngine elements may raise an
"undefined array key" PHP warning, or may create empty id attributes in
their HTML output if accessing
itemFormElID.
Affected installations
Instances with extensions that deliver custom FormEngine elements may
be affected.
Migration
A typical use case for a unique
id attribute on a form element is to
connect it with a
label element. Accessing
itemFormElID can
usually be easily avoided by creating a unique string using
StringUtility::getUniqueId(), with a custom prefix:
FlexForm handling details can be troublesome in certain scenarios. The Core
suffers from some nasty issues in this area, especially when relations
to other tables are used in FlexForms - the system for instance tends to mix
up things with language and workspace on this level.
The Core strives to get these scenarios sorted out, and a couple of patches to
prepare towards better flex form handling have been done with v13.0 already.
To unblock further development in this area, one detail is restricted a bit more
than with previous versions: FlexForm container section data structures must no
longer contain fields that configure relations to other database tables.
This has already been restricted since TYPO3 v8 for TCA
type="inline" and
has been partially extended to
type="category" and others later, if they
configured
MM relations in FlexForm sections containers. Now, especially
type="select" with
foreign_table will also throw an exception.
In general, anonymous FlexForm container section data can and should not point to
database entities. Their use is tailored for "simple" types like
input,
email and similar, support of those will not be restricted.
Note this does not restrict using casual FlexForms without containers sections,
like FlexForm data structures that rely on casual fields in sheets: Those can
continue to work with TCA types like
inline,
group and
select,
and the Core development tries to actively fix existing problematic scenarios
in this area.
Impact
When editing records that configure FlexForms with container sections that use
database relation-aware
TCA types, an exception will be thrown by
FormEngine. The related code may later be relocated to a lower level place
that can be triggered by DataHandler as well.
Affected installations
Instances with extensions that use FlexForm container sections configuring
database relations to tables.
Since previous core versions restricted database relations within FlexForm
container sections already, and since container sections are a relatively rarely
used feature in the first place, we don't expect too many extensions to be
affected by this.
You can easily spot custom usage of FlexForm sections by searching for a
<section>
tag within your FlexForm .xml files, or within a TCA definition
with
type="flex". These will be the instances you need to migrate,
when those sections contain
type="select" fields (or others mentioned above).
<?xml version="1.0" encoding="utf-8" standalone="yes" ?><T3DataStructure><sheets><sSection><ROOT><sheetTitle>section</sheetTitle><type>array</type><el><section_1><title>section_1</title><type>array</type><!-- this is what to look out for: --><section>1</section><el><container_1><type>array</type><title>container_1</title><el><select_tree_1><label>select_tree_1 pages description</label><description>field description</description><config><type>select</type><renderType>selectTree</renderType><foreign_table>pages</foreign_table><foreign_table_where>ORDER BY pages.sorting</foreign_table_where><size>20</size><treeConfig><parentField>pid</parentField><appearance><expandAll>true</expandAll><showHeader>true</showHeader></appearance></treeConfig></config></select_tree_1></el></container_1></el></section_1></el></ROOT></sSection></sheets></T3DataStructure>
Some extensions tried to work around existing restrictions by switching from
type="inline" to
type="group" or
type="select", ending
up with the same problematic scenario.
The basic issue is still, that binding database entities to anonymous data
structures is a problematic approach in the first place: A container section
that can be repeated often, combined with the additional built-in feature to
have multiple different sections at the same time, is close to impossible to
manage in a way that does not easily destroy data integrity.
Extensions that rely on this feature need to get rid of this approach: It
typically means rewriting the extension to model relations using
type="inline"
bound to database columns directly.
Breaking: #102971 - Most classes of EXT:workspaces declared internal
A few additional classes of extension "workspaces" have been declared
@internal.
With this, most of the classes are now considered internal handling, except, of
course, dispatched events.
Impact
Extensions extending or using workspace classes as PHP API that are now marked
@internal may break, when the Core changes such classes. This will not
be considered breaking.
Affected installations
Few extensions extend workspaces as such, and the backend workspaces
application in particular.
Migration
Extension authors who need to extend from classes within EXT:workspaces should
reconsider on why this needs to be done. They should expect these may break
without further notice.
Legit use cases can often be moved towards some additional event instead.
Extension authors are encouraged to come up with specific solutions in those cases.
Breaking: #102975 - Use full md5 hashes in indexed_search
For historical reasons an integer representation for castrated md5 hashes has
been used in several places for the ext:indexed_search provided database schema
and functionality. This led to conflicts that manifested as "duplicate key" errors.
Therefore, the database fields are transformed to varchar fields and the whole
indexed search codebase changed to work with full md5 hashes now.
Due to the database changes it is necessary to truncate the indexed search tables,
which is done within the database analyzer. Reindexing the data is therefore
required.
Field types of following table fields are changed now:
index_phash: phash, phash_grouping, contentHash
index_fulltext: phash
index_rel: phash, wid
index_words: wid
index_section: phash, phash_t3
index_grlist: phash, phash_x, hash_gr_list
index_debug: phash
Note
Remember to reindex your installation to fill the index again.
Impact
Installations using the ext:indexed_search need to apply a database schema
change which involves the truncation of the corresponding tables and reindex
the installation.
Affected installations
All installations using EXT:indexed_search are affected.
Migration
The database analyzer takes care of updating affected columns and truncates
index related tables to be ready for reindexing.
Class
\TYPO3\CMS\Core\TimeTracker is used in the TYPO3 frontend rendering.
It allows tracking time consumed by single code sections. The admin panel uses
gathered data and renders a "time elapsed" overview from it.
All methods and properties that enable or disable tracking details and return
the gathered data have been marked
@internal and partially moved to
EXT:adminpanel.
Extensions should only write data to
TimeTracker, methods that are
considered API are these:
TimeTracker->push() (second argument may vanish)
TimeTracker->pull()
TimeTracker->setTSlogMessage()
Impact
Extensions using methods other than the ones listed above may raise PHP fatal
errors or different result structures when the underlying code is further
refactored.
Affected installations
Most extensions in the wild use only the above listed methods. There is little
reason to use other methods, except for extension that mimic or extend
functionality of EXT:adminpanel. Instances with such extensions need to follow
changes of class
TimeTracker.
Migration
No direct migration possible.
Breaking: #102980 - getAllPageNumbers() in PaginationInterface
A method has been added to
\TYPO3\CMS\Core\Pagination\PaginationInterface
with this signature:
public function getAllPageNumbers(): array;. It should
return a list of all available page numbers.
The method has already been implemented in
\TYPO3\CMS\Core\Pagination\SimplePagination and
\TYPO3\CMS\Core\Pagination\SlidingWindowPagination .
Impact
Custom implementations of
PaginationInterface must implement the method.
Affected installations
Instances with extensions that provide own pagination classes that implement
PaginationInterface may be affected.
Migration
See the two Core classes
SimplePagination and
SlidingWindowPagination
for examples on how the method is implemented.
Breaking: #102985 - Declare Indexed Search as Content Type
The plugin configuration of the "Indexed Search" plugin has been changed. The
plugin is now configured as a proper "content element" using the CType plugin
type. This allows to further shrink down the CType=list and
list_type=<plugin_name> combination, like it has already been done with other
plugins, e.g. the "Frontend Login" plugin.
Impact
The "Indexed Search" plugin is now configured as a content element, using
CType=indexedsearch_pi2 instead of the CType=list and
list_type=indexedsearch_pi2 combination.
An upgrade wizard is in place, migrating existing content elements as well
as corresponding backend user group permissions.
Affected installations
All installations with extensions, relying on the "Indexed Search" plugin
using the CType=list and list_type=indexedsearch_pi2 combination. This
might be done in custom database queries, frontend data providers or in
TSconfig. Also in cases where the corresponding backend user group permissions
(
be_groups.explicit_allowdeny) are manually evaluated.
Migration
Execute the Migrate "Indexed Search" plugins to content elements. upgrade
wizard to automatically migrate existing records. Make sure to have the
Migrate backend groups "explicit_allowdeny" field to simplified format.
upgrade wizard executed beforehand.
Additionally, adjust any place relying on the plugin using the
CType=list and list_type=indexedsearch_pi2 combination.
Example SQL migrations:
-- BeforeSELECT * FROM tt_content WHERE CType = 'list'AND list_type = 'indexedsearch_pi2';
-- AfterSELECT * FROM tt_content WHERE CType = 'indexedsearch_pi2';
Copied!
-- BeforeSELECT * FROM be_groups WHERE explicit_allowdeny LIKE'%tt_content:list_type:indexedsearch_pi2%';
-- AfterSELECT * FROM be_groups WHERE explicit_allowdeny LIKE'%tt_content:CType:indexedsearch_pi2%';
Copied!
Feature: #82855 - Update Metadata of online media assets
A new action Reload Metadata has been added to the secondary
options' dropdown of online media assets, such as YouTube and Vimeo videos,
in the File > Filelist module. Additionally, also the context menu of
such files has been extended for the new action.
The action allows to reload the corresponding information from the external
service. That information is, for example, the preview image, the author or the
dimensions of the online media asset.
Impact
It's now possible to reload the Metadata of an online media asset using the
new Reload Metadata action.
The TYPO3 backend URL is made configurable in order to enable optional
protection against application admin interface infrastructure
enumeration (WSTG-CONF-05). Both, frontend and backend requests are
now handled by the PHP script /index.php to enable virtual admin
interface URLs.
The default TYPO3 backend entry point path /typo3 can be changed by
specifying a custom URL path or domain name in
$GLOBALS['TYPO3_CONF_VARS']['BE']['entryPoint'] .
This change requires web server adaption. A silent migration and
according documentation for custom web server configurations is added.
A deprecation layer (for non-adapted systems) is in place that rewrites
the server environment variables passed to /typo3/index.php as if
/index.php was used directly. This layer will be removed in TYPO3 v14.
This change does not take assets into account, only routing is adapted.
That means Composer mode will use assets provided via /_assets as before
and TYPO3 classic mode will serve backend assets from /typo3/* even if
another backend URL is used and configured.
Now point your browser to https://backend.example.com/ to log into the TYPO3
backend.
Legacy-Free installation
The legacy entry point /typo3/index.php is no longer needed and deprecated in
favor of handling all backend and frontend requests with /index.php. The
entry point is still in place, in case webserver configuration has not been adapted
yet. The maintenance and emergency tool is still available via
/typo3/install.php in order to work in edge cases like broken web server
routing.
In Composer mode there is an additional opt-out for the installation of the
legacy entrypoint that can be defined in your project's composer.json
file:
The TYPO3 backend route path is made configurable in order to protected against
application admin interface infrastructure enumeration (WSTG-CONF-05).
Therefore, all requests are handled by the PHP script /index.php in order to
allow for variable admin interface URLs.
Feature: #88537 - WebP image format support for Image Processing
WebP [https://en.wikipedia.org/wiki/WebP] is a modern image format for the web
that comes with several advantages over PNG or JPEG image files:
WebP images have roughly 30% smaller file size compared to JPEG or PNG files
WebP images support an alpha channel (transparency) which JPEG files do not support
WebP is support by all modern browsers [https://caniuse.com/webp], and is
available for processing / generation in most ImageMagick / GraphicsMagick
versions.
TYPO3 can now generate WebP images, if the underlying
ImageMagick / GraphicsMagick library supports WebP.
Impact
By default, WebP images can now be generated, as TYPO3's configuration setting
$GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] is now extended with
"webp".
Integrators can now use the file extension webp in their Fluid template or
Fluid templates or PHP code when interacting with the underlying Processing API
or the Graphical Functions API.
The Install Tool / Environment Module displays if support for generating WebP
image files is possible. In addition, a new report in the System > Reports
module of TYPO3 backend shows, if TYPO3 is properly configured for generating WebP
image files.
If the underlying ImageMagick / GraphicsMagick library is not built with
WebP support, the server administrators can install or recompile the library
with WebP support by installing the cwebp or dwebp libraries.
The default quality of generated WebP image files can be defined via
$GLOBALS['TYPO3_CONF_VARS']['GFX']['webp_quality'] which requires a value
between 1 (low quality, small file size) and 100 (best quality, large file size),
or set to lossless which uses the lossless compression format. Even lossless
compression for converting, for example, PNG files will result in smaller file
sizes as WebP [https://developers.google.com/speed/webp/gallery2].
Depending on the target audience of the TYPO3 Frontend, it may be valid to
disable WebP support by removing "webp" from the imagefile_ext setting.
Feature: #88817 - Make autocomplete selectable in EXT:form backend
Autocomplete options can already be added to input
fields in EXT:form via editing the YAML. This was
hard or impossible to do for editors.
The autocomplete tag has to be set for form fields
to be accessibility compliant, where applicable.
The parameter can have arbitrary content according
to the HTML standard. However, assistive
technology only supports a finite number of values,
of which only few are commonly used in contact
forms.
Projects that desire additional parameter values
can set them via YAML.
Impact
Editors can now select the autocomplete input purpose when editing forms.
In installations that extended the form YAML configuration with keys that
are used in this change, the autocomplete field might be overridden and
not be displayed in the editor by default.
Feature: #94501 - FAL support for FlexFormProcessor
The
FlexFormProcessor is now able to resolve FAL
references by its own.
Each FlexForm field, which should be resolved, needs a reference definition
to the
foreign_match_fields. This reference is later used in the
FilesProcessor to resolve the correct FAL resource.
Example of an advanced TypoScript configuration, which processes the field
my_flexform_field, resolves its FAL references and assigns the
array to the
myOutputVariable variable:
FAL references within a FlexForm can now be resolved for the direct usage
in Fluid templates. This makes resolving the file references by using additional
data processors obsolete.
Feature: #95808 - Enable item groups from foreign tables
A new TCA option
foreign_table_item_group has been introduced for the TCA
types select and category. It allows extension authors to define a
specific field in the foreign table, holding an item group identifier.
As described in the TCA reference,
this needs to be a
string.
Therefore, it's now possible to also use the item groups feature, introduced
with forge#91008, for TCA columns with a foreign table lookup.
In case the
foreign_table_item_group field of a foreign record
contains an item group identifier, not set in the local
itemGroups
configuration, the database value will be used as label in the select box,
as it's also the case for static items with a
group set to a value,
which is not configured in
itemGroups.
Impact
Using the new
foreign_table_item_group TCA config option, it's now
possible to use the items group feature even for items from foreign tables.
Feature: #97664 - Add search functionality to form manager
It can be difficult for an editor to find the right form definition to edit, if
there are many form definitions in the system.
To make it easier, a search field is displayed in the form manager.
This allows a case-insensitive search by name or persistenceIdentifier.
Impact
It's now possible to search for a form definition inside the form manager
backend module.
Feature: #99165 - Add "Edit Metadata" button to element information view
A new button Edit Metadata has been added to the element information
view of files. It allows to directly edit corresponding Metadata without leaving
the context. The element information view for files can be accessed via the
context menu or via the secondary action of files in any file listing, for
example, in the File > Filelist module or the File selector.
Impact
It's now possible to edit a file's Metadata directly in the element information
view, which improves the UX as the context is not lost.
Feature: #99323 - PSR-14 event for modifying records after fetching content
A new PSR-14 event
\TYPO3\CMS\Frontend\ContentObject\Event\ModifyRecordsAfterFetchingContentEvent
has been introduced which serves as a more powerful replacement for the now
removed
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content_content.php']['modifyDBRow']
hook.
The event allows to modify the fetched records next to the possibility to
manipulate most of the options, such as slide. Listeners are also able
to set the final content and change the whole TypoScript configuration,
used for further processing.
This can be achieved with the following methods:
getRecords()
getFinalContent()
getSlide()
getSlideCollect()
getSlideCollectReverse()
getSlideCollectFuzzy()
getConfiguration()
setRecords()
setFinalContent()
setSlide()
setSlideCollect()
setSlideCollectReverse()
setSlideCollectFuzzy()
setConfiguration()
Example
The event listener class, using the PHP attribute
#[AsEventListener] for
registration:
Using the new PSR-14 event, it's now possible to modify the records
fetched by the "Content" ContentObject, before they are being further
processed, or even skip TYPO3's default processing of records by setting
an empty array for the records to be rendered.
Additionally, next to the final content, also most of the options and the
whole TypoScript configuration can be modified.
Feature: #99485 - Show the redirect integrity status
The integrity check command checks redirects and displays the information in the
CLI or in the status report. This status information is now used and stored on
the redirect.
The command
redirects:cleanup has been extended by the option
integrityStatus.
This allows you to remove specific redirects according to status.
The event
\TYPO3\CMS\Redirects\Event\ModifyRedirectManagementControllerViewDataEvent
has been extended by two new functions:
setIntegrityStatusCodes(): Allows to set integrityStatusCodes. Can be
used to filter for integrityStatusCodes
getIntegrityStatusCodes(): Returns all integrityStatusCodes.
Impact
In the redirect module, the conflicting redirects are now marked. In addition,
you can now filter for conflicting redirects.
In the
redirects:checkintegrity command, the type of conflict is now displayed
in the table.
The
\TYPO3\CMS\Seo\Event\ModifyUrlForCanonicalTagEvent , used by listeners
to manipulate the URL of the canonical tag, has been improved. The event is
now being dispatched after the standard functionality, such as fetching the
URL from the page properties, has been executed.
Additionally, the event is now even dispatched, in case the canonical tag
generation is disabled via TypoScript
disableCanonical or via
page properties
no_index. If disabled, the new
\TYPO3\CMS\Seo\Exception\CanonicalGenerationDisabledException is being
thrown in the
CanonicalGenerator. The exception is caught and transferred
to the event, allowing listeners to determine whether generation is disabled,
using the new
getCanonicalGenerationDisabledException() method, which
either returns the exception with the corresponding reason or
null.
Impact
By relocating and extending the
ModifyUrlForCanonicalTagEvent,
listeners are now able to fully manipulate the canonical tag generation, even
if the generation is disabled and after the standard functionality has been
executed.
Feature: #100268 - Provide full userdata in password recovery email
A new array variable
userData has been added to the password
recovery
\TYPO3\CMS\Core\Mail\FluidEmail object. It contains the values
of all fields belonging to the affected frontend user.
Impact
It is now possible to use the
{userData} variable in the Fluid template
of the password recovery to access data from the affected frontend user.
Feature: #100926 - Introduce RotatingFileWriter for log rotation
TYPO3 log files tend to grow over time, if not manually cleaned on a regular
basis, potentially leading to full disks. Also, reading its contents may be
hard when several weeks of log entries are printed as a wall of text.
To circumvent such issues, established tools like logrotate are available for
a long time already. However, TYPO3 may be installed on a hosting environment
where logrotate is not available and cannot be installed by the customer.
To cover such cases, a simple log rotation approach has been implemented,
following the "copytruncate" approach: when rotating files, the currently
opened log file is copied (for example, to typo3_[hash].log.20230616094812) and
the original log file is emptied. This saves the hassle with properly
closing and re-creating open file handles.
A new file writer
\TYPO3\CMS\Core\Log\Writer\RotatingFileWriter has been
added, which extends the already existing
\TYPO3\CMS\Core\Log\Writer\FileWriter class. The
RotatingFileWriter accepts all options of
FileWriter in addition
of the following:
interval - how often logs should be rotated, can be any of
daily or
\TYPO3\CMS\Core\Log\Writer\Enum\Interval::DAILY (default)
weekly or
\TYPO3\CMS\Core\Log\Writer\Enum\Interval::WEEKLY
monthly or
\TYPO3\CMS\Core\Log\Writer\Enum\Interval::MONTHLY
yearly or
\TYPO3\CMS\Core\Log\Writer\Enum\Interval::YEARLY
maxFiles - how many files should be retained (by default 5 files, 0 never deletes any file)
The
RotatingFileWriter is configured like any other log writer.
Note
When configuring
RotatingFileWriter in system/settings.php,
the string representations of the
Interval must be used for the
interval option, as otherwise this might break the Install Tool.
Example
The following example introduces log rotation for the "main" log file.
system/additional.php
$GLOBALS['TYPO3_CONF_VARS']['LOG']['TYPO3']['CMS']['Core']['Resource']['ResourceStorage']['writerConfiguration'][\Psr\Log\LogLevel::ERROR] = [
\TYPO3\CMS\Core\Log\Writer\RotatingFileWriter::class => [
'interval' => \TYPO3\CMS\Core\Log\Writer\Enum\Interval::DAILY,
'maxFiles' => 5,
],
\TYPO3\CMS\Core\Log\Writer\DatabaseWriter::class => [], // this is part of the default configuration
];
Copied!
The following example introduces log rotation for the "deprecation" log file.
system/additional.php
$GLOBALS['TYPO3_CONF_VARS']['LOG']['TYPO3']['CMS']['deprecations']['writerConfiguration'][\Psr\Log\LogLevel::NOTICE] = [
\TYPO3\CMS\Core\Log\Writer\RotatingFileWriter::class => [
'logFileInfix' => 'deprecations',
'interval' => \TYPO3\CMS\Core\Log\Writer\Enum\Interval::WEEKLY,
'maxFiles' => 4,
'disabled' => false,
],
\TYPO3\CMS\Core\Log\Writer\DatabaseWriter::class => [], // this is part of the default configuration
];
Copied!
Impact
When configured, log files may be rotated before writing a new log entry,
depending on the configured interval, where
Interval::DAILY is the
default. When rotating, the log files are suffixed with a rotation incremental
value.
Example:
Directory listing of var/log/ with rotated logs
$ ls -1 var/log
typo3_[hash].log
typo3_[hash].log.20230613065902
typo3_[hash].log.20230614084723
typo3_[hash].log.20230615084756
typo3_[hash].log.20230616094812
Copied!
If
maxFiles is configured with a value greater than 0, any exceeding
log file is removed.
Feature: #101113 - Show if redirects were checked in report
In the status report is an entry to show, if redirect conflicts have been
found.
However, there was previously no indication if / when the last check was run.
If there were no conflicts, a status of "ok" was reported which could be quite
misleading, if a redirects check was not performed lately.
Now we write a timestamp into the registry when checking redirects,
along with the result of "checkintegrity". These are 2 separate
registry entries.
The timestamp is queried in the report generation and an additional
"info" status is displayed, if the timestamp indicates that the
check was run more than 24 hours ago or never run at all:
List of conflicting redirects may not be up to date!
Regularly run the console command redirects:checkintegrity.
Copied!
This can be deactivated in the extension configuration and the time (24 hours)
can be changed as well.
Impact
An additional informational message will appear in the system report, if
checkintegrity was not run within the last 24 hours
This can be configured in the extension configuration of EXT:redirects
If extensions provide other means to check redirects, they should write the
entries to the registry as well as the timestamp (see
\TYPO3\CMS\Redirects\Command\CheckIntegrityCommand ):
A new native backed enum
\TYPO3\CMS\Core\Imaging\IconState has been
introduced for streamlined usage within
\TYPO3\CMS\Core\Imaging\Icon and
\TYPO3\CMS\Core\Imaging\IconFactory .
Impact
The new
\TYPO3\CMS\Core\Imaging\IconState native backed enum is meant
to be a drop-in replacement for the former
\TYPO3\CMS\Core\Type\Icon\IconState class.
The new
\TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior native backed
enum is meant to be a drop-in replacement for the former
\TYPO3\CMS\Core\Resource\DuplicationBehavior class.
A new native backed enum
\TYPO3\CMS\Backend\Toolbar\InformationStatus
has been introduced as a drop-in replacement for the for former
\TYPO3\CMS\Backend\Toolbar\Enumeration\InformationStatus class. It
is used to specify the severity of a system information, displayed in the
backend toolbar.
The new enum features the following values:
NOTICE
INFO
OK
WARNING
ERROR
Additionally, the
isGreaterThan() method is available to compare severities.
Impact
It's now possible to use the native
\TYPO3\CMS\Backend\Toolbar\InformationStatus
enum to describe the severity of the system information for the backend toolbar.
Note
Compared to the deprecated
\TYPO3\CMS\Backend\Toolbar\Enumeration\InformationStatus class,
the new enum does not use the prefix
STATUS_ for its values. Also
a special
__default constant is not available.
Feature: #101396 - Let Extbase handle native enums
With PHP 8.1, native support for enums has been introduced. This is quite handy
if a database field has a specific set of values which can be represented by a
PHP enum.
It is now possible to use backed enums in entities like this:
<?phpdeclare(strict_types=1);
namespaceMyVendor\MyExtension\Domain\Model\Enum;
enum Level: string
{
case INFO = 'info';
case ERROR = 'error';
}
TYPO3 provides the
@typo3/backend/hotkeys.js module that allows developers
to register custom keyboard shortcuts in the TYPO3 backend.
It is also possible and highly recommended to register hotkeys in a dedicated
scope to avoid conflicts with other hotkeys, perhaps registered by other
extensions.
The module provides an enum with common modifier keys (Ctrl, Meta,
Alt, and Shift), and also a public property describing the common
hotkey modifier based on the user's operating system: Cmd (Meta) on macOS,
Ctrl on anything else. Using any modifier is optional, but highly
recommended.
A hotkey is registered with the
register() method. The method takes three
arguments:
hotkey - An array defining the keys that must be pressed
handler - A callback that is executed when the hotkey is invoked
options - Object that configured a hotkey's behavior.
scope - The scope a hotkey is registered in
allowOnEditables - If
false (default), handlers are not executed when an editable element is focussed
allowRepeat - If
false (default), handlers are not executed when the hotkey is pressed for a long time
bindElement - If given, an aria-keyshortcuts attribute is added to the element. This is recommended for accessibility reasons.
import Hotkeys, {ModifierKeys} from'@typo3/backend/hotkeys.js';
Hotkeys.register(
[Hotkeys.normalizedCtrlModifierKey, ModifierKeys.ALT, 'e'],
function (keyboardEvent) => {
console.log('Triggered on Ctrl/Cmd+Alt+E');
},
{
scope: 'my-extension/module',
bindElement: document.querySelector('.some-element')
}
);
// Get the currently active scopeconst currentScope = Hotkeys.getScope();
// Make use of registered scope
Hotkeys.setScope('my-extension/module');
Copied!
Note
TYPO3 specific hotkeys may be registered in the reserved all scope.
When invoking a hotkey from a different scope, the all scope is handled in
any case at first.
Impact
If properly used, common functionality is easier to access with hotkeys. The
following hotkeys are configured within TYPO3:
Ctrl/Cmd + K - open LiveSearch
Ctrl/Cmd + S - save current document opened in FormEngine
Feature: #101544 - Introduce PHP attribute to autoconfigure event listeners
A new custom PHP attribute
\TYPO3\CMS\Core\Attribute\AsEventListener
has been added in order to autoconfigure a class as a PSR-14 event listener.
The attribute supports the following properties, which are all optional,
as if you would register the listener by manually tagging it in the
Configuration/Services.yaml or Configuration/Services.php file:
identifier - Event listener identifier (unique) - uses the service name,
if not provided
event - Fully-qualified class name of the PSR-14 event to listen to
method - Method to be called - if omitted,
__invoke() is called by
the listener provider.
before - List of listener identifiers
after - List of listener identifiers
The attribute can be used on class and method level. Additionally, the new
attribute is repeatable, which allows to register the same class to listen
for different events.
Using the PHP attribute
\TYPO3\CMS\Core\Attribute\AsEventListener , it is
now possible to tag any PHP class as an event listener. By adding the attribute
the class is automatically tagged as event.listener and is therefore
autoconfigured by the
\TYPO3\CMS\Core\DependencyInjection\ListenerProviderPass .
Feature: #101553 - Auto-create DB fields from TCA columns
The TYPO3 v13 Core strives to auto-create database columns derived from
TCA
columns definitions without explicitly declaring them in
ext_tables.sql.
Creating "management" fields like
uid,
pid automatically derived
from TCA
ctrl settings is available for a couple of Core versions
already, the Core now extends this to single TCA
columns.
As a goal, extension developers should not need to maintain a
ext_tables.sql definition for casual table columns anymore, the file can
vanish from extensions and the Core takes care of creating fields with sensible
defaults.
Of course, it is still possible for extension authors to override single
definitions in ext_tables.sql files in case they feel the Core does
not define them in a way the extension author wants: Explicit definition in
ext_tables.sql always take precedence over auto-magic.
New TCA config option
dbFieldLength
For fields of type
select a new TCA config option
dbFieldLength has
been introduced. It contains an integer value that is applied to
varchar fields
(not
text) and defines the length of the database field. It will not be respected for
fields that resolve to an integer type. Developers who wish to optimize field
length can use
dbFieldLength for
type=select fields to increase or
decrease the default length the Core comes up with.
Example:
// will result in SQL text field'config' => [
'itemsProcFunc => 'something',
],
// will result in SQL varchar field length for 200 characters
'config' => [
'itemsProcFunc => 'something',
'dbFieldLength' => 200,
],
Copied!
Impact
Extension authors should start removing single column definitions from
ext_tables.sql for extensions being compatible with TYPO3 v13 and up.
If all goes well, the database analyzer will not show any changes since the Core
definition is identical to what has been defined in ext_tables.sql before.
In various cases though, the responsible class
DefaultTcaSchema may come
to different conclusions than the extension author. Those cases should be reviewed
by extension authors one-by-one: Most often, the Core declares a more restricted
field, which is often fine. In some cases though, the extension author may
know the particular field definition better than the Core default, and may decide
to keep the field definition within ext_tables.sql.
Columns are auto-created for these TCA
columns types:
Migration of
NULL to
NOT NULL definitions, data truncation
As mentioned, the automatic database schema migration is based on TCA configuration,
and will also take the
nullable TCA definition of a field into consideration.
This can lead to scenarios in which a field (from both the TYPO3 Core or
third party extension table definitions) will be converted in both type and
attributes, and where data conversion might lead to error message like:
MySQL/MariaDB error message
Error: Data truncated for column 'image' at row 1
Copied!
This can happen if previously a field was defined via
ext_tables.sql,
and then the definition was removed so that the TCA automatism could take
over, but the definition mismatches the TCA definition (which might have changed as well).
This can best be showcased with the following example:
Previous EXT:frontend/ext_tables.sql definition from TYPO3 v12
would lead to the error mentioned above, because any row that currently contains a
NULL value would no longer be allowed. The solution for this is to fix these
records before the schema migration is executed, by setting all currently existing
NULL values to the new schema's
DEFAULT value (here: 0).
This solution is provided by the TYPO3 Core via the migration wizard
Migrate NULL field values to DEFAULT values.
The wizard looks for all existing records of a table where a schema conversion of
NULL to
NOT NULL would take place, iterates all rows of the table, and applies
the default like this:
SQL command to fix database records NULL/NOT NULL state as executed by the upgrade wizard
Bottom line: When a definition in an extension's ext_table.sql is removed,
so that the DB fields are auto-created from TCA definitions, make sure that:
the TCA definition for nullable is properly set and
existing record values must fit into the new definition.
Otherwise, executing the migration wizard or custom data migration might be needed
to prevent data truncation.
This may not only affect
NOT NULL/NULL definitions, but also scenarios where
data types are changed from, for example,
TEXT to smaller
VARCHAR columns.
It is fine to keep ext_tables.sql definitions in place to adjust to special needs.
Feature: #101603 - PSR-14 event for modifying record overlay icon identifier
A new PSR-14 event
\TYPO3\CMS\Core\Imaging\Event\ModifyRecordOverlayIconIdentifierEvent
has been introduced which serves as a direct replacement for the now removed
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Core\Imaging\IconFactory']['overrideIconOverlay']
hook.
To modify the overlay icon identifier, the following methods are available:
setOverlayIconIdentifier(): Allows to set the overlay icon identifier
getOverlayIconIdentifier(): Returns the overlay icon identifier
getTable(): Returns the record's table name
getRow(): Returns the record's database row
getStatus(): Returns the record's visibility status
A new method within
\TYPO3\CMS\Backend\Routing\UriBuilder named
buildUriFromRequest is added which allows to generate a URL to a backend route
of this request.
Impact
This is typically useful when linking to the current route or module in the TYPO3
backend for extension authors to avoid internals with any PSR-7 request attribute.
Usage within a PHP module controller in the TYPO3 backend context:
The symfony PHP attribute
\Symfony\Component\Messenger\Attribute\AsMessageHandler
is now respected and allows to register services as message handlers by setting
the attribute on the class or the method.
The registration can be removed from the Configuration/Services.yaml
file and the attribute is assigned to the handler class instead:
EXT:my_extension/Classes/Queue/Handler.php
<?phpnamespaceMyVendor\MyExtension\Queue\Handler;
useMyVendor\MyExtension\Queue\Message\DemoMessage;
useSymfony\Component\Messenger\Attribute\AsMessageHandler;
#[AsMessageHandler]finalclassDemoHandler{
publicfunction__invoke(DemoMessage $message): void{
// do something with $message
}
}
Copied!
It's also possible to set the attribute on the method:
EXT:my_extension/Classes/Queue/Handler.php
<?phpnamespaceMyVendor\MyExtension\Queue\Handler;
useMyVendor\MyExtension\Queue\Message\DemoMessage;
useSymfony\Component\Messenger\Attribute\AsMessageHandler;
finalclassDemoHandler{
#[AsMessageHandler]publicfunction__invoke(DemoMessage $message): void{
// do something with $message
}
}
Copied!
Impact
The registration of services as message handlers has been simplified by
respecting the
\Symfony\Component\Messenger\Attribute\AsMessageHandler
attribute. When using this attribute, there is no need to register such
service in the Configuration/Services.yaml file anymore. Existing
configuration will work as before.
Feature: #101807 - Automatic inclusion of user TSconfig of extensions
Extension authors can now put a file named
Configuration/user.tsconfig in their extension folder.
This file is then recognized to load the contents as global user TSconfig
for the whole TYPO3 installation during build-time. This is
more performant than the existing solution using
ExtensionManagementUtility::addUserTSConfig() in
ext_localconf.php, which is added to
$TYPO3_CONF_VARS[SYS][defaultUserTSconfig] during runtime.
Impact
When a file is created, the user TSconfig is loaded automatically without a
custom registration, cached within the Core caches, and more
performant than the existing registration format. The old registration
format has been marked as deprecated, see
Deprecated ExtensionManagementUtility::addUserTSConfig()
for more details.
The PSR-14 event
\TYPO3\CMS\Core\TypoScript\IncludeTree\Event\BeforeLoadedPageTsConfigEvent
can be used to add global static page TSconfig before anything else is loaded.
This is especially useful, if page TSconfig is generated automatically as a
string from a PHP function.
It is important to understand that this config is considered static and thus
should not depend on runtime / request.
Example
<?phpnamespaceVendor\MyExtension\EventListener;
useTYPO3\CMS\Core\Attribute\AsEventListener;
useTYPO3\CMS\Core\TypoScript\IncludeTree\Event\BeforeLoadedPageTsConfigEvent;
#[AsEventListener(identifier: 'vendor/my-extension/global-pagetsconfig')]finalclassAddGlobalPageTsConfig{
publicfunction__invoke(BeforeLoadedPageTsConfigEvent $event): void{
$event->addTsConfig('global = a global setting');
}
}
Copied!
Impact
Developers are able to define an event listener which is dispatched before any
other page TSconfig is loaded.
The PSR-14 event
\TYPO3\CMS\Core\TypoScript\IncludeTree\Event\BeforeLoadedUserTsConfigEvent
can be used to add global static user TSconfig before anything else is loaded.
This is especially useful, if user TSconfig is generated automatically as a
string from a PHP function.
It is important to understand that this config is considered static and thus
should not depend on runtime / request.
Example
<?phpnamespaceVendor\MyExtension\EventListener;
useTYPO3\CMS\Core\Attribute\AsEventListener;
useTYPO3\CMS\Core\TypoScript\IncludeTree\Event\BeforeLoadedUserTsConfigEvent;
#[AsEventListener(identifier: 'vendor/my-extension/global-usertsconfig')]finalclassAddGlobalUserTsConfig{
publicfunction__invoke(BeforeLoadedUserTsConfigEvent $event): void{
$event->addTsConfig('global = a global setting');
}
}
Copied!
Impact
Developers are able to define an event listener which is dispatched before any
other user TSconfig is loaded.
Feature: #101843 - Allow configuration of color palettes in FormEngine
TYPO3 uses a color picker component that already supports color palettes, or
swatches. Integrators are now able to configure colors and assign colors to
palettes. Palettes then may be used within FormEngine.
Impact
In case commonly used colors or, for example, colors defined in a corporate design should
be made accessible in an easy way, integrators may configure multiple color palettes
to be used in FormEngine via page TSconfig.
EXT:my_sitepackage/Configuration/page.tsconfig
# Configure colors and assign colors to palettes
colorPalettes {
colors {
typo3 {
value = #ff8700
}
blue {
value = #0080c9
}
darkgray {
value = #515151
}
valid {
value = #5abc55
}
error {
value = #dd123d
}
}
palettes {
main = typo3
key_colors = typo3, blue, darkgray
messages = valid, error
}
}
# Assign palette to a specific field
TCEFORM.[table].[field].colorPalette = messages# Assign palette to all color pickers used in a table
TCEFORM.[table].colorPalette = key_colors# Assign global palette
TCEFORM.colorPalette = main
Copied!
Configuration allows to define the color palette either on a specific field of
a table, for all fields within a table or a global configuration affecting all
color pickers within FormEngine. If no palette is defined, FormEngine falls
back to all configured colors.
Feature: #101933 - Dispatch AfterUserLoggedInEvent for frontend user login
The
AfterUserLoggedInEvent PSR-14 event, which has been introduced
with TYPO3 12.3, is now also triggered, when a frontend user has successfully
been authenticated.
The Ajax API (
@typo3/core/ajax/ajax-request) has been enhanced to accept
native URL-related objects.
Impact
The constructor now accepts a
URL object as argument, along with the
already established string type. Also, the
withQueryArguments() method
accepts an object of type
URLSearchParams as argument.
Example
import AjaxRequest from'@typo3/core/ajax/ajax-request.js';
const url = new URL('https://example.com/page/1/2/');
const queryArguments = new URLSearchParams({
foo: 'bar',
baz: 'bencer'
});
const request = new AjaxRequest(url).withQueryArguments(queryArguments);
request.get().then(/* ... */);
A new native backed enum
\TYPO3\CMS\Core\Resource\FileType is
introduced as a replacement for the public FILETYPE_* constants in
\TYPO3\CMS\Core\Resource\AbstractFile
Impact
The new
\TYPO3\CMS\Core\Resource\FileType native backed enum is meant
to be a drop-in replacement for the former public
FILETYPE_* constants:
A new PSR-14 event
\TYPO3\CMS\Core\Configuration\Event\BeforeTcaOverridesEvent
has been introduced, enabling developers to listen to the state between loaded
base TCA and merging of TCA overrides.
The new PSR-14 event can be used to dynamically generate TCA and add it as additional
base TCA. This is especially useful for "TCA generator" extensions, which add
TCA based on another resource, while still enabling users to override TCA via
the known TCA overrides API.
Note
$GLOBALS['TCA'] is not set at this point. Event listeners can
only work on the TCA coming from
$event->getTca() and must not access
$GLOBALS['TCA'] .
Note
Please note that TCA is always "runtime cached". This means that dynamic
additions must never depend on runtime state, for example, the current PSR-7
request or similar, because such information might not even exist when
the first call is done, for example, from CLI.
Feature: #102072 - Allow redirect filtering by "protected" state
The Redirects administration module now allows to filter redirects
based on the
protected state. Additionally, protected redirects now
show a lock icon in the list of redirects, so it is better visualized, that a
redirect is protected and excluded from automatic deletion (for example, with
redirects:cleanup).
Impact
The administration of redirects has become more user-friendly, because users
can now easily filter protected redirects in the Redirects
administration module.
Feature: #102077 - Allow custom default value in getFormValue() conditions function
The
getFormValue() function can be used in conditions of form variants to
safely retrieve form values. Before, null was returned as default value. This
made it impossible to use this, for example, with the
in operator to check
values in multi-value form fields. An additional check was necessary to avoid
type issues:
variants:-identifier:variant-1condition:'getFormValue("multiCheckbox") && "foo" in getFormValue("multiCheckbox")'
Copied!
A second argument has been added to this function to set a custom default value.
This allows shortening conditions accordingly:
variants:-identifier:variant-1condition:'"foo" in getFormValue("multiCheckbox", [])'
Copied!
Impact
Form variant conditions can be shortened.
Feature: #102177 - WebP support for images generated by GIFBUILDER
GIFBUILDER, the image manipulation library for TypoScript based on GDlib, a PHP
extension bundled into PHP, now also supports generating resulting files of
type "webp".
WebP is an image format, that is supported by all modern browsers, and usually
has a better compression (= smaller file size) than jpg files.
Impact
If defined via format=webp within a GifBuilder setup, the generated files are
now webp instead of png (the default).
It is possible to define the quality of a webp image similar to jpg images
globally via
$TYPO3_CONF_VARS['GFX']['webp_quality'] or via TypoScript's
"quality" property on a per-image basis. Setting the quality to "101" equivalents
to "lossless" compression.
A new test in the Environment module / Install Tool can be used to check if the
bundled GDlib extension of your PHP version supports the WebP image format.
Feature: #102496 - Introduce global Doctrine DBAL driver middlewares
Since v3, Doctrine DBAL supports adding custom driver middlewares. These
middlewares act as a decorator around the actual Driver component.
Subsequently, the Connection, Statement and Result components can be
decorated as well. These middlewares must implement the
\Doctrine\DBAL\Driver\Middleware interface.
A common use case would be a middleware for implementing SQL logging capabilities.
Now it's also possible to register global driver middlewares once, which are applied
to all configured connections and then the specific connection middlewares.
Do not remove or disable provided global Core driver middlewares which are
essential.
Registering a new global driver middleware
useMyVendor\MyExt\Doctrine\Driver\CustomGlobalDriverMiddleware;
// Register a global middleware
$GLOBALS['TYPO3_CONF_VARS']['DB']['globalDriverMiddlewares']['my-ext/custom-global-driver-middleware'] = [
'target' => CustomGlobalDriverMiddleware::class,
'after' [
// NOTE: Custom driver middleware should be registered after essential// TYPO3 Core driver middlewares. Use the following identifiers// to ensure that.'typo3/core/custom-platform-driver-middleware',
'typo3/core/custom-pdo-driver-result-middleware',
],
];
Copied!
Disable a global middleware for a specific connection
useMyVendor\MyExt\Doctrine\Driver\CustomGlobalDriverMiddleware;
// Register a global middleware
$GLOBALS['TYPO3_CONF_VARS']['DB']['globalDriverMiddlewares']['my-ext/custom-global-driver-middleware'] = [
'target' => CustomGlobalDriverMiddleware::class,
'after' [
// NOTE: Custom driver middleware should be registered after essential// TYPO3 Core driver middlewares. Use the following identifiers// to ensure that.'typo3/core/custom-platform-driver-middleware',
'typo3/core/custom-pdo-driver-result-middleware',
],
];
// Disable a global driver middleware for a specific connection
$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['SecondDatabase']['driverMiddlewares']['my-ext/custom-global-driver-middleware']['disabled'] = true;
Copied!
Impact
Using custom global middlewares allows to enhance the functionality of Doctrine
components for all connections.
Feature: #102581 - PSR-14 event for modifying ContentObjectRenderer
A new PSR-14 event
\TYPO3\CMS\Frontend\ContentObject\Event\AfterContentObjectRendererInitializedEvent
has been introduced which serves as a drop-in replacement for the now removed
hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['postInit'] .
The event is being dispatched after
ContentObjectRenderer has been
initialized in its
start() method. The
ContentObjectRenderer
instance can be accessed using the
getContentObjectRenderer() method.
Example
The event listener class, using the PHP attribute
#[AsEventListener] for
registration:
A new CLI Symfony command option
--all is added to the
CLI command
bin/typo3 cleanup:localprocessedfiles that allows
to reset all entries in the database to force re-creating processed
files.
When developing FAL features or updating installations with large
user-generated content in fileadmin storages, it may be helpful to
clean the
sys_file_processedfile database table completely to
force a rebuild (i.e. when new FAL processors are added).
This table holds all locally generated processed files with
specific crop or size variants (or references to unaltered
originals, or "proxy" entries).
The new command option will also report the numbers of deleted records
before execution, and allows you to review execution. It is
not set by default.
Impact
It is now possible to use the
--all CLI command option for
bin/typo3 cleanup:localprocessedfiles that allows to not
only clear missing processed files, but also existing ones.
TYPO3 v12 introduced the ability to register Doctrine DBAL driver middlewares for connections,
using a simple
'identifier' => MyClass::class,' configuration schema.
TYPO3 v13 introduces Doctrine DBAL driver middleware registration on a global configuration
level, allow extension authors to register middleware once but using it for all connections.
The way to register and order PSR-15 middlewares has proven to be a reliable way,
and understood by extension authors and integrators.
TYPO3 makes the global and connection driver middleware configuration sortable using the
DependencyOrderingService (
\TYPO3\CMS\Core\Service\DependencyOrderingService )
similar to the PSR-15 middleware stack. Available structure for a middleware configuration is:
Basic driver middleware configuration array and PHPStan doc-block definition
/** @var array{target: string, disabled?: bool, after?: string[], before?: string[]} $middlewareConfiguration */
$middlewareConfiguration = [
// target is required - for example use MyDriverMiddleware::class'target' => 'class fqdn',
// disabled can be used to disable a global middleware for a specific// connection. This is optional and defaults to `false` if not provided'disabled' => false,
// list of middleware identifiers, the current middleware should be registered after'after' => [
// NOTE: Custom driver middleware should be registered after essential// TYPO3 Core driver middlewares. Use the following identifiers// to ensure that.'typo3/core/custom-platform-driver-middleware',
'typo3/core/custom-pdo-driver-result-middleware',
],
// list of middleware identifiers, the current middleware should be registered before'before' => [
'some-driver-middleware-identifier',
],
];
// Register global driver middleware
$GLOBALS['TYPO3_CONF_VARS']['DB']['globalDriverMiddlewares']['global-driver-middleware-identifier']
= $middlewareConfiguration;
// Register connection driver middleware
$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['SecondDatabase']['driverMiddlewares']['connection-driver-middleware-identifier']
= $middlewareConfiguration;
// Simple disable a global driver middleware for a connection
$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['SecondDatabase']['driverMiddlewares']['global-driver-middleware-identifier'] = [
// to disable a global driver middleware, setting disabled to true for a connection// is enough. Repeating target, after and/or before configuration is not required.'disabled' => false,
];
Copied!
Note
All custom driver middlewares, global or connection based, should be placed after the
'typo3/core/custom-platform-driver-middleware' and 'typo3/core/custom-pdo-driver-result-middleware'
driver middleware to ensure essential Core driver middlewares has been processed first.
Tip
If ext:lowlevel is installed and active, a Doctrine DBAL Driver Middleware section
is provided to view the raw middleware configuration and the ordered middleware for each
connection.
Impact
Using custom driver middlewares allows to enhance the functionality of Doctrine
components for all connections or a specific connection and have control over
the sorting configuration - and it's now also possible to disable global driver
middleware for a specific connection.
Since v3, Doctrine DBAL supports adding custom driver middlewares. These
middlewares act as a decorator around the actual Driver component.
Subsequently, the Connection, Statement and Result components can be
decorated as well. These middlewares must implement the
\Doctrine\DBAL\Driver\Middleware interface.
That means, that Doctrine DBAL driver middlewares can be registered globally for
all connections or for specific connections. Due to the nature of the decorator
pattern it may become hard to determine for specific configuration or drivers,
if a middleware needs only be executed for a subset, for example only specific
drivers.
TYPO3 now provides a custom
\TYPO3\CMS\Core\Database\Middleware\UsableForConnectionInterface
driver middleware interface which requires the implementation of the method
This allows to decide if a middleware should be used for specific connection,
either based on the
$connectionName or the
$connectionParams,
for example the concrete
$connectionParams['driver'].
Note
Real use cases to use this interface should be rare edge cases, usually
a driver middleware should only be configured on a connection where is
needed - or does not harm if used for all connection types as global
driver middleware.
Custom driver middleware example using the interface
namespaceMyVendor\MyExt\DoctrineDBAL;
useDoctrine\DBAL\Driver\ConnectionasDriverConnection;
// Using the abstract class minimize the methods to implement and therefore// reduces a lot of boilerplate code. Override only methods needed to be// customized.useDoctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware;
finalclassCustomDriverextendsAbstractDriverMiddleware{
publicfunctionconnect(#[\SensitiveParameter] array $params): DriverConnection{
$connection = parent::connect($params);
// @todo Do something custom on connect, for example wrapping the driver// connection class or executing some queries on connect.return $connection;
}
}
namespaceMyVendor\MyExt\DoctrineDBAL;
useDoctrine\DBAL\DriverasDoctrineDriverInterface;
useMyVendor\MyExt\DoctrineDBAL\CustomDriverasMyCustomDriver;
useTYPO3\CMS\Core\Database\Middleware\UsableForConnectionInterface;
finalclassCustomMiddlewareimplementsUsableForConnectionInterface{
publicfunctionwrap(DoctrineDriverInterface $driver): DoctrineDriverInterface{
// Wrap the original or already wrapped driver with our custom driver// decoration class to provide additional features.returnnew MyCustomDriver($driver);
}
publicfunctioncanBeUsedForConnection(
string $identifier,
array $connectionParams
): bool{
// Only use this driver middleware, if the configured connection driver// is 'pdo_sqlite' (sqlite using php-ext PDO).return ($connectionParams['driver'] ?? '') === 'pdo_sqlite';
}
}
useMyVendor\MyExt\DoctrineDBAL\CustomMiddleware;
$middlewareConfiguration = [
'target' => CustomMiddleware::class,
'after' => [
// NOTE: Custom driver middleware should be registered after essential// TYPO3 Core driver middlewares. Use the following identifiers// to ensure that.'typo3/core/custom-platform-driver-middleware',
'typo3/core/custom-pdo-driver-result-middleware',
],
];
// Register middleware globally, to include it for all connection which// uses the 'pdo_sqlite' driver.
$GLOBALS['TYPO3_CONF_VARS']['DB']['globalDriverMiddlewares']['myvendor/myext/custom-pdosqlite-driver-middleware']
= $middlewareConfiguration;
Copied!
Impact
Extension author can provide conditional-based Doctrine driver middlewares by
implementing the
\TYPO3\CMS\Core\Database\Middleware\UsableForConnectionInterface
along with the
canBeUsedForConnection() method.
Feature: #102614 - PSR-14 event for modifying GetData result
A new PSR-14 event
\TYPO3\CMS\Frontend\ContentObject\Event\AfterGetDataResolvedEvent
has been introduced which serves as a drop-in replacement for the now removed
hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getData'] .
The event is being dispatched just before
ContentObjectRenderer->getData()
is about to return the resolved "data". The event is therefore in comparison to
the removed hook not dispatched for every section of the parameter string, but
only once, making the former
$secVal superfluous.
To modify the
getData() result, the following methods are available:
setResult(): Allows to set the "data" to return
getResult(): Returns the resolved "data"
getParameterString(): Returns the parameter string, e.g.
field : title
getAlternativeFieldArray(): Returns the alternative field array, if provided
getContentObjectRenderer(): Returns the current
ContentObjectRenderer instance
Example
The event listener class, using the PHP attribute
#[AsEventListener] for
registration:
A new PSR-14 event
\TYPO3\CMS\Frontend\ContentObject\Event\ModifyImageSourceCollectionEvent
has been introduced which serves as a drop-in replacement for the now removed
hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImageSourceCollection'] .
The event is being dispatched in
ContentObjectRenderer->getImageSourceCollection()
for each configured
sourceCollection and allows to enrich the final
source collection result.
To modify
getImageSourceCollection() result, the following methods are available:
setSourceCollection(): Allows to modify a source collection based on the corresponding configuration
getSourceCollection(): Returns the source collection
getFullSourceCollection(): Returns the current full source collection, being enhanced by the current
sourceCollection
getSourceConfiguration(): Returns the current
sourceCollection configuration
getSourceRenderConfiguration(): Returns the corresponding renderer configuration for the source collection
getContentObjectRenderer(): Returns the current
ContentObjectRenderer instance
Example
The event listener class, using the PHP attribute
#[AsEventListener] for
registration:
TYPO3 v13 introduces the new frontend-related PSR-7 request attribute
frontend.cache.instruction
implemented by class
\TYPO3\CMS\Frontend\Cache\CacheInstruction . This replaces the
previous
TyposcriptFrontendController->no_cache property and boolean
noCache request
attribute.
Impact
The attribute can be used by middlewares to disable cache mechanics of the frontend rendering.
In early middlewares before
typo3/cms-frontend/tsfe, the attribute may or may not exist
already. A safe way to interact with it is like this:
A new custom PHP attribute
\TYPO3\CMS\Core\Attribute\AsController has
been introduced in order to automatically tag backend controllers, making them
available in the service container and enabling dependency injection.
Instead of adding the
backend.controller manually, the attribute
can be set on the class:
TYPO3 v13 introduces the new frontend-related PSR-7 request attribute
frontend.page.information
implemented by class
\TYPO3\CMS\Frontend\Page\PageInformation . The object aims to replace
various page related properties of
\TYPO3\CMS\Frontend\Controller\TyposcriptFrontendController.
Note the class is currently still marked as experimental. Extension authors are however encouraged
to use information from this request attribute instead of the
TyposcriptFrontendController
properties already: TYPO3 Core v13 will try to not break especially the getters / properties not
marked as
@internal.
Impact
There are three properties in
TyposcriptFrontendController frequently used by extensions,
which are now modeled in
\TYPO3\CMS\Frontend\Page\PageInformation . The attribute is
attached to the PSR-7 frontend request by middleware
TypoScriptFrontendInitialization,
middlewares below can rely on existence of that attribute. Examples:
They serve as more powerful replacement of the removed,
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['stdWrap'] hook.
Instead of registering one hook class, implementing four different methods - due
to the deprecated interface
- extension authors are now able to register dedicated listeners. Next to the
individual events, it's also possible to register listeners to listen on the
parent
\TYPO3\CMS\Frontend\ContentObject\Event\EnhanceStdWrapEvent . Since
this event is extended by all other events, registered listeners are called
on each occurrence.
All events provide the same functionality. The difference is only the execution
order in which they are called in the stdWrap processing chain.
Available methods:
getContent() - Returns the current content (stdWrap result)
setContent() - Allows to modify the final content (stdWrap result)
getConfiguration() - Returns the corresponding TypoScript configuration
getContentObjectRenderer() - Returns the current
ContentObjectRenderer instance
Example
The event listener class, using the PHP attribute
#[AsEventListener] for
registration:
useTYPO3\CMS\Core\Attribute\AsEventListener;
useTYPO3\CMS\Frontend\ContentObject\Event\AfterStdWrapFunctionsExecutedEvent;
useTYPO3\CMS\Frontend\ContentObject\Event\AfterStdWrapFunctionsInitializedEvent;
useTYPO3\CMS\Frontend\ContentObject\Event\BeforeStdWrapFunctionsInitializedEvent;
useTYPO3\CMS\Frontend\ContentObject\Event\EnhanceStdWrapEvent;
finalclassEnhanceStdWrapEventListener{
#[AsEventListener]publicfunction__invoke(EnhanceStdWrapEvent $event): void{
// listen to all events
}
#[AsEventListener]publicfunctionindividualListener(BeforeStdWrapFunctionsInitializedEvent $event): void{
// listen on BeforeStdWrapFunctionsInitializedEvent only
}
#[AsEventListener]publicfunctionlistenOnMultipleEvents(AfterStdWrapFunctionsInitializedEvent|AfterStdWrapFunctionsExecutedEvent $event): void{
// Union type to listen to different events
}
}
Copied!
Impact
Using the new PSR-14 events, it's now possible to fully influence the stdWrap
functionality in TYPO3's Core API class
\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer .
Using the new individual events, developers are now also able to simplify their
code by just listening for the relevant parts in the stdWrap processing.
Feature: #102755 - PSR-14 event for modifying getImageResource result
A new PSR-14 event
\TYPO3\CMS\Frontend\ContentObject\Event\AfterImageResourceResolvedEvent
has been introduced which serves as a replacement for the now removed
hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImgResource'] .
The event is being dispatched just before
ContentObjectRenderer->getImgResource()
is about to return the resolved
\TYPO3\CMS\Core\Imaging\ImageResource DTO.
The event is therefore in comparison to the removed hook always dispatched,
even if no
ImageResource could be resolved. In this case, the
corresponding return value is
null.
Note
Instead of an
array
ContentObjectRenderer now handles
the image resource with the new
ImageResource DTO.
This means,
ContentObjectRenderer->getImgResource() returns either the new
DTO or null.
To modify the
getImgResource() result, the following methods are available:
setImageResource(): Allows to set the
ImageResource to return
getImageResource(): Returns the resolved
ImageResource or
null
getFile(): Returns the
$file, passed to the
getImageResource function
getFileArray(): Returns the
$fileArray, passed to the
getImageResource function
Example
The event listener class, using the PHP attribute
#[AsEventListener] for
registration:
Using the new PSR-14 Event, it's now possible to modify the resolved
getImageResource() result.
Additionally, the
ImageResource DTO allows an improved API as
developers do no longer have to deal with unnamed array keys but benefit
from the object-oriented approach, using corresponding getter and setter.
Feature: #102761 - Introduce class to generate/validate HMAC hashes
A new class
\TYPO3\CMS\Core\Crypto\HashService has been introduced to
enhance the security and flexibility in generating Hash-based Message
Authentication Codes (HMACs). This class combines the functionality of
GeneralUtility::hmac() and Extbase's
HashService, while
enforcing the use of an additional, mandatory secret for HMAC generation and
HMAC string validation.
Impact
Using the new class
\TYPO3\CMS\Core\Crypto\HashService , it is now
possible to mitigate the risk of HMAC reuse in unauthorized scenarios for the
same input.
Feature: #102793 - PSR-14 event for modifying default constraints in PageRepository
The API class
\TYPO3\CMS\Core\Domain\Repository\PageRepository has a
method
getDefaultConstraints() which accumulates common restrictions for
a database query to limit a query for TCA-based tables in order to filter out
disabled, or scheduled records.
A new PSR-14 event
\TYPO3\CMS\Core\Domain\Event\ModifyDefaultConstraintsForDatabaseQueryEvent has
been introduced, which allows to remove, alter or add constraints compiled by
TYPO3 for a specific table to further limit these constraints.
Impact
The new event contains a list of
CompositeExpression objects, allowing
to modify them via the
getConstraints() and
setConstraints(array $constraints) methods.
Additional information, such as the used
ExpressionBuilder object or the
table name and the current
Context are also available within the event.
Feature: #102806 - BeforePageIsRetrievedEvent in PageRepository
A new PSR-14 event
\TYPO3\CMS\Core\Domain\Event\BeforePageIsRetrievedEvent
has been introduced, which serves as a more powerful replacement of the removed
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPage']
hook.
The new event therefore allows to modify the resolving of page records within
\TYPO3\CMS\Core\Domain\PageRepository->getPage().
Impact
The event can be used to alter the incoming page ID or to even fetch a fully
loaded page object before the default TYPO3 behaviour is executed, effectively
bypassing the default page resolving.
To modify the incoming parameters, the following methods are available:
setPageId(): Allows to set the
$uid of a page to resolve
setPage(): Allows to set a
Page object which bypasses TYPO3 Core functionality
Example
The event listener class, using the PHP attribute
#[AsEventListener] for
registration:
Content element types defined in TCA field
CType are now automatically
registered for the New Content Element Wizard. This replaces the former extra
step to define a wizard entry in page TSconfig
mod.wizards.newContentElement.wizardItems.<group>.
The item entries
value,
label,
description,
group
and
icon are used to define the wizard entry.
The migration looks as follows:
Before:
EXT:my_extension/Configuration/page.tsconfig
# Add a new element (header) to the "common" group
mod.wizards.newContentElement.wizardItems.common.elements.header {
iconIdentifier = content-header
title = LLL:EXT:backend/Resources/Private/Language/locallang_db_new_content_el.xlf:common_headerOnly_title
description = LLL:EXT:backend/Resources/Private/Language/locallang_db_new_content_el.xlf:common_headerOnly_description
tt_content_defValues {
CType = header
}
}
mod.wizards.newContentElement.wizardItems.common.show := addToList(header)
Probably it will only be necessary to migrate the
description,
as the other values are already set most of the time. This can be done
for plugins as well, using the
$pluginDescription argument of
the
ExtensionUtility::registerPlugin() method.
Additionally, the group
common is now called
default.
This will be migrated automatically for page TSconfig.
The
saveAndClose option is now defined through TCA as well:
Removing items from the select box still works as before through page
TSconfig
TCEFORM. This will remove both the TCA items entry
and the wizard entry.
To hide groups or elements in the wizard a new option
removeItems
is available.
EXT:my_extension/Configuration/page.tsconfig
# Before
mod.wizards.newContentElement.wizardItems.special.show := removeFromList(html)
# After
mod.wizards.newContentElement.wizardItems.special.removeItems := addToList(html)
Copied!
As mentioned, it's also possible to remove a whole group:
EXT:my_extension/Configuration/page.tsconfig
# This will remove the "menu" group
mod.wizards.newContentElement.wizardItems.removeItems := addToList(menu)
Copied!
Impact
The groups and elements of the new Content Element Wizard are now registered
automatically from the TCA type field. This eases the creation of new content
elements and plugins for integrators and developers, since the whole definition
is done at a central place.
Feature: #102835 - Add PSR-14 events to manipulate TypoLinkCodecService
TYPO3's main API for encoding and decoding TypoLink's has been extended
and now provides two new PSR-14 events
\TYPO3\CMS\Core\LinkHandling\Event\BeforeTypoLinkEncodedEvent
and
\TYPO3\CMS\Core\LinkHandling\Event\AfterTypoLinkDecodedEvent , which
allow developers to fully manipulate the encoding and decoding functionality.
A common use case for extensions is to extend the TypoLink parts to allow
editors adding additional information, e.g. custom attributes to be added
to the link markup. Previously, this required extensions to extended / cross
class
TypoLinkCodecService. This is no longer necessary when using the
new events.
The
BeforeTypoLinkEncodedEvent therefore allows to set
$parameters,
to be encoded while the
AfterTypoLinkDecodedEvent allows to modify the
decoded
$typoLinkParts..
Both events provide the used
$delimiter and the
$emptyValueSymbol
next to the corresponding input value, either the
$typoLinkParts to be
encoded or the
$typoLink to be decoded.
Example
The event listener class, using the PHP attribute
#[AsEventListener] for
registration:
A new PSR-14 event
\TYPO3\CMS\Frontend\ContentObject\Event\BeforeStdWrapContentStoredInCacheEvent
has been introduced which serves as a more powerful replacement for the now removed
hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['stdWrap_cacheStore'] .
The event is being dispatched just before the final stdWrap content is added to
the cache and allows to fully manipulate the
$content to be added, the
cache
$tags to be used as well as the corresponding cache
$key
and the cache
$lifetime. Therefore, listeners can use the public getter
and setter methods.
Additionally, the new event provides the full TypoScript
$configuration
and the current
$contentObjectRenderer instance.
Example
The event listener class, using the PHP attribute
#[AsEventListener] for
registration:
Using the new PSR-14 event, it's now possible to fully manipulate the content,
the cache tags as well as further relevant information, used by the caching
functionality of stdWrap.
Feature: #102855 - PSR-14 event for modifying resolved link result data
A new PSR-14 event
\TYPO3\CMS\Core\LinkHandling\Event\AfterLinkResolvedByStringRepresentationEvent
has been introduced which serves as a more powerful replacement for the now removed
hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['Link']['resolveByStringRepresentation'] .
The event is being dispatched after
LinkService has tried to resolve a
given
$urn using defined link handlers. This means, the new event is
always dispatched, even if a handler successfully resolved the
$urn
and also even in cases, TYPO3 would have thrown the
UnknownLinkHandlerException exception.
Therefore, the new event can not only be used to resolve custom link types
but also to modify the link result data of existing link handlers and
can additionally also be used to resolve situations where no handler could be
found for a t3:// URN.
The event features the following methods:
getResult() - Returns the resolved link result data
setResult() - Allows to modify the final link result data
getUrn() - Returns the link parameter (URN) to be resolved
getResolveException() - Returns the exception, which will be thrown in case no link type has been resolved
Example
The event listener class, using the PHP attribute
#[AsEventListener] for
registration:
Using the new PSR-14 event, it's now possible to fully modify the resolved
link result data from
LinkService->resolveByStringRepresentation(),
just before the result is being returned. Therefore, even the resolved data
of existing handlers can be manipulated.
Feature: #102865 - PSR-14 event for modifying loaded form definition
A new PSR-14 event
\TYPO3\CMS\Form\Mvc\Persistence\Event\AfterFormDefinitionLoadedEvent
has been introduced which allows extensions to modify loaded form definitions.
The event is being dispatched after
FormPersistenceManager has loaded
the definition from either the cache or the filesystem. In latter case, the
event is dispatched after
FormPersistenceManager has stored the loaded
definition in cache. This means, it's always possible to modify the cached
version. However, the modified form definition is then overridden by TypoScript,
in case a corresponding
formDefinitionOverrides exists.
The event features the following methods:
getFormDefinition() - Returns the loaded form definition
setFormDefinition() - Allows to modify the loaded form definition
getPersistenceIdentifier() - Returns the persistence identifier, used to load the definition
getCacheKey() - Returns the calculated cache key
Example
The event listener class, using the PHP attribute
#[AsEventListener] for
registration:
A couple of new PSR-14 events have been added to the frontend rendering chain:
BeforePageCacheIdentifierIsHashedEvent
ModifyTypoScriptConfigEvent
AfterTypoScriptDeterminedEvent
These events allow reacting and modifying details during frontend rendering related
to TypoScript determination and page cache calculation. See the event class comments
and signature for further details.
Impact
The events allow more fine grained modification of frontend TypoScript and
page cache code flow. They are substitutions of hooks that have been
available with TYPO3 versions before v13. See
Removed Frontend hooks
for details.
Feature: #102935 - PSR-14 event for package initialization functionality
A new PSR-14 event
\TYPO3\CMS\Core\Package\Event\PackageInitializationEvent
has been introduced. It allows listeners to execute custom functionality after
a package has been activated. The event is therefore being dispatched at several
places, where packages get activated. Those are e.g. on extension installation
by the extension manager, or on calling the typo3 extension:setup command. The
main component, dispatching the event however is the new
PackageActivationService. The new service is a drop-in replacement for
the
InstallUtility->install() method, which is from now on just a wrapper
around
PackageActivationService->activate(). The wrapper is used to still
pass the current instance to listeners of the
AfterPackageActivationEvent.
TYPO3 already registers a couple of listeners to this event:
Developers are able to listen to the new event before or after TYPO3 Core
listeners have been executed, using
before and
after in the
listener registration. All listeners are able to store arbitrary data
in the Event using the
addStorageEntry() method. This is also used
by the core listeners to store their result, which was previously passed
to the removedEXT:extensionmanager PSR-14 events.
Listeners can access that information using corresponding
getStorageEntry()
method. Those entries are a
PackageInitializationResult object, which
features the following methods:
getIdentifier() - Returns the entry identifier, which is the listener service name for the TYPO3 Core listeners
getResult() - Returns the result data, added by the corresponding listener
Using the new Event, listeners are equipped with following methods:
getExtensionKey() - Returns the extension key for the activated package
getPackage() - Returns the
PackageInterface object of the activated package
getContainer() - Returns the
ContainerInterface, used on activating the package
getEmitter() - Returns the emitter / the service, which has dispatched the event
hasStorageEntry() - Whether a storage entry for a given identifier exists
getStorageEntry() - Returns a storage entry for a given identifier
addStorageEntry() - Adds a storage entry (
PackageInitializationResult) to the event
removeStorageEntry() - Removes a storage entry by a given identifier
Note
In case you have previously called
InstallUtility->processExtensionSetup()
directly, you can now just dispatch the new event.
Example
The event listener class, using the PHP attribute
#[AsEventListener] for
registration, placing the listener after a specific core listener and adding
a storage entry, using the listener class name as identifier (which is
recommended and also done by TYPO3 Core):
Using the new PSR-14 event, it's now possible to execute custom functionality
when a package has been activated. Since TYPO3 Core also uses listeners to
this event, custom extensions can easily place their functionality in between
and fetch necessary information directly from the event's storage, instead of
registering dedicated listeners.
Deprecation: #87889 - TYPO3 backend entry point script deprecated
The TYPO3 backend entry point script /typo3/index.php is no longer needed and
deprecated in favor of handling all backend and frontend requests with /index.php.
It is still in place in case webserver configuration has not been adapted yet.
Note that the maintenance tool is still available via /typo3/install.php.
Impact
The TYPO3 backend route path is made configurable in order to protect against
application admin interface infrastructure enumeration (WSTG-CONF-05).
Therefore, all requests are handled by the PHP script /index.php in order to
allow for variable admin interface URLs.
(via
$GLOBALS['TYPO3_CONF_VARS']['BE']['entryPoint'] ).
Affected installations
All installations using the TYPO3 backend /typo3.
Migration
There is a silent update in place which automatically updates the
webserver configuration file when accessing the install tool, at
least for Apache and Microsoft IIS webservers.
Note: This does not work if you are not using the default configuration,
which is shipped with Core and automatically applied during the TYPO3
installation process, as basis.
If you however use a custom web server configuration you may adapt as follows:
Apache configuration
It is most important to rewrite all typo3/* requests to /index.php, but also
RewriteCond %{REQUEST_FILENAME} !-d should be removed in order for a request
to /typo3/ to be directly served via /index.php instead of the deprecated
entry point /typo3/index.php.
The class
\TYPO3\CMS\Core\Type\Icon\IconState is marked
as deprecated.
Impact
The class
\TYPO3\CMS\Core\Type\Icon\IconState will be removed in
TYPO3 v14.0. Passing an instance of this class to
\TYPO3\CMS\Core\Imaging\IconFactory->getIcon() will lead to a deprecation
level log entry.
Affected installations
All installations using the class
\TYPO3\CMS\Core\Type\Icon\IconState.
Migration
// Before
$state = \TYPO3\CMS\Core\Type\Icon\IconState::cast(
\TYPO3\CMS\Core\Type\Icon\IconState::STATE_DEFAULT
);
// After
$state = \TYPO3\CMS\Core\Imaging\IconState::STATE_DEFAULT;
The class
\TYPO3\CMS\Backend\Toolbar\Enumeration\InformationStatus has
been marked as deprecated in favour of the new nativ
enum
\TYPO3\CMS\Backend\Toolbar\InformationStatus .
Additionally, passing a
string as
$status to either
addSystemInformation() or
addSystemMessage() of
class
\TYPO3\CMS\Backend\Backend\ToolbarItems\SystemInformationToolbarItem
has been deprecated as well. An instance of the new enum has to be provided.
Impact
Usage of the class
\TYPO3\CMS\Backend\Toolbar\Enumeration\InformationStatus,
its constants or methods will trigger a PHP
E_USER_DEPRECATED error. The
class will be removed in TYPO3 v14.0.
Passing a
string as
$status to either
addSystemInformation()
or
addSystemMessage() of class
\TYPO3\CMS\Backend\Backend\ToolbarItems\SystemInformationToolbarItem will
trigger a PHP
E_USER_DEPRECATED error.
Affected installations
All installations using the class
\TYPO3\CMS\Backend\Toolbar\Enumeration\InformationStatus directly or
passing a
string as
$status to either
addSystemInformation()
or
addSystemMessage() of class
\TYPO3\CMS\Backend\Backend\ToolbarItems\SystemInformationToolbarItem .
The extension scanner will report any usage of the deprecated class as
strong match.
Migration
// Before
$status = \TYPO3\CMS\Backend\Toolbar\Enumeration\InformationStatus::cast(
\TYPO3\CMS\Backend\Toolbar\Enumeration\InformationStatus::STATUS_INFO
);
$statusString = (string)$status;
// After
$status = \TYPO3\CMS\Backend\Toolbar\Enumeration\InformationStatus::INFO;
$statusString = $status->value;
The methods
\TYPO3\CMS\Core\Versioning\VersionState::cast() and
\TYPO3\CMS\Core\Versioning\VersionState->equals() have been
marked as deprecated.
Impact
Calling the methods
\TYPO3\CMS\Core\Versioning\VersionState::cast()
and
\TYPO3\CMS\Core\Versioning\VersionState->equals() will trigger a
PHP deprecation warning.
Affected installations
TYPO3 installations calling
\TYPO3\CMS\Core\Versioning\VersionState::cast()
and
\TYPO3\CMS\Core\Versioning\VersionState->equals().
Migration
Before:
$versionState = \TYPO3\CMS\Core\Versioning\VersionState::cast($value);
if ($versionState->equals(VersionState::MOVE_POINTER) {
// ...
}
Also migrate from
\TYPO3\CMS\Core\Imaging\Event\ModifyIconForResourcePropertiesEvent->getSize()
to
\TYPO3\CMS\Core\Imaging\Event\ModifyIconForResourcePropertiesEvent->getIconSize().
When configuring
MM relations in TCA, the field
MM_hasUidField
has been obsoleted: A
uid column is only needed when
multiple
is set to true - when a record is allowed to be selected multiple times in
a relation. In this case, the
uid field is added automatically by the
database analyzer.
Impact
The TCA configuration option
MM_hasUidField is obsolete and can be removed.
The TCA migration, which is performed during TCA warmup, will automatically
remove this option and creates according log entries, if needed.
Affected installations
Instances with extensions using
MM relations may be affected.
Migration
Remove all occurrences of php:MM_hasUidField from TCA. The
uid column
is added as primary key automatically, if
multiple = true is set, otherwise
a combined primary key of the fields
uid_local,
uid_foreign plus
eventually
tablenames and
fieldname is used.
The backend
DataHandler had a functionality to verify written records
after they have been persisted in the database and log unexpected collisions.
This feature has been removed since it is rather useless with many databases
in strict mode nowadays and since the default configuration was to not
actually check single fields but to still create overhead by always
querying records from the database without benefit.
There should be little to no impact for instances, except some less database
queries when using the
DataHandler. Extensions setting the
DataHandler
properties should stop using them, they will be removed with TYPO3 v14 and
have no functionality with v13 anymore.
Affected installations
In rare cases, instances with extensions setting the
DataHandler properties
are affected. The extension scanner will find possible usages with a weak
match.
Instances setting the
TYPO3_CONF_VARS toggles in
settings.php
are updated silently by the install tool during the upgrade process to TYPO3 v13.
Migration
Extensions aiming for compatibility with TYPO3 v12 and v13 can continue to set the
properties
DataHandler->checkStoredRecords and
DataHandler->checkStoredRecords_loose,
they are kept in v13, but functionality bound to them is removed.
Extensions aiming for compatibility with TYPO3 v13 and above should remove
usages of
DataHandler->checkStoredRecords and
DataHandler->checkStoredRecords_loose,
they are without functionality in TYPO v13 and will be removed with TYPO3 v14.
The method
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig()
has been marked as deprecated in TYPO3 v13 and will be removed with TYPO3 v14.
The global configuration option
$GLOBALS['TYPO3_CONF_VARS']['BE']['defaultPageTSconfig']
has been marked as deprecated in TYPO3 v13, will be ignored and removed from instance configuration
files as silent upgrade with TYPO3 v14.
Impact
Setting default page TSconfig using
ExtensionManagementUtility::addPageTSConfig()
in ext_localconf.php files has been superseded by
Automatic inclusion of page TSconfig of extensions with
TYPO3 v12 already. The old way has been deprecated now, extensions should switch to
the new functionality by placing default page TSconfig in Configuration/page.tsconfig
files.
Affected installations
Instances with extensions using
ExtensionManagementUtility::addPageTSConfig()
or directly extending
$GLOBALS['TYPO3_CONF_VARS']['BE']['defaultPageTSconfig']
are affected: Using
ExtensionManagementUtility::addPageTSConfig() triggers a
deprecation level log message. The extension scanner will find usages of
ExtensionManagementUtility::addPageTSConfig() as strong match.
Migration
Add default page TSconfig to a Configuration/page.tsconfig file within an
extension and remove calls to
ExtensionManagementUtility::addPageTSConfig().
Placing default page TSconfig in Configuration/page.tsconfig files is
available since TYPO3 v12, extensions aiming for v12 and v13 compatibility can
simply switch over to the new way.
The method
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addUserTSConfig()
has been marked as deprecated in TYPO3 v13 and will be removed with TYPO3 v14.
The global configuration option
$GLOBALS['TYPO3_CONF_VARS']['BE']['defaultUserTSconfig']
has been marked as deprecated in TYPO3 v13, will be ignored and removed from instance configuration
files as silent upgrade with TYPO3 v14.
Impact
Setting default user TSconfig using
ExtensionManagementUtility::addUserTSConfig()
in ext_localconf.php files has been superseded by
Automatic inclusion of user TSconfig of extensions. The
old way has been deprecated, extensions should switch to the new functionality by placing
default user TSconfig in Configuration/user.tsconfig files.
Affected installations
Instances with extensions using
ExtensionManagementUtility::addUserTSConfig()
or directly extending
$GLOBALS['TYPO3_CONF_VARS']['BE']['defaultUserTSconfig']
are affected: Using
ExtensionManagementUtility::addUserTSConfig() triggers a
deprecation level log message. The extension scanner will find usages of
ExtensionManagementUtility::addUserTSConfig() as strong match.
Migration
Add default user TSconfig to a Configuration/user.tsconfig file within an
extension and remove calls to
ExtensionManagementUtility::addUserTSConfig().
Extensions with compatibility for both TYPO3 v12 and v13 should keep the old
way and switch to the new way when v12 support is dropped.
Deprecation: #101912 - Passing jQuery objects to FormEngine validation
Both methods,
validateField() and
markFieldAsChanged() accept a form
field as argument that is either of type
HTMLInputElement,
HTMLSelectElement,
HTMLTextareaElement, or
jQuery.
Passing all of the aforementioned types is supported since TYPO3 v11, therefore,
passing a jQuery object has been deprecated.
Impact
Calling any method,
validateField() or
markFieldAsChanged() with
passing jQuery-based objects will render a warning in the browser console, along
with a stacktrace to help identifying the caller code.
Affected installations
All third-party extensions using the deprecated methods of the
@typo3/backend/form-engine-validation module are affected.
Migration
Do not pass jQuery-based objects into the deprecated methods. Consider migrating
away from jQuery at all, or use
$field.get(0) as interim solution.
The JavaScript module specifier for modules shipped with the previous "t3editor"
extension has changed from
@typo3/t3editor/ to
@typo3/backend/code-editor/. The old specifier
@typo3/t3editor/ is
still available, but deprecated.
The value of the existing TCA option renderType switched from t3editor to
codeEditor.
Impact
The module specifier
@typo3/t3editor/ automatically maps to
@typo3/backend/code-editor/. The TCA render type t3editor is
automatically migrated to codeEditor, triggering a deprecation log entry.
Affected installations
All extensions using t3editor are affected.
Migration
The JavaScript module namespace
@typo3/t3editor/ maps to
@typo3/backend/code-editor/.
Rewrite all TCA render types usages of t3editor to codeEditor.
Deprecation: #102581 - Unused Interface for ContentObjectRenderer hook
To use the
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['postInit']
hook, implementations had to implement
\TYPO3\CMS\Frontend\ContentObject\ContentObjectPostInitHookInterface.
Since the mentioned hook has been removed,
the interface is not in use anymore and has been marked as deprecated.
Impact
Using the interface has no effect anymore and the extension scanner will
report any usage.
Affected installations
TYPO3 installations using the PHP interface in custom extension code.
Migration
The PHP interface is still available for TYPO3 v13, so extensions can
provide a version which is compatible with TYPO3 v12 (using the hook)
and TYPO3 v13 (using the new PSR-14 event),
at the same time. Remove any usage of the PHP interface and use the new PSR-14
event to avoid any further problems in TYPO3 v14+.
Using the simple
'identifier' => MyClass::class,' configuration schema to register
Doctrine DBAL middlewares for connection is now deprecated in favour of using a sortable
registration configuration similar to the PSR-15 middleware registration.
Impact
Connection driver middleware registration using a simple string will emit a corresponding
message to the deprecation log since TYPO3 v13, but converting it on-the-fly to a valid
array configuration.
Affected installations
TYPO3 instances using third-party extension providing custom Doctrine DBAL driver
middlewares and having them registered for one or more connections will emit a
deprecation message since TYPO3 v13 and either an exception with TYPO3 v14 or
an PHP type error.
Migration
Simple driver middleware registration, for example
Registration for driver middlewares for TYPO3 v12 and v13
Extension authors providing dual Core support with one extension version can use the
Typo3Version class to provide the configuration suitable for the Core version
and avoiding the deprecation notice:
Using the
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getData']
hook, implementations had to implement
\TYPO3\CMS\Frontend\ContentObject\ContentObjectGetDataHookInterface.
Since the mentioned hook has been removed,
the interface is not in use anymore and has been marked as deprecated.
Impact
Using the interface has no effect anymore and the extension scanner will
report any usage.
Affected installations
TYPO3 installations using the PHP interface in custom extension code.
Migration
The PHP interface is still available for TYPO3 v13, so extensions can
provide a version which is compatible with TYPO3 v12 (using the hook)
and TYPO3 v13 (using the new PSR-14 event),
at the same time. Remove any usage of the PHP interface and use the new PSR-14
event to avoid any further problems in TYPO3 v14+.
Deprecation: #102624 - Unused Interface for getImageSourceCollection Hook
Using the
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImageSourceCollection']
hook, implementations had to implement
\TYPO3\CMS\Frontend\ContentObject\ContentObjectOneSourceCollectionHookInterface.
Since the mentioned hook has been removed,
the interface is not in use anymore and has been marked as deprecated.
Impact
Using the interface has no effect anymore and the extension scanner will
report any usage.
Affected installations
TYPO3 installations using the PHP interface in custom extension code.
Migration
The PHP interface is still available for TYPO3 v13, so extensions can
provide a version which is compatible with TYPO3 v12 (using the hook)
and TYPO3 v13 (using the new PSR-14 event),
at the same time. Remove any usage of the PHP interface and use the new PSR-14
event to avoid any further problems in TYPO3 v14+.
Deprecation: #102631 - Deprecated Controller attribute for auto configuring backend controllers
In order to unify PHP attribute naming, the former introduced
\TYPO3\CMS\Backend\Attribute\Controller attribute has been deprecated
and is replaced by the new
\TYPO3\CMS\Backend\Attribute\AsController attribute.
Impact
The attribute has changed from
\TYPO3\CMS\Backend\Attribute\Controller
to
\TYPO3\CMS\Backend\Attribute\AsController and the old name
has been deprecated.
Affected installations
All installations using the deprecated attribute
\TYPO3\CMS\Backend\Attribute\Controller. The extension
scanner will report usages.
Migration
Replace usages with the new attribute
\TYPO3\CMS\Backend\Attribute\AsController
in custom extension code.
Deprecation: #102745 - Unused interface for stdWrap hook
The ContentObject stdWrap hook required hook implementations to implement the
\TYPO3\CMS\Frontend\ContentObject\ContentObjectStdWrapHookInterface.
Since the mentioned hook has been removed,
the interface is not in use anymore and has been marked as deprecated.
Impact
Using the interface has no effect anymore and the extension scanner will
report any usage.
Affected installations
TYPO3 installations using the PHP interface in custom extension code.
Migration
The PHP interface is still available for TYPO3 v13, so extensions can
provide a version which is compatible with TYPO3 v12 (using the hook)
and TYPO3 v13 (using the new PSR-14 events),
at the same time. Remove any usage of the PHP interface and use the new PSR-14
events to avoid any further problems in TYPO3 v14+.
Deprecation: #102755 - Unused interface for getImageResource hook
Using the
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImgResource']
hook, implementations had to implement
\TYPO3\CMS\Frontend\ContentObject\ContentObjectGetImageResourceHookInterface.
Since the mentioned hook has been removed,
the interface is not in use anymore and has been marked as deprecated.
Impact
Using the interface has no effect anymore and the extension scanner will
report any usage.
Affected installations
TYPO3 installations using the PHP interface in custom extension code.
Migration
The PHP interface is still available for TYPO3 v13, so extensions can
provide a version which is compatible with TYPO3 v12 (using the hook)
and TYPO3 v13 (using the new PSR-14 event),
at the same time. Remove any usage of the PHP interface and use the new PSR-14
event to avoid any further problems in TYPO3 v14+.
Internal class
\TYPO3\CMS\Extbase\Security\Cryptography\HashService
is deprecated in favor of
\TYPO3\CMS\Core\Crypto\HashService ,
which requires an additional secret to prevent re-using generated hashes in
different contexts.
Impact
Using class
\TYPO3\CMS\Extbase\Security\Cryptography\HashService will
trigger a PHP deprecation warning.
Affected installations
TYPO3 installations with custom extensions using
\TYPO3\CMS\Extbase\Security\Cryptography\HashService.
Migration
Class
\TYPO3\CMS\Core\Crypto\HashService must be used to migrate.
One of the common PHP APIs used in TYPO3 Core for fetching records is
\TYPO3\CMS\Core\Domain\Repository\PageRepository . The method
enableFields() is used to enhance a database query with additional
restrictions such as filtering out versioned records from workspaces, hidden
database entries or scheduled database entries.
This method has been marked as deprecated in favor of a new method
getDefaultConstraints().
Impact
Calling the method will trigger a PHP deprecation warning.
Affected installations
TYPO3 installations with custom extensions using the method
enableFields()
of the
PageRepository class.
Migration
A new method called
getDefaultConstraints() has been introduced
which supersedes the old method. The new method returns an array of
CompositeExpression objects, which can be used instead.
Using the hooks
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][\TYPO3\CMS\Core\Domain\PageRepository::class]['init']
and
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPage'] ,
implementations had to implement the
\TYPO3\CMS\Core\Domain\Repository\PageRepositoryInitHookInterface
respectively
\TYPO3\CMS\Core\Domain\Repository\PageRepositoryGetPageHookInterface
interface.
Since the mentioned hooks have been removed,
the interfaces are not in use anymore and have been marked as deprecated.
Impact
The removed hooks are no longer evaluated, thus the interfaces are not in use
anymore, but are kept for backwards-compatibility. As they are interfaces, they
do not trigger a deprecation warning.
Affected installations
TYPO3 installations with third-party extensions utilizing the hooks and their
interfaces.
The extension scanner in the install tool can find any usages to these
interfaces and their interfaces.
Migration
The PHP interfaces are still available for TYPO3 v13, so extensions can
provide a version which is compatible with TYPO3 v12 (using the hooks)
and TYPO3 v13 (using the new PSR-14 event),
at the same time. Remove any usage of the PHP interface and use the new PSR-14
event to avoid any further problems in TYPO3 v14+.
The PHP method
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExtensionIcon
has been deprecated in favor of
\TYPO3\CMS\Core\Package\Package->getPackageIcon.
Impact
Calling the method
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExtensionIcon
will trigger a PHP deprecation warning.
Affected installations
TYPO3 installations with custom extensions calling the method.
Migration
Migrate towards the
PackageManager implementation, which can be added
via Dependency Injection or retrieved via
GeneralUtility::makeInstance().
Content parsers implemented in Indexed Search return an array solely defined for
the internal indexer. It is now encouraged to return an instance of
\TYPO3\CMS\IndexedSearch\Dto\IndexingDataAsString instead.
Impact
Returning an array is deprecated. The indexing process will catch such cases,
convert the result to an
IndexingDataAsString object and raise a
deprecation warning.
Affected installations
All installations with custom content parsers are affected, which very
unlikely do exist.
Migration
Let the custom content parser return an instance of
IndexingDataAsString.
Either use the constructor, or the static helper method
fromArray().
In both cases, the following input is accepted:
title
body
keywords
description
Examples
// Using constructorreturnnew IndexingDataAsString('<title>', '<body>', '<keywords>', '<description>');
The following upgrade wizard related classes have been moved from EXT:install
to EXT:extensionmanager:
\TYPO3\CMS\Install\Updates\AbstractDownloadExtensionUpdate, new name
\TYPO3\CMS\Extensionmanager\Updates\AbstractDownloadExtensionUpdate
\TYPO3\CMS\Install\Updates\ExtensionModel, new name
\TYPO3\CMS\Extensionmanager\Updates\ExtensionModel
Class aliases have been established for TYPO3 v13, which will be removed with
TYPO3 v14.
Impact
Extensions that extend
AbstractDownloadExtensionUpdate and
then most likely use
ExtensionModel as well, should update the namespace.
Affected installations
Few instances should be affected: There are a couple of extensions that try to
extend the upgrade range from two major Core versions, and ship older
upgrade wizards. Apart from that, the abstract is most likely rarely used.
Consuming extensions should adapt the namespace, the old class names will stop
working with TYPO3 v14.
The extension scanner will find usages as strong match.
Migration
Adapt the namespaces in extension classes that extend
AbstractDownloadExtensionUpdate
from
\TYPO3\CMS\Install to
\TYPO3\CMS\Extensionmanager.
The Import/Export backend module is based on code that is
very hard to maintain, and is tightly coupled with both
the
DataHandler and
RefIndex routines.
To improve maintainability and reliability in these areas,
parts of the Import/Export module need to be refactored
as an ongoing effort.
The documentation of the Import/Export module now addresses
these challenges.
The ongoing refactoring may affect importing dumps from
older versions of TYPO3. Importing these dumps may lead
to missing data, also due to changes made
longer ago (i.e. the
pages_language_overlay table no longer
exists, changes in workspaces, ...).
When performing an import of outdated TYPO3 versions,
thoroughly check the generated warnings and errors, so that
you can either recreate or upload missing data manually.
The Core needs to adapt some internal classes to prepare towards doctrine/dbal
major version 4.x. The Doctrine team deprecated especially the Doctrine
event manager, the Core used to populate custom adaptions.
The proposed way to mitigate the old events is to extend classes and integrate
custom handling code directly. TYPO3 thus extends a couple of classes and replaces
them using a factory.
Affected code is marked
@internal. Extension author must not rely on the
TYPO3 class names for
instanceof checks and should check using the original
Doctrine classes instead.
For example, doctrine/dbal has the following inheritance chain:
Custom extension code that needs to implement
instanceof checks for specific platforms
should use the Doctrine classes and not the TYPO3 Core classes, for example:
<?phpuseDoctrine\DBAL\Platforms\MySQLPlatformasDoctrineMySQLPlatform;
useTYPO3\CMS\Core\Database\Platform\MySQL80PlatformasTypo3MySQL80Platform;
// Usually incoming from elsewhere, eg. DI.
$platform = new Typo3MySQL80Platform();
$check = $platform instanceof DoctrineMySQLPlatform();
Copied!
Important: #102551 - FlexForm section _TOGGLE control removed
Historically, FlexForms store their section collapsing state within the flex
structure in the database, having the impact that the state is reflected to
every backend user. The control field _TOGGLE responsible for this behavior
is now removed, the state is persisted in the backend user's local storage
instead.
It is highly recommended to clean existing FlexForm records by invoking the
following command:
bin/typo3 cleanup:flexforms
Copied!
If this is not possible, a scheduler task of type
Execute console commands with the command
cleanup:flexforms: Clean up database FlexForm fields that do not match the chosen data structure.
may be set up and used.
TYPO3 v13 ships with Symfony components with at least version 7.0. Next to new
features and bugfixes to be released in future Symfony 7 versions, the security
support for Symfony 7 LTS reaches end-of-life in November 2028, allowing TYPO3
Core to run a stable and secure Symfony component library underneath.
Custom extensions relying on older versions of Symfony components need to adapt,
see upgrade guides for Symfony on how to migrate.
TYPO3 v13 ships with Doctrine DBAL with at least version 4.0.
TYPO3 extends some Doctrine DBAL classes, enriching behaviour and provide
these as public API surface, for example
Connection,
QueryBuilder
and the
ExpressionBuilder and are most likely used by extensions. Minor
signature changes and removed methods are not mitigated and passed as breaking
changes.
Custom extensions using low-level Doctrine DBAL API and functionality
directly need to adapt, consult the upgrade guides for Doctrine DBAL on how
to migrate.
TYPO3 v13 expects all database core system tables and especially all tables from
extensions that have
TCA attached to be configured for the main
Default connection.
The TYPO3 core historically allowed configuration of any database table to
point to additional configured database connections. This technically allows
"ripping off" any table from the default connection table set, and have it on
a different database.
TYPO3 now needs to restrict this a bit more to unblock further development and
performance improvements: The core now declares that all "main" core tables
(especially
sys_*,
pages,
tt_content and in general all
tables that have
TCA) must not be declared for any connection
other than the configured
Default connection.
The reasons for this are actually pretty obvious: When looking at performance
issues of bigger instances, the sheer amount of queries is usually the top-one
bottleneck. The core aims to reduce this mid-term using more clever queries that
join and prepare more data in fewer queries. Cross database joins are pretty much
impossible.
This restriction has practically been the case with earlier core versions already:
For instance when a
TCA table configured "categories" and used them, the
core already uses various joins to find categories attached to a record. Other
places have been adapted with TYPO3 v13 already, for instance the
ReferenceIndex. The core will try to additionally simplify the current
API by avoiding
getConnectionForTable() with further patches.
Apart from this, instances can still configure additional database connections.
One target is directly querying data from some third party application in some
custom extension. Another use case are database based caches: Those will of
course never execute queries to join non-cache related data. A typical use is
configuring a special database server for speed over integrity and persistence
(for instance RAM driven) to power the "page" cache tables. This will continue to work,
but might be turned into a dedicated feature of specific database backends, later.
13.x Changes by type
This lists all changes to the TYPO3 Core of minor versions grouped by their type.
With the CKEditor5 integration in TYPO3 v12 a custom CKEditor5 build in form of
a bundle has been introduced. Missing plugins had to be merged into that bundle
again and again which lead to an increased bundle size. Also plugin authors had
to reference the bundle module in order to fetch plugin exports from CKEditor.
With CKEditor5 suggestion to use named exports from the CKEditor5 package entry
point modules, it became feasible to create smaller bundles. One bundle per
scoped subpackage. For that reason
@typo3/ckeditor5-bundle.js is now
deprecated.
Impact
TYPO3 can ship all available CKEditor5 modules and only actually requested modules
are loaded. Developers can write plugins as suggested by upstream documentation.
Affected Installations
Installations having custom extensions activated, that provide custom CKEditor5
plugins. Extensions that use
@typo3/ckeditor5-bundle.js will still work
as before (as the bundle module re-exports the exports of the split bundles)
but will trigger a deprecation log message to the browser console.
Migration
Extension authors should import from scoped
@ckeditor/ckeditor5-* packages
directly.
// Beforeimport {Core, UI} from'@typo3/ckeditor5-bundle.js';
// Afterimport * as Core from'@ckeditor/ckeditor5-core';
import * as UI from'@ckeditor/ckeditor5-ui';
Copied!
Important: #96218 - Use proper surrounding "html" tags for Fluid SystemEmail
Due to usage of
data-namespace-typo3-fluid="true" in the
<html> declaration of the file
EXT:core/Resources/Private/Layouts/SystemEmail.html,
the whole
<html>..</html> structure is removed from a sent
HTML mail.
Validation and possibly utilities like SpamAssassin may fail
or negatively score these mails due to these tags being missing.
Since the
xmlns declaration of the ViewHelpers is semantically
not wrong, it can actually be included in the email by removing
the
data-namespace-typo3-fluid attribute, instead of requiring
the alternate more intrusive Fluid ViewHelper declaration.
Affected installations
All setups with customizations of the file
EXT:core/Resources/Private/Layouts/SystemEmail.html for sending
FluidEmails.
Migration
Adjust custom copies of the file EXT:core/Resources/Private/Layouts/SystemEmail.html
like this:
Before (EXT:your_extension/Resources/Private/Layouts/SystemEmail.html)
There are two different options for exporting records in the
Web->List module.
One is using the export functionality, which is provided by EXT:impexp and is
available via the "Export" docheader button in the single table view. It is
possible to manage the display of the button using the Page TSconfig
mod.web_list.noExportRecordsLinks option. However, the export
functionality is by default disabled for non-admin users, making the button
not showing up unless the functionality is explicitly enabled for the user
with the user TSconfig
options.impexp.enableExportForNonAdminUser
option.
The "Download" functionality is available via the "Download" button in each
tables header row. It is available in both, the list and also the single table
view and can be managed using the Page TSconfig
mod.web_list.displayRecordDownload option, which is enabled by
default. Next to the general option is it also possible to set this option on
a per-table basis using the
mod.web_list.table.<tablename>.displayRecordDownload option.
In case this option is set, it takes precedence over the general option.
The font plugin has been added to the CKEditor5.
In order to use the font plugin, the RTE configuration needs to be adapted:
editor:config:toolbar:items:# add button to select font family-fontFamily# add button to select font size-fontSize# add button to select font color-fontColor# add button to select font background color-fontBackgroundColorfontColor:colors:-{label:'Orange',color:'#ff8700'}-{label:'Blue',color:'#0080c9'}-{label:'Green',color:'#209d44'}fontBackgroundColor:colors:-{label:'Stage orange light',color:'#fab85c'}fontFamily:options:-'default'-'Arial, sans-serif'fontSize:options:-'default'-18-21importModules:-{'module':'@ckeditor/ckeditor5-font','exports':['Font']}
Copied!
More information can be found in the official documentation.
Important: #100889 - Allow insecure site resolution by query parameters
Resolving sites by the id and L HTTP query parameters is now denied by
default. However, it is still allowed to resolve a particular page by, for
example, "example.org" - as long as the page ID 123 is in the scope of the
site configured for the base URL "example.org".
The new feature flag
security.frontend.allowInsecureSiteResolutionByQueryParameters - which is
disabled per default - can be used to reactivate the previous behavior:
To implement native JSON database field and TCA type=json
support for TYPO3 v12 the need to cache the database schema
information raised due to performance reason.
Using the core cache for schema information comes with
various drawbacks:
There is no way to flush single core cache entries,
thus the complete core cache needs to be flushed when
changing the database schema.
The PHP Frontend provides no benefit, when the to be cached
information has to be serialized anyway.
Therefore, a new cache is introduced that can be flushed
individually after schema updates.
Additionally, some internal steps taken to mitigate some side
effects are reverted. They are no longer needed with the dedicated
cache.
Due to the nature of the chosen cache no database updates,
configuration changes or other steps are needed.
Important: #101128 - CKEditor's highlight plugin introduces mark HTML tag
The introduction of the CKEditor plugin
@ckeditor/ckeditor5-language
allows an editor to use the
mark tag, as well as the
s tag.
It may become necessary to explicitly allow this tag in the
lib.parseFunc_RTE TypoScript setup to allow the tag to be
rendered properly in the frontend:
Custom CSS styling for different markers classes needs to be
implemented in a sitepackage for example, as no frontend
CSS for this is emitted by default.
Important: #101567 - Use Symfony attribute to autoconfigure cli commands
The Symfony PHP attribute
\Symfony\Component\Console\Attribute\AsCommand
is now accepted to register console commands.
This way CLI commands can be registered by setting the attribute on the command
class. Only the parameters command, description, aliases and hidden are
still viable. In order to overwrite the schedulable parameter use the old
Services.yaml way to register console commands. By default schedulable
is true.
The registration of cli commands is simplified that way.
When using this attribute there is no need to register the command in the
Services.yaml file. Existing configurations work as before.
The feature flag security.frontend.reportContentSecurityPolicy
(
$GLOBALS['TYPO3_CONF_VARS']['SYS']['features']['security.frontend.reportContentSecurityPolicy'] )
can be used to apply the Content-Security-Policy-Report-Only HTTP header for
frontend responses.
When both feature flags are activated, both headers are sent.
You can deactivate one disposition in the site-specific configuration.
This allows to test and assess the potential impact on introducing
Content-Security-Policy in the frontend - without actually blocking
any functionality.
The
GeneralUtility::validEmail() method uses the package
egulias/email-validator
for validating emails.
This library treats an email address like email @example.com with a space before the @
character as valid, but issues a warning, which has previously not been caught by TYPO3. Warnings
like these are defined as "deviations from the RFC that in a broader interpretation are accepted."
In the context of TYPO3, such non-RFC email address shall be rejected.
Thus, this specific warning (
CFWSNearAt) will now be caught, and the warning is turned into an
invalidation of the given email address.
This will have the effect, that if integrators previously accepted email addresses formatted like
these, validation will now fail (as the RFC implies).
Important: #102314 - Add title argument to IconViewhelper
The IconViewhelper in EXT:core has been extended with a new argument title.
The new argument allows to set a corresponding title, which will be rendered
as title attribute in the icon HTML markup. The title attribute will only
be rendered, if explicitly passed. You can also pass an empty string.
This title attribute will improve accessibility, since screenreaders can
choose not to ignore aria-hidden elements (e.g. the icons above the page tree),
which is a mode people with low visibility might choose. If a title attribute
is missing, a purely technical output will be given, which is very hard to
make sense of.
With TYPO3 v12.4.7 (see forge#99738) an option to allow all classes in
CKEditor5 has been enabled in the TYPO3 default configuration which implicitly
caused all custom html elements to be allowed. This rule has now been dropped
from the default configuration:
The configuration matched to any HTML element available in the CKEditor5 General
HTML Support (GHS) schema definition.
This became an issue, since CKEditor5 relies on the set of allowed elements and
classes when processing content that is pasted from Microsoft Office.
Installations that relied on the fact that v12.4.7 allowed all CSS classes in
CKEditor5 should encode the set of available style definitions via
editor.config.style.definitions which will make them accessible to editors
via the style dropdown toolbar element:
When using TCA type
inline, developers have the possibility to use the
"foreign selector" feature by defining the
foreign_selector option,
pointing to a field on the foreign (child) table. This way, editors can
use the corresponding selector field to choose existing child records,
to create a new inline relation. This can be further extended, using the
useCombination appearance option, which allows to modify the child record
via the parent record globally.
The field referenced in
foreign_selector is usually a field with TCA type
select, using the foreign_table option itself to provide the corresponding
items to choose.
It's nevertheless also possible to use a TCA type
group field as
foreign_selector. In this case, the child records have to be selected
from the table, defined via the
allowed option. For this use case,
only one table can be defined. This means, the first table name in
allowed is taken, no matter if there are multiple table names defined.
Note
This unfortunately does not work out of the box for Extbase. Therefore, the
corresponding table has to be defined additionally via the
foreign_table
option. This option is only used as a
workaround
by Extbase and is not sufficient for the TYPO3 Form editor, which will always
just consider the value from the
allowed option.
Example using an intermediate table and the
useCombination feature:
// Inline field in parent table "tx_extension_inline_usecombination"'inline' => [
'label' => 'inline',
'config' => [
'type' => 'inline',
'foreign_table' => 'tx_extension_inline_usecombination_mm', // Referencing the intermediate table'foreign_field' => 'group_parent',
'foreign_selector' => 'group_child',
'foreign_unique' => 'group_child',
'appearance' => [
'useCombination' => true,
],
],
],
// Reference fields in intermediate table "tx_extension_inline_usecombination_mm"'group_parent' => [
'label' => 'group parent',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'foreign_table' => 'tx_extension_inline_usecombination', // Referencing the parent table
],
],
'group_child' => [
'label' => 'group child',
'config' => [
'type' => 'group',
'allowed' => 'tx_extension_inline_usecombination_child', // Referencing the child table'foreign_table' => 'tx_extension_inline_usecombination_child', // ONLY USED FOR extbase!
],
],
// Child table "tx_extension_inline_usecombination_child" does not have any relation fields
Copied!
Important: #103392 - Form framework select markup changed
With forge#103117, the elementClassAttribute of the "SingleSelect",
"CountrySelect" and "MultiSelect" fields got changed from form-control to
form-select in EXT:form, as defined by Bootstrap, if the Bootstrap 5 markup
(
templateVariant: version2) is used.
If needed, the old markup can be restored by overriding the configuration as
follows:
The feature flags
$GLOBALS['TYPO3_CONF_VARS']['SYS']['features']['security.frontend.enforceContentSecurityPolicy']
and
$GLOBALS['TYPO3_CONF_VARS']['SYS']['features']['security.frontend.reportContentSecurityPolicy'] apply
Content-Security-Policy headers to any frontend site. The dedicated sites/<my-site>/csp.yaml can now be
used as alternative to declare the desired disposition of Content-Security-Policy and
Content-Security-Policy-Report-Only individually.
It now is also possible, to apply both Content-Security-Policy and Content-Security-Policy-Report-Only
HTTP headers at the same time with different directives for a particular site. Besides that it is possible
to disable the disposition completely for a site.
The following new configuration schemes were introduced for sites/<my-site>/csp.yaml:
active (false) for disabling CSP for a particular site, which overrules any other setting for enforce or report
enforce (bool|disposition-array) for compiling the Content-Security-Policy HTTP header
report (bool|disposition-array) for compiling the Content-Security-Policy-Report-Only HTTP header
The disposition-array for enforce and report allows these properties:
includeResolutions (bool) includes dynamic resolutions, as persisted in the database via backend module (true per default)
mutations (mutation-item-array) defines additional directive mutations to be applied to the specific site
packages (package-item-array) defines packages/extensions whose static CSP mutations shall be dropped or included
Example: Disable Content-Security-Policy
The following example would completely disable CSP for a particular site.
config/sites/<my-site>/csp.yaml
# `active` is enabled per default if omittedactive:false
Copied!
Example: Use report disposition
The following example would dispose only Content-Security-Policy-Report-Only
for a particular site (since the enforce property is not given).
config/sites/<my-site>/csp.yaml
report:# `inheritDefault` is enabled per default if omittedinheritDefault:truemutations:-mode:extenddirective:img-srcsources:-https://*.typo3.org
Copied!
The following example is equivalent to the previous, but shows that the
legacy configuration (having inheritDefault and mutations on the top-level)
is still supported.
The effective HTTP headers would then be resolved from the active feature flags
security.frontend.enforceContentSecurityPolicy and
security.frontend.reportContentSecurityPolicy - in case both flags are active,
both HTTP headers Content-Security-Policy and Content-Security-Policy-Read-Only
would be used.
config/sites/<my-site>/csp.yaml
# `inheritDefault` is enabled per default if omittedinheritDefault:truemutations:-mode:extenddirective:img-srcsources:-https://*.typo3.org
Copied!
Example: Use enforce and report dispositions at the same time
The following example would dispose Content-Security-Policy (enforce)
and Content-Security-Policy-Report-Only (report) for a particular site.
This allows to test new CSP directives in the frontend - the example drops
the static CSP directives of the package my-vendor/my-package in the
enforced disposition and only applies it to the reporting disposition.
config/sites/<my-site>/csp.yaml
enforce:# `inheritDefault` is enabled per default if omittedinheritDefault:true# `includeResolutions` is enabled per default if omittedincludeResolutions:truemutations:-mode:extenddirective:img-srcsources:-https://*.typo3.orgpackages:# all (`*`) packages shall be included (`true`)'*':true# the package `my-vendor/my-package` shall be dropped (`false`)my-vendor/my-package:falsereport:# `inheritDefault` is enabled per default if omittedinheritDefault:true# `includeResolutions` is enabled per default if omittedincludeResolutions:truemutations:-mode:extenddirective:img-srcsources:-https://*.my-vendor.example.org/# the `packages` section can be omitted in this case, since all packages# listed there shall be included - which is the default behavior in case# `packages` would not be configuredpackages:# all (`*`) packages shall be included (`true`)'*':true# the package `my-vendor/my-package` shall be included (`true`)my-vendor/my-package:true
Copied!
Important: #104693 - Setting allowLanguageSynchronization via columnsOverrides
Setting the TCA option
allowLanguageSynchronization for a specific
column in a record type via
columnsOverrides is currently not supported
by TYPO3 and therefore might lead to exceptions in the corresponding field wizard
(
LocalizationStateSelector). To mitigate this, the option is now
automatically removed from the TCA configuration via a TCA migration. A
corresponding deprecation log entry is added to inform integrators about
the necessary code adjustments.
Migration
Remove the
allowLanguageSynchronization option from
columnsOverrides
for now.
The CKEditor plugin can now be configured with YAML syntax utilizing
Regular Expression objects for certain keys. By defining a Regular Expression,
the CKEditor replacement/transformation functionality feature is now fully
usable.
The CKEditor v5 configuration API allows to specify
Regular Expression JavaScript objects, for example in
editor.config.typing.transformations.extra.from or
editor.config.htmlSupport.allow.name:
Example CKEditor JavaScript configuration excerpt
// part of `editor.config`
{
typing: {
transformations: {
extra: {
from: /(tsconf|t3ts)$/,
to: 'TYPO3 TypoScript TSConfig'
}
}
}
htmlSupport: {
allow: {
name: /^(div|section|article)$/
}
}
}
Copied!
When TYPO3 passes YAML configuration of the CKEditor forward
to JavaScript, it uses a html-entity encoded representation,
which does not allow to utilize Regular Expression objects,
and also the CKEditor API method buildQuotesRegExp() is not
usable in this scenario.
This was remedied already for the configuration key
htmlSupport
with its sub-keys, so that when a YAML key named
pattern
was found, TYPO3 automatically converted that to a proper JavaScript
Regular Expression:
Please note that the / character from the beginning and end
of the regular expression must not be specified manually in YAML.
Also take care of the ending $ character, which is vital to CKEditor's
proper parsing of a rule. The
flags key can contain Regular
Expression flags, and can also be omitted.
This is now also possible for the editor.config.typing.transformations
structure:
This conversion of Regular Expressions must be explicitly applied to
CKEditor configuration keys within the TYPO3 API, and cannot be used
generally for every key.
Thus, using a
pattern sub-key is currently applied only to the following
configuration structures (and recursively their sub-structures):
editor.config.typing.transformations
editor.config.htmlSupport
Hint
This means, that the pattern sub-key can be used for all of:
Short version: With this bugfix, any save process
to the contents of an existing RTE element will now properly apply
the
removeTags default configuration (unless configured otherwise).
To prevent a breaking change, the tags
center,
font,
strike and
u are now allowed to be saved by default (like it was with the bug in
effect). This is planned to be changed with TYPO3 v14 as a breaking change.
The unexpected tags
link,
meta,
o:p,
sdfield,
style,
title will now be removed.
This behaviour can always be customized by setting
removeTags appropriately.
TYPO3 allows to configure which HTML tags are allowed to be persisted
to the database in case of Richtext-elements. This can be configured
either within the CKEditor YAML context, or via Page TSconfig:
Due to a bug in interpreting the YAML configuration, the syntax using
an array was actually never in effect.
This means, any implementation relying on such a YAML configuration (without
providing Page TSconfig), would not have removed the listed tags.
Due to TYPO3's internal processing, from those tags listed above,
the previous default tags
center,
font,
strike and
u were persisted to the database and also later evaluated in the frontend.
The other tags
link,
meta,
o:p,
sdfield,
style and
title were displayed as HTML encoded entities
due to other sanitizing in the output (but still stored as HTML tags in the database).
These tags will no longer be stored by default now, and is considered a non-breaking
bugfix, because these tags should not occur within an RTE.
This wrong parsing has now been fixed, so that now both an array syntax as
well as string syntax is allowed in the YAML processing and will
be applied. Adapting the
removeTags setting allows to change
the now applied defaults to any tag configuration needed.
Hint
Custom YAML configuration that used a string representation of
removeTags
(instead of an array) was already properly evaluated.
This bugfix has not been backported to TYPO3 v11 installations, to prevent
a change of behaviour in a security-maintenance-only environment. If this fix
is needed, you can convert the CKEditor array syntax by removing the square
brackets in a Processing.yaml override:
TYPO3 setups with RTE YAML configurations utilizing either a custom
removeTags processing directive or the default, defined via array
notation instead of string.
Migration
Adjust the RTE YAML configuration processing directive removeTags
to suit the expected tag removal, or accept the new defaults.
The way Content-Security-Policy reporting endpoints are configured has
been enhanced. Administrators can now disable the reporting endpoint
globally or configure it per site as needed.
The global scope-specific setting contentSecurityPolicyReportingUrl can
be set to zero ('0') to disable the CSP reporting endpoint:
After TYPO3 v12.0, only new functionality with a solid migration path
can be added on top, with aiming for as little as possible breaking changes
after the initial v12.0 release on the way to LTS.
Since forge#77349 it is possible to place the extension icon, which is
displayed at various places in the backend, e.g. in the extension manager, in
an extension's Resources/Public/Icons/ directory. The Resources/ directory
is by convention the place to
store such files. To simplify the extension registration and to fully follow the
convention the following file locations have been deprecated:
ext_icon.png
ext_icon.svg
ext_icon.gif
Impact
Adding an extension icon using one of the mentioned file locations will raise
a deprecation level log message and will stop working with TYPO3 v13.
Affected installations
TYPO3 installations with custom extensions using the deprecated file locations.
The class
\TYPO3\CMS\Core\Resource\Service\MagicImageService, which was
previously used for inline images by EXT:rtehtmlarea has been marked as
deprecated, since its functionality is no longer needed for CKeditor.
Impact
Using
\TYPO3\CMS\Core\Resource\Service\MagicImageService or one of its
public methods will raise a deprecation level log message.
Affected installations
TYPO3 installations with custom extensions using the class or its public
methods. The extension scanner will report usages as strong match.
Migration
There is no direct migration. In case you rely on any of the provided
functionality, just copy the corresponding code into your custom extension.
Deprecation: #100173 - Various methods and properties in UserAuthentication classes now internal
Various methods and properties within the main classes regarding frontend
user and backend user (
$GLOBALS[BE_USER]) authentication handling
have been either marked as internal or have been deprecated for usage
outside of the classes.
This is due to the further refactorings and decoupling work, as subclasses of
AbstractUserAuthentication deal with many more functionality nowadays,
and therefore have been moved to service classes. The tight coupling of these
classes, for example, the database fields, or login form field names are now marked as
internal, as these properties should not be modified from the outside scope.
The following properties and methods are now marked as internal in all
user authentication related classes (extending
\TYPO3\CMS\Core\Authentication\AbstractUserAuthentication ):
lastLogin_column
formfield_uname
formfield_uident
formfield_status
loginSessionStarted
dontSetCookie
isSetSessionCookie()
isRefreshTimeBasedCookie()
removeCookie()
isCookieSet()
unpack_uc()
appendCookieToResponse()
Additionally, the following properties of the
\TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication
implementation are marked as internal:
formfield_permanent
is_permanent
Impact
The affected properties and methods have been marked as @internal and set to
protected. With an additional trait, it is still possible to access them
in TYPO3 v12. In case third-party extensions call them, a PHP deprecation
warning is thrown.
Affected installations
TYPO3 installations with custom extensions accessing the properties or methods.
The extension scanner reports corresponding places.
Migration
Depending on the specific requirements, it is recommended to use
PSR-14 events or
authentication services to modify behaviour
of the authentication classes.
The TCA option
MM_insert_fields has been marked
as deprecated and should not be used anymore.
Impact
Using
MM_insert_fields raises a deprecation level log message
during TCA cache warmup. Its functionality is kept in TYPO3 v12 but will
be removed in v13.
Affected installations
There may be extensions that use this option when configuring database
MM relations. In most cases, the option can be removed. The migration
section gives more details.
Migration
General scope:
MM_insert_fields is used in combination with "true"
database MM intermediate tables to allow many-to-many relations between
two tables for
group,
select and sometimes even
inline
type fields.
A core example is the
sys_category to
tt_content
relation, with
sys_category_record_mm as intermediate table: The
intermediate table has field
uid_local (pointing to a uid of
the "left"
sys_category table), and
uid_foreign (pointing to a
uid of the "right"
tt_content table). Note this specific relation also
allows multiple different "right-side" table-field combinations, using the two
additional fields
tablenames and
fieldname. All this is configured
with TCA on the "left" and the "right" side table field, while table
sys_category_record_mm has no TCA itself. Rows within the intermediate
table are transparently handled by TYPO3 by the
RelationHandler and
extbase TCA-aware domain logic.
The
MM_insert_fields now allows to configure a hard coded value for
an additional column within the intermediate table. This is obsolete: There is
no API to retrieve this value again, having a "stable" value in an additional
column is useless. This config option should be removed from TCA
definition.
Note on the related option
MM_match_fields: This is important when an
MM relation allows multiple "right" sides. In the example above, when a category
is added to a
tt_content record using the
categories field, and when editing
this relation from the "right" side (editing a
tt_content record), then this option
is used to select only relations for this
tt_content.categories combination. The
TCA column
categories thus uses
MM_match_fields to restrict the
query. Note
MM_match_fields is not set for the "left-side"
sys_category
items fields, this would indicate a TCA misconfiguration.
Various extensions in the wild did not get these details right, and often simply
set both
MM_insert_fields and
MM_match_fields to the same values.
Removing
MM_insert_fields helps reducing confusion and simplifies this
construct a bit. Affected extensions can simply remove the
MM_insert_fields
configuration and keep the
MM_match_fields. Note the Core strives to further
simplify these options and
MM_match_fields may become fully obsolete in the
future as well.
Deprecation: #100349 - TypoScript loginUser() and usergroup() conditions
The two TypoScript / TSconfig related condition functions
[loginUser()] and
[usergroup()] have
been marked as deprecated with TYPO3 v12, should not be used anymore
and will be removed in TYPO3 v13. They can be substituted using
conditions based on the variables
frontend.user and
backend.user.
Impact
Using the old conditions in frontend TypoScript or TSconfig triggers a
deprecation level log entry in TYPO3 v12 and will stop working with
TYPO3 v13.
Affected installations
Instances with TypoScript or TSconfig using one of the above functions
may be affected. This is a relatively common use case, but affected
instances can be adapted quite easily.
Migration
There is a rather straightforward migration path. In general, switch to
either
frontend.user to test for frontend user state
(available in frontend TypoScript), or to
backend.user (available
in frontend TypoScript and TSconfig).
Note the transition can be done in existing TYPO3 v11 projects already.
Some examples:
[loginUser('*')]
page = PAGE
page.20 = TEXT
page.20.value = User is logged in<br />
[end][frontend.user.isLoggedIn]
page = PAGE
page.21 = TEXT
page.21.value = User is logged in<br />
[end][loginUser('*') === false]
page = PAGE
page.30 = TEXT
page.30.value = User is not logged in<br />
[end][!frontend.user.isLoggedIn]
page = PAGE
page.31 = TEXT
page.31.value = User is not not logged in<br />
[end][loginUser(13)]
page = PAGE
page.40 = TEXT
page.40.value = Frontend user has the uid 13<br />
[end][frontend.user.userId == 13]
page = PAGE
page.41 = TEXT
page.41.value = Frontend user has the uid 13<br />
[end][loginUser('1,13')]
page = PAGE
page.50 = TEXT
page.50.value = Frontend user uid is 1 or 13<br />
[end][frontend.user.userId in [1,13]]
page = PAGE
page.51 = TEXT
page.51.value = Frontend user uid is 1 or 13<br />
[end][usergroup('*')]
page = PAGE
page.60 = TEXT
page.60.value = A Frontend user is logged in and belongs to some usergroup.<br />
[end]# Prefer [frontend.user.isLoggedIn] to not rely on magic array values.[frontend.user.userGroupIds !== [0, -1]]
page = PAGE
page.61 = TEXT
page.61.value = A Frontend user is logged in and belongs to some usergroup.<br />
[end][usergroup(11)]
page = PAGE
page.70 = TEXT
page.70.value = Frontend user is member of group with uid 11<br />
[end][11 in frontend.user.userGroupIds]
page = PAGE
page.71 = TEXT
page.71.value = Frontend user is member of group with uid 11<br />
[end][usergroup('1,11')]
page = PAGE
page.80 = TEXT
page.80.value = Frontend user is member of group 1 or 11<br />
[end][1 in frontend.user.userGroupIds || 11 in frontend.user.userGroupIds]
page = PAGE
page.81 = TEXT
page.81.value = Frontend user is member of group 1 or 11<br />
[end]
Copied!
Deprecation: #100355 - Deprecate methods in PasswordChangeEvent in ext:felogin
The following methods in the PSR-14 event
PasswordChangeEvent of
ext:felogin have been marked as deprecated and should not be used any more:
setAsInvalid()
getErrorMessage()
isPropagationStopped()
setHashedPassword()
Impact
Event listeners, who use one of the deprecated methods of the
PasswordChangeEvent PSR-14 event, will raise a deprecation level log
message. The functionality is kept in TYPO3 v12 but will be removed in v13.
Affected installations
Instances who use the PSR-14 event
PasswordChangeEvent for password
validation and who use one of the deprecated methods.
The extension scanner reports usages as a weak match.
Migration
Password validation for the password recovery functionality in ext:felogin
must be implemented using a custom password policy validator.
The public property
type of the main class in TYPO3 frontend
\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController has been
marked as internal, as it should not be used outside of this PHP class anymore
in the future.
This is part of the overall part to reduce dependencies on this PHP class, as
it is not always available in TYPO3 frontend.
Impact
Accessing this property will trigger a PHP deprecation notice. Accessing this
property might also happen via TypoScript and TypoScript conditions.
Affected installations
TYPO3 installations using this property on checking various typeNum settings
from TypoScript.
Migration
When using this property in PHP code via
$GLOBALS['TSFE']->type , it is
recommended to move to the PSR-7 request via
$request->getAttribute('routing')->getPageType(), which is the property
of the
PageArguments object, as a result of the
GET parameter
type, or $GLOBALS['TSFE']->getPageArguments()->getPageType() if
the request object is not available.
Within TypoScript, conditions and getData properties need to be adapted:
Due to many refactorings in TYPO3's tree implementations in the past versions,
many implementations and functionality of the legacy rendering
\TYPO3\CMS\Backend\Tree\AbstractTreeView
is not needed anymore.
The following PHP classes are not in use anymore and have been marked as deprecated:
The base class is still available, but discouraged to be used or extended,
even though TYPO3 still uses this in a few places.
The following properties and methods within the base class
AbstractTreeView have either been marked as deprecated or
declared as internal:
AbstractTreeView->thisScript
AbstractTreeView->BE_USER
AbstractTreeView->clause
AbstractTreeView->title
AbstractTreeView->table
AbstractTreeView->parentField
AbstractTreeView->orderByFields
AbstractTreeView->fieldArray
AbstractTreeView->defaultList
AbstractTreeView->determineScriptUrl()
AbstractTreeView->getThisScript()
AbstractTreeView->PM_ATagWrap()
AbstractTreeView->addTagAttributes()
AbstractTreeView->getRootIcon()
AbstractTreeView->getIcon()
AbstractTreeView->getRootRecord()
AbstractTreeView->getTitleStr()
AbstractTreeView->getTitleAttrib()
Impact
Instantiating the deprecated classes or calling the deprecated methods will
trigger a PHP deprecation warning, except for
AbstractTreeView->getThisScript(), which is still used internally by
deprecated code.
The Extension Scanner will find those usages and additionally also reports
usages of the corresponding public properties of the
AbstractTreeView
class.
Affected installations
TYPO3 installations with custom extensions using this functionality. This is
usually the case for old installations from TYPO3 v6 or TYPO3 v4 times.
Migration
It is recommended to avoid generating the markup directly in PHP. Instead use
one of various other tree functionalities (for example, see PageTree implementations)
in PHP and render trees via web components or Fluid.
The method
\TYPO3\CMS\Backend\Utility\BackendUtility::getRecordToolTip()
has been marked as deprecated.
Impact
Calling this method will trigger a PHP deprecation warning.
Affected installations
TYPO3 installations with custom extensions using this method. This is usually
the case for old installations where Fluid templates or Extbase backend modules
were not common.
Migration
As this method is just a wrapper around
BackendUtility::getRecordIconAltText()
with a "title" attribute for the markup, the replacement is straightforward:
The TypoScript option
config.xhtmlDoctype has been marked as
deprecated. This is done in order to consolidate TypoScript options, as the
option
config.doctype is now the default.
Impact
Having
config.xhtmlDoctype set, but not
config.doctype
will trigger a TypoScript deprecation warning.
Affected installations
TYPO3 installations having this TypoScript instruction set.
Migration
If the property
config.xhtmlDoctype is set, replace it with
config.doctype.
The backend FormEngine construct (editing records in the backend)
now expects the current
ServerRequestInterface object to
be hand over as initial data.
Impact
Backend modules that use the FormEngine data provider construct to
render records should provide the current request object. Failing
to do so will trigger a deprecation level log message and the system
will fall back to
$GLOBALS['TYPO3_REQUEST']. This will stop
working with TYPO3 v13.
Affected installations
Instances with extensions that provide custom modules using the FormEngine
construct are affected. This is a relatively seldom case.
Migration
Provide the request object as "initial data" when using the
FormDataCompiler:
When instantiating the backend FormEngine related
FormDataCompiler,
the constructor argument
FormDataGroupInterface should be omitted,
the form data group should be provided as second argument to
compile()
instead.
Impact
Handing over the form data group as second argument to
compile()
allows injecting
FormDataCompiler into controllers with TYPO3 v13
since the manual constructor argument will be removed.
Affected installations
Instances with own backend modules that use FormEngine to render records
may be affected. Handing over the form data group as constructor argument
to
FormDataCompiler will trigger a deprecation level log warning
with TYPO3 v12. With TYPO3 v13, the form data group must be provided as
second argument to
compile() and will not be optional anymore.
The method
\TYPO3\CMS\Core\Utility\GeneralUtility::linkThisScript()
has been marked as deprecated and should not be used any longer.
The method uses the super global
$_GET which should be avoided. Instead,
data should be retrieved via the PSR-7
ServerRequestInterface.
Controllers should typically create URLs using the
\TYPO3\CMS\Backend\Routing\UriBuilder .
Impact
Using the method triggers a deprecation level log entry in TYPO3 v12, the
method will be removed with TYPO3 v13.
Affected installations
The method was typically used in backend context: Extensions with own
backend modules may be affected. The extension scanner finds usages
with a strong match.
Migration
linkThisScript() was typically used when a link to some view is
created that should return back to the current view later.
Controllers usually "know" the route a view should return to and the relevant
GET parameters.
The result property additionalJavaScriptPost of the form engine result array
is deprecated. It was used, for instance, in custom eval definitions, that provided
inline JavaScript (configured via
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tce']['formevals'] ).
Impact
Custom form engine components that assign the result property additionalJavaScriptPost,
or custom eval class implementations for method
returnFieldJS() that return a plain
string (which is used as inline JavaScript), will raise a deprecation level log message.
Affected installations
Installations that use custom form engine components modifying the result array,
or custom eval class implementations for method
returnFieldJS() returning
a plain string.
Migration
Instead of using inline JavaScript, functionality has to be bundled in a static
JavaScript module. Custom eval class implementations for method
returnFieldJS()
have to return an instance of
\TYPO3\CMS\Core\Page\JavaScriptModuleInstruction
instead of a plain string.
The method
\TYPO3\CMS\Core\Utility\GeneralUtility::_GET() has
been marked as deprecated and should not be used any longer.
Modern code should access GET and POST data from the PSR-7
ServerRequestInterface,
and should avoid accessing superglobals
$_GET directly. This also avoids
future side-effects when using sub-requests. Some
GeneralUtility related
helper methods like
_GET() violate this, using them is considered a technical
debt. They are being phased out.
Impact
Calling the method from PHP code will log a PHP deprecation level entry,
the method will be removed with TYPO3 v13.
Affected installations
TYPO3 installations with third-party extensions using
GeneralUtility::_GET()
are affected, typically in TYPO3 installations which
have been migrated to the latest TYPO3 Core versions and
haven't been adapted properly yet.
The extension scanner will find usages with a strong match.
Migration
GeneralUtility::_GET() is a helper method that retrieves
incoming HTTP GET query arguments and returns the value.
The same result can be achieved by retrieving arguments from the request object.
An instance of the PSR-7
ServerRequestInterface is handed over to
controllers by TYPO3 Core's PSR-15
\TYPO3\CMS\Core\Http\RequestHandlerInterface
and middleware implementations, and is available in various related scopes
like the frontend
\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer .
Typical code:
useTYPO3\CMS\Core\Utility\GeneralUtility;
// Before
$value = GeneralUtility::_GET('tx_scheduler');
// After
$value = $request->getQueryParams()['tx_scheduler'] ?? null;
Copied!
Deprecation: #100597 - BackendUtility methods getThumbnailUrl() and getLinkToDataHandlerAction()
The methods
\TYPO3\CMS\Backend\Utility\BackendUtility::getThumbnailUrl()
and
\TYPO3\CMS\Backend\Utility\BackendUtility::getLinkToDataHandlerAction()
have been marked as deprecated.
Impact
Calling those methods will trigger a PHP deprecation level log warning.
Affected installations
TYPO3 installations with custom extensions using those methods. The extension
scanner will report usages as strong match.
Migration
Instead of calling
BackendUtility::getThumbnailUrl(), inject and use
the
\TYPO3\CMS\Core\Resource\ResourceFactory directly:
In case the second paramter $redirectUrl was omitted,
getLinkToDataHandlerAction automatically used the current request URI
as the return URL. In case you relied on this, make sure the redirect
parameter is set to
$request->getAttribute('normalizedParams')->getRequestUri().
Deprecation: #100614 - Deprecate PageRenderer::$inlineJavascriptWrap and $inlineCssWrap
The protected properties
$inlineJavascriptWrap and
$inlineCssWrap
of the class
\TYPO3\CMS\Core\Page\PageRenderer have been deprecated and
shall not be used any longer.
Impact
PageRenderer specifics concerning rendering XHTML or non-HTML5 content are
not working any longer in affected installations having custom code extending
\TYPO3\CMS\Core\Page\PageRenderer .
Affected installations
Installations with custom code extending
\TYPO3\CMS\Core\Page\PageRenderer
that are reading from or writing to the mentioned protected properties
$inlineJavascriptWrap or
$inlineCssWrap.
Migration
Avoid using the protected properties
$inlineJavascriptWrap and
$inlineCssWrap. In case any custom code needs to wrap with inline
<script> or
<style> tags, use the new protected methods
wrapInlineScript($content) and
wrapInlineStyle($content)
within
\TYPO3\CMS\Core\Page\PageRenderer .
Extbase has an own system for feature toggles next to the Core feature
toggle API. It has always been marked as internal, but is used for
a couple of toggles within the Extbase framework.
All toggles and the internal PHP API have been marked as deprecated
in TYPO3 v12 and should be avoided.
Impact
The PHP API for Extbase toggles has always been marked as internal. It will
be removed with TYPO3 v13.
The single toggles can still be used in TYPO3 v12, but their triggered
functionality will be removed with TYPO3 v13, if set to 1.
Affected installations
Extensions should not rely on
\TYPO3\CMS\Extbase\ConfigurationConfigurationManagerInterface->isFeatureEnabled().
The method is marked as internal and should never have been used by extensions. The
extension scanner still finds usages of this method in extensions as weak match.
All feature toggles have been marked as deprecated. Setting one of them to 1 in
TypoScript will trigger a deprecation level log message, they will stop working with
TYPO3 v13.
Migration
Extbase has three feature toggles in TYPO3 v12. All of them will be removed
with TYPO3 v13. Instances with extensions setting those to 1 in TypoScript
may need adaptions. Instances setting the toggles to 0 can simply remove them
from TypoScript.
skipDefaultArguments = 1
This is an ancient toggle that was used before routing has been added with
TYPO3 v9. It allowed to skip the controller and action argument in frontend
plugin links, when linking to the default Extbase controller / action combination.
This toggle has been documented as being broken in combination with
Extbase plugin enhancer already.
Consuming instances should switch to proper routing configuration instead.
ignoreAllEnableFieldsInBe = 1
This is another ancient toggle that triggers
\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings->setIgnoreEnableFields(true)
for Extbase repositories when used in backend scope. It allows ignoring default
TCA
flags like suppressing of deleted records in queries.
Extbase-based backend modules that rely on this toggle being set to 1 can easily
migrate this: When the repository in question is only used in backend context, the
code below should trigger the same behavior. Note as with other query settings,
this toggle needs to be used with care, otherwise backend users may see records
they are not supposed to see.
When the repository is used in both backend and frontend context, the code
should be refactored a bit towards a public method that can be set by the
Extbase backend controller only.
enableNamespacedArgumentsForBackend = 1
This toggle has been introduced in TYPO3 v12. See Feature: #97096 - Non-namespaced arguments in Extbase backend modules
for more details. Extbase backend modules should no longer expect the
namespace to be set. It may be necessary to adapt some Ajax calls and
request-related argument checks in custom modules.
Deprecation: #100637 - Third argument ContentObjectRenderer->start()
When creating instances of the
\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer , the
third argument
$request when calling
start() should not be
handed over anymore. Instead,
setRequest() should be used
after creating the object.
Impact
Handing over the third argument to
start() has been marked as deprecated
in TYPO3 v12, it will be ignored with TYPO3 v13.
Affected installations
Instances with casual extensions are probably not affected by this: Instances
of
ContentObjectRenderer are usually set-up framework internally.
Using the third argument on
start() triggers a deprecation level log
message. The extension scanner will not find usages, since the method
name
start() is used in different context as well and would lead to
too many false positives.
Migration
Ensure the request is an instance of
\Psr\Http\Message\ServerRequestInterface ,
and call
setRequest() after instantiation instead of calling
start() with three arguments.
The following methods in
\TYPO3\CMS\Core\Utility\DebugUtility have been
marked as deprecated:
debugInPopUpWindow()
debugRows()
printArray()
While
debugRows() and
printArray() duplicate already existing
methods,
debugInPopUpWindow() is discouraged to use as either external
debuggers, e.g. Xdebug or
\TYPO3\CMS\Extbase\Utility\DebuggerUtility may
be used instead.
Impact
Calling any of the aforementioned methods will trigger deprecation log entries.
Affected installations
Instances using any of the aforementioned methods are affected.
The extension scanner will find and report usages.
Migration
In case of
debugRows(), the identical method
debug() can be used.
The method
printArray() can be replaced with
viewArray(). However,
the former method directly outputs the contents, which is not the case with
viewArray().
The method
debugInPopUpWindow() is deprecated without a direct
replacement, consider using an external debugger or
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump() instead.
The configuration option
$GLOBALS['TYPO3_CONF_VARS']['BE']['languageDebug']
has been marked as deprecated in TYPO3 v12, it will be removed with TYPO3 v13
along with the property
\TYPO3\CMS\Core\Localization->debugKey.
Setting the configuration option languageDebug to true adds the label name
including the path to the .xlf file to the output in the backend.
The intention was to allow translators to see where a specific localized
string comes from in the backend to allow locating missing localization
sources.
Judging from translators feedback, the option isn't used in practice, though:
Setting the toggle to true leads to a massively convoluted backend experience
that breaks tons of CSS and renders the backend so unusable that it's hardly
a benefit at all.
TYPO3 v12 cleaned up lots of label usages and makes them more unique.
Translators should find single label usages much more easily by searching
the code base for label names and label files. Also, many Fluid templates are
located more transparently and are easier to find, localizing labels within
PHP classes is also improving a lot. Translators should in general have
less headaches to see where labels are used, and this will improve further.
Impact
The option has been marked as deprecated in TYPO3 v12 and does not have any
effect anymore with TYPO3 v13.
Affected installations
The target of this toggle were translators, production sites are not affected
by this. Extensions using the property
\TYPO3\CMS\Core\Localization->debugKey
are found by the extension scanner as weak match.
Migration
Remove access to
\TYPO3\CMS\Core\Localization->debugKey.
The Extbase-related method
\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface->getContentObject()
has been marked as deprecated in TYPO3 v12 and should not be used anymore.
Impact
Calling
ConfigurationManagerInterface->getContentObject() will trigger
a deprecation level log message in TYPO3 v12, the method will be removed
from the interface together with their implementations with TYPO3 v13.
Affected installations
Instances with Extbase extensions that use
getContentObject() on
injected
ConfigurationManager instances are affected. The extension
scanner has not been configured to find these calls, since the method
name is used in different scope as well and would trigger too many
false positives.
Migration
There may be instances with Extbase controllers that need to retrieve
data from the current content object that initiated the frontend Extbase
plugin call.
In this case, controllers can access the current content object from the
Extbase request object using
$request->getAttribute('currentContentObject')
instead.
When the FormEngine construct (used when editing records in the backend) has
been rewritten back in TYPO3 v7, dependency injection for non-Extbase
constructs has not been a thing, yet.
With dependency injection being part of the TYPO3 Core extension since TYPO3 v10,
and the Extbase solution being out-phased, it is time to make FormEngine
dependency injection aware as well.
This has some impact on classes implementing
\TYPO3\CMS\Backend\Form\NodeInterface directly, or indirectly by
extending
\TYPO3\CMS\Backend\Form\AbstractNode and
\TYPO3\CMS\Backend\Form\Element\AbstractFormElement . Custom
implementations can use this already, but the full power will
only be leveraged with TYPO3 v13.
Similar changes as described below can be done for classes implementing
\TYPO3\CMS\Backend\Form\NodeResolverInterface as well, but the
impact is much smaller since this construct is used less often in the wild.
Additionally, classes should either implement one of the interfaces
directly, or extend an appropriate abstract. They must not extend any
of the existing "leaf" classes the core provides, since those will be
declared
final with TYPO3 v13.
Impact
Using dependency injection within FormEngine related classes
becomes possible in TYPO3 v12.
Affected installations
Instances with extensions that come with own FormEngine additions
may be affected. The extensions scanner is not configured to find
affected classes.
Migration
Compatibility with TYPO3 v11 and v12
Extensions that strive for both TYPO3 v11 and v12 compatibility should
just keep their implementation as is.
Compatibility with TYPO3 v12 and v13
Extensions that strive for TYPO3 v12 compatibility, skipping v11, that
want to support v13 as well, must adapt their implementations.
As main change,
NodeInterface no longer declares
__construct(),
the class constructor is now "free" for injection. The
NodeFactory uses
the existence of method
setData() as indicator if
NodeFactory and
$data array should be hand over as manual constructor argument (old way),
or if
setData() should be called after object instantiation. Note
setData() will be activated as interface method with TYPO3 v13.
A class with both TYPO3 v12 and v13 compatibility should look like this:
publicfunction__construct(
// If the class creates sub elements
NodeFactory $nodeFactory,
// If the class needs IconFactory
IconFactory $iconFactory,
// Further dependencies
private readonly MyService $myService,
){
$this->nodeFactory = $nodeFactory;
$this->iconFactory = $iconFactory;
}
publicfunctionsetData(array $data): void{
$this->data = $data;
}
publicfunctionrender(): array{
// Implement render(), note the "array" return type hint,// which will be mandatory in TYPO3 v13.
}
Copied!
The class has to be registered for public DI in Services.yaml as well, since
it is instantiated by
NodeFactory using
GeneralUtility::makeInstance():
Extensions dropping TYPO3 v12 compatibility and going with v13 and up, can
simplify the construct: In v13,
setData() will be added to
AbstractNode,
extending classes don't need to implement it anymore. The class
property
$iconFactory (
AbstractFormElement
only) will be removed from the abstracts, constructor property promotion
can be used.
NodeFactory will be injected in the abstracts, without
polluting
__construct(). Also, a dependency injection service provider pass will
be added, to automatically set classes public that implement implement
NodeInterface,
so a
public: true entry in Services.yaml can be skipped.
A typical class extending
AbstractNode looks like this:
The method
\TYPO3\CMS\Core\Localization\LanguageService->getLL() has been
marked as deprecated.
Along with the deprecation the method
\TYPO3\CMS\Core\Localization\LanguageService->includeLLFile() has been
marked as internal, as it is still used in TYPO3 Core for backwards-compatibility
internally, but not part of TYPO3's Core API anymore.
With the introduction of Locales, it is also now not recommended anymore to use
custom alternative language keys.
For this reason the argument "alternativeLanguageKeys" of the
<f:translate> ViewHelper has been deprecated as well, along with the
method argument of the same name in
\TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate().
Impact
Calling the method
\TYPO3\CMS\Core\Localization\LanguageService->getLL()
will trigger a PHP deprecation warning.
Calling
\TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate() with
the argument "alternativeLanguageKeys" will also trigger a PHP deprecation warning,
which is the underlying deprecation warning when using the argument
"alternativeLanguageKeys" of the
<f:translate> ViewHelper.
Affected installations
TYPO3 installations within backend modules using the method
getLL() or
extensions or templates using the translate methods.
The former usually happens in extensions which have been migrated from older
TYPO3 versions with legacy functionality in backend modules along
with
$GLOBALS['LANG'] as
LanguageService object.
Migration
It is highly recommended to use the full path to a label file along
with the
sL() method of
\TYPO3\CMS\Core\Localization\LanguageService :
Sudo mode
has been integrated since TYPO3 v9.5.x to protect only Install Tool components. With TYPO3 v12
it has been changed to a generic configuration for backend routes (and implicitly modules).
Besides that, access to the Extension Manager now needs to pass the sudo mode verification as well.
Process in a nutshell
All simplified classnames below are located in the namespace
\TYPO3\CMS\Backend\Security\SudoMode\Access).
The low-level request orchestration happens in the middleware
\TYPO3\CMS\Backend\Middleware\SudoModeInterceptor ,
markup rendering and payload processing in controller
\TYPO3\CMS\Backend\Controller\Security\SudoModeController .
A backend route is processed, that requires sudo mode for route URI /my/route
in
\TYPO3\CMS\Backend\Http\RouteDispatcher .
Using
AccessFactory and
AccessStorage, the
RouteDispatcher
tries to find a valid and not expired
AccessGrant item for the specific
RouteAccessSubject('/my/route') aspect in the current backend user session data.
In case no
AccessGrant can be determined, a new
AccessClaim is created
for the specific
RouteAccessSubject instance and temporarily persisted in the
current user session data - the claim also contains the originally requested route
as
ServerRequestInstruction (a simplified representation of a
ServerRequestInterface).
Next, the user is redirected to the user interface for providing either their own password, or
the global install tool password as alternative.
Given, the password was correct, the
AccessClaim is "converted" to an
AccessGrant, which is only valid for the specific subject (URI /my/route)
and for a limited lifetime.
Configuration
In general, the configuration for a particular route or module looks like this:
group (optional): if given, grants access to other objects of the same group
without having to verify sudo mode again for a the given lifetime. Example:
Admin Tool modules Maintainance and Settings are configured with the same
systemMaintainer group - having access to one (after sudo mode verification)
grants access to the other automatically.
lifetime: enum value of
\TYPO3\CMS\Backend\Security\SudoMode\Access\AccessLifetime ,
defining the lifetime of a sudo mode verification, afterwards users have to go through
the process again - cases are veryShort (5 minutes), short (10 minutes),
medium (15 minutes), long (30 minutes), veryLong (60 minutes)
For backend routes declared via Configuration/Backend/Routes.php, the
relevant configuration would look like this:
This document explains the intended way in which the Extbase ORM thaws/hydrates objects.
Hydrating objects
Hydrating (the term originates from doctrine/orm), or in Extbase terms thawing, is
the act of creating an object from a given database row. The responsible class involved
is the
DataMapper. During the process of hydrating, the
DataMapper creates
objects to map the raw database data onto.
Before diving into the framework internals, let's take a look at models from the
user's perspective.
Creating objects with constructor arguments
Imagine you have a table
tx_extension_domain_model_blog and a corresponding model
or entity (entity is used as a synonym here)
\Vendor\Extension\Domain\Model\Blog.
Now, also imagine there is a domain rule which states, that all blogs must have a
title. This rule can easily be followed by letting the blog class have a constructor
with a required argument
string $title.
This example also shows how the
posts property is initialized. It is done in
the constructor because PHP does not allow setting a default value that is of
type object.
Hydrating objects with constructor arguments
Whenever the user creates new blog objects in extension code, the aforementioned
domain rule is followed. It is also possible to work on the
posts
ObjectStorage
without further initialization.
new Blog('title') is all I need to create
a blog object with a valid state.
What happens in the
DataMapper however, is a totally different thing. When
hydrating an object, the
DataMapper cannot follow any domain rules. Its only
job is to map the raw database values onto a Blog instance. The
DataMapper
could of course detect constructor arguments and try to guess which argument
corresponds to what property but only if there is an easy mapping, i.e. if the
constructor takes argument
string $title and updates property title with it.
To avoid possible errors due to guessing, the
DataMapper simply
ignores the constructor at all. It does so with the help of the library doctrine/instantiator.
This pretty much explains the title of this document in detail. But there is more
to all this.
Initializing objects
Have a look at the
$posts property in the example above. If the
DataMapper
ignores the constructor, that property is in an invalid state, i.e. uninitialized.
To address this problem and possible others, the
DataMapper will call the method
initializeObject(): void on models, if it exists.
This example demonstrates how Extbase expects the user to set up their model(s). If
method
initializeObject() is used for initialization logic that needs to be
triggered on initial creation AND on hydration. Please mind that
__construct()SHOULD call
initializeObject().
If there are no domain rules to follow, the recommended way to set up a model
would then still be to define a
__construct() and
initializeObject()
method like this:
I'd like to add a few more words on mutators (setter, adder, etc.). One might think that
DataMapper uses mutators during object hydration but it DOES NOT. mutators
are the only way for the user (developer) to implement business rules besides
using the constructor.
The
DataMapper uses the @internal method
AbstractDomainObject::_setProperty()
to update object properties. This looks a bit dirty and is a way around all business
rules but that's what the
DataMapper needs in order to leave the mutators to
the users.
Warning
While
DataMapper does not use any mutators, other parts of Extbase do.
Both, validation and property mapping, either use existing mutators or gather
type information from them. This will change in the future but as of TYPO3 v12 LTS
this information is correct.
Property visibility
One important thing to know is that Extbase needs entity properties to be protected
or public. As written in the former paragraph,
AbstractDomainObject::_setProperty()
is used to bypass setters.
AbstractDomainObject however, is not able to access
private properties of child classes, hence the need to have protected or public
properties.
Dependency injection
Without digging too deep into this topic the following statements have to be made.
Extbase expects entities to be so called prototypes, i.e. classes that do have a
different state per instance. DataMapper DOES NOT use dependency injection for the
creation of entities, i.e. it does not query the object container. This also means,
that dependency injection is not possible in entities.
If you think that your entities need to use/access services, you need to find other
ways to implement it.
Important: #100525 - Dropped usage of .text(-)-right and .text(-)-left classes
The Core has dropped support for directional class names to
better support RTL languages. We are now preferring the logical
class names over the directional ones. This change also affects
the default RTE configuration.
In summary, that means we are dropping the classes
.text-right
and
.text-left and replacing them with their logical counterparts
.text-end and
.text-start.
We are still shipping the
.text-right and
.text-left classes
with the default RTE content styling. Your content is
persisted as is and we have no intention of changing this.
You will see the following:
Your content is still aligned as you set it once
The alignment button will not be active anymore for
.text-left
and
.text-right
New alignments will now use
.text-end and
.text-start
While there is never a good time to introduce such a change,
we still think this will benefit us all over time.
If you want to follow us on that route, we suggest that you
add the following CSS to your frontend and or the custom
CSS for your RTE.
Back in TYPO3 v3.x there was an RTE integrated into TYPO3 which only worked
in Internet Explorer 4+, but not in Mozilla / Firefox browsers. This was a
huge mess, as not every user / client was able to use an RTE and instead to had
to write pure HTML in a
<textarea> input field with special tags ("typolink" etc).
Since TYPO3 v4 a huge effort were made to integrate HTMLarea as Rich Text Editor,
which was forked and developed by the TYPO3 community. It was then possible for
most users working with a real RTE.
In v8, TYPO3 migrated towards CKEditor 4 as a dependency, and CKEditor 5 with
TYPO3 v12, the Rich Text Editor is working very browser-native for modern browsers
without an iframe around the RTE.
A lot of legacy code was moved and migrated, however, one option - the option
to deactivate the Rich Text Editor on a per-user basis - which was necessary in
TYPO3 v3, has now been removed, as it is not needed in 99.99%
of TYPO3 installations and users anymore nowadays.
Impact
The previous user TSconfig setting
setup.edit_RTE has no effect anymore.
Important: #100658 - Drop use TSconfig options createFoldersInEB and folderTree.hideCreateFolder
The user TSconfig options
createFoldersInEB and
folderTree.hideCreateFolder were
used in the past to control the existence of the "Create folder" form in Element
Browser instances. With the migration of the "Create folder" view into a separate
modal used in EXT:filelist, which is based on Element Browser as well, those
options became useless and are therefore dropped.
After TYPO3 v12.0, only new functionality with a solid migration path
can be added on top, with aiming for as little as possible breaking changes
after the initial v12.0 release on the way to LTS.
A new TypoScript option is introduced which allows additional tag attributes to be set
to links of pages which are access restricted by frontend user group
restriction. Usually these links will not be generated, but it is possible to
link them to another page, for example, a special login page:
Allowing integrators to set custom
ATagParams such as class attributes or
arbitrary data attributes to use client-side styling via CSS or JavaScript event
listeners to handle such links differently.
Feature: #45039 - Command to clean up local processed files
It is now possible to set up a recurring scheduler task or execute a CLI command
to clean up locally processed files and their database records.
Impact
The command will delete
sys_file_processedfile records with references to
non-existing files. Also, files in the configured temporary directory
(typically _processed_) will be deleted if there are no references to them.
Example
Delete files and records with confirmation:
./bin/typo3 cleanup:localprocessedfiles
Copied!
Delete files and records:
./bin/typo3 cleanup:localprocessedfiles -f
Copied!
Only show which files and records would be deleted:
When working with file references (
sys_file_reference records) within FormEngine,
there are up to three buttons available:
"Create new relation"
"Select & upload files"
"Add media by URL"
Whereas the first button text can be changed via TCA on a per-field basis via
[config][appearance][createNewRelationLinkTitle] = 'LLL:my_extension/...';
the two other label fields are hard-coded. It is especially useful to override such a label
when only a certain type of media is required (for example, just images) or online media of type YouTube.
It is now possible to do so by using two new TCA configuration settings for TCA type=file
[config][appearance][uploadFilesLinkTitle]
[config][appearance][addMediaLinkTitle]
Impact
An extension author can now completely modify the label texts of all buttons.
A new PSR-14 event
\TYPO3\CMS\Core\Resource\Event\AfterDefaultUploadFolderWasResolvedEvent
has been added, which allows the default upload folder to be modified after it has
been resolved for the current page or user.
The new event can be used as a better alternative to the
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['getDefaultUploadFolder']
hook, serving the same purpose.
The event features the following methods:
getUploadFolder() returns the currently resolved
$uploadFolder
setUploadFolder() sets a new upload folder
getPid() returns the PID of the record we fetch the upload folder for
getTable() returns the table name of the record we fetch the upload folder for
getFieldName() returns the field name of the record we fetch the upload folder for
Registration of the event in your extension's Services.yaml:
As resolving the event was moved from
BackendUserAuthentication to its own
DefaultUploadFolderResolver class, this event is now the preferred way
of modifying the default upload folder.
Feature: #84594 - Additional parameters to email links
Editors in TYPO3 now have more possibilities to set options when
creating a link to a specific email address, in accordance with the "mailto:"
protocol.
This way, editors can now pre-fill the fields "subject", "CC", "BCC"
and "body" in the TYPO3 backend when creating a link to an email
address, which are then percent-encoded to the actual email link.
In addition, the <f:link.email> ViewHelper has the same additional
attributes as well:
<f:link.emailemail="foo@bar.tld"subject="Check out this website"cc="foo@example.com"bcc="bar@example.com"
>
some custom content
</f:link.email>
Copied!
All of the properties and the link fields are optional.
For custom email links, it is now also possible to restrict the additional
options via TCA:
On clicking, the TYPO3 backend login now displays an additional button to reveal the user's
password, once something has been typed in the password field.
Impact
A user who is about to log in to the backend is now able to reveal the typed
password. Once the password field is cleared, the visibility mode automatically
switches back to its default to avoid revealing sensitive data by accident.
Warning
Revealing login credentials is always a security risk. Please use this
feature with caution when nobody can watch your input, either remotely or by
looking over your shoulders!
If source_host and source_path lead to the same outcome for page type 0
using full URI building, like the
\TYPO3\CMS\Redirects\RedirectUpdate\PlainSlugReplacementSource, the
PlainSlugReplacementSource is replaced with the
PageTypeSource.
It is not possible to configure page types for which sources should be added. If
you need to do so, read additional PageTypeSource auto-create redirect source type
which provides an example of how to implement custom event listeners based on
PageTypeSource.
If
PageTypeSource for page type 0 results in a different
source, the
PlainSlugReplacementSource is not removed to keep the original
behaviour, which some instances may rely on.
Registration of the event in your extension's Services.yaml:
EXT:my_extension/Configuration/Services.yaml
MyExtension\MyPackage\Redirects\MyEventListener:tags:-name:event.listeneridentifier:'my-extension/custom-page-type-redirect'# Registering after core listener is important, otherwise we would# not know if there is a PageType source for page type 0after:'redirects-add-page-type-zero-source'
namespaceMyVendor\MyExtension\Redirects;
useTYPO3\CMS\Redirects\Event\SlugRedirectChangeItemCreatedEvent;
useTYPO3\CMS\Redirects\RedirectUpdate\PageTypeSource;
useTYPO3\CMS\Redirects\RedirectUpdate\PlainSlugReplacementRedirectSource;
useTYPO3\CMS\Redirects\RedirectUpdate\RedirectSourceCollection;
useTYPO3\CMS\Redirects\RedirectUpdate\RedirectSourceInterface;
finalclassMyEventListener{
publicfunction__invoke(
SlugRedirectChangeItemCreatedEvent $event
): void{
$changeItem = $event->getSlugRedirectChangeItem();
$sources = $changeItem->getSourcesCollection()->all();
$pageTypeZeroSource = $this->getPageTypeZeroSource(
...array_values($sources)
);
if ($pageTypeZeroSource === null) {
// nothing we can do - no page type 0 source foundreturn;
}
// Remove plain slug replacement redirect source from sources. We// already know, that if it is there it differs from the page type// 0 source, therefor it is safe to simply remove it by class check.
$sources = array_filter(
$sources,
static fn ($source) => !($source instanceof PlainSlugReplacementRedirectSource)
);
// update sources
$changeItem = $changeItem->withSourcesCollection(
new RedirectSourceCollection(
...array_values($sources)
)
);
// update change item with updated sources
$event->setSlugRedirectChangeItem($changeItem);
}
privatefunctiongetPageTypeZeroSource(
RedirectSourceInterface ...$sources
): ?PageTypeSource{
foreach ($sources as $source) {
if ($source instanceof PageTypeSource
&& $source->getPageType() === 0
) {
return $source;
}
}
returnnull;
}
}
Copied!
Impact
An additional redirect source is automatically added if a PageType suffix
is configured in the
SiteConfiguration for page type 0. In that case
two redirects are created, one for the plain slug change and one with the suffix
in the source_path. That way it does not break instances relying on the
fact that plain slug based redirects are created.
Note
This behaviour can be modified by adding an event listener for
SlugRedirectChangeItemCreatedEvent.
It can check if both variants are in the source collection and remove the
PlainSlugReplacementSource, as found in the example above.
Feature: #94499 - Provide additional PageTypeSource auto-create redirect source type
A new source type implementation based on
\TYPO3\CMS\Redirects\RedirectUpdate\RedirectSourceInterface
is added, providing the page type number as an additional value. The main use case
for this source type is to provide additional source types where the source host
and path are taken from a fully built URI before the page slug change occurred for
a specific page type. That avoids the need for extension authors to implement a
custom source type for the same task, and instead provides a custom event
listener to build sources for non-zero page types. Sources can be added by
implementing an event listener for
\TYPO3\CMS\Redirects\Event\SlugRedirectChangeItemCreatedEvent.
Note
TYPO3 Core implements a listener to add a
PageTypeSource for page
type 0 with AddPageTypeZeroSource Event Listener.
This source class can be re-used, if page type related sources should be added
for non-zero page types.
This class features the following methods:
getHost(): Returns the source host for the redirect
getPath(): Returns the source path for the redirect
getPageType(): Returns the page type used to provide the host/path
getTargetLinkParameters(): Returns the link parameters which should
be used to create the target based on t3:// syntax
Values can be set only by the constructor.
Example:
Registration of the event in your extension's Services.yaml:
namespaceMyVendor\MyExtension\Redirects;
useTYPO3\CMS\Core\Context\Context;
useTYPO3\CMS\Core\Routing\InvalidRouteArgumentsException;
useTYPO3\CMS\Core\Routing\RouterInterface;
useTYPO3\CMS\Core\Routing\UnableToLinkToPageException;
useTYPO3\CMS\Core\Site\Entity\Site;
useTYPO3\CMS\Core\Site\Entity\SiteLanguage;
useTYPO3\CMS\Core\Utility\GeneralUtility;
useTYPO3\CMS\Redirects\Event\SlugRedirectChangeItemCreatedEvent;
useTYPO3\CMS\Redirects\RedirectUpdate\PageTypeSource;
useTYPO3\CMS\Redirects\RedirectUpdate\RedirectSourceCollection;
useTYPO3\CMS\Redirects\RedirectUpdate\RedirectSourceInterface;
finalclassMyEventListener{
protectedarray $customPageTypes = [ 1234, 169999 ];
publicfunction__invoke(
SlugRedirectChangeItemCreatedEvent $event
): void{
$changeItem = $event->getSlugRedirectChangeItem();
$sources = $changeItem->getSourcesCollection()->all();
foreach ($this->customPageTypes as $pageType) {
try {
$pageTypeSource = $this->createPageTypeSource(
$changeItem->getPageId(),
$pageType,
$changeItem->getSite(),
$changeItem->getSiteLanguage(),
);
if ($pageTypeSource === null) {
continue;
}
} catch (UnableToLinkToPageException) {
// Could not properly link to page. Continue to next page typecontinue;
}
if ($this->isDuplicate($pageTypeSource, ...$sources)) {
// not adding duplicate,continue;
}
$sources[] = $pageTypeSource;
}
// update sources
$changeItem = $changeItem->withSourcesCollection(
new RedirectSourceCollection(
...array_values($sources)
)
);
// update change item with updated sources
$event->setSlugRedirectChangeItem($changeItem);
}
privatefunctionisDuplicate(
PageTypeSource $pageTypeSource,
RedirectSourceInterface ...$sources
): bool{
foreach ($sources as $existingSource) {
$existingHost = $existingSource->getHost();
$pageTypeSourceHost = $pageTypeSource->getHost();
$existingPath = rtrim($existingSource->getPath(), '/');
$pageTypeSourcePath = rtrim($pageTypeSource->getPath(), '/');
if ($existingSource instanceof PageTypeSource
&& $existingHost === $pageTypeSourceHost
&& $existingPath === $pageTypeSourcePath
) {
// we do not check for the type, as that is irrelevant. Same// host+path tuple would lead to duplicated redirects if// type differs.returntrue;
}
}
returnfalse;
}
privatefunctioncreatePageTypeSource(
int $pageUid,
int $pageType,
Site $site,
SiteLanguage $siteLanguage
): ?PageTypeSource{
if ($pageType === 0) {
// pageType 0 is handled by \TYPO3\CMS\Redirects\EventListener\AddPageTypeZeroSourcereturnnull;
}
try {
$context = $this->getAdjustedContext();
$uri = $site->getRouter($context)->generateUri(
$pageUid,
[
'_language' => $siteLanguage,
'type' => $pageType,
],
'',
RouterInterface::ABSOLUTE_URL
);
returnnew PageTypeSource(
$uri->getHost() ?: '*',
$uri->getPath(),
$pageType,
[
'type' => $pageType,
],
);
} catch (\InvalidArgumentException | InvalidRouteArgumentsException $e) {
thrownew UnableToLinkToPageException(
sprintf(
'The link to the page with ID "%d" and type "%d" could not be generated: %s',
$pageUid,
$pageType,
$e->getMessage()
),
1675618235,
$e
);
}
}
/**
* Returns the adjusted current context with modified visibility settings
* to build source url for hidden or scheduled pages.
*/privatefunctiongetAdjustedContext(): Context{
$adjustedVisibility = new VisibilityAspect(
true,
true,
false,
true,
);
$originalContext = GeneralUtility::makeInstance(Context::class);
$context = clone $originalContext;
$context->setAspect('visibility', $adjustedVisibility);
return $context;
}
}
Copied!
Impact
The new
PageTypeSource can be used to provide additional sources, for example,
based on custom page types using full URI building, which would take
configured PageTypeSuffix decorators into account. For page type 0 (default), the Core
implements an event listener which adds the source based on this source class for
page type 0 with AddPageTypeZeroSource event listener.
Feature: #97389 - Add password policy validation for TCA type=password
It is now possible to assign a password policy to TCA fields of type
password. For configured fields, the password policy validator will be used
in DataHandler to ensure that the new password complies with the configured
password policy.
Password policy requirements are shown below the password field when the focus
is changed to the password field.
The TCA field password for tables
be_users and
fe_users uses
now by default the password policy configured in
$GLOBALS['TYPO3_CONF_VARS']['FE']['passwordPolicy'] (fe_users) or
$GLOBALS['TYPO3_CONF_VARS']['BE']['passwordPolicy'] (be_users).
The password reset feature for TYPO3 frontend users now takes into account the
configurable password policy introduced in #97388,
if the feature toggle security.usePasswordPolicyForFrontendUsers is
set to true (default for new TYPO3 websites).
Impact
Password validation configured through
plugin.tx_felogin_login.settings.passwordValidators has been
marked as deprecated, but will still be used for password validation, if
the feature toggle security.usePasswordPolicyForFrontendUsers is set
to false.
TYPO3 websites, which have the feature toggle
security.usePasswordPolicyForFrontendUsers set to true, will use the globally
configured password policy when a TYPO3 frontend user resets their password.
The TYPO3 default password policy contains the following password requirements:
At least 8 chars
At least one number
At least one upper case char
At least one special char
Must be different than current password (if available)
Feature: #97667 - Add keyboard support for Multiselect
Extbase reflection now supports the detection of union types in entity properties.
Previously, whenever a union type was needed, union type declarations led to Extbase
not detecting any type at all, resulting in the property not being mapped. Union
types could be resolved via doc blocks however:
This is especially useful for lazy loaded relations where the property type is LazyLoadingProxy|ChildEntity.
There is something important to understand about how Extbase detects unions when
it comes to property mapping, i.e. when a database row is mapped onto an object.
In this case, Extbase needs to know the desired target type - no union, no
intersection, just one type. In order to achieve this, Extbase uses the first
declared type as a so-called primary type.
In this case, string is the primary type. int|string would result in int as primary type.
There is one important thing to note and one exception to this rule. First of
all, null is not considered a type. null|string results in primary type
string, which is nullable. null|string|int also results in primary type
string. In fact, null means that all other types are nullable.
null|string|int boils down to ?string or ?int.
Secondly, LazyLoadingProxy is never detected as primary type because it is
just a proxy and not the actual target type, once loaded.
Extbase supports this and detects ChildEntity as primary type, although
LazyLoadingProxy is the first item in the list. However, it is recommended to
place the actual type first, for consistency reasons: ChildEntity|LazyLoadingProxy.
A final word on LazyObjectStorage: LazyObjectStorage is a subclass of
ObjectStorage, therefore the following code works and has always worked:
Many users forget their login username and try to login with their email address.
The username of the backend user is now displayed in the password recovery email
alongside the reset link.
Impact
The username of the backend user is displayed in the password recovery email
alongside the reset link.
Note
Be aware, this feature comes with security risks:
Previously, a third-party that gained access to the email account could only
reset the password of the TYPO3 backend user, but not login if the username
was different to the email address.
Now it has all the information needed to login into the TYPO3 backend and
potentially could cause damage to the website.
We highly recommend protecting backend accounts using MFA.
It is also possible to override the ResetPassword email template to remove
the username and customize the result.
Feature: #99258 - Add minimum age option to EXT:lowlevel cleanup:deletedrecords command
Using the CLI command cleanup:deletedrecords to clean up the database
periodically is not really possible with EXT:recycler, because all
records marked for deletion are deleted immediately and thus the recycler seems
less useful.
The new option --min-age added to the cleanup:deletedrecords CLI command
allows a minimum age of the X days that a record needs to be marked as deleted
before it really gets deleted to be defined.
Impact
Executing bin/typo3 cleanup:deletedrecords --min-age 30 will only delete
records that have been marked for more than 30 days for deletion.
When adding a new language to a site, an integrator can now
choose
a) to create a new language by defining all values themselves
b) from a list of default language settings ("presets")
c) to use an existing language if it is already used in a different site
Although c) is always recommended when working with multi-site setups,
to keep language IDs between sites in sync, b) is now a quick start
to setup a new site.
Impact
Integrators spend less time adding new site languages.
Feature: #99436 - List commands in scheduler module
Commands based on Symfony commands are the successor of regular tasks since TYPO3 v8.
The scheduler submodule Available scheduler commands & tasks has been extended
to list not only available scheduler tasks, but CLI commands that can be added
as scheduler tasks.
Impact
The submodule Available scheduler commands & tasks has been improved to
list schedulable commands as well. This improves the overview and makes it easier
to set up commands.
A corresponding representation of the W3C standard of
Content-Security-Policy (CSP)
has been introduced to TYPO3. Content-Security-Policy declarations can either be provided by using
the general builder pattern of
\TYPO3\CMS\Core\Security\ContentSecurityPolicy\Policy , extension-specific
mutations (changes to the general policy) via Configuration/ContentSecurityPolicies.php
located in corresponding extension directories, or YAML path
contentSecurityPolicies.mutations for
site-specific declarations in the website frontend.
The PSR-15 middlewares
ContentSecurityPolicyHeaders apply Content-Security-Policy HTTP headers
to each response in the frontend and backend scope. In the case that other components have already added either the
header Content-Security-Policy or Content-Security-Policy-Report-Only, those existing headers will be
kept without any modification - these events will be logged with an info severity.
To delegate CSP handling to TYPO3, the scope-specific feature flags need to be enabled:
For new installations security.backend.enforceContentSecurityPolicy is enabled via factory default settings.
Potential CSP violations are reported back to the TYPO3 system and persisted internally in the database table
sys_http_report. A corresponding Content-Security-Policy backend module supports users to keep track of
recent violations and - if applicable - to select potential resolutions (stored in database table
sys_csp_resolution) which extends the Content-Security-Policy for the given scope during runtime.
As an alternative, the reporting URL can be configured to use third-party services as well:
Introducing CSP to TYPO3 aims to reduce the risk of being affected by Cross-Site-Scripting
due to the lack of proper encoding of user-submitted content in corresponding outputs.
Configuration
Policy builder approach
<?phpuseTYPO3\CMS\Core\Security\ContentSecurityPolicy\Directive;
useTYPO3\CMS\Core\Security\ContentSecurityPolicy\Policy;
useTYPO3\CMS\Core\Security\ContentSecurityPolicy\SourceKeyword;
useTYPO3\CMS\Core\Security\ContentSecurityPolicy\SourceScheme;
useTYPO3\CMS\Core\Security\ContentSecurityPolicy\UriValue;
useTYPO3\CMS\Core\Security\Nonce;
$nonce = Nonce::create();
$policy = (new Policy())
// results in `default-src 'self'`
->default(SourceKeyword::self)
// extends the ancestor directive ('default-src'), thus reuses 'self' and adds additional sources// results in `img-src 'self' data: https://*.typo3.org`
->extend(Directive::ImgSrc, SourceScheme::data, new UriValue('https://*.typo3.org'))
// extends the ancestor directive ('default-src'), thus reuses 'self' and adds additional sources// results in `script-src 'self' 'nonce-[random]'` ('nonce-proxy' is substituted when compiling the policy)
->extend(Directive::ScriptSrc, SourceKeyword::nonceProxy)
// sets (overrides) the directive, thus ignores 'self' of the 'default-src' directive// results in `worker-src blob:`
->set(Directive::WorkerSrc, SourceScheme::blob);
header('Content-Security-Policy: ' . $policy->compile($nonce));
Copied!
The result of the compiled and serialized result as HTTP header would look similar to this
(the following sections are using the same example, but utilize different techniques for the declarations).
<?phpuseTYPO3\CMS\Core\Security\ContentSecurityPolicy\Directive;
useTYPO3\CMS\Core\Security\ContentSecurityPolicy\Mutation;
useTYPO3\CMS\Core\Security\ContentSecurityPolicy\MutationCollection;
useTYPO3\CMS\Core\Security\ContentSecurityPolicy\MutationMode;
useTYPO3\CMS\Core\Security\ContentSecurityPolicy\Scope;
useTYPO3\CMS\Core\Security\ContentSecurityPolicy\SourceKeyword;
useTYPO3\CMS\Core\Security\ContentSecurityPolicy\SourceScheme;
useTYPO3\CMS\Core\Security\ContentSecurityPolicy\UriValue;
useTYPO3\CMS\Core\Type\Map;
return Map::fromEntries([
// provide declarations for the backend
Scope::backend(),
// NOTICE: When using `MutationMode::Set` existing declarations will be overriddennew MutationCollection(
// results in `default-src 'self'`new Mutation(MutationMode::Set, Directive::DefaultSrc, SourceKeyword::self),
// extends the ancestor directive ('default-src'), thus reuses 'self' and adds additional sources// results in `img-src 'self' data: https://*.typo3.org`new Mutation(MutationMode::Extend, Directive::ImgSrc, SourceScheme::data, new UriValue('https://*.typo3.org')),
// NOTICE: the following two instructions for `Directive::ImgSrc` are identical to the previous instruction,// `MutationMode::Extend` is a shortcut for `MutationMode::InheritOnce` and `MutationMode::Append`// new Mutation(MutationMode::InheritOnce, Directive::ImgSrc, SourceScheme::data),// new Mutation(MutationMode::Append, Directive::ImgSrc, SourceScheme::data, new UriValue('https://*.typo3.org')),// extends the ancestor directive ('default-src'), thus reuses 'self' and adds additional sources// results in `script-src 'self' 'nonce-[random]'` ('nonce-proxy' is substituted when compiling the policy)new Mutation(MutationMode::Extend, Directive::ScriptSrc, SourceKeyword::nonceProxy),
// sets (overrides) the directive, thus ignores 'self' of the 'default-src' directive// results in `worker-src blob:`new Mutation(MutationMode::Set, Directive::WorkerSrc, SourceScheme::blob),
),
]);
Copied!
Site-specific (frontend)
In the frontend, the dedicated sites/<my-site>/csp.yaml can be used to declare CSP for a specific site as well.
config/sites/<my-site>/csp.yaml
# inherits default site-unspecific frontend policy mutations (enabled per default)inheritDefault:truemutations:# results in `default-src 'self'`-mode:setdirective:'default-src'sources:-"'self'"# extends the ancestor directive ('default-src'), thus reuses 'self' and adds additional sources# results in `img-src 'self' data: https://*.typo3.org`-mode:extenddirective:'img-src'sources:-'data:'-'https://*.typo3.org'# extends the ancestor directive ('default-src'), thus reuses 'self' and adds additional sources# results in `script-src 'self' 'nonce-[random]'` ('nonce-proxy' is substituted when compiling the policy)-mode:extenddirective:'script-src'sources:-"'nonce-proxy'"# results in `worker-src blob:`-mode:setdirective:'worker-src'sources:-'blob:'
Copied!
PSR-14 events
PolicyMutatedEvent
The
\TYPO3\CMS\Core\Security\ContentSecurityPolicy\Event\PolicyMutatedEvent will
be dispatched once all mutations have been applied to the current policy object, just
before the corresponding HTTP header is added to the HTTP response object.
This allows individual changes for custom implementations. Next to the
Scope, the
Policy's and the
MutationCollection's might the Event also provide
the current PSR-7
ServerRequestInterface for additional context.
InvestigateMutationsEvent
The
\TYPO3\CMS\Core\Security\ContentSecurityPolicy\Event\InvestigateMutationsEvent will
be dispatched when the Content-Security-Policy backend module searches for potential resolutions
to a specific CSP violation report. This way, third-party integrations that rely on external resources
(for example, maps, file storage, content processing/translation, ...) can provide the necessary mutations.
Feature: #99608 - Add password policy action to exclude validators in SU mode
The new password policy action UPDATE_USER_PASSWORD_SWITCH_USER_MODE has been
added in order to allow administrators to exclude a password policy validator,
if the current user is in switch user mode.
The new password policy action is used in the global default password policy for
the NotCurrentPasswordValidator.
Impact
When the current backend user is in switch user mode, it is not validated,
if the new password equals the current user password in ext:setup.
Feature: #99629 - Webhooks - Outgoing webhooks for TYPO3
A webhook is an automated message sent from one application to another via HTTP.
This feature adds the possibility to configure webhooks in TYPO3.
A new backend module System > Webhooks provides the possibility to
configure webhooks. The module is available in the TYPO3 backend for users with
administrative rights.
A webhook is defined as an authorized POST or GET request to a defined URL.
For example, a webhook can be used to send a notification to a Slack channel
when a new page is created in TYPO3.
Any webhook record is defined by a universally unique identifier (UUID), a speaking name, an optional
description, a trigger, the target URL and a signing-secret.
Both the unique identifier and the signing-secret are generated in the backend
when a new webhook is created.
Triggers provided by the TYPO3 Core
The TYPO3 Core currently provides the following triggers for webhooks:
Page Modification: Triggers when a page is created, updated or deleted
File Added: Triggers when a file is added
File Updated: Triggers when a file is updated
File Removed: Triggers when a file is removed
Login Error Occurred: Triggers when a login error occurred
Redirect Was Hit: Triggers when a redirect has been hit
These triggers are meant as a first set of triggers that can be used to send webhooks,
further triggers will be added in the future. In most projects however, it is likely
that custom triggers are required.
Custom triggers
Trigger by PSR-14 events
Custom triggers can be added by creating a Message for an specific PSR-14 event and
tagging that message as a webhook message.
The following example shows how to create a simple webhook message for the
\TYPO3\CMS\Core\Resource\Event\AfterFolderAddedEvent :
Create a final class implementing \TYPO3\CMS\Core\Messaging\WebhookMessageInterface.
Add the
\TYPO3\CMS\Core\Attribute\WebhookMessage attribute to the class.
The attribute requires the following information:
identifier: The identifier of the webhook message.
description: The description of the webhook message. This description
is used to describe the trigger in the TYPO3 backend.
Add a static method createFromEvent() that creates a new instance of the
message from the event you want to use as a trigger.
Add a method jsonSerialize() that returns an array with the data that
should be sent with the webhook.
Trigger by hooks or custom code
In case a trigger is not provided by the TYPO3 Core or a PSR-14 event is not available,
it is possible to create a custom trigger - for example by using a TYPO3 hook.
The message itself should look similar to the example above, but does not need the
createFromEvent() method.
Instead, the custom code (hook implementation) will create the message
and dispatch it.
Example hook implementation for a DataHandler hook (see
\TYPO3\CMS\Webhooks\Listener\PageModificationListener ):
Instead of the PHP attribute the Services.yaml can be used to define the
webhook message. The following example shows how to define the webhook message
from the example above in the Services.yaml:
With every webhook request, the following HTTP headers are sent:
Content-Type: application/json
Webhook-Signature-Algo: sha256
Webhook-Signature: <hash>
The hash is calculated with the secret of the webhook and the JSON encoded data
of the request. The hash is created with the PHP function
hash_hmac.
See the following section about the hash calculation.
Hash calculation
The hash is calculated with the following PHP code:
$hash = hash_hmac('sha256', sprintf(
'%s:%s',
$identifier, // The identifier of the webhook (uuid)
$body // The JSON encoded body of the request
), $secret); // The secret of the webhook
Copied!
The hash is sent as HTTP header Webhook-Signature and should be used to
validate that the request was sent from the TYPO3 instance and has not been
manipulated.
To verify this on the receiving end, build the hash with the same algorithm and
secret and compare it with the hash that was sent with the request.
The hash is not meant to be used as a security mechanism, but as a way to verify
that the request was sent from the TYPO3 instance.
Technical background and advanced usage
The webhook system is based on the Symfony Messenger component. The messages
are simple PHP objects that implement an interface that denotes
them as webhook messages.
That message is then dispatched to the Symfony Messenger bus. The TYPO3 Core
provides a
\TYPO3\CMS\Webhooks\MessageHandler\WebhookMessageHandler
that is responsible for sending the webhook
requests to the third-party system, if configured to do so. The handler looks up
the webhook configuration and sends the request to the configured URL.
Messages are sent to the bus in any case. The handler is then responsible for checking
whether or not an external request (webhook) should be sent.
If advanced request handling is necessary or a custom implementation should be used,
a custom handler can be created that handles
WebhookMessageInterface
messages.
The TYPO3 Core now provides a convenient GUI to create and send webhooks to
third-party systems.
In combination with the system extension reactions
TYPO3 can now be used as a
low-code/no-code integration platform between multiple systems.
Since Feature: #99618 - List of countries in the world and their localized names, TYPO3 provides a list of countries, together with an API
and a Fluid form ViewHelper. A new "Country select" form element has now been
added to the TYPO3 Form Framework for creating a country select in a form
easily. The new form element features a couple of configuration options, which
can either be configured via the Forms module or directly in the
corresponding YAML file.
Available options
First option (
prependOptionLabel): Define the "empty option", i.e. the first element of the select. You can use this to provide additional guidance for the user.
Prioritized countries (
prioritizedCountries): Define a list of countries which should be listed as first options in the form element.
Only countries (
onlyCountries): Restrict the countries to be rendered in the list.
Exclude countries (
excludeCountries): Define which countries should not be shown in the list.
The new element will be rendered as single select (
<select>) HTML
element in the frontend.
Impact
The new "Country select" form element is now available in the Form
Framework with a couple of specific configuration options.
Feature: #99739 - Associative array keys for TCA items
It is now possible to define associative array keys for the
items
configuration of TCA types
select,
radio and
check. The
new keys are called:
label,
value,
icon,
group and
description.
It is now much easier and clearer to define the TCA
items configuration
with associative array keys. The struggle to remember which option is first,
label or value, is now over. In addition, optional keys like
icon and
group can be omitted, for example, when one desires to set the
description option.
Feature: #99802 - New PSR-14 ModifyRedirectManagementControllerViewDataEvent
A new PSR-14 event
\TYPO3\CMS\Redirects\Event\ModifyRedirectManagementControllerViewDataEvent
is introduced, allowing extension authors to modify or enrich view data for the
\TYPO3\CMS\Redirects\Controller\ManagementController . This allows to
display more or other information along the way.
This event features the following methods:
getDemand(): Return the demand object used to retrieve the redirects
getRedirects(): Return the retrieved redirects
setRedirects(): Can be used to set the redirects, for example, after enriching redirect fields
getRequest(): Return the current request
getHosts(): Returns the hosts to be used for the host filter select-box
setHosts(): Can be used to update which hosts are available in the filter select-box
getStatusCodes(): Returns the status codes for the filter select box
setStatusCodes(): Can be used to update which status codes are available in the filter select-box
getCreationTypes(): Returns creation types for the filter select box
setCreationTypes(): Can be used to update which creation types are available in the filter select-box
getShowHitCounter(): Returns if hit counter should be displayed
setShowHitCounter(): Can be used to manage if the hit counter should be displayed
getView(): Returns the current view object, without controller data assigned yet
setView(): Can be used to assign additional data to the view
For example, this event can be used to add additional information to current page records.
Therefore, it can be used to generate custom data, directly assigning to the view.
With overriding the backend view template via page TSconfig this custom data can
be displayed where it is needed, and rendered the way it is wanted.
With the new
ModifyRedirectManagementControllerViewDataEvent, it is
now possible to modify view data or inject further data to the view for the
management view of redirects.
Feature: #99803 - New PSR-14 BeforeRedirectMatchDomainEvent
A new PSR-14 event
\TYPO3\CMS\Redirects\Event\BeforeRedirectMatchDomainEvent
is introduced to the
\TYPO3\CMS\Redirects\Service\RedirectService , allowing extension authors to implement a
custom redirect matching upon the loaded redirects or return matched redirect
record from other sources.
This event features following methods:
getDomain(): Returns the domain for which redirects should be
checked for, "*" for all domains.
getPath(): Returns the path which should be checked.
getQuery(): Returns the query part which should be checked.
getMatchDomainName(): Returns current check domain name.
getMatchedRedirect(): Returns the matched
sys_redirect record,
set by another event listener or null.
setMatchedRedirect(): Can be used to clear prior matched redirect
by setting it to
null or set a matched
sys_redirect record.
Note
Full
sys_redirect record must be set using setMatchedRedirect() method.
Otherwise later Core code would fail, as it expects, for example, the uid of the record
to set the X-Redirect-By response header. Therefore, the getMatchedRedirect()
method returns null or a full
sys_redirect record.
Note
The
BeforeRedirectMatchDomainEvent is dispatched before cached redirects
are retrieved. That means, that the event does not contain any
sys_redirect
records. Internal redirect cache may vanish eventually if possible. Therefore,
it is left out to avoid a longer bound state to the event by properly deprecate it.
namespaceMyVendor\MyExtension\Redirects;
useTYPO3\CMS\Backend\Utility\BackendUtility;
useTYPO3\CMS\Redirects\Event\BeforeRedirectMatchDomainEvent;
finalclassMyEventListener{
publicfunction__invoke(BeforeRedirectMatchDomainEvent $event): void{
$matchedRedirectRecord = $this->customRedirectMatching($event);
if ($matchedRedirectRecord !== null) {
$event->setMatchedRedirect($matchedRedirectRecord);
}
}
privatefunctioncustomRedirectMatching(
BeforeRedirectMatchDomainEvent $event
): ?array{
// @todo Implement custom redirect record loading and matching. If// a redirect based on custom logic is determined, return the// :sql:`sys_redirect` tables conform redirect record.// Note: Below is simplified example code with no real value.
$record = BackendUtility::getRecord('sys_redirect', 123);
// Do custom matching logic against the record and return matched// record - if there is one.if ($record
&& /* custom condition against the record */
) {
return $record;
}
// return null to indicate that no matched redirect could be foundreturnnull;
}
}
Copied!
Impact
With the new
BeforeRedirectMatchDomainEvent it is now possible to
implement custom redirect matching methods before core matching is processed.
Feature: #99834 - New PSR-14 AfterAutoCreateRedirectHasBeenPersistedEvent
A new PSR-14 event
\TYPO3\CMS\Redirects\Event\AfterAutoCreateRedirectHasBeenPersistedEvent
is introduced, allowing extension authors to react on persisted auto-created redirects. This
can be used to call external API or do other tasks based on the real persisted redirects.
Note
To handle later updates or react on manual created redirects in the backend
module, available hooks of
\TYPO3\CMS\Core\DataHandling\DataHandler
can be used.
namespaceMyVendor\MyExtension\Redirects;
useTYPO3\CMS\Redirects\Event\AfterAutoCreateRedirectHasBeenPersistedEvent;
useTYPO3\CMS\Redirects\RedirectUpdate\PlainSlugReplacementRedirectSource;
classMyEventListener{
publicfunction__invoke(
AfterAutoCreateRedirectHasBeenPersistedEvent $event
): void{
$redirectUid = $event->getRedirectRecord()['uid'] ?? null;
if ($redirectUid === null
&& !($event->getSource() instanceof PlainSlugReplacementRedirectSource)
) {
return;
}
// Implement code what should be done with this information. E.g.// write to another table, call a rest api or similar. Find your// use-case.
}
}
Copied!
Impact
With the new
AfterAutoCreateRedirectHasBeenPersistedEvent, it is now possible
to react on persisted auto-created redirects. Manually created redirects can be handled
by using one of the available
\TYPO3\CMS\Core\DataHandling\DataHandler hooks,
not suitable for auto-created redirects.
Feature: #99834 - New PSR-14 ModifyAutoCreateRedirectRecordBeforePersistingEvent
A new PSR-14
\TYPO3\CMS\Redirects\Event\ModifyAutoCreateRedirectRecordBeforePersistingEvent
is introduced, allowing extension authors to modify the redirect record before it is persisted to
the database. This can be used to change values based on circumstances, for example, like
different sub tree settings, not covered by the Core site configuration. Another use-case
could be to write data to additional
sys_redirect columns added by a custom
extension for later use.
Note
To handle later updates or react on manually created redirects in the backend
module, available hooks of
\TYPO3\CMS\Core\DataHandling\DataHandler
can be used.
namespaceMyVendor\MyExtension\Redirects;
useTYPO3\CMS\Redirects\Event\ModifyAutoCreateRedirectRecordBeforePersistingEvent;
useTYPO3\CMS\Redirects\RedirectUpdate\PlainSlugReplacementRedirectSource;
finalclassMyEventListener{
publicfunction__invoke(
ModifyAutoCreateRedirectRecordBeforePersistingEvent $event
): void{
// only work on plain slug replacement redirect sources.if (!($event->getSource() instanceof PlainSlugReplacementRedirectSource)) {
return;
}
// Get prepared redirect record and change some values
$record = $event->getRedirectRecord();
// override the status code, eventually to another value than// configured in the site configuration
$record['status_code'] = 307;
// Set value to a field extended by a custom extension, to persist// additional data to the redirect record.
$record['custom_field_added_by_a_extension']
= 'page_' . $event->getSlugRedirectChangeItem()->getPageId();
// Update changed record in event to ensure changed values are saved.
$event->setRedirectRecord($record);
}
}
Copied!
Impact
With the new
ModifyAutoCreateRedirectRecordBeforePersistingEvent, it is now
possible to modify the auto-create redirect record before it is persisted to the database.
Manually created redirects or updated redirects can be handled by using the well-known
\TYPO3\CMS\Core\DataHandling\DataHandler and the available hooks.
Feature: #99861 - Add tile view to element browser
The file list is the default implementation for TYPO3 to navigate and
manage assets. This patch extends the usage of the file list to the
element browser, the build-in component to select the assets for file
fields and folder fields in the backend.
Impact
The rendering of files and folder now deliver a unified experience and
allow the user to use the tile view to select assets.
The search within the file browser now respects the selected folder and
searches all subfolders for the provided search term.
To have an even more reliable experience, the user will now always start
the selection process in the root folder of the default storage.
Resource tiles are now adapting to the surrounding container instead of
the viewport, to make better use of the available space.
The file list now holds all related code to the file and folder browser.
Feature: #99874 - Edit task groups within the Scheduler module
Task groups can be managed in the backend module itself. Users can create, update and
delete task groups within the Scheduler module. Sorting is done via drag&drop (drag the panel header)
and inline-style editing is used to change the title name. Only empty groups may be deleted.
Impact
Users may edit groups in the Scheduler module.
Note
The group's description has never been displayed in the Scheduler module and has been
deprecated. Editing the description is and has always been only possible via the List module.
It is now possible to exclude empty FlexForm settings from being merged into
Extbase extension settings. Extension authors and integrators can use the new
Extbase TypoScript configuration
ignoreFlexFormSettingsIfEmpty
to define FlexForm settings, which will be ignored in the merge process of the
extension settings, if their value is considered empty (either an empty string or a
string containing 0).
In the following example,
settings.showForgotPassword and
settings.showPermaLogin from FlexForm will not be merged into extension
settings, if the individual value is empty:
If an extension already defined
ignoreFlexFormSettingsIfEmpty,
integrators are advised to use
addToList or
removeFromList to modify existing settings as shown in the
following example:
It is possible to define the
ignoreFlexFormSettingsIfEmpty
configuration globally for an extension using the
plugin.tx_extension TypoScript configuration or for an individual
plugin using the
plugin.tx_extension_plugin TypoScript
configuration.
Extension authors can use the new PSR-14 event
\TYPO3\CMS\Extbase\Event\Configuration\BeforeFlexFormConfigurationOverrideEvent
to implement a FlexForm override process in a custom extension based on the original
FlexForm configuration and the framework configuration.
Additionally, the new Extbase TypoScript configuration is used in EXT:felogin to
ensure that empty FlexForm settings are not merged into extension settings.
Event example
Register an event listener in your Services.yaml file:
Empty FlexForm extension settings can now conditionally be excluded from the
FlexForm configuration merge process.
Also, it is now possible again to use global TypoScript extension settings
in EXT:felogin, which previously might have been overridden by empty FlexForm
settings.
In addition, with the new
BeforeFlexFormConfigurationOverrideEvent it is
now possible to further manipulate the merged configuration after standard
override logic is applied.
Feature: #100027 - Copy files and folders within the File > List module
With TYPO3 v12.2, the feature to
drag+drop files and folders between the tree
structure was added. Now it is also possible to copy or move resources within
the actual file listing (tile view or list view), for example, into a different subfolder
by selecting them, and using the mouse to drop them on to a target folder.
Impact
The File > List module is now fully usable with drag+drop between
the tree and within the listing itself.
All features make it easier for editors to manage and organize the digital
assets used within TYPO3.
Extbase repositories come with a magic
__call() method to allow calling
the following methods without implementing:
findBy[PropertyName]($propertyValue)
findOneBy[PropertyName]($propertyValue)
countBy[PropertyName]($propertyValue)
Magic methods are quite handy but they have a huge disadvantage. There is no
proper IDE support i.e. most IDEs show an error or at least a warning,
saying method
findByAuthor() does not exist. Also, type declarations are
impossible to use because with
__call() everything is
mixed. And
last but not least, static code analysis - like PHPStan - cannot properly
analyze those and give meaningful errors.
Therefore, there is a new set of methods without all those downsides:
The naming of those methods follows those of doctrine/orm and only
count() differs from the formerly
countBy(). While all magic
methods only allow for a single comparison (propertyName = propertyValue),
those methods allow for multiple comparisons, called constraints.
In our effort of introducing dedicated TCA types for special use cases,
a new TCA field type called
json has been added to TYPO3 Core.
Its main purpose is to simplify the TCA configuration when working with
fields, containing JSON data. It therefore replaces
the previously introduced
dbtype=json of TCA type
user.
Using the new type, TYPO3 automatically takes care of adding the corresponding
database column.
The TCA type
json features the following column configuration:
behaviour:
allowLanguageSynchronization
cols
default
enableCodeEditor
fieldControl
fieldInformation
fieldWizard
placeholder
readOnly
required
rows
Note
In case
enableCodeEditor is set to
true, which is the default
and the system extension t3editor is installed and active, the JSON value
is rendered in the corresponding code editor. Otherwise it is rendered in a
standard textarea HTML element.
The following column configuration can be overwritten by page TSconfig:
cols
rows
readOnly
Impact
It is now possible to use a dedicated TCA type for rendering of JSON fields.
Using the new TCA type, corresponding database columns are added automatically.
Since v3, Doctrine DBAL supports adding custom driver middlewares. These
middlewares act as a decorator around the actual Driver component.
Subsequently, the Connection, Statement and Result components can be
decorated as well. These middlewares must implement the
\Doctrine\DBAL\Driver\Middleware interface.
A common use case would be a middleware for implementing SQL logging capabilities.
To ease the usage of group fields in the FormEngine, for example, like in the
"Insert records" content element, the record overview now shows the path to the
location where each assigned record is stored, respectively.
Impact
Elements of type group now show the path to the page where any assigned record
is stored in.
Feature: #100116 - Make PSR-7 request accessible for authentication services
Authentication services can now access the PSR-7 request object via the
$authInfo array. Previously, custom TYPO3 authentication services
did not have direct access to the object and therefore had to either
use PHP super globals or TYPO3's GeneralUtility::getIndpEnv() method.
The following example shows how to retrieve the PSR-7 request in the
initAuth() method of a custom authentication service:
Custom TYPO3 authentication services can now directly access the PSR-7
request object from the authentication process. It is available via the
request key of the
$authInfo array, which is handed over
to the
initAuth() method.
Feature: #100143 - Add scheduler command to execute and list tasks
The CLI command
scheduler:run of EXT:scheduler offers a way to run a
task using a cronjob. It also allows to run tasks if the UID of the task
is known.
To make it more convenient to use the command,
scheduler:list and
scheduler:execute were introduced.
The
scheduler:list command shows an overview of all available tasks or
a given group with an option to watch and reload the list every X seconds
(default every 1 second).
Example:
# List all tasks in group 1 and group 2 and watch for changes every second.
vendor/bin/typo3 scheduler:list --group 1 --group 2 --watch
# List all tasks without a group and watch for changes every 2 seconds.
vendor/bin/typo3 scheduler:list --group 0 --watch 2
# Same as above with shortcut parameter
vendor/bin/typo3 scheduler:list -g 0 -w 2
Copied!
The
scheduler:execute command displays a list of groups and available
tasks for the selection. If a group is selected all tasks within this group are
executed.
Example:
# Run alls tasks without a group and task 8
vendor/bin/typo3 scheduler:execute --task g:0 --task 8
# Same as above with shortcut parameter
vendor/bin/typo3 scheduler:execute -t g:0 -t 8
Copied!
Impact
The new commands
scheduler:list and
scheduler:execute enable
the user to manage and run tasks without leaving the terminal.
Feature: #100167 - AdminPanel: Add SQL and memory metrics to toolbar
In our effort of introducing dedicated TCA types for special use cases,
a new TCA field type called
uuid has been added to TYPO3 Core.
Its main purpose is to simplify the TCA configuration when working with
fields, containing a UUID.
The TCA type
uuid features the following column configuration:
enableCopyToClipboard
fieldInformation
required: Defaults to
true
size
version
Note
In case
enableCopyToClipboard is set to
true, which is the
default, a button is rendered next to the input field, which allows to copy
the UUID to the clipboard of the operating system.
Note
The
version option defines the UUID version to be used. Allowed
values are 4, 6 or 7. The default is 4. For more information
about the different versions, have a look at the corresponding
symfony documentation.
The following column configuration can be overwritten by page TSconfig:
size
enableCopyToClipboard
An example configuration looks like the following:
It is now possible to use a dedicated TCA type for rendering of a UUID field.
Using the new TCA type, corresponding database columns are added automatically.
Feature: #100187 - ICU-based date and time formatting
TYPO3 now supports rendering date and time based on formats/patterns defined by
the International Components for Unicode standard (ICU).
TYPO3 previously only supported rendering of dates based on the PHP-native
functions
date() and
strftime().
However,
date() can only format dates with English texts, such as
"December" as non-localized values, the C-based
strftime() function works
only with the locale defined in PHP and availability in the underlying operating
system.
In addition, ICU-based date and time formatting is much more flexible in
rendering, as it ships with default patterns for date and time (namely
FULL, LONG, MEDIUM and SHORT) which are based on the given locale.
This means, that when the locale en-US is given, the short date is rendered
as mm/dd/yyyy whereas de-AT uses the dd.mm.yyyy syntax automatically,
without having to define a custom pattern just by using the SHORT default
pattern.
In addition, the patterns can be adjusted more fine-grained, and can easily
deal with time zones for output when DateTime objects are handed in.
TYPO3 also adds prepared custom patterns:
FULLDATE (like FULL, but only the date information)
FULLTIME (like FULL, but only the time information)
LONGDATE (like LONG, but only the date information)
LONGTIME (like LONG, but only the time information)
MEDIUMDATE (like MEDIUM, but only the date information)
MEDIUMTIME (like MEDIUM, but only the time information)
SHORTDATE (like SHORT, but only the date information)
SHORTTIME (like SHORT, but only the time information)
A new stdWrap feature called formattedDate is added, and the new formatting
can also be used in Fluid's
<f:format.date> ViewHelper.
The locale is typically fetched from the locale of the site language (stdWrap or
ViewHelper), or the backend user's language (in backend context) for the
ViewHelper usages.
Examples for stdWrap:
page.10 = TEXT
page.10.value = 1998-02-20 3:00:00
# see all available options https://unicode-org.github.io/icu/userguide/format_parse/datetime/#datetime-format-syntax
page.10.formattedDate = FULL
# optional, if a different locale is wanted other than the Site Language's locale
page.10.formattedDate.locale = de-DE
Copied!
will result in "Freitag, 20. Februar 1998 um 03:00:00 Koordinierte Weltzeit".
page.10 = TEXT
page.10.value = -5 days
page.10.formattedDate = FULL
page.10.formattedDate.locale = fr-FR
With this change, we are rolling out the universal file-list
rendering for files and folders to the link browser. The link
browser implementation for files and folders is now part of the
filelist extension.
The link browser now allows the user to choose the display type
of resources to match the personal preference between list and
tile rendering.
When the user now edits a link for a folder, the entry point is
the parent folder of the selected element folder instead of
showing the contents of the selected resource. The user sees
the selected folder in the presented list, this behavior mimics
the handling of selected files.
Impact
The user is now presented a unified experience when handling
resources. The modern filelist rendering is now rolled out to
the link browser and now covers, the filelist module, element
browser and link browser.
Feature: #100218 - Improved TypoScript and page TSconfig modules
The new parser allowed us to refactor the related backend modules along the way:
While many of these have been done with earlier v12 releases already, v12.3 now
finishes the basic feature set of these new and refactored modules.
This is a summary of these UI changes:
Frontend TypoScript
The well-known main module Web > Template has been renamed and moved,
and can be found as Site Management > TypoScript.
"TypoScript records overview": This submodule was more hidden in previous versions.
It gives an overview which page records have TypoScript template records.
"Constant Editor": This submodule is mainly kept as-is from previous versions.
"Edit TypoScript Record": This submodule was known as "Info / Modify" from previous
versions. Its main functionality is kept.
"Active TypoScript": This submodule was known as "TypoScript Object Browser" in
previous versions. The UI of this module received a major streamlining and gives
a better overview of the compiled TypoScript on a page: The module now shows
both "constants" and "setup" at the same time, gives more detail information,
and the tree is quicker to navigate.
"Included TypoScript": This submodule was known as "Template Analyzer" in
previous versions. Similar to "Active TypoScript", it shows "constants" and
"setup" at the same time. It allows to simulate the effect of conditions
to the include tree, and shows sub-includes from
@import and
similar as nodes within the tree. A basic syntax scanner finds broken TypoScript
syntax snippets.
Page TSconfig
The previous submodule Web > Info > Page TSconfig has been heavily refactored
and can be found as new main module Site Management > Page TSconfig.
The new page TSconfig module is similar in its look and feel to the TypoScript
module.
"Page TSconfig Records": This submodule did not exist as such in previous versions
and gives an overview which page records in the system contain page TSconfig settings.
"Active Page TSconfig": This is similar to "Active TypoScript" from the "TypoScript"
module. It allows browsing current page TSconfig and allows simulating the effect
of conditions.
"Included page TSconfig": This is similar to the "Included TypoScript" from the
"TypoScript" module. It shows all source files and records that create the final
page TSconfig of a page. A basic syntax scanner finds broken syntax snippets.
Impact
The refactored modules allow more fine grained analysis
of page TSconfig and TypoScript.
Feature: #100232 - Load additional stylesheets in TYPO3 backend
It is now possible to load additional CSS files for the TYPO3
backend interface via regular
$TYPO3_CONF_VARS settings in a
settings.php file of a project (previously known as LocalConfiguration.php)
file or in an extension's ext_localconf.php.
Previously this was done via the outdated
$TBE_STYLES
global array which has been deprecated.
Impact
By defining a specific stylesheet, a single CSS file or all CSS files
of a folder, extension authors can now modify the styling via:
A new PSR-14 event
\TYPO3\CMS\Core\Authentication\Event\LoginAttemptFailedEvent
has been introduced. The event allows to notify remote systems about failed logins.
The event features the following methods:
isFrontendAttempt(): Whether this was a login attempt from a frontend login form
isBackendAttempt(): Whether this was a login attempt in the backend
getUser(): Returns the
\TYPO3\CMS\Core\Authentication\AbstractUserAuthentication derivative in question
getRequest(): Returns the current PSR-7 request object
getLoginData(): The attempted login data without sensitive information
Registration of the event in your extension's Services.yaml:
namespaceMyVendor\MyExtension\Authentication\EventListener;
useTYPO3\CMS\Core\Authentication\Event\LoginAttemptFailedEvent;
finalclassMyEventListener{
publicfunction__invoke(LoginAttemptFailedEvent $event): void{
if ($event->getRequest()->getAttribute('normalizedParams')->getRemoteAddress() !== '198.51.100.42') {
// send an email because an external user login attempt failed
}
}
}
Copied!
Impact
It is now possible to notify external loggers about failed login attempts
while having the full request.
Feature: #100284 - Add CKEditor Inspector for backend RTE forms
This feature introduces the ability to show the CKEditor Inspector for backend RTE forms.
With CKEditor 5 and the introduction of the intermediate CKEditor model, knowing
the internals is a requirement to build plugins. The best way to debug during the plugin
development is the CKEditor Inspector.
For regular pages, there is a simple bookmarklet that can be included to show
the Inspector, but in the TYPO3 backend the usage of frames does not allow this
option. Giving developers a config option in the RTE simplifies this process.
The Inspector can be activated in two different ways:
By enabling
$GLOBALS['TYPO3_CONF_VARS']['BE']['debug'] and
being in the Development context
By setting the option
editor.config.debug to
true in your
CKEditor configuration
Example for setting the CKEditor configuration:
editor:config:debug:true
Copied!
Impact
Being in the right context or enabling the given option, it is now possible
to debug CKEditor instances for plugin development in an easier way.
Feature: #100293 - New ContentObject EXTBASEPLUGIN in TypoScript
The old way still works, but it is recommended to use the
EXTBASEPLUGIN
ContentObject, as the direct reference to a PHP class (Bootstrap) might be
optimized in future versions.
Impact
This change is an effort to distinguish between plugins and regular other
more static content.
Extbase is the de-facto standard for plugins, which serve dynamic content by
custom PHP code divided in controllers and actions by extension developers.
Regular other content can be written in pure TypoScript, such as ContentObjects
like FLUIDTEMPLATE, HMENU, COA or TEXT is used for other kind of renderings
in the frontend.
A new PSR-14 event
\TYPO3\CMS\Core\PasswordPolicy\Event\EnrichPasswordValidationContextDataEvent
has been added, which allows extension authors to enrich the
\TYPO3\CMS\Core\PasswordPolicy\Validator\Dto\ContextData
DTO used in password policy validation.
The PSR-14 event is dispatched in all classes, where a user password is
validated against the globally configured password policy.
The event features the following methods:
getContextData() returns the current
ContextData DTO
getUserData() returns an array with user data available from the
initiating class
getInitiatingClass() returns the class name, where the
ContextData DTO is created
The event can be used to enrich the
ContextData DTO with additional data
used in custom password policy validators.
Note
The user data returned by
getUserData() will include user data
available from the initiating class only. Therefore, event listeners should
always consider the initiating class name when accessing data from
getUserData(). If required user data is not available via
getUserData(), it can possibly be retrieved by a custom database
query (e.g. data from user table in the password reset process by fetching
the user with the
uid given in
getUserData() array).
Registration of the event in your extension's Services.yaml:
With the new
EnrichPasswordValidationContextDataEvent, it is now
possible to enrich the
ContextData DTO used in password policy
validation with additional data.
Feature: #100307 - PSR-14 events for user login & logout
The purpose of these events is to trigger any kind of action when a user
has been successfully logged in or logged out.
TYPO3 Core itself uses
AfterUserLoggedInEvent in the TYPO3 backend
to send an email to a user, if the login was successful.
The event features the following methods:
getUser(): Returns the
\TYPO3\CMS\Core\Authentication\AbstractUserAuthentication derivative in question
The PSR-14 event
BeforeUserLogoutEvent on top has the possibility
to bypass the regular logout process by TYPO3 (removing the cookie and
the user session) by calling
$event->disableRegularLogoutProcess()
in an event listener.
The PSR-14 event
AfterUserLoggedInEvent contains the method
getRequest() to return PSR-7 request object of the current request.
Registration of the event in your extension's Services.yaml:
The hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['getDefaultUploadFolder'] has been marked
as deprecated in favor of a new PSR-14 event
AfterDefaultUploadFolderWasResolvedEvent.
The TypoScript password validation configured through
plugin.tx_felogin_login.settings.passwordValidators has been
marked as deprecated.
The TypoScript validators are used when the feature toggle
security.usePasswordPolicyForFrontendUsers is set to false (default for
existing TYPO3 installations).
An upgrade wizard will ask the user during the TYPO3 upgrade
if security.usePasswordPolicyForFrontendUsers should be activated or, if
deprecated, TypoScript validators should be used.
Impact
Validators configured in
plugin.tx_felogin_login.settings.passwordValidators will
trigger a deprecation log entry when a password reset is performed.
Affected installations
TYPO3 installations using validators configured in
plugin.tx_felogin_login.settings.passwordValidators.
Migration
Special password requirements configured using custom validators in TypoScript
must be migrated to a custom password policy validator as described
in #97388.
Before creating a custom password policy validator, it is recommended to
check if the
CorePasswordValidator used in the default password
policy suits current password requirements.
Deprecation: #99739 - Indexed array keys for TCA items
Using indexed array keys for the
items configuration of TCA types
select,
radio and
check is now deprecated.
Impact
Using indexed array keys for the
items configuration array items of TCA
types
select,
radio and
check will trigger a deprecation
level log entry. A TCA migration is in place.
Affected installations
All installations having custom extensions that make use of TCA types
select,
radio or
check and define at least one entry in
the
items array.
itemsProcFunc
The
items array handed over to custom
itemsProcFunc functions
contains the new object type
\TYPO3\CMS\Core\Schema\Struct\SelectionItem
which acts as a compatibility layer for old style indexed keys. Accessing,
writing and reading items still work in the old way. Added items will be
automatically converted. For third-party extensions supporting both TYPO3 v11
(or lower) and v12 it is recommended to keep using indexed keys.
Migration
To migrate your TCA, change all indexed keys according to the following mapping
table:
The system-wide setting
$TYPO3_CONF_VARS['FE']['versionNumberInFilename']
was previously evaluated as a "string" value, having three possible options:
""
"querystring"
"embed"
Depending on the option, resources used in TYPO3's frontend templates, such as
JavaScript or CSS assets, had their "modification time" in either the
querystring (myfile.js?1675703622), or in the file name itself
myfile.1675703622.js - the "embed" option). The latter option required a
.htaccess rule.
This existing feature ("cachebusting") is especially important for proxy / CDN
setups.
For the sake of simplicity, the option is now a boolean option - and behaves
similarly to the backend variant
$TYPO3_CONF_VARS['BE']['versionNumberInFilename'].
Impact
If the option is now set to "false", it behaves as "querystring" did before, setting
it to "true", the feature behaves exactly as "embed". The original empty option
is removed, so all assets within the TYPO3 frontend rendering always include
cachebusting, by default a querystring, which is fully backwards-compatible.
Affected installations
TYPO3 installations that have actively set this option in
LocalConfiguration.php, AdditionalConfiguration.php or in an
extension ext_localconf.php.
Migration
When updating TYPO3 and accessing the maintenance area, an explicitly set option
is automatically migrated. If this is not possible - for example, configuration in
AdditionalConfiguration.php is set - the value is always migrated
on-the-fly when the setting is evaluated.
Deprecation: #99882 - Site language "typo3Language" setting
A language configuration defined for a site has had various settings, one of
them being
typo3Language. The setting is used to define the language key which
should be used for fetching the proper XLF file (such as de_AT.locallang.xlf).
Since TYPO3 v12 it is unnecessary to set this property in the site configuration
and it is removed from the backend UI. The information is now automatically
derived from the
locale setting of the site configuration.
The previous value "default", which matched "en" as language key is now unnecessary
as "default" is now a synonym for "en".
As a result, the amount of options in the user interface for integrators is
reduced.
Impact
An administrator cannot select a value for the
typo3Language setting anymore
via the TYPO3 backend. If a custom value is required, the site configuration
needs to be manually edited and the
typo3Language setting needs to be added.
If this is the case, please file a bug report in order to give the TYPO3
development team feedback on what use case is required.
However, saving a site configuration via the TYPO3 backend will still
keep the
typo3Language setting so no values will be lost.
Affected installations
TYPO3 installations created before TYPO3 v12.3.
Migration
No migration is needed as the explicit option is still evaluated. It is however
recommended to check if the setting is really necessary.
Examples:
If
typo3Language: "default" and
locale: "en_US.UTF-8", the setting can be removed.
If
typo3Language: "pt_BR" and
locale: "pt_BR.UTF-8", the setting can be removed.
If
typo3Language: "de" and
locale: "de_AT.UTF-8" , the setting can be removed,
plus the label files check for de_AT.locallang.xlf and de.locallang.xlf
as fallback when accessing a translated label.
If
typo3Language: "pt_BR" and
locale: "de_DE.UTF-8" it is likely
a misconfiguration in the setup, and should be analyzed if the custom value is really needed.
Deprecation: #99900 - $limit parameter of GeneralUtility::intExplode()
The static method
GeneralUtility::intExplode() has a lesser known fourth
parameter
$limit. The reason it was added to the
intExplode() method
is purely historical, when it used to extend the
trimExplode() method. The
dependency was resolved, but the parameter stayed. As this method is supposed to
only return
int values in an array, the
$limit parameter is now
deprecated.
Impact
Calling
GeneralUtility::intExplode() with the fourth parameter
$limit will trigger a deprecation warning and will add an entry to the
deprecation log.
Affected installations
TYPO3 installations that call
GeneralUtility::intExplode() with the
fourth parameter
$limit.
Migration
In the rare case that you are using the
$limit parameter you will need to
switch to PHP's native
explode() function, and then use
array_map() to convert the resulting array to integers. If that's
impractical, you can simply copy the old
intExplode method to your own
code.
Deprecation: #99905 - Site language "iso-639-1" setting
A language configuration defined for a site has had various settings, one of
them being
iso-639-1 (also known as "twoLetterIsoCode").
This setting was previously introduced to define the current ISO 639-1 code, which
was different from the
locale or the
typo3Language setting. However,
this information is now properly retrieved with the method:
SiteLanguage->getLocale()->getLanguageCode().
Since TYPO3 v12 it is not necessary to set this property in the site configuration
anymore, and it has been removed from the backend UI. The information is now automatically
derived from the
locale setting of the site configuration.
This property originally came from an option in TypoScript called
config.sys_language_isocode which in turn was created in favor of
the previous
sys_language database table. The TYPO3 Core never evaluated this
setting properly before TYPO3 v9.
As a result, the amount of options in the user interface for integrators is
reduced.
The PHP method
SiteLanguage->getTwoLetterIsoCode() serves no purpose
anymore and is deprecated.
This also affects the TypoScript
getData property
siteLanguage:twoLetterIsoCode,
and the TypoScript condition
[siteLanguage("twoLetterIsoCode")].
Impact
Using the TypoScript settings or the PHP method will trigger a PHP deprecation notice.
An administrator cannot select a value for the
iso-639-1 setting anymore
via the TYPO3 backend. However, saving a site configuration via the
TYPO3 backend will still keep the
iso-639-1 setting so no information is lost.
Affected installations
TYPO3 installations actively accessing this property via PHP or TypoScript.
Migration
No migration is needed as the explicit option is still evaluated. It is however
recommended to check if the setting is really necessary, and if the first part of the
locale setting matches the
iso-639-1 setting. If so, the line with
iso-639-1 can be removed.
As for TypoScript, it is recommended to use
siteLanguage:locale:languageCode
instead of
siteLanguage:twoLetterIsoCode.
Deprecation: #99908 - Site language "hreflang" setting
A language configuration defined for a site has had various settings, one of
them being
hreflang. The setting is used to generate hreflang meta tags to
link to alternative language versions of a translated page, and to add the
lang attribute to the
<html> tag of a frontend page in HTML format.
Since TYPO3 v12 it is not necessary to set this property in the site configuration
anymore. The information is now automatically
derived from the
locale setting of the site configuration if not set
in the site configuration.
This also affects the TypoScript
getData property
siteLanguage:hrefLang, and the TypoScript condition
[siteLanguage("hrefLang")].
Impact
Using the TypoScript settings or the PHP method will trigger a PHP deprecation
notice.
An administrator cannot select a value for the
hreflang setting anymore
via the TYPO3 backend. However, when saving a site configuration via the
TYPO3 backend it will still keep the
hreflang setting so no information is lost.
Affected installations
TYPO3 installations actively accessing this property via PHP or TypoScript.
Migration
No migration is needed as the explicit option is still evaluated. It is however
recommended to check if the setting is really necessary, and if the locale of
the site language in the config.yaml matches the same value - even in a
different format (
locale: "de_AT.UTF-8",
hreflang: "de-AT") - the setting
hreflang can be removed.
Any calls to
SiteLanguage->getHrefLang() can be replaced by
SiteLanguage->getLocale()->getName().
As for TypoScript, it is recommended to use
siteLanguage:locale:full
instead of
siteLanguage:hrefLang.
Deprecation: #99916 - Site language "direction" setting
A language configuration defined for a site has had various settings, one of
them being
direction. The setting is used to add the
dir attribute to the
<html> tag of a frontend page in HTML format, defining the direction of the
language.
Since TYPO3 v12 it is not necessary to set this property in the site configuration
anymore, and has been removed from the backend UI. The information is now automatically
derived from the
locale setting of the site configuration.
As a result, the amount of options in the user interface for integrators is
reduced.
The PHP method
SiteLanguage->getDirection() serves no purpose anymore and
is deprecated.
Impact
Using the PHP method will trigger a PHP deprecation notice.
An administrator can not select a value for the
direction setting anymore
via the TYPO3 backend. However, when saving a site configuration via the
TYPO3 backend it will still keep the
direction setting so no information is lost.
Affected installations
TYPO3 installations actively accessing this property via PHP or TypoScript, and
mainly related to TYPO3 installations with languages that have a "right-to-left"
reading direction.
Migration
No migration is needed as the explicit option is still evaluated. It is however
not necessary in 99.99% of the use cases. If the locale of the site language in the
site's config.yaml matches the natural direction of the language
(Arabic and direction = rtl), the setting
direction can be removed.
Any calls to
SiteLanguage->getDirection() can be replaced by
SiteLanguage->getLocale()->isRightToLeftLanguageDirection() ? 'rtl' : 'ltr'.
The method acts as as shortcut to quickly disable some functions in the backend
context to ease output inspection. However, the properties set by the
method are ignored in the backend context anyway, the method is obsolete.
Impact
Using the method will raise a deprecation level log entry and will stop
working in TYPO3 v13.
Affected installations
Instances with extensions that call the method are affected.
The extension scanner reports usages as a weak match.
Migration
All calls to the deprecated messages should be removed from the codebase.
Deprecation: #100014 - Function getParameterFromUrl() of @typo3/backend/utility module
The function
getParameterFromUrl() of the
@typo3/backend/utility
module was used to obtain a query string argument from an arbitrary URL.
Meanwhile, browsers received the URLSearchParams API that can be used
instead.
Therefore,
getParameterFromUrl() has been marked as deprecated.
Impact
Calling
getParameterFromUrl() will trigger a deprecation warning.
Affected installations
All installations using third-party extensions relying on the deprecated code are
affected.
Migration
Migrate to the following snippet to get the same result:
const paramValue = new URL(url, window.location.origin).searchParams.get(parameter);
Copied!
Deprecation: #100033 - TBE_STYLES stylesheet and stylesheet2
The usage of
$GLOBALS['TBE_STYLES']['stylesheet'] and
$GLOBALS['TBE_STYLES']['stylesheet2'] to add custom CSS files
to the TYPO3 backend has been marked as deprecated in TYPO3 v12 and will be
removed in TYPO3 v13.
Impact
Using any of the following configuration declarations
$GLOBALS['TBE_STYLES']['stylesheet']
$GLOBALS['TBE_STYLES']['stylesheet2']
will trigger a PHP deprecation notice and will throw a fatal PHP error in
TYPO3 v13.
Affected installations
The extension scanner will find extensions using
$GLOBALS['TBE_STYLES']['stylesheet']
$GLOBALS['TBE_STYLES']['stylesheet2']
as "weak" matches.
Migration
Extensions should use
$GLOBALS['TYPO3_CONF_VARS']['BE']['stylesheets']['my_extension']
where
'my_extension' is the extension key.
The TYPO3 Core only uses these classes within the old TypoScript parser classes,
which have been deprecated as well.
Using the classes will trigger a deprecation level log entry.
Affected installations
There was probably little need to implement new variants of the above classes as
the underlying
ExpressionLanguage construct has its own API to add new
variables and functions for this TypoScript condition related to Symfony expression
language usage.
Migration
No direct migration possible. These classes have been merged into the new
TypoScript parser approach, specifically for class
\TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeConditionMatcherVisitor .
Adding TypoScript related expression language variables and functions should be
done using
\TYPO3\CMS\Core\ExpressionLanguage\ProviderInterface .
Deprecation: #100047 - Page TSconfig and user TSconfig must not rely on request
Using
request and function
ip() in page TSconfig or
user TSconfig conditions has been marked as deprecated in TYPO3 v12. Such conditions
will stop working in TYPO3 v13 and will always evaluate to false.
Page TSconfig and user TSconfig should not rely on request related data: They should
not check for given arguments or similar: the main reason is that the Backend
DataHandler makes heavy use of page TSconfig, but the DataHandler itself is
not request-aware. The DataHandler (the code logic that updates data in the database
in the backend) can be used and must work in a CLI context, so any page TSconfig that
depends on a given request is flawed by design since it will never act as expected
in a CLI context.
To avoid further issues with the DataHandler in web and CLI contexts,
TSconfig-related conditions must no longer be request-aware.
Impact
Using request-related conditions in page TSconfig or user TSconfig will raise a
deprecation level warning in TYPO3 v12 and will always evaluate to false in
TYPO3 v13.
Affected installations
There may be instances of page TSconfig using conditions using
request-related conditions. These need to look for different solutions
that achieve a similar goal.
Migration
Try to get rid of
ip() or request related information in
page TSconfig conditions.
A typical example is highlighting something when a developer is
using the live domain:
[request.getRequestHost() == 'development.my.site']
mod.foo = bar
[end]
Copied!
Switch to the application context in such cases:
[applicationContext == "Development"]
mod.foo = bar
[end]
Copied!
There are similar alternatives for other use cases: You can not rely on given
GET / POST arguments anymore, but it should be possible to switch to
backend.user.isAdmin or similar conditions in most cases, or to
handle related switches within controller classes in PHP.
Relying on request arguments for page TSconfig conditions is fiddly,
especially when using this for core related controllers: those are not considered
API and may change at anytime. Instead, needs should be dealt with explicitly using
toggles within controllers.
The method
\TYPO3\CMS\Core\Utility\GeneralUtility::_GP() has
been marked as deprecated and should not be used any longer.
Modern code should access GET and POST data from the PSR-7
ServerRequestInterface,
and should avoid accessing superglobals
$_GET and
$_POST
directly. This also avoids future side-effects when using sub-requests. Some
GeneralUtility related helper methods like
_GP() violate this,
using them is considered a technical debt. They are being phased out.
Impact
Calling the method from PHP code will log a PHP deprecation level entry,
the method will be removed with TYPO3 v13.
Affected installations
TYPO3 installations with third-party extensions using
GeneralUtility::_GP()
are affected, typically in TYPO3 installations which
have been migrated to the latest TYPO3 Core versions and
haven't been adapted properly yet.
The extension scanner will find usages with a strong match.
Migration
GeneralUtility::_GP() is a helper method that retrieves
incoming HTTP GET query arguments and POST body parameters and returns the value.
The same result can be achieved by retrieving arguments from the request object.
An instance of the PSR-7
ServerRequestInterface is handed over to
controllers by TYPO3 Core's PSR-15
\TYPO3\CMS\Core\Http\RequestHandlerInterface
and middleware implementations, and is available in various related scopes
like the frontend
\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer .
Typical code:
useTYPO3\CMS\Core\Utility\GeneralUtility;
// Before
$value = GeneralUtility::_GP('tx_scheduler');
// After
$value = $request->getParsedBody()['tx_scheduler'] ?? $request->getQueryParams()['tx_scheduler'] ?? null;
Extbase repositories come with a magic
__call() method to allow calling
the following methods without implementing them:
findBy[PropertyName]($propertyValue)
findOneBy[PropertyName]($propertyValue)
countBy[PropertyName]($propertyValue)
These have now been marked as deprecated, as they are "magic", meaning
that proper IDE support is not possible, and other PHP-related tool
functionality such as PhpStorm.
In addition, it is not possible for Extbase repositories
to build their own magic method functionality as the logic is already
in use.
Impact
As these methods are widely used in almost all Extbase-based extensions,
they are marked as deprecated in TYPO3 v12, but will only trigger a deprecation
notice in TYPO3 v13, as they will be removed in TYPO3 v14.
This way, migration towards the new API methods can be made without
pressure.
Affected installations
All installations with third-party extensions that use those magic methods.
Migration
A new set of methods without all the downsides have been added:
The naming of the methods follows those of doctrine/orm and only
count() differs from the formerly
countBy(). While all magic
methods only allow for a single comparison (propertyName = propertyValue),
those methods allow for multiple comparisons, called constraints.
findBy[PropertyName]($propertyValue) can be replaced with a call to findBy:
Please note that the (not-magic) methods findByUid() and findByIdentifier() did not
get deprecated or removed, and are still valid to be used.
Using these methods will fetch a given domain object by it's UID, ignoring possible storage
page settings - unlike findBy([...]), which does respect those settings.
The global configuration array
$TBE_STYLES has been deprecated in favor of a new
setting
$TYPO3_CONF_VARS['BE']['stylesheets']. Previously, before
TYPO3 v6.0,
$TBE_STYLES allowed for defining more styles within PHP instead
of using CSS.
However, now that CSS has become been much more powerful than 10 years ago,
it is time to change the logic and also consolidate TYPO3's internal configuration
settings.
This deprecation is in order to be more flexible for styling purposes, as
the registration of custom stylesheets can now be handled on a per-project
basis.
Extensions can use almost the same syntax, however registration is now done
in an extension's ext_localconf.php to reduce loading times for
ext_tables.php files.
Impact
Registration of backend styles via
$GLOBALS['TBE_STYLES']['skins'] in
an extension's ext_tables.php file will trigger a PHP
deprecation notice.
Setting
$GLOBALS['TBE_STYLES']['stylesheets']['admPanel'] will also
trigger a deprecation notice every time the Admin Panel is loaded in the
TYPO3 frontend.
Affected installations
TYPO3 installations with custom styling in the TYPO3 backend or the Admin Panel
via
$GLOBALS['TBE_STYLES'].
Migration
Migrate to the new configuration setting
$GLOBALS['TYPO3_CONF_VARS']['BE']['stylesheets']
which can be set per site or within an extension's ext_localconf.php.
For a custom stylesheet in the TYPO3 Admin Panel, it is recommended to use the
new AdminPanel Module API (available since TYPO3 v9 LTS) where custom CSS and
JavaScript files can be registered dynamically.
Both exceptions should have been marked
@internal within the core, but
were not.
The exception
\TYPO3\CMS\Core\Exception\MissingTsfeException was an internal
communication class and was caught internally, the use case was solved in a more
simple way avoiding the exception.
The exception
\TYPO3\CMS\Core\Configuration\TypoScript\Exception\InvalidTypoScriptConditionException
was related to conditions which triggered a warning within the symfony expression language. Those were
turned into this exception in TYPO3 v11. In TYPO3 v12, the original exception will bubble up, forcing
developers to fix the broken Symfony condition syntax.
Affected installations
Third-party extensions most likely neither throw nor catch these exceptions, the
extension scanner will find possible usages.
Migration
No direct migration available.
Note
Using the
getTSFE() function, developers have to ensure
that "TSFE" is available before accessing its properties. A missing "TSFE",
e.g. in backend context, does no longer automatically evaluate the whole
condition to
FALSE. Instead, the function returns
NULL,
which can be checked using either
[getTSFE() && getTSFE().id == 42]
or the null-safe operator
[getTSFE()?.id == 42].
Deprecation: #100247 - Various interconnected methods in EXT:scheduler
The scheduler system extension, responsible for executing long-running, timed
or recurring tasks, has been included since TYPO3 v4.3, but never received an
overhaul of its code base.
Back then, the main
\TYPO3\CMS\Scheduler\Scheduler class and the
\TYPO3\CMS\Scheduler\Task\AbstractTask class were the main API classes, all logic being included,
whereas
AbstractTask is the main class that all custom tasks within
extensions derive from.
However, in the past 15 years TYPO3's code base has undergone a lot of API
design changes related to separation of concerns. In order to achieve this in
the scheduler extension, almost all access to the actual database access around
task retrieving and scheduling has been moved into its own
\TYPO3\CMS\Scheduler\Domain\Repository\SchedulerTaskRepository class.
For this reason, the following methods within the original API classes are now
either marked as deprecated or internal - not part of TYPO3's public API
anymore - as they have now been moved into the new repository class.
Scheduler->addTask()
Scheduler->log() - marked as internal
Scheduler->removeTask()
Scheduler->saveTask()
Scheduler->fetchTask()
Scheduler->fetchTaskRecord()
Scheduler->fetchTaskWithCondition()
Scheduler->isValidTaskObject()
Scheduler->log() - marked as internal
AbstractTask->isExecutionRunning()
AbstractTask->markExecution()
AbstractTask->unmarkExecution()
AbstractTask->unmarkAllExecutions()
AbstractTask->save() - marked as internal
AbstractTask->remove()
AbstractTask->setScheduler() - marked as internal
AbstractTask->unsetScheduler() - marked as internal
AbstractTask->registerSingleExecution() - marked as internal
AbstractTask->getExecution() - marked as internal
AbstractTask->setExecution() - marked as internal
AbstractTask->getNextDueExecution() - marked as internal
AbstractTask->areMultipleExecutionsAllowed() - marked as internal
AbstractTask->stop() - marked as internal
Impact
Calling any of the deprecated methods will trigger a PHP warning. Using the
internal methods should be avoided and is not covered by the TYPO3 backwards
compatibility promise.
Affected installations
TYPO3 installations with extensions that include custom scheduler tasks accessing
these methods. The Extension Scanner might be helpful to detect these usages.
The hook
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['postLoginFailureProcessing']
which can be used to handle custom notifications that a login in a frontend or
backend context failed, has been marked as deprecated.
Impact
If the hook is registered in a TYPO3 installation, a PHP
E_USER_DEPRECATED
error is triggered.
The extension scanner also detects any usage of the deprecated interface as
a strong match, and the definition of the hook as a weak match.
Affected installations
TYPO3 installations with custom extensions using this hook.
The following HTTP security headers are now added by default for the TYPO3
backend:
Strict-Transport-Security: max-age=31536000 (only if
$GLOBALS[TYPO3_CONF_VARS][BE][lockSSL] is active)
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
The default HTTP security headers are configured globally in
$GLOBALS['TYPO3_CONF_VARS']['BE']['HTTP']['Response']['Headers'] and include
a unique array key, so it is possible to individually unset/remove unwanted
headers.
Important
TYPO3 websites, which already use custom HTTP headers for the TYPO3 backend,
must ensure that individual HTTP security headers are not sent multiple
times.
Important: #100088 - Remove dbType json for TCA type user
With forge#99226 the dbType=json option has been added for
TCA type user. After some reconsideration, it has been decided
to drop this option again in favor of the dedicated TCA type json.
Have a look to the according changelog
for further information.
Since the dbType option has not been released in any LTS version yet,
the option is dropped without further deprecation. Also no TCA migration
is applied.
In case you make already use of this dbType in your custom extension,
you need to migrate to the new TCA type.
The cookie warning message in ext:felogin is never shown, since it depends on
conditions, which will never be met. The cookie warning message can also be
considered superfluous, since a similar message is already shown, if
authentication was not successful.
Code affecting the non-working cookie warning message has therefore been
removed from ext:felogin. TYPO3 users should remove code from custom templates,
which depend on the {cookieWarning} variable.
After TYPO3 v12.0, only new functionality with a solid migration path
can be added on top, with aiming for as little as possible breaking changes
after the initial v12.0 release on the way to LTS.
The password used to create the backend user during install (GUI and setup
command) now considers the configurable password policy introduced in
#97388.
Impact
The globally configured password policy is now taken into account
when the backend user is created during the install process.
For each violation of the password policy a message will be
displayed to the user (GUI and setup command).
Feature: #86913 - Automatic support for language files of languages with region suffix
TYPO3's native support for label files - that is: translatable text for system
labels such as from plugins, and for texts within TYPO3 backend - supports over
50 languages. Languages are identified by their "language key" of the ISO 639-1
standard, which also allows the use of a region-specific language. This happens
mostly in countries/regions that have a variation of the language, such
as "en-US" for American English, or "de-CH" for the German language
in Switzerland.
To support these region-specific language keys, which are composed of ISO 639-1
and ISO 3166-1 and separated with -, TYPO3 integrators had to configure the
additional language manually to translate region-specific terms.
Common examples are "Behavior" (American English) vs. "Behaviour"
(British English), or "Offerte" (Swiss German) vs. "Angebot" (German),
where all labels except a few terms should stay the same.
Impact
TYPO3 now allows integrators to use a custom label file with the
locale prefix de_CH.locallang.xlf in an extension next to
de.locallang.xlf and locallang.xlf
(default language English).
When integrators then use de-CH within their site configuration, TYPO3
first checks if a term is available in the translation file de_CH.locallang.xlf,
and then automatically falls back to the non-region-specific de
translation file de.locallang.xlf without any further configuration to
TYPO3.
Previously, such region-specific locales had to be configured via:
TYPO3's site handling was introduced in TYPO3 v9 and allows to define a
"fallback type".
A fallback type allows to define the behavior of how pages and the content
should be fetched from the database when rendering a page in the frontend.
The option strict only renders content which was explicitly translated or
created in the defined language, and keeps the sorting behavior of the
default language.
The option free does not consider the default language or its sorting,
and only fetches directly content of the given language ID.
The option fallback allows to define a fallback chain of languages.
If a certain page is not available in the given language, TYPO3
first checks the fallback chain if a page is available in one of the languages
in the fallback chain.
A common scenario is this:
German (Austria) - Language = 2
German (Germany) - Language = 1
English (Default) - Language = 0
TYPO3 now can deal with the language chain in fallback mode not only for pages,
but also for any kind of content.
Impact
When working in a scenario with fallback and multiple languages in the fallback
chain, TYPO3 now checks for each content if the target language is available,
and then checks for the same content if it is translated in the language of the
fallback chain (example above in "German (Germany)"), before falling back to
the default language - which was the behavior until now.
The language chain processing works with fallback mode (a.k.a. "overlays in mixed mode"),
both in TypoScript and Extbase code. Under the hood, the method
PageRepository->getLanguageOverlay() is responsible for the chaining.
Current limitations:
Content fallback only works in fallbackType=fallback
Content fallback always stops at the default language (as this was the
previous behavior)
Feature: #92517 - Custom namespace for Extbase plugin enhancer
The Extbase plugin enhancer for frontend routing allows to either set extension
and plugin OR to set namespace. If extension and plugin were given,
those were used.
However, the namespace option is automatically constituted by the extension and
plugin options if it was not set intentionally. It is mainly used when overriding
the custom extension and plugin options with a custom (usually shortened) namespace,
so that the namespace is now always respected and preferred if all three options
are set.
Impact
If all of namespace and extension and plugin options are configured,
the namespace option is now preferred within the Extbase plugin enhancer.
Feature: #97392 - Use password policy for new admin users created in ext:install
The password for a new administrative backend user created using EXT:install
now considers the configurable password policy introduced by
#97388.
Impact
The global password policy is now taken into account when a
new administrative backend user is created using EXT:install.
Password policy requirements are shown below the password field and a message
is shown, if the new password does not meet the password policy requirements.
Feature: #97700 - Adopt Symfony Messenger as a message bus and queue
This feature provides a basic implementation of a message bus based on the
Symfony Messenger component.
For backwards compatibility, the default implementation uses the synchronous
transport. This means that the message bus will behave exactly as before, but it
will be possible to switch to a different (async) transport on a per-project
base. To offer asynchronicity, the feature also provides a transport implementation
based on the Doctrine DBAL messenger transport from Symfony and a basic
implementation of a consumer command.
As an example, the workspace StageChangeNotification has been rebuilt as a
message and corresponding handler.
"Everyday" usage - as a developer
Dispatch a message
Add a PHP class for your message object (arbitrary PHP class)
(
DemoMessage)
By default, the system behaves as before. This means that the message bus
uses the synchronous transport and all messages are handled immediately.
To benefit from the message bus, it is recommended to switch to an asynchronous
transport. Using asynchronous transports increases the resilience of the system
by decoupling external dependencies even further.
The TYPO3 Core currently provides an asynchronous transport based on the
Doctrine DBAL messenger transport. This transport is configured to use the
default TYPO3 database connection. It is pre-configured and can be used
by changing the settings in config/settings.php:
This will route all messages to the asynchronous transport.
If you are using the Doctrine transport, make sure to take care of running the
consume command (see below).
Async message handling - The consume command
Run the command
./bin/typo3 messenger:consume <receiver-name> to consume messages.
By default, you should run ./bin/typo3 messenger:consume doctrine. The command is a
slimmed-down wrapper for the Symfony command messenger:consume, it only provides
the basic consumption functionality. As this command is running as a worker,
it is stopped after 1 hour to avoid memory leaks. The command should therefore
be run from a service manager like systemd to automatically restart it after
the command exits due to the time limit.
Create a service via /etc/systemd/system/typo3-message-consumer.service:
[Unit]Description=Run the TYPO3 message consumer
Requires=mariadb.service
After=mariadb.service
[Service]Type=simple
User=www-data
Group=www-data
ExecStart=/usr/bin/php8.1 /var/www/myproject/vendor/bin/typo3 messenger:consume doctrine --exit-code-on-limit 133# Generally restart on errorRestart=on-failure
# Restart on exit code 133 (which is returned by the command when limits are reached)RestartForceExitStatus=133# ..but do not interpret exit code 133 as an error (as it's just a restart request)SuccessExitStatus=133[Install]WantedBy=multi-user.target
Copied!
The message worker can than be enabled and started via
systemctl enable --now typo3-message-consumer
Advanced Usage
Configure a custom transport (senders/receivers)
Set up transports in services configuration. To configure one transport per
message, the TYPO3 configuration (config/settings.php,
config/additional.php on system level or ext_localconf.php) is
used. The transport/sender name used in the settings is
resolved to a service that has been tagged with message.sender and the
respective identifier.
$GLOBALS['TYPO3_CONF_VARS']['SYS']['messenger'] = [
'routing' => [
// use "messenger.transport.demo" as transport for DemoMessage
\TYPO3\CMS\Queue\Message\DemoMessage::class => 'demo',
// use "messenger.transport.default" as transport for all other messages'*' => 'default',
]
];
\Symfony\Component\Messenger\Transport\InMemory\InMemoryTransport is a
transport that should only be used while testing. See the SymfonyCasts
tutorial
for more details.
Set up a middleware in the services configuration. By default,
\Symfony\Component\Messenger\Middleware\SendMessageMiddleware
and
\Symfony\Component\Messenger\Middleware\HandleMessageMiddleware
are registered - see also Symfony's documentation.
To add your own message middleware, tag it as
messenger.middleware
and set the order using TYPO3's before and after ordering mechanism.
The two fields
storage and
folder of the
sys_file_collection
table are now combined into the new field
folder_identifier. The field
contains the so-called combined identifier in the format storage:folder,
where storage is the
uid of the corresponding
sys_file_storage
record and folder the absolute path to the folder, e.g. 1:/user_upload.
An upgrade wizard is in place to migrate the two fields of the existing records
to the new field.
The TCA type folder is now used in the backend editing form to improve the
usability on selecting the corresponding folder via the folder selector, when
using the file collections with type folder.
Impact
Editing
sys_file_collection records for the record type folder in the
backend is improved. Instead of selecting the storage first, reloading the form
and selecting the folder in a possibly large list afterwards, are users now
able to select the folder using the folder selector in a single step.
This additionally improves the performance of the backend form, especially for
storages with a huge amount of folders.
Also working with such records is improved, since only one field has to be
taken into account.
Feature: #98394 - Introduce event to prevent downloading of language packs
With the newly introduced event, it is possible to ignore extensions or
individual language packs for extensions when downloading the language packs.
However, only language packs for extensions and languages
available in the system can be downloaded. The options of the language:update
command can be used to further restrict the download (ignore additional
extensions or download only specific languages), but not to ignore decisions
made by the event.
Feature: #98528 - New file location for ENABLE_INSTALL_TOOL
To access the standalone Install Tool, the file
typo3conf/ENABLE_INSTALL_TOOL needed to be created.
With TYPO3 v12, the location of this file has been changed.
For Composer-based installations the following file paths are checked:
var/transient/ENABLE_INSTALL_TOOL
config/ENABLE_INSTALL_TOOL
For legacy installations the following file paths are checked:
typo3temp/var/transient/ENABLE_INSTALL_TOOL
typo3conf/ENABLE_INSTALL_TOOL
Using the previous known path typo3conf/ENABLE_INSTALL_TOOL is
still possible.
Impact
Especially for Composer-based installation this change allows to completely
drop the usage of the typo3conf/ directory.
Add the new paths to your
.gitignore file to avoid deploying this file to
production environments.
The creation of new folders in the File > Filelist module has been
improved. Instead of a new window, the Create Folder button
now opens a modal window to create a folder.
Both the button in the docheader and the corresponding option in the context
menu are affected.
The modal window also contains the folder tree to select the parent folder.
To allow editors creating folders sequentially, the modal is not
automatically closed.
Impact
With the new modal window, backend users are able to create folders in an
improved way: They do not lose focus of the current view anymore.
Additionally, the parent folder can easily be changed inside the modal window,
which allows to create folders for different levels without leaving the form.
After closing the modal window, the File > Filelist module
automatically reloads to instantly display the latest changes.
Feature: #99220 - Add event to modify search results
A new PSR-14 event
\TYPO3\CMS\Backend\Search\Event\ModifyResultItemInLiveSearchEvent
is added to allow extension developers to take control over search result items
rendered in the backend search.
The event has a public method called
getResultItem(), returning the
\TYPO3\CMS\Backend\Search\LiveSearch\ResultItem instance of the search
result item.
Impact
Search result items may be modified within a custom event listener, e.g. to add
custom actions.