TYPO3 v15 dev-main snapshot ()

This commit is contained in:
2026-08-10 22:31:09 +02:00
commit af8cc155b5
6818 changed files with 642608 additions and 0 deletions
@@ -0,0 +1,63 @@
.. include:: /Includes.rst.txt
.. _deprecation-101559-1721761906:
==========================================================
Deprecation: #101559 - Extbase uses ext:core ViewInterface
==========================================================
See :issue:`101559`
Description
===========
The default view of ext:extbase now returns a view that implements
:php:`\TYPO3\CMS\Core\View\ViewInterface` and not only
:php:`\TYPO3Fluid\Fluid\View\ViewInterface` anymore. This allows
implementing any view that implements :php-short:`\TYPO3\CMS\Core\View\ViewInterface`,
and frees the direct dependency to Fluid.
The default return object is an instance of
:php:`\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:
* :php:`getRenderingContext()`
* :php:`setRenderingContext()`
* :php:`renderSection()`
* :php:`renderPartial()`
Method calls not being part of :php-short:`\TYPO3\CMS\Core\View\ViewInterface` or the above
listed method names have been marked as deprecated and will be removed in TYPO3 v14.
Impact
======
Extbase controllers that extend :php-short:`\TYPO3\CMS\Extbase\Mvc\Controller\ActionController`
and call methods not part of :php-short:`\TYPO3\CMS\Core\View\ViewInterface`, should
test for :php:`$view instanceof FluidViewAdapter` before calling
:php:`getRenderingContext()`, :php:`setRenderingContext()`, php:`renderSection()`
and :php:`renderPartial()`.
All other Fluid related methods called on :php:`$view` have been marked as
deprecated and will log a deprecation level error message.
Affected installations
======================
Instances with Extbase based extensions that call :php:`$view` methods without
testing for :php-short:`\TYPO3\CMS\Fluid\View\FluidViewAdapter`.
Migration
=========
Methods on "old" Fluid instances were wrapper methods for
:php-short:`\TYPO3\CMS\Fluid\Core\Rendering\RenderingContext`. Controllers
should call :php:`$view->getRenderingContext()`
to perform operations instead.
.. index:: Fluid, PHP-API, NotScanned, ext:extbase
@@ -0,0 +1,65 @@
.. include:: /Includes.rst.txt
.. _deprecation-102422-1700563266:
============================================================================================
Deprecation: #102422 - TypoScriptFrontendController->addCacheTags() and ->getPageCacheTags()
============================================================================================
See :issue:`102422`
Description
===========
The methods :php:`\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->addCacheTags()` and
:php:`\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->getPageCacheTags()`
have been marked as deprecated.
Impact
======
Calling the methods
:php-short:`\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->addCacheTags()`
and
:php-short:`\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->getPageCacheTags()`
will trigger a PHP deprecation warning.
Affected installations
======================
TYPO3 installations calling
:php-short:`\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->addCacheTags()`
or
:php-short:`\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->getPageCacheTags()`.
Migration
=========
.. code-block:: php
// Before
$GLOBALS['TSFE']->addCacheTags([
'tx_myextension_mytable_123',
'tx_myextension_mytable_456'
]);
// After
use TYPO3\CMS\Core\Cache\CacheTag;
$request->getAttribute('frontend.cache.collector')->addCacheTags(
new CacheTag('tx_myextension_mytable_123', 3600),
new CacheTag('tx_myextension_mytable_456', 3600)
);
.. code-block:: php
// Before
$GLOBALS['TSFE']->getPageCacheTags();
// After
$request->getAttribute('frontend.cache.collector')->getCacheTags();
.. index:: PHP-API, FullyScanned, ext:core
@@ -0,0 +1,54 @@
.. include:: /Includes.rst.txt
.. _deprecation-102821-1709843835:
================================================================
Deprecation: #102821 - ExtensionManagementUtility::addPItoST43()
================================================================
See :issue:`102821`
Description
===========
The method :php:`\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPItoST43()`
has been marked as deprecated in TYPO3 v13 and will be removed with TYPO3 v14.
Impact
======
Using the :php:`ExtensionManagementUtility::addPItoST43()` will raise a deprecation
level log entry and a fatal error in TYPO3 v14.
Affected installations
======================
Extensions using :php:`ExtensionManagementUtility::addPItoST43()` are affected:
Using :php:`ExtensionManagementUtility::addPItoST43()` triggers a deprecation level log message.
The extension scanner will find usages of :php:`ExtensionManagementUtility::addPItoST43()` as strong match.
Migration
=========
.. code-block:: php
// Before:
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPItoST43('my_extkey', '', '_pi1');
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTypoScript(
'tx_myextkey',
'setup',
'plugin.tx_myextkey_pi1.userFunc = MY\MyExtkey\Plugins\Plugin->main'
);
// After:
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTypoScript(
'my_extkey',
'setup',
'plugin.tx_myextkey_pi1 = USER_INT
plugin.tx_myextkey_pi1.userFunc = MY\MyExtkey\Plugins\Plugin->main'
);
.. index:: LocalConfiguration, PHP-API, FullyScanned, ext:core
@@ -0,0 +1,70 @@
.. include:: /Includes.rst.txt
.. _deprecation-104223-1721383576:
===============================================
Deprecation: #104223 - Fluid standalone methods
===============================================
See :issue:`104223`
Description
===========
Some methods in Fluid standalone v2 have been marked as deprecated:
* :php:`\TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper->registerUniversalTagAttributes()`
* :php:`\TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper->registerTagAttribute()`
Impact
======
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 :php:`registerUniversalTagAttributes()` should be removed.
This method has been marked as :php:`@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
:php:`$this->additionalArguments`, and no longer in :php:`$this->arguments`. This *may* need
adaption within single ViewHelpers, *if* they handle such attributes on their own. For example,
the common ViewHelper :html:`f:image` was affected within the TYPO3 Core. The following attributes
may need attention when removing :php:`registerUniversalTagAttributes()`: :html:`class`, :html:`dir`,
:html:`id`, :html:`lang`, :html:`style`, :html:`title`, :html:`accesskey`, :html:`tabindex`,
:html:`onclick`.
registerTagAttribute()
----------------------
Within tag based ViewHelpers, calls to :php:`registerTagAttribute()` should be removed.
This method has been marked as :php:`@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 :php:`\TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper`.
This only needs attention
if single view helpers deal with such attributes within the :php:`render()` method:
When removing the call, those arguments are no longer available in :php:`$this->arguments`,
but in :php:`$this->additionalArguments`. Additional attention is needed with
attributes registered with type :php:`boolean`: Those usually have some handling
within :php:`render()`. To stay compatible, it can be helpful to not simply
remove the :php:`registerTagAttribute()` call, but to turn it into a call to
:php:`registerArgument()`.
.. index:: Fluid, PHP-API, FullyScanned, ext:fluid
@@ -0,0 +1,61 @@
.. include:: /Includes.rst.txt
.. _deprecation-104304-1720084447:
===============================================================
Deprecation: #104304 - BackendUtility::getTcaFieldConfiguration
===============================================================
See :issue:`104304`
Description
===========
The method :php:`\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 :php:`$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 :php:`BackendUtility::getTcaFieldConfiguration` will
trigger a PHP deprecation warning.
Affected installations
======================
TYPO3 installations with custom extensions using this method.
Migration
=========
Either access :php:`$GLOBALS['TCA']` directly (in order to support TYPO3 v12 and TYPO3 v13),
or migrate to the new Schema API:
.. code-block:: php
public function __construct(
private readonly TcaSchemaFactory $tcaSchemaFactory
) {}
private function getFieldConfiguration(string $table, string $fieldName): array
{
return $this->tcaSchemaFactory
->get($table)
->getField($fieldName)
->getConfiguration();
}
.. index:: PHP-API, TCA, FullyScanned, ext:backend
@@ -0,0 +1,53 @@
.. include:: /Includes.rst.txt
.. _deprecation-104325-1720298173:
=====================================================
Deprecation: #104325 - DiffUtility->makeDiffDisplay()
=====================================================
See :issue:`104325`
Description
===========
Method :php:`\TYPO3\CMS\Core\Utility\DiffUtility->makeDiffDisplay()`
and class property :php:`DiffUtility->stripTags` have been
deprecated in favor of new method :php:`DiffUtility->diff()`.
The new method no longer applies :php:`strip_tags()` to the input strings.
This change makes class :php-short:`\TYPO3\CMS\Core\Utility\DiffUtility` stateless: Property
:php:`$stripTags` will vanish in v14.
Impact
======
Using method :php:`DiffUtility->makeDiffDisplay()` will trigger a
deprecation level error message.
Affected installations
======================
Instances with extensions calling :php:`DiffUtility->makeDiffDisplay()`.
Migration
=========
If :php:`DiffUtility->stripTags` *is not* explicitly set to false, a typical
migration looks like this:
.. code-block:: php
// before
$diffUtility->DiffUtility->makeDiffDisplay($from, $to);
// after
$diffUtility->DiffUtility->diff(strip_tags($from), stripTags($to));
If :php:`DiffUtility->stripTags = false` is set before calling
:php:`DiffUtility->makeDiffDisplay()`, method :php:`diff()` can be called
as before, and :php:`DiffUtility->stripTags = false` can be removed.
.. index:: PHP-API, FullyScanned, ext:core
@@ -0,0 +1,42 @@
.. include:: /Includes.rst.txt
.. _deprecation-104463-1721754926:
========================================================
Deprecation: #104463 - Fluid standalone overrideArgument
========================================================
See :issue:`104463`
Description
===========
Fluid standalone method :php:`\TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper->overrideArgument()`
has been marked as deprecated.
Impact
======
Using :php:`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, :php:`registerArgument()` no longer throws an exception if an
argument is already registered. This allows to override existing arguments transparently
without using :php:`overrideArgument()`.
Affected installations
======================
Instances with custom ViewHelpers using :php:`overrideArgument()` are affected.
Migration
=========
Update `typo3fluid/fluid` to at least 2.14 and use :php:`registerArgument()`.
.. index:: PHP-API, FullyScanned, ext:fluid
@@ -0,0 +1,48 @@
.. include:: /Includes.rst.txt
.. _deprecation-104607-1723556132:
==================================================================
Deprecation: #104607 - BackendUserAuthentication:returnWebmounts()
==================================================================
See :issue:`104607`
Description
===========
Method :php:`\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::returnWebmounts()` has
been marked as deprecated and will be removed with TYPO3 v14.
Method :php:`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 :php:`BackendUserAuthentication::returnWebmounts()` will trigger a PHP
deprecation warning.
Affected installations
======================
All installations using :php:`BackendUserAuthentication::returnWebmounts()`
are affected.
Migration
=========
Existing calls to :php:`BackendUserAuthentication::returnWebmounts()` should
be replaced by :php:`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().
.. index:: PHP-API, TCA, FullyScanned, ext:core
@@ -0,0 +1,93 @@
.. include:: /Includes.rst.txt
.. _deprecation-104662-1724058079:
===============================================
Deprecation: #104662 - BackendUtility thumbCode
===============================================
See :issue:`104662`
Description
===========
The method :php:`\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 :php:`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 :php-short:`\TYPO3\CMS\Core\Resource\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 :php:`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:
.. code-block:: php
// 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 defined
[
'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() . '">
Example of the HTML markup for a thumbnail:
.. code-block:: html
<div class="preview-thumbnails" style="--preview-thumbnails-size: 64px">
<div class="preview-thumbnails-element">
<div class="preview-thumbnails-element-image">
<img src="' . $fileReference->getOriginalFile()->process()->getPublicUrl() . '" width="64px" height="64px" alt="' . $fileReference->getAlternative() ?: $fileReference->getName() . '" loading="lazy"/>
</div>
</div>
</div>
.. index:: PHP-API, FullyScanned, ext:backend
@@ -0,0 +1,94 @@
.. include:: /Includes.rst.txt
.. _deprecation-104684-1724258020:
===========================================================
Deprecation: #104684 - Fluid RenderingContext->getRequest()
===========================================================
See :issue:`104684`
Description
===========
The following methods have been marked as deprecated in TYPO3 v13 and will
be removed with TYPO3 v14:
* :php:`\TYPO3\CMS\Fluid\Core\Rendering\RenderingContext->setRequest()`
* :php:`\TYPO3\CMS\Fluid\Core\Rendering\RenderingContext->getRequest()`
Impact
======
Calling above methods triggers a deprecation level log entry in TYPO3 v13 and
will trigger a fatal PHP error with TYPO3 v14.
Affected installations
======================
:php:`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 :php:`\TYPO3\CMS\Fluid\Core\Rendering\RenderingContext` of the Core
extension Fluid extends class :php:`\TYPO3Fluid\Fluid\Core\Rendering\RenderingContext`
of Fluid standalone and adds the methods :php:`setRequest()` and :php:`getRequest()`.
These methods are however not part of :php:`\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 :php-short:`\Psr\Http\Message\ServerRequestInterface`
dependencies. Having those
methods in ext:fluid :php-short:`\TYPO3\CMS\Fluid\Core\Rendering\RenderingContext`
however collides with :php-short:`\TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface`,
which is type hinted in Fluid view helper method signatures.
Fluid standalone instead added three methods to handle arbitrary additional data
in :php-short:`\TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface`:
:php:`setAttribute()`, :php:`hasAttribute()`
and :php:`getAttribute()`. Those should be used instead.
A typical usage in a view helper before:
.. code-block:: php
/** @var \TYPO3Fluid\Fluid\Core\Rendering\RenderingContext $renderingContext */
$renderingContext = $this->renderingContext;
$request = $renderingContext->getRequest();
After:
.. code-block:: php
// use Psr\Http\Message\ServerRequestInterface
$request = null;
if ($renderingContext->hasAttribute(ServerRequestInterface::class)) {
$request = $renderingContext->getAttribute(ServerRequestInterface::class);
}
To stay compatible to previous TYPO3 versions while avoiding deprecation notices,
the following code can be used:
.. code-block:: php
// use Psr\Http\Message\ServerRequestInterface
if (
method_exists($renderingContext, 'getAttribute') &&
method_exists($renderingContext, 'hasAttribute') &&
$renderingContext->hasAttribute(ServerRequestInterface::class)
) {
$request = $renderingContext->getAttribute(ServerRequestInterface::class);
} else {
$request = $renderingContext->getRequest();
}
.. index:: Fluid, PHP-API, NotScanned, ext:fluid
@@ -0,0 +1,50 @@
.. include:: /Includes.rst.txt
.. _deprecation-104764-1724851918:
=====================================================================
Deprecation: #104764 - Fluid TemplatePaths->fillDefaultsByPackageName
=====================================================================
See :issue:`104764`
Description
===========
Method :php:`\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
:php:`setTemplateRootPaths()`, :php:`setLayoutRootPaths()` and
:php:`setPartialRootPaths()`, or - even better - be handled by
:php:`ViewFactoryInterface`, which comes as new feature in TYPO3 v13.
See :ref:`feature-104773-1724939348` for more details of the generic
view interface.
Impact
======
Calling :php:`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 :php:`ActionController` has been refactored away. The extension
scanner will find candidates.
Note class :php:`TemplatePaths` is marked `@internal` and should not be
used by extensions at all.
Migration
=========
Use :php:`\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.
.. index:: PHP-API, FullyScanned, ext:fluid
@@ -0,0 +1,53 @@
.. include:: /Includes.rst.txt
.. _deprecation-104773-1724942036:
=====================================================
Deprecation: #104773 - Custom Fluid views and Extbase
=====================================================
See :issue:`104773`
Description
===========
These classes have been marked as deprecated in TYPO3 v13 and will be removed in v14:
* :php:`\TYPO3\CMS\Fluid\View\StandaloneView`
* :php:`\TYPO3\CMS\Fluid\View\TemplateView`
* :php:`\TYPO3\CMS\Fluid\View\AbstractTemplateView`
* :php:`\TYPO3\CMS\Extbase\Mvc\View\ViewResolverInterface`
* :php:`\TYPO3\CMS\Extbase\Mvc\View\GenericViewResolver`
This change is related to the general :ref:`View refactoring <feature-104773-1724939348>`.
Impact
======
Using one of the above classes triggers a deprecation level log entry.
Affected installations
======================
Instances with extensions that create view instances of
:php-short:`\TYPO3\CMS\Fluid\View\StandaloneView` or
:php-short:`\TYPO3\CMS\Fluid\View\TemplateView` are affected. The extension
scanner will find possible candidates.
Migration
=========
Extensions should no longer directly instantiate own views, but should get
:php:`\TYPO3\CMS\Core\View\ViewFactoryInterface` injected and use :php:`create()`
to retrieve a view.
Within Extbase, :php:`ActionController->defaultViewObjectName` should only be
set to Extbase :php:`JsonView` if needed, or not set at all. Custom view implementations
should implement an own :php-short:`\TYPO3\CMS\Core\View\ViewFactoryInterface` and configure
controllers to inject an instance, or can set :php:`$this->defaultViewObjectName = JsonView::class`
in a custom :php:`__construct()`.
.. index:: PHP-API, PartiallyScanned, ext:core
@@ -0,0 +1,74 @@
.. include:: /Includes.rst.txt
.. _deprecation-104773-1724940753:
=================================================================
Deprecation: #104773 - ext:backend LoginProviderInterface changes
=================================================================
See :issue:`104773`
Description
===========
Method :php:`\TYPO3\CMS\Backend\LoginProvider\LoginProviderInterface->render()` has been marked as deprecated
and is substituted by :php:`LoginProviderInterface->modifyView()` that will
be added to the interface in TYPO3 v14, removing :php:`render()` from the
interface in v14.
Related to this, event :php:`\TYPO3\CMS\Backend\LoginProvider\Event\ModifyPageLayoutOnLoginProviderSelectionEvent`
has been changed to deprecate :php:`getController()` and :php:`getPageRenderer()`,
while :php:`getRequest()` has been added. :php:`getView()` now typically returns
an instance of :php:`ViewInterface`.
This change is related to the general :ref:`View refactoring <feature-104773-1724939348>`.
Impact
======
The default :php-short:`\TYPO3\CMS\Backend\LoginProvider\LoginProviderInterface`
implementation is
:php-short:`\TYPO3\CMS\Backend\LoginProvider\UsernamePasswordLoginProvider`
provided by ext:core. This consumer has been adapted.
Using :php:`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 :php:`render()` is too common. A deprecation
level log message is triggered upon use of the old method.
Migration
=========
Consumers of :php-short:`\TYPO3\CMS\Backend\LoginProvider\LoginProviderInterface`
should implement :php:`modifyView()` instead, the transition should be smooth.
Consumers that need the :php-short:`\TYPO3\CMS\Core\Page\PageRenderer`
for JavaScript magic, should use :ref:`dependency injection <t3coreapi:Dependency-Injection>`
to receive an instance.
The default implementation in :php-short:`\TYPO3\CMS\Backend\LoginProvider\UsernamePasswordLoginProvider`
is a good example. Extensions that need to configure additional template, layout or
partial lookup paths can extend them:
.. code-block:: php
if ($view instanceof FluidViewAdapter) {
$templatePaths = $view->getRenderingContext()->getTemplatePaths();
$templateRootPaths = $templatePaths->getTemplateRootPaths();
$templateRootPaths[] = 'EXT:my_extension/Resources/Private/Templates';
$templatePaths->setTemplateRootPaths($templateRootPaths);
}
Consumers of :php-short:`\TYPO3\CMS\Backend\LoginProvider\Event\ModifyPageLayoutOnLoginProviderSelectionEvent`
should use the request instead, and/or should get an instance of
:php-short:`\TYPO3\CMS\Core\Page\PageRenderer` injected as well.
.. index:: PHP-API, NotScanned, ext:backend
@@ -0,0 +1,82 @@
.. include:: /Includes.rst.txt
.. _deprecation-104778-1724953249:
=========================================================================
Deprecation: #104778 - Instantiation of IconRegistry in ext_localconf.php
=========================================================================
See :issue:`104778`
Description
===========
Since TYPO3 v11 it is possible to automatically register own icons via
:file:`Configuration/Icons.php`. Prior to this, extension authors used to register
icons manually via instantiating the php:`\TYPO3\CMS\Core\Imaging\IconRegistry`
in their :file:`ext_localconf.php`
files. This method has now been deprecated. It is recommended to switch to
the newer method introduced with :issue:`94692`.
Impact
======
Instantiating :php-short:`\TYPO3\CMS\Core\Imaging\IconRegistry` inside
:file:`ext_localconf.php` files will trigger a deprecation-level log entry.
Affected installations
======================
All installations, which instantiate :php-short:`\TYPO3\CMS\Core\Imaging\IconRegistry`
before the :php:`\TYPO3\CMS\Core\Core\Event\BootCompletedEvent`. This includes
:file:`ext_localconf.php` files as well as :path:`TCA/Overrides`.
Migration
=========
The most common use-cases can be accomplished via the :file:`Configuration/Icons.php`
file.
Before:
.. code-block:: php
:caption: EXT:example/ext_localconf.php
<?php
$iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
\TYPO3\CMS\Core\Imaging\IconRegistry::class,
);
$iconRegistry->registerIcon(
'example',
\TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class,
[
'source' => 'EXT:example/Resources/Public/Icons/example.svg'
],
);
After:
.. code-block:: php
:caption: EXT:example/Configuration/Icons.php
<?php
return [
'example' => [
'provider' => \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class,
'source' => 'EXT:example/Resources/Public/Icons/example.svg',
],
];
For more complex tasks, it is recommended to register an event listener for the
:php-short:`\TYPO3\CMS\Core\Core\Event\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 :path:`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.
.. index:: PHP-API, NotScanned, ext:core
@@ -0,0 +1,40 @@
.. include:: /Includes.rst.txt
.. _deprecation-104789-1725196704:
========================================================
Deprecation: #104789 - Fluid variables true, false, null
========================================================
See :issue:`104789`
Description
===========
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 :php:`$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.
.. index:: Fluid, NotScanned, ext:fluid
@@ -0,0 +1,155 @@
.. include:: /Includes.rst.txt
.. _deprecation-104789-1725195584:
===========================================================
Deprecation: #104789 - renderStatic() for Fluid ViewHelpers
===========================================================
See :issue:`104789`
Description
===========
The usage of :php:`renderStatic()` for Fluid ViewHelpers has been deprecated.
Also, Fluid standalone traits
:php:`\TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithContentArgumentAndRenderStatic`
and :php:`\TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic`
have been marked as deprecated.
Impact
======
Using one of the mentioned traits or :php:`renderStatic()` in ViewHelpers
logs a deprecation level error message in Fluid standalone v4. :php:`renderStatic()`
will no longer be called in Fluid standalone v5. :php:`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 :php:`renderStatic()` are affected.
Migration
=========
ViewHelpers should always use :php:`render()` as their primary rendering method.
ViewHelpers using just :php:`renderStatic()` without any trait or with the trait
:php-short:`\TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic`
can be migrated by converting the static rendering method to a non-static method:
Before:
.. code-block:: php
class MyViewHelper extends AbstractViewHelper
{
use CompileWithRenderStatic;
public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext): string
{
return $renderChildrenClosure();
}
}
After:
.. code-block:: php
class MyViewHelper extends AbstractViewHelper
{
public function render(): string
{
return $this->renderChildren();
}
}
ViewHelpers using :php:`\TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithContentArgumentAndRenderStatic`
can use the new contentArgumentName feature added with Fluid v2.15:
Before:
.. code-block:: php
class MyViewHelper extends AbstractViewHelper
{
use CompileWithContentArgumentAndRenderStatic;
public function initializeArguments(): void
{
$this->registerArgument('value', 'string', 'a value');
}
public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext): string
{
return $renderChildrenClosure();
}
public function resolveContentArgumentName(): string
{
return 'value';
}
}
After:
.. code-block:: php
class MyViewHelper extends AbstractViewHelper
{
public function initializeArguments(): void
{
$this->registerArgument('value', 'string', 'a value');
}
public function render(): string
{
return $this->renderChildren();
}
public function getContentArgumentName(): string
{
return 'value';
}
}
Here is a basic recipe to perform this migration, preferably utilizing
statical code analysis/replacement tools on your :file:`*ViewHelper.php`
files:
* Find definitions of :php:`renderStatic`
* Rename method to :php:`render()`, remove the arguments, remove :php:`static` declaration
* Within that method:
* Replace :php:`$arguments` with :php:`$this->arguments`
* Replace :php:`$renderingContext` with :php:`$this->renderingContext`
* Replace :php:`$renderChildrenClosure()` with :php:`$this->renderChildren()`
* Replace remaining :php:`$renderChildrenClosure` usages with proper closure handling, like :php:`$this->renderChildren(...)`.
* Replace :php:`resolveContentArgumentName(` with :php:`getContentArgumentName(`
* Remove the mentioned definitions:
* :php:`use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;`
* :php:`use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;`
* :php:`use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithContentArgumentAndRenderStatic;`
* :php:`use CompileWithRenderStatic;` (class trait)
* :php:`use CompileWithContentArgumentAndRenderStatic;` (class trait)
* (Optionally remove custom phpdoc annotations to the `renderStatic` parameters)
* If you previously called ViewHelper's :php:`renderStatic` methods in other places,
you may utilize something like:
.. code-block:: php
$this->renderingContext->getViewHelperInvoker()->invoke(
MyViewHelper::class,
$arguments,
$this->renderingContext,
$this->renderChildren(...),
);
.. index:: Fluid, PartiallyScanned, ext:fluid
@@ -0,0 +1,62 @@
.. include:: /Includes.rst.txt
.. _feature-101252-1715447531:
=============================================================================
Feature: #101252 - Introduce ErrorHandler for 403 errors with redirect option
=============================================================================
See :issue:`101252`
Description
===========
The new error handler :php:`\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
:php:`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 :php-short:`\TYPO3\CMS\Core\Error\PageErrorHandler\RedirectLoginErrorHandler`
allows to define a
:php:`loginRedirectTarget`, which must be configured to the page, where the
login process is handled. Additionally, the :php:`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 :php:`loginRedirectParameter`, so that the user can be redirected
back to the original page after a successful login.
The error handler allows :php:`return_url` or :php:`redirect_url` as values
for :php:`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
:typoscript:`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 :composer:`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
:php-short:`\TYPO3\CMS\Core\Error\PageErrorHandler\PageErrorHandlerInterface`.
.. index:: Frontend, ext:core
@@ -0,0 +1,35 @@
.. include:: /Includes.rst.txt
.. _feature-101391-1689772689:
==========================================================
Feature: #101391 - Add base64 attribute to ImageViewHelper
==========================================================
See :issue:`101391`
Description
===========
The ViewHelpers :ref:`<f:image> <t3viewhelper:typo3-fluid-image>` and
:ref:`<f:uri.image> <t3viewhelper:typo3-fluid-uri-image>` now
support the attribute :fluid:`base64="true"` that will provide
a possibility to return the value of the image's :fluid:`src` attribute
encoded in base64.
.. code-block:: html
<f:image base64="true" src="EXT:backend/Resources/Public/Images/typo3_logo_orange.svg" height="20" class="pr-2" />
<img src="{f:uri.image(base64: 'true', src:'EXT:backend/Resources/Public/Images/typo3_logo_orange.svg')}">
Will result in the according HTML tag providing the image encoded in base64.
.. code-block:: html
<img class="pr-2" src="data:image/svg+xml;base64,PHN2...cuODQ4LTYuNzU3Ii8+Cjwvc3ZnPgo=" alt="" width="20" height="20">
<img src="data:image/svg+xml;base64,PHN2...cuODQ4LTYuNzU3Ii8+Cjwvc3ZnPgo=">
This can be particularly useful inside `\TYPO3\CMS\Core\Mail\FluidEmail` or
to prevent unneeded HTTP calls.
.. index:: Fluid, ext:fluid
@@ -0,0 +1,36 @@
.. include:: /Includes.rst.txt
.. _feature-101472-1721137289:
================================================
Feature: #101472 - Allow static routes to assets
================================================
See :issue:`101472`
Description
===========
It is now possible to configure static routes with the type `asset` to link to
resources which are typically located in the directory
:file:`EXT:my_extension/Resources/Public/`.
.. code-block:: yaml
:caption: config/sites/my-site/config.yaml
routes:
-
route: example.svg
type: asset
asset: 'EXT:backend/Resources/Public/Icons/Extension.svg'
Note that the asset URL can be configured on a per-site basis.
This allows to deliver site-dependent custom favicon or manifest
assets, for example.
Impact
======
Static routes to files shipped with extensions can now be configured in the site configuration.
.. index:: Frontend, YAML, ext:frontend
@@ -0,0 +1,51 @@
.. include:: /Includes.rst.txt
.. _feature-102255-1726090749:
=================================================================
Feature: #102255 - Option to skip URL processing in AssetRenderer
=================================================================
See :issue:`102255`
Description
===========
The :php:`\TYPO3\CMS\Core\Page\AssetCollector` options have been extended to
include an `external`
flag. When set for asset files using :php:`$assetCollector->addStyleSheet()`
or :php:`$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:
.. code-block:: php
$assetCollector->addStyleSheet(
'myCssFile',
PathUtility::getAbsoluteWebPath(GeneralUtility::getFileAbsFileName('EXT:my_extension/Resources/Public/MyFile.css')),
[],
['external' => true]
);
Resulting in the following HTML output:
.. code-block:: html
<link rel="stylesheet" href="/_assets/<hash>/myFile.css" />
Impact
======
Developers can now use the :php-short:`\TYPO3\CMS\Core\Page\AssetCollector`
API to embed JavaScript or CSS files without any processing of the
supplied asset URI.
.. index:: PHP-API, ext:core
@@ -0,0 +1,63 @@
.. include:: /Includes.rst.txt
.. _feature-102353-1699523309:
==================================================================
Feature: #102353 - AVIF support for images generated by GIFBUILDER
==================================================================
See :issue:`102353`
Description
===========
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 :php:`$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.
Example
-------
.. code-block:: typoscript
page.10 = IMAGE
page.10 {
file = GIFBUILDER
file {
backColor = yellow
XY = 1024,199
format = avif
quality = 44
speed = 1
10 = IMAGE
10.offset = 10,10
10.file = 1:/my-image.jpg
}
}
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.
.. index:: Frontend, TypoScript, ext:frontend
@@ -0,0 +1,102 @@
.. include:: /Includes.rst.txt
.. _feature-109999-1700506000:
===================================================
Feature: #102422 - Introduce CacheDataCollector Api
===================================================
See :issue:`102422`
Description
===========
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
:php:`'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:`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
-------
.. code-block:: php
:caption: Add a single cache tag with 24 hours lifetime
use TYPO3\CMS\Core\Cache\CacheTag;
$cacheDataCollector = $request->getAttribute('frontend.cache.collector');
$cacheDataCollector->addCacheTags(
new CacheTag('tx_myextension_mytable', 86400)
);
.. code-block:: php
:caption: Add multiple cache tags with different lifetimes
use TYPO3\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)
);
.. code-block:: php
:caption: Remove a cache tag
use TYPO3\CMS\Core\Cache\CacheTag;
$cacheDataCollector = $request->getAttribute('frontend.cache.collector');
$cacheDataCollector->removeCacheTags(
new CacheTag('tx_myextension_mytable_123')
);
.. code-block:: php
:caption: Remove multiple cache tags
use TYPO3\CMS\Core\Cache\CacheTag;
$cacheDataCollector = $request->getAttribute('frontend.cache.collector');
$cacheDataCollector->removeCacheTags(
new CacheTag('tx_myextension_mytable_123'),
new CacheTag('tx_myextension_mytable_456')
);
.. code-block:: php
:caption: Get minimum lifetime, calculated from all cache tags
$cacheDataCollector = $request->getAttribute('frontend.cache.collector');
$cacheDataCollector->resolveLifetime();
.. code-block:: php
:caption: Get all cache tags
$cacheDataCollector = $request->getAttribute('frontend.cache.collector');
$cacheDataCollector->getCacheTags();
The following event should only be used in code that has no access to the
request attribute :php:`'frontend.cache.collector'`, it is marked :php:`@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.
.. code-block:: php
:caption: Add cache tag without access to the request object
$this->eventDispatcher->dispatch(
new AddCacheTagEvent(
new CacheTag('tx_myextension_mytable_123', 3600)
)
);
.. index:: PHP-API, ext:core
@@ -0,0 +1,87 @@
.. include:: /Includes.rst.txt
.. _feature-103090-1707479280:
====================================================
Feature: #103090 - Make link type label configurable
====================================================
See :issue:`103090`
Description
===========
It is now possible to provide a translated label for custom link types.
For this, a new interface
:php:`\TYPO3\CMS\Linkvalidator\Linktype\LabelledLinktypeInterface` has been
created, which offers the method :php:`getReadableName` for implementation.
That method can return the translated label.
The default abstract implementation
:php:`\TYPO3\CMS\Linkvalidator\Linktype\AbstractLinktype` has been enhanced
to implement that interface. Any custom class extending this abstract is
able to override the method :php:`getReadableName` to provide the
custom translation.
Example extending the abstract:
-------------------------------
.. code-block:: php
:caption: EXT:extension/Classes/Linktype/CustomLinktype.php
use TYPO3\CMS\Linkvalidator\Linktype\AbstractLinktype;
#[Autoconfigure(public: true)]
class CustomLinktype extends AbstractLinktype
{
public function getReadableName(): string
{
$type = $this->getIdentifier();
return $this->getLanguageService()->sL(
'LLL:EXT:linkvalidator_example/Resources/Private/Language/Module/locallang.xlf:linktype_'
. $type
) ?: $type;
}
}
Example implementing the interface:
-----------------------------------
.. code-block:: php
:caption: EXT:extension/Classes/Linktype/CustomLinktype.php
use TYPO3\CMS\Linkvalidator\Linktype\LinktypeInterface;
use TYPO3\CMS\Linkvalidator\Linktype\LabelledLinktypeInterface;
#[Autoconfigure(public: true)]
class CustomLinktype implements LinktypeInterface, LabelledLinktypeInterface
{
// implement all LinktypeInterface methods:
// getIdentifier, checkLink, setAdditionalConfig, ...
// Implement the LabelledLinktypeInterface method getReadableName()
public function getReadableName(): string
{
$type = $this->getIdentifier();
return $this->getLanguageService()->sL(
'LLL:EXT:linkvalidator_example/Resources/Private/Language/Module/locallang.xlf:linktype_'
. $type
) ?: $type;
}
}
Impact
======
Custom linktype classes should now configure a label by implementing the method
:php:`LabelledLinktypeInterface::getReadableName()`.
All existing custom implementations of the
:php-short:`\TYPO3\CMS\Linkvalidator\Linktype\AbstractLinktype` class or the
:php-short:`\TYPO3\CMS\Linkvalidator\Linktype\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.
.. index:: Backend, ext:linkvalidator
@@ -0,0 +1,429 @@
.. include:: /Includes.rst.txt
.. _feature-103511-1711894330:
======================================================================
Feature: #103511 - Introduce Extbase file upload and deletion handling
======================================================================
See :issue:`103511`
Description
===========
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 :php-short:`\TYPO3\CMS\Extbase\Domain\Model\FileReference`
in a domain model
* Property of type
:php:`\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 :php:`\TYPO3\CMS\Extbase\Annotation\FileUpload` attribute.
Example:
.. code-block:: php
#[FileUpload([
'validation' => [
'required' => true,
'maxFiles' => 1,
'fileSize' => ['minimum' => '0K', 'maximum' => '2M'],
'mimeType' => ['allowedMimeTypes' => ['image/jpeg', 'image/png']],
'fileExtension' => ['allowedFileExtensions' => ['jpg', 'jpeg', 'png']],
],
'uploadFolder' => '1:/user_upload/files/',
])]
protected ?FileReference $file = null;
All configuration settings of the
:php:`\TYPO3\CMS\Extbase\Mvc\Controller\FileUploadConfiguration` object can
be defined using the :php-short:`\TYPO3\CMS\Extbase\Annotation\FileUpload`
attribute. It is however not possible
to add custom validators using the
:php-short:`\TYPO3\CMS\Extbase\Annotation\FileUpload` attribute, which you
can achieve with a manual configuration as shown below.
The currently available configuration array keys are:
* `validation` (:php:`array` with keys `required`, `maxFiles`, `minFiles`,
`fileSize`, `fileExtension`, `allowedMimeTypes`, `mimeType`, `imageDimensions`,
see :ref:`83749-validationkeys`)
* `uploadFolder` (:php:`string`, destination folder)
* `duplicationBehavior` (:php:`object`, behaviour when file exists)
* `addRandomSuffix` (:php:`bool`, suffixing files)
* `createUploadFolderIfNotExist` (:php:`bool`, whether to create missing
directories)
It is also possible to use the :php-short:`\TYPO3\CMS\Extbase\Annotation\FileUpload` annotation to configure
file upload properties, but it is recommended to use the
:php-short:`\TYPO3\CMS\Extbase\Annotation\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 :php:`initialize*Action`.
Example:
.. code-block:: php
public function initializeCreateAction(): void
{
$mimeTypeValidator = GeneralUtility::makeInstance(MimeTypeValidator::class);
$mimeTypeValidator->setOptions(['allowedMimeTypes' => ['image/jpeg']]);
$fileExtensionValidator = GeneralUtility::makeInstance(FileExtensionValidator::class);
$fileExtensionValidator->setOptions(['allowedFileExtensions' => ['jpg', 'jpeg']]);
$fileHandlingServiceConfiguration = $this->arguments->getArgument('myArgument')->getFileHandlingServiceConfiguration();
$fileHandlingServiceConfiguration->addFileUploadConfiguration(
(new FileUploadConfiguration('myPropertyName'))
->setRequired()
->addValidator($mimeTypeValidator)
->addValidator($fileExtensionValidator)
->setMaxFiles(1)
->setUploadFolder('1:/user_upload/files/')
);
$this->arguments->getArgument('myArgument')->getPropertyMappingConfiguration()->skipProperties('myPropertyName');
}
Configuration options for file uploads
--------------------------------------
The configuration for a file upload is defined in a
:php:`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 :php-short:`\TYPO3\CMS\Extbase\Annotation\FileUpload` attribute. If the
:php-short:`\TYPO3\CMS\Extbase\Mvc\Controller\FileUploadConfiguration` object
is created manually, it must be set using the :php:`$propertyName`
constructor argument.
Validation:
~~~~~~~~~~~
File upload validation is defined in an array of validators in the
:php-short:`\TYPO3\CMS\Extbase\Mvc\Controller\FileUploadConfiguration` object.
The validators
:php:`\TYPO3\CMS\Extbase\Validation\Validator\FileNameValidator`,
(ensures that no executable PHP files can
be uploaded) and :php:`\TYPO3\CMS\Extbase\Validation\Validator\FileExtensionMimeTypeConsistencyValidator`
(ensuring that the file extension matches the expected mime-type assumptions),
are enforced and executed by default.
In addition, Extbase includes the following validators to validate an
:php-short:`\TYPO3\CMS\Core\Http\UploadedFile` object:
* :php:`\TYPO3\CMS\Extbase\Validation\Validator\FileExtensionValidator`
* :php:`\TYPO3\CMS\Extbase\Validation\Validator\FileSizeValidator`
* :php:`\TYPO3\CMS\Extbase\Validation\Validator\MimeTypeValidator`
* :php:`\TYPO3\CMS\Extbase\Validation\Validator\ImageDimensionsValidator`
Those validators can either be configured with the
:php-short:`\TYPO3\CMS\Extbase\Annotation\FileUpload` attribute or added
manually to the configuration object
with the :php:`addValidator` method.
Required:
~~~~~~~~~
Defines whether a file must be uploaded. If it is set to `true`, the
:php:`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. :php:`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 :php:`createUploadFolderIfNotExist`
(:php:`bool`, default :php:`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
:php:`job-application.pdf` will be persisted as
:php:`job-application-<random-hash>.pdf` in the upload folder.
The default value for this configuration is :php:`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 :php:`DuplicationBehavior::RENAME` (default),
:php:`DuplicationBehavior::REPLACE` and :php:`DuplicationBehavior::CANCEL`.
Modifying existing configuration
--------------------------------
File upload configuration defined by the
:php-short:`\TYPO3\CMS\Extbase\Annotation\FileUpload` attribute can be
changed in the :php:`initialize*Action`.
Example:
.. code-block:: php
public function initializeCreateAction(): void
{
$validator = GeneralUtility::makeInstance(MyCustomValidator::class);
$argument = $this->arguments->getArgument('myArgument');
$configuration = $argument->getFileHandlingServiceConfiguration()->getFileUploadConfigurationForProperty('file');
$configuration?->setMinFiles(2);
$configuration?->addValidator($validator);
$configuration?->setUploadFolder('1:/user_upload/custom_folder');
}
The example shows how to modify the file upload configuration for the argument
:php:`item` and the property :php:`file`. The minimum amount of files to be
uploaded is set to :php:`2` and a custom validator is added.
To remove all defined validators except the :php:`FileNameValidator`, use
the :php:`resetValidators()` method.
Using TypoScript configuration for file uploads configuration
-------------------------------------------------------------
When a file upload configuration for a property has been added using the
:php-short:`\TYPO3\CMS\Extbase\Annotation\FileUpload` attribute, it may be
required make the upload folder or
other configuration options configurable with TypoScript.
Extension authors should use the :php:`initialize*Action` to apply settings
from TypoScript to a file upload configuration.
Example:
.. code-block:: php
public function initializeCreateAction(): void
{
$argument = $this->arguments->getArgument('myArgument');
$configuration = $argument->getFileHandlingServiceConfiguration()->getFileUploadConfigurationForProperty('file');
$configuration?->setUploadFolder($this->settings['uploadFolder'] ?? '1:/fallback_folder');
}
.. _83749-validationkeys:
File upload validation
----------------------
Each uploaded file can be validated against a configurable set of validators.
The :php:`validation` section of the :php-short:`\TYPO3\CMS\Extbase\Annotation\FileUpload` attribute allows to
configure commonly used validators using a configuration shorthand.
The following validation rules can be configured in the :php:`validation`
section of the :php-short:`\TYPO3\CMS\Extbase\Annotation\FileUpload` attribute:
* :php:`required`
* :php:`minFiles`
* :php:`maxFiles`
* :php:`fileExtension` (for :php:`TYPO3\CMS\Extbase\Validation\Validator\FileExtensionValidator`)
* :php:`fileSize` (for :php:`TYPO3\CMS\Extbase\Validation\Validator\FilesizeValidator`)
* :php:`imageDimensions` (for :php:`TYPO3\CMS\Extbase\Validation\Validator\ImageDimensionsValidator`)
* :php:`mimeType` (for :php:`TYPO3\CMS\Extbase\Validation\Validator\MimeTypeValidator`)
* :php:`allowedMimeTypes` (shorthand notation for configuration option :php:`allowedMimeTypes` of the :php:`MimeTypeValidator`)
Example:
.. code-block:: php
#[FileUpload([
'validation' => [
'required' => true,
'maxFiles' => 1,
'fileSize' => ['minimum' => '0K', 'maximum' => '2M'],
'mimeType' => ['allowedMimeTypes' => ['image/jpeg']],
'fileExtension' => ['allowedFileExtensions' => ['jpg', 'jpeg']],
'imageDimensions' => ['maxWidth' => 4096, 'maxHeight' => 4096]
],
'uploadFolder' => '1:/user_upload/extbase_single_file/',
])]
Extbase will internally use the Extbase file upload validators for
:php:`fileExtensionMimeTypeConsistency`, :php:`fileExtension`, :php:`fileSize`,
:php:`mimeType` and :php:`imageDimensions` validation.
Custom validators can be created according to project requirements and must
extend the Extbase :php-short:`\TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator`.
The value to be validated is
always a PSR-7 :php-short:`\TYPO3\CMS\Core\Http\UploadedFile` object.
Custom validators can however not
be used in the :php-short:`\TYPO3\CMS\Extbase\Annotation\FileUpload` attribute
and must be configured manually.
Shorthand notation for `allowedMimeTypes`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Using the :php:`mimeType` configuration array, all options of the `MimeTypeValidator`
can be set as sub-keys (since TYPO3 13.4.1):
.. code-block:: php
#[FileUpload([
'validation' => [
'required' => true,
'mimeType' => [
'allowedMimeTypes' => ['image/jpeg'],
'ignoreFileExtensionCheck' => false,
'notAllowedMessage' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:validation.mimetype.notAllowedMessage',
'invalidExtensionMessage' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:validation.mimetype.invalidExtensionMessage',
],
],
'uploadFolder' => '1:/user_upload/files/',
])]
The shorthand notation via :php:`'allowedMimeTypes'` continues to
exist, in case only the mime type validation is needed. However, it is recommended
to utilize the full :php:`'mimeType'` configuration array.
Deletion of uploaded files and file references
----------------------------------------------
The new Fluid ViewHelper
:ref:`Form.uploadDeleteCheckbox ViewHelper <f:form.uploadDeleteCheckbox> <t3viewhelper:typo3-fluid-form-uploaddeletecheckbox>`
can be used to show a "delete file" checkbox in a form.
Example for object with :php-short:`\TYPO3\CMS\Extbase\Domain\Model\FileReference` property:
.. code-block:: php
<f:form.uploadDeleteCheckbox property="file" fileReference="{object.file}" />
Example for an object with an
:php:`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):
.. code-block:: php
<f:form.uploadDeleteCheckbox property="file.0" fileReference="{object.file}" />
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 :php-short:`\TYPO3\CMS\Extbase\Annotation\FileUpload`)
* delete the affected :php:`sys_file_reference` record
* delete the affected file
Internally, Extbase uses :php:`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
:php-short:`\TYPO3\CMS\Extbase\Domain\Model\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 :php-short:`\TYPO3\CMS\Extbase\Event\Service\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.
.. index:: PHP-API, ext:extbase
@@ -0,0 +1,66 @@
.. include:: /Includes.rst.txt
.. _feature-103521-1718028096:
=====================================================================================
Feature: #103521 - Change table restrictions UI to combine read and write permissions
=====================================================================================
See :issue:`103521`
Description
===========
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:
:php:`\TYPO3\CMS\Backend\Form\Element\TablePermissionElement`.
It uses a dedicated data provider defined in:
:php:`\TYPO3\CMS\Backend\Form\FormDataProvider\TcaTablePermission`.
The JavaScript code is handled by a new web component:
:js:`@typo3/backend/form-engine/element/table-permission-element.js`.
When the :php-short:`\TYPO3\CMS\Backend\Form\FormDataProvider\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.
.. index:: Backend, JavaScript, PHP-API, TCA, ext:core
@@ -0,0 +1,35 @@
.. include:: /Includes.rst.txt
.. _feature-103576-1720813198:
===================================================================
Feature: #103576 - Allow defining opacity in TCA type=color element
===================================================================
See :issue:`103576`
Description
===========
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.
.. code-block:: php
'my_color' => [
'label' => 'My Color',
'config' => [
'type' => 'color',
'opacity' => true,
],
],
Impact
======
If `opacity` is enabled, editors can select not only a color but also its
opacity in a corresponding color element.
.. index:: TCA, ext:backend
@@ -0,0 +1,167 @@
.. include:: /Includes.rst.txt
.. _feature-103581-1723209131:
==============================================================================
Feature: #103581 - Automatically transform TCA field values for record objects
==============================================================================
See :issue:`103581`
Description
===========
With :issue:`103783` the new :php:`\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
:ref:`RecordTransformationProcessor <t3tsref:RecordTransformationProcessor>`
(:typoscript:`record-transformation`) or by collecting content elements with the
:ref:`PageContentFetchingProcessor <t3tsref:PageContentFetchingProcessor>`
(:typoscript:`page-content`).
The Records API - introduced together with the Schema API in :issue:`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 :php-short:`\TYPO3\CMS\Core\Domain\Record`,
:php-short:`\TYPO3\CMS\Core\Resource\FileReference`,
:php:`\TYPO3\CMS\Core\Resource\Folder` or :php:`\DateTimeImmutable` objects.
This works for the following "relation" TCA types:
* :php:`category`
* :php:`file`
* :php:`folder`
* :php:`group`
* :php:`inline`
* :php:`select` with :php:`MM` and :php:`foreign_table`
In addition, the values of following TCA types are also resolved and
expanded automatically:
* :php:`datetime`
* :php:`flex`
* :php:`json`
* :php:`link`
* :php:`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 (:php:`category`, :php:`group`, :php:`inline`,
:php:`select` with :php:`MM` and :php:`foreign_table`), a collection
(:php:`LazyRecordCollection`) of new :php-short:`\TYPO3\CMS\Core\Domain\Record` objects is attached as
value. In case of :php:`file`, a collection (:php:`LazyFileReferenceCollection`)
of :php:`FileReference` objects and in case of type :php:`folder`, a collection
(:php:`LazyFolderCollection`) of :php:`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.
Example
=======
.. code-block:: html
<f:for each="{myContent.main.records}" as="record">
<f:for each="{record.image}" as="image">
<f:image image="{image}" />
</f:for>
</f:for>
New TCA option `relationship`
=============================
In order to define cardinality on TCA level, the option :php:`relationship` is
introduced for all "relation" TCA types listed above. If this option is set to
:php:`oneToOne` or :php:`manyToOne`, then relations are resolved directly
without being wrapped into collection objects. In case the relation can
not be resolved, :php:`NULL` is returned.
.. code-block:: php
'image' => [
'config' => [
'type' => 'file',
'relationship' => 'manyToOne',
]
]
.. code-block:: html
<f:for each="{myContent.main.records}" as="record">
<f:image image="{record.image}" />
</f:for>
.. note::
The TCA option :php:`maxitems` does not influence this behavior. This means
it is possible to have a :php:`oneToMany` relation with maximum one value
allowed. This way, overrides of this value will not break functionality.
Field expansion
===============
For TCA type :php:`flex`, the corresponding FlexForm is resolved and therefore
all values within this FlexForm are processed and expanded as well.
Fields of TCA type :php:`datetime` will be transformed into a full
:php:`\DateTimeInterface` object.
Fields of TCA type :php:`json` will provide the decoded JSON value.
Fields of TCA type :php:`link` will provide the
:php:`\TYPO3\CMS\Core\LinkHandling\TypolinkParameter` object,
which is an object oriented representation of the corresponding TypoLink
:typoscript:`parameter` configuration.
Fields of TCA type :php:`select` without a :php:`relationship` will always provide
an array of static values.
.. note::
TYPO3 tries to automatically resolve the :php:`relationship` for type
:php:`select` fields, which use :php:`renderType=selectSingle` and
having a :php:`foreign_table` set. This means, in case no
:php:`relationship` has been defined yet, it is set to either :php:`manyToOne`
as the default or :php:`manyToMany` for fields with option :php:`MM`.
Impact
======
When using :php-short:`\TYPO3\CMS\Core\Domain\Record` objects through the
:php:`\TYPO3\CMS\Core\Domain\RecordFactory` API, e.g. via
:ref:`RecordTransformationProcessor <t3tsref:RecordTransformationProcessor>`
(:typoscript:`record-transformation`) or
:ref:`PageContentFetchingProcessor <t3tsref:PageContentFetchingProcessor>`
(`page-content`), the corresponding :php-short:`\TYPO3\CMS\Core\Domain\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:
.. code-block:: typoscript
mod.web_layout.tt_content.preview {
textmedia = EXT:site/Resources/Private/Templates/Preview/Textmedia.html
}
In such template the newly available variable :html:`{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.
:php-short:`\TYPO3\CMS\Frontend\DataProcessing\FilesProcessor` (:typoscript:`files`),
becomes superfluous since all relations are resolved automatically when
requested.
.. index:: Backend, FlexForm, Frontend, TCA, ext:core
@@ -0,0 +1,86 @@
.. include:: /Includes.rst.txt
.. _feature-103789-1714805317:
=========================================================================
Feature: #103789 - Add "close"-button to page layout, if returnUrl is set
=========================================================================
See :issue:`103789`
Description
===========
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 :fluid:`<be:moduleLink>` ViewHelper:
.. code-block:: html
:caption: Fluid example
<a href="{be:moduleLink(route:'web_layout', arguments:'{id:pageUid, returnUrl: returnUrl}')}"
class="btn btn-default"
title="{f:translate(key: 'LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:title')}">
<core:icon identifier="actions-document" size="small"/>
</a>
The behaviour is similar to the :html:`<be:uri.editRecord>` ViewHelper,
where setting the `returnUrl` argument will also cause a "close"-button to
be displayed.
.. important::
When using the :fluid:`<be:uri.editRecord>` ViewHelper, `returnUrl` is
passed directly as argument. However, using :fluid:`<be:moduleLink>`, the
`returnUrl` argument must be passed as an additional parameter via the Fluid
ViewHelper's argument :fluid:`arguments` or :fluid:`query`.
The `returnUrl` should usually return to the calling (originating) module.
You can build the `returnUrl` with the Fluid ViewHelper :fluid:`be:uri`:
.. code-block:: html
:caption: Fluid example for building returnUrl to module "linkvalidator"
<f:be.uri route="web_linkvalidator" parameters="{id: pageUid}"/>
Here is an example for building the `returnUrl` via PHP:
.. code-block:: php
:caption: Backend module controller
use TYPO3\CMS\Backend\Routing\UriBuilder;
public function __construct(
protected readonly UriBuilder $uriBuilder
) {}
protected function generateModuleUri(array $parameters = []): string
{
return $this->uriBuilder->buildUriFromRoute('web_linkvalidator', $parameters);
}
public function __invoke(ServerRequestInterface $request): ResponseInterface
{
// ...
$this->view->assign('returnUrl', $this->generateModuleUri(['pageUid' => $this->id]));
// ...
}
Impact
======
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.
.. index:: Backend, ext:backend
@@ -0,0 +1,51 @@
.. include:: /Includes.rst.txt
.. _feature-104126-1714290385:
===========================================================================
Feature: #104126 - Add configuration setting to define backend-locking file
===========================================================================
See :issue:`104126`
Description
===========
TYPO3 supports the ability to lock the backend for maintenance reasons. This
is controlled with a :file:`LOCK_BACKEND` file that was previously stored in
:path:`typo3conf/`.
With :ref:`<important-104126-1714290385>` this directory is no longer needed,
so now the location to this file can be adjusted via the new configuration setting
:php:`$GLOBALS['TYPO3_CONF_VARS']['BE']['lockBackendFile']`.
When empty, it falls back to a file :file:`LOCK_BACKEND`, which is now stored
by default in:
* :path:`var/lock/` for Composer Mode
* :path:`config/` for Legacy Mode
If you previously manually maintained the :file:`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 :bash:`vendor/bin/typo3 backend:lock` and
:bash:`vendor/bin/typo3 backend:unlock`.
The backend locking functionality is now contained in a distinct service class
:php:`\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 :path:`var/lock/`.
Remember, if you want locked backend state to persist between deployments, ensure that the
used directory (:path:`var/lock` by default) is shared between deployment releases.
Impact
======
The location for :file:`LOCK_BACKEND` to lock (and unlock) the backend can now be controlled
by maintainers of a TYPO3 installation, and has moved outside of :path:`typo3conf/` by default
to either :path:`var/lock/` (Composer) or :path:`config/` (Legacy).
.. index:: Backend, CLI, LocalConfiguration, ext:backend
@@ -0,0 +1,95 @@
.. include:: /Includes.rst.txt
.. _feature-104168-1719373149:
=======================================================
Feature: #104168 - PSR-14 event for modifying countries
=======================================================
See :issue:`104168`
Description
===========
A new PSR-14 event :php:`\TYPO3\CMS\Core\Country\Event\BeforeCountriesEvaluatedEvent`
has been introduced to modify the list of countries provided by
:php:`\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 :html:`<f:form.countrySelect />`.
.. note::
The DTO :php:`\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 :ref:`locallangXMLOverride <t3coreapi:xliff-translating-custom>`.
Example
=======
An example corresponding event listener class:
.. code-block:: php
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\EventListener;
use TYPO3\CMS\Core\Attribute\AsEventListener;
use TYPO3\CMS\Core\Country\Country;
use TYPO3\CMS\Core\Country\Event\BeforeCountriesEvaluatedEvent;
final readonly class EventListener
{
#[AsEventListener(identifier: 'my-extension/before-countries-evaluated')]
public function __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);
}
}
.. code-block:: php
:caption: EXT:my_extension/ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride']
['EXT:core/Resources/Private/Language/Iso/countries.xlf'][]
= 'EXT:my_extension/Resources/Private/Language/countries.xlf';
.. code-block:: xml
:caption: EXT:my_extension/Resources/Private/Language/countries.xlf
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<xliff version="1.0">
<file source-language="en" datatype="plaintext" date="2024-01-08T18:44:59Z" product-name="my_extension">
<body>
<trans-unit id="XX.name" approved="yes">
<source>Magic Kingdom</source>
</trans-unit>
<trans-unit id="XX.official_name" approved="yes">
<source>Kingdom of Magic and Wonders</source>
</trans-unit>
</body>
</file>
</xliff>
Impact
======
Using the PSR-14 event :php-short:`\TYPO3\CMS\Core\Country\Event\BeforeCountriesEvaluatedEvent` allows
modification of countries provided by :php-short:`\TYPO3\CMS\Core\Country\CountryProvider`.
.. index:: PHP-API, ext:core
@@ -0,0 +1,133 @@
.. include:: /Includes.rst.txt
.. _feature-104221-1715591178:
========================================================================
Feature: #104221 - PSR-14 events for RTE <-> Persistence transformations
========================================================================
See :issue:`104221`
Description
===========
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 :php:`\TYPO3\CMS\Core\Html\RteHtmlParser` class, by utilizing the
methods :php:`transformTextForRichTextEditor` and :php:`transformTextForPersistence`.
With :issue:`96107` and :issue:`92992`, the former hook
:php:`$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 :php:`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):
* :php:`\TYPO3\CMS\Core\Html\Event\BeforeTransformTextForPersistenceEvent`
* :php:`\TYPO3\CMS\Core\Html\Event\AfterTransformTextForPersistenceEvent`
Modify data when retrieving content from the database and pass to the RTE:
* :php:`\TYPO3\CMS\Core\Html\Event\BeforeTransformTextForRichTextEditorEvent`
* :php:`\TYPO3\CMS\Core\Html\Event\AfterTransformTextForRichTextEditorEvent`
All four events have the same structure (for now):
* :php:`getHtmlContent()` - retrieve the current HTML content
* :php:`setHtmlContent()` - used to set modifications of the HTML content
* :php:`getInitialHtmlContent()` - retrieve the untampered initial HTML content
* :php:`getProcessingConfiguration()` - retrieve processing configuration array
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 :php:`$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.
The corresponding event listener class:
.. code-block:: php
:caption: EXT:MyExtension/Classes/EventListener/TransformListener.php
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\EventListener;
use TYPO3\CMS\Core\Attribute\AsEventListener;
class TransformListener
{
/**
* Transforms the current value the RTE delivered into a value that is stored (persisted) in the database.
*/
#[AsEventListener('rtehtmlparser/modify-data-for-persistence')]
public function modifyPersistence(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')]
public function modifyRichTextEditor(AfterTransformTextForRichTextEditorEvent $event): void
{
$value = $event->getHtmlContent();
$value = str_replace('[tag:typo3]', 'TYPO3', $value);
$event->setHtmlContent($value);
}
}
Impact
======
Using the new PSR-14 events
* :php:`\TYPO3\CMS\Core\Html\Event\BeforeTransformTextForPersistenceEvent`
* :php:`\TYPO3\CMS\Core\Html\Event\AfterTransformTextForPersistenceEvent`
* :php:`\TYPO3\CMS\Core\Html\Event\BeforeTransformTextForRichTextEditorEvent`
* :php:`\TYPO3\CMS\Core\Html\Event\AfterTransformTextForRichTextEditorEvent`
allows to apply custom transformations for `database <-> RTE content`
transformations.
.. index:: Backend, PHP-API, ext:core
@@ -0,0 +1,465 @@
.. include:: /Includes.rst.txt
.. _feature-104311-1720176189:
==================================================
Feature: #104311 - Auto created system TCA columns
==================================================
See :issue:`104311`
Description
===========
Introduction
------------
There are various :php:`TCA` table :php:`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 :php:`$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 :php:`ctrl` settings require TCA :php:`columns` definitions. Default definitions
of such :php:`columns` are now automatically added to :php:`TCA` if not manually
configured. Extension developers can now remove and avoid a significant amount
of boilerplate field definitions in :php:`columns` and rely on TYPO3 Core to create
them automatically. Note the Core does *not* automatically add such columns to TCA
:php:`types` or :php:`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 :php:`file`, :php:`category`, :php:`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 :file:`ext_tables.sql` largely
unnecessary. Additionally, an object-oriented approach called
:php-short:`\TYPO3\CMS\Core\Schema\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
:php:`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 :php:`types` and :php:`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 (:path:`Configuration/TCA`, not
in :path:`Configuration/TCA/Overrides`), the TYPO3 Core will add default :php:`columns`
definition for this field name if no definition exists in a base file.
`$GLOBALS['TCA']['ctrl']['enablecolumns']['disabled']`
......................................................
This setting makes database table rows "disable aware": A row with this flag
being set to 1 is not rendered in the frontend to casual website users.
Typical usage:
.. code-block:: php
'ctrl' => [
'enablecolumns' => [
'disabled' => 'disabled',
],
],
Default configuration added by the TYPO3 Core:
.. code-block:: php
'disabled' => [
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.enabled',
'exclude' => true,
'config' => [
'type' => 'check',
'renderType' => 'checkboxToggle',
'default' => 0,
'items' => [
[
'label' => '',
'invertStateDisplay' => true,
],
],
],
],
`$GLOBALS['TCA']['ctrl']['enablecolumns']['starttime']`
.......................................................
This setting makes database table rows "starttime aware": A row having a start
time in the future is not rendered in the frontend.
Typical usage:
.. code-block:: php
'ctrl' => [
'enablecolumns' => [
'starttime' => 'starttime',
],
],
Default configuration added by the TYPO3 Core:
.. code-block:: php
'starttime' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime',
'config' => [
'type' => 'datetime',
'default' => 0,
],
],
`$GLOBALS['TCA']['ctrl']['enablecolumns']['endtime']`
.....................................................
This setting makes database table rows "endtime aware": A row having an end
time in the past is not rendered in the frontend.
Typical usage:
.. code-block:: php
'ctrl' => [
'enablecolumns' => [
'endtime' => 'endtime',
],
],
Default configuration added by the TYPO3 Core:
.. code-block:: php
'endtime' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime',
'config' => [
'type' => 'datetime',
'default' => 0,
'range' => [
'upper' => mktime(0, 0, 0, 1, 1, 2106),
],
],
],
`$GLOBALS['TCA']['ctrl']['enablecolumns']['fe_group']`
......................................................
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.
Typical usage:
.. code-block:: php
'ctrl' => [
'enablecolumns' => [
'fe_group' => 'fe_group',
],
],
Default configuration added by the TYPO3 Core:
.. code-block:: php
'fe_group' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.fe_group',
'config' => [
'type' => 'select',
'renderType' => 'selectMultipleSideBySide',
'size' => 5,
'maxitems' => 20,
'items' => [
[
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.hide_at_login',
'value' => -1,
],
[
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.any_login',
'value' => -2,
],
[
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.usergroups',
'value' => '--div--',
],
],
'exclusiveKeys' => '-1,-2',
'foreign_table' => 'fe_groups',
],
],
`$GLOBALS['TCA']['ctrl']['editlock']`
.....................................
This setting makes database table rows "backend lock aware": A row with this
being flag enabled can only be edited by backend administrators.
Typical usage:
.. code-block:: php
'ctrl' => [
'editlock' => 'editlock',
],
Default configuration added by the TYPO3 Core:
.. code-block:: php
'endtime' => [
'displayCond' => 'HIDE_FOR_NON_ADMINS',
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:editlock',
'config' => [
'type' => 'check',
'renderType' => 'checkboxToggle',
],
],
`$GLOBALS['TCA']['ctrl']['descriptionColumn']`
..............................................
This setting makes database table rows "description aware": Backend editors
have a database field to add row specific notes.
Typical usage:
.. code-block:: php
'ctrl' => [
'descriptionColumn' => 'description',
],
Default configuration added by the TYPO3 Core:
.. code-block:: php
'description' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.description',
'config' => [
'type' => 'text',
'rows' => 5,
'cols' => 30,
'max' => 2000,
],
],
`$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 :php:`languageField` is
set, and :php:`transOrigPointerField` is not, the TYPO3 Core will automatically set
:php:`transOrigPointerField` to :php:`l10n_parent` since both fields must be
always set in combination.
Typical usage:
.. code-block:: php
'ctrl' => [
'languageField' => 'sys_language_uid',
'transOrigPointerField' => 'l10n_parent',
],
Default configuration added by the TYPO3 Core, note string :php:`$table` corresponds
to the current table name.
.. code-block:: php
'sys_language_uid' => [
'exclude' => true,
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
'config' => [
'type' => 'language',
],
],
'l10n_parent' => [
'displayCond' => 'FIELD:sys_language_uid:>:0',
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'items' => [
[
'label' => '',
'value' => 0,
],
],
'foreign_table' => $table,
'foreign_table_where' => 'AND {#' . $table . '}.{#pid}=###CURRENT_PID### AND {#' . $table . '}.{#' . $languageFieldName . '} IN (-1,0)',
'default' => 0,
],
],
`$GLOBALS['TCA']['ctrl']['transOrigDiffSourceField']`
.....................................................
This setting makes database table rows "parent language record change aware": Backend
editors can have an indicator when the parent column has been changed.
Typical usage:
.. code-block:: php
'ctrl' => [
'transOrigDiffSourceField' = 'l10n_diffsource',
],
Default configuration added by the TYPO3 Core:
.. code-block:: php
'l10n_diffsource' => [
'config' => [
'type' => 'passthrough',
'default' => '',
],
],
`$GLOBALS['TCA']['ctrl']['translationSource']`
..............................................
This setting makes database table rows "parent language source aware" to
determine the difference between "connected mode" and "free mode".
Typical usage:
.. code-block:: php
'ctrl' => [
'translationSource' = 'l10n_source',
],
Default configuration added by the TYPO3 Core:
.. code-block:: php
'l10n_source' => [
'config' => [
'type' => 'passthrough',
'default' => '',
],
],
Load order when building TCA
----------------------------
To understand if and when TCA column auto-creation from :php:`ctrl` definitions
kicks in, it is important to have an overview of the order of the single loading
steps:
#. Load single files from extension :file:`Configuration/TCA` files
#. NEW - Enrich :php:`columns` from :php:`ctrl` settings
#. Load single files from extension :file:`Configuration/TCA/Overrides` files
#. Apply TCA migrations
#. Apply TCA preparations
As a result of this strategy, :php:`columns` fields are *not* auto-created, when
a :php:`ctrl` capability is added in a :path:`Configuration/TCA/Overrides`
file, and *not* in a :path:`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 :php:`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 (: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 :file:`Configuration/TCA/Overrides` files.
As example, "base" :php:`pages` file defines this (step 1 above):
.. code-block:: php
'ctrl' => [
'enablecolumns' => [
'disabled' => 'disabled',
],
],
The TYPO3 Core thus creates this :php:`columns` definition (step 2 above):
.. code-block:: php
'columns' => [
'disabled' => [
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.enabled',
'exclude' => true,
'config' => [
'type' => 'check',
'renderType' => 'checkboxToggle',
'default' => 0,
'items' => [
[
'label' => '',
'invertStateDisplay' => true,
],
],
],
],
],
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 :file:`Configuration/TCA/Overrides/pages.php` file does this:
.. code-block:: php
<?php
// New pages are disabled by default
$GLOBALS['TCA']['pages']['columns']['hidden']['config']['default'] = 1;
Impact
======
Extension developers can typically remove :php:`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 :php:`ctrl` with
its field names, and the system will create the according :php:`columns`
definitions automatically.
.. index:: TCA, ext:core
@@ -0,0 +1,59 @@
.. include:: /Includes.rst.txt
.. _feature-104321-1720369379:
====================================================================================
Feature: #104321 - Allow handling of argument mapping exceptions in ActionController
====================================================================================
See :issue:`104321`
Description
===========
A new method :php:`handleArgumentMappingExceptions` has been introduced in
Extbase :php:`\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:
* :php:`\TYPO3\CMS\Extbase\Property\Exception\TargetNotFoundException`,
which occurs, when a given object UID can not be resolved to an existing record.
* :php:`\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.
* :typoscript:`config.tx_extbase.mvc.showPageNotFoundIfTargetNotFoundException = 1`
* :typoscript:`config.tx_extbase.mvc.showPageNotFoundIfRequiredArgumentIsMissingException = 1`
The exception handling can also be configured on extension level with the
following TypoScript configuration.
* :typoscript:`plugin.tx_yourextension.mvc.showPageNotFoundIfTargetNotFoundException = 1`
* :typoscript:`plugin.tx_yourextension.mvc.showPageNotFoundIfRequiredArgumentIsMissingException = 1`
* :typoscript:`plugin.tx_yourextension_plugin1.mvc.showPageNotFoundIfTargetNotFoundException = 1`
* :typoscript:`plugin.tx_yourextension_plugin1.mvc.showPageNotFoundIfRequiredArgumentIsMissingException = 1`
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 :php:`pageNotFound` response is propagated, resulting in a 404 error being
shown.
Additionally, extension authors can extend or override the method
:php:`handleArgumentMappingExceptions` in relevant Controllers in order
to implement custom argument mapping exception handling.
Impact
======
Extension authors can now handle exceptions in implementations of a
:php-short:`\TYPO3\CMS\Extbase\Mvc\Controller\ActionController`,
which are thrown during argument mapping.
.. index:: Frontend, ext:extbase
@@ -0,0 +1,82 @@
.. include:: /Includes.rst.txt
.. _feature-104451-1721646565:
===========================================================
Feature: #104451 - Redis backends support for key prefixing
===========================================================
See :issue:`104451`
Description
===========
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)
.. code-block:: php
:caption: additional.php example for using Redis as session backend
$GLOBALS['TYPO3_CONF_VARS']['SYS']['session']['BE'] = [
'backend' => \TYPO3\CMS\Core\Session\Backend\RedisSessionBackend::class,
'options' => [
'hostname' => 'redis',
'database' => '11',
'compression' => true,
'keyPrefix' => 'be_sessions_',
],
];
$GLOBALS['TYPO3_CONF_VARS']['SYS']['session']['FE'] = [
'backend' => \TYPO3\CMS\Core\Session\Backend\RedisSessionBackend::class,
'options' => [
'hostname' => 'redis',
'database' => '11',
'compression' => true,
'keyPrefix' => 'fe_sessions_',
'has_anonymous' => true,
],
];
.. code-block:: php
:caption: additional.php example for pages cache
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['pages'] = [
'backend' => \TYPO3\CMS\Core\Cache\Backend\RedisBackend::class,
'options' => [
'hostname' => 'redis',
'database' => 11,
'compression' => true,
'keyPrefix' => 'pages_';
],
];
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['rootline'] = [
'backend' => \TYPO3\CMS\Core\Cache\Backend\RedisBackend::class,
'options' => [
'hostname' => 'redis',
'database' => 11,
'compression' => true,
'keyPrefix' => 'rootline_';
],
];
Impact
======
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.
.. index:: Frontend, LocalConfiguration, ext:core
@@ -0,0 +1,87 @@
.. include:: /Includes.rst.txt
.. _feature-104482-1721939108:
========================================================
Feature: #104482 - Add if() support to ExpressionBuilder
========================================================
See :issue:`104482`
Description
===========
The TYPO3 :php:`\TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder`
provides a new method to phrase "if-then-else" expressions. Those are translated
into :sql:`IF` or :sql:`CASE` statements depending on the used database engine.
`ExpressionBuilder::if()`
-------------------------
Creates an IF-THEN-ELSE expression.
.. code-block:: php
:caption: 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`
* ```
*/
public function if(
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 => throw new \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;
}
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.
.. index:: Database, PHP-API, ext:core
@@ -0,0 +1,99 @@
.. include:: /Includes.rst.txt
.. _feature-104493-1722127314:
=============================================================================
Feature: #104493 - Add `castText()` expression support to `ExpressionBuilder`
=============================================================================
See :issue:`104493`
Description
===========
The TYPO3 :php:`\TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder`
provides a new method to cast expression results to text like datatypes. This
is done to large :sql:`VARCHAR/CHAR` types using the :sql:`CAST/CONVERT` or similar
methods based on the used database engine.
.. note::
This should not be mixed with :sql:`TEXT`, :sql:`CHAR` or :sql:`VARCHAR`
data types for column (fields) definition used to describe the structure
of a table.
`ExpressionBuilder::castText()`
-------------------------------
Creates a :sql:`CAST` expression.
.. code-block:: php
:caption: 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.
*/
public function castText(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);
}
throw new \RuntimeException(
sprintf(
'%s is not implemented for the used database platform "%s", yet!',
__METHOD__,
get_class($this->connection->getDatabasePlatform())
),
1722105672
);
}
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.
.. index:: Database, PHP-API, ext:core
@@ -0,0 +1,80 @@
.. include:: /Includes.rst.txt
.. _feature-104526-1722603089:
===============================================================================
Feature: #104526 - Provide validators for PSR-7 UploadedFile objects in Extbase
===============================================================================
See :issue:`104526`
Description
===========
4 new Extbase validators have been added to allow common validation tasks of a
PSR-7 :php:`\TYPO3\CMS\Core\Http\UploadedFile` object or an
:php:`\TYPO3\CMS\Extbase\Persistence\ObjectStorage` containing PSR-7
:php-short:`\TYPO3\CMS\Core\Http\UploadedFile` objects.
Note, that the new validators can only be applied to the TYPO3 implementation
of the PSR-7 :php:`\Psr\Http\Message\UploadedFileInterface` because they validate the uploaded
files before it has been moved.
Custom implementations of the :php-short:`\Psr\Http\Message\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:
* :php:`minimum` - The minimum size as string (e.g. 100K)
* :php:`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:
* :php:`allowedMimeTypes` - An array of allowed MIME types
* :php:`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:
* :php:`width` - Fixed width of the image as integer
* :php:`height` - Fixed height of the image as integer
* :php:`minWidth` - Minimum width of the image as integer. Default is `0`
* :php:`maxWidth` - Maximum width of the image as integer. Default is `PHP_INT_MAX`
* :php:`minHeight` - Minimum height of the image as integer. Default is `0`
* :php:`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
:php-short:`\TYPO3\CMS\Core\Http\UploadedFile` object.
.. index:: Backend, ext:extbase
@@ -0,0 +1,175 @@
.. include:: /Includes.rst.txt
.. _feature-104631-1723714985:
=================================================================
Feature: #104631 - Add `UNION Clause` support to the QueryBuilder
=================================================================
See :issue:`104631`
Description
===========
The :sql:`UNION` clause is used to combine the result sets of two or more
:sql:`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:
.. code-block:: sql
SELECT column_name(s) FROM table1
WHERE ...
UNION <ALL | DISTINCT>
SELECT column_name(s) FROM table2
WHERE ...
ORDER BY ...
LIMIT x OFFSET y
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 :sql:`UNION` clause support has been contributed to `Doctrine DBAL` and
is included since `Release 4.1.0 <https://github.com/doctrine/dbal/releases/tag/4.1.0>`__
which introduces two new API method on the
:php-short:`\Doctrine\DBAL\Query\QueryBuilder`:
* :php:`union(string|QueryBuilder $part)` to create first UNION query part
* :php:`addUnion(string|QueryBuilder $part, UnionType $type = UnionType::DISTINCT)`
to add additional :sql:`UNION (ALL|DISTINCT)` query parts with the selected union
query type.
TYPO3 decorates the Doctrine DBAL :php-short:`\Doctrine\DBAL\Query\QueryBuilder`
to provide for most API methods automatic
quoting of identifiers and values **and** to apply database restrictions automatically
for :sql:`SELECT` queries.
The Doctrine DBAL API has been adopted now to provide the same surface for the
TYPO3 :php:`\TYPO3\CMS\Core\Database\Query\QueryBuilder` and the intermediate
:php:`\TYPO3\CMS\Core\Database\Query\ConcreteQueryBuilder` to make it easier to
create :sql:`UNION` clause queries. The API on both methods allows to provide
dedicated :php-short:`\TYPO3\CMS\Core\Database\Query\QueryBuilder` instances
or direct queries as strings in case it is needed.
.. note::
Providing :sql:`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
:php-short:`\TYPO3\CMS\Core\Database\Query\QueryBuilder` object,
similar to advanced query creation with :sql:`SUB QUERIES`.
.. warning::
:php-short:`\TYPO3\CMS\Core\Database\Query\QueryBuilder` can be used create
:sql:`UNION` clause queries not compatible with all database providers,
for example using :sql:`LIMIT/OFFSET` in each part query or other stuff.
UnionType::DISTINCT and UnionType::ALL
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Each subsequent part needs to be defined either as :sql:`UNION DISTINCT` or
:sql:`UNION ALL` which could have not so obvious effects.
For example, using :sql:`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 :sql:`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 :sql:`UNION` clause query
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: php
:caption: Custom service class using a UNION query to retrieve data.
use Doctrine\DBAL\Query\UnionType;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
final readonly class MyService {
public function __construct(
private ConnectionPool $connectionPool,
) {}
public function executeUnionQuery(
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();
}
}
This would create the following query for MySQL with :php:`$pageIdOne = 100` and
:php:`$pageIdTwo = 10`:
.. code-block:: sql
(SELECT `uid`, `pid`, `title` FROM pages WHERE `pages`.`uid` = 100)
UNION
(SELECT `uid`, `pid`, `title` FROM pages WHERE `pages`.`uid` = 10)
ORDER BY `uid` ASC
Impact
======
Extension authors can use the new
:php-short:`\TYPO3\CMS\Core\Database\Query\QueryBuilder` methods to build more
advanced queries.
.. index:: Database, PHP-API, ext:core
@@ -0,0 +1,33 @@
.. include:: /Includes.rst.txt
.. _feature-104655-1724859386:
========================================================================
Feature: #104655 - Add console command to mark upgrade wizards as undone
========================================================================
See :issue:`104655`
Description
===========
A new CLI command :bash:`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
:bash:`typo3 upgrade:mark:undone <wizardIdentifier>`
.. index:: CLI, ext:install
@@ -0,0 +1,59 @@
.. include:: /Includes.rst.txt
.. _feature-104773-1724939348:
=======================================
Feature: #104773 - Generic view factory
=======================================
See :issue:`104773`
Description
===========
Class :php:`\TYPO3\CMS\Core\View\ViewFactoryInterface` has been added as a
generic view interface to create views that return an instance of
:php:`\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 :php-short:`\TYPO3\CMS\Core\View\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 :file:`Services.yaml` file.
A casual example to create and render a view looks like this.
.. code-block:: php
use TYPO3\CMS\Core\View\ViewFactoryInterface;
class MyController
{
public function __construct(
private readonly ViewFactoryInterface $viewFactory,
) {}
public function myAction(ServerRequestInterface $request): string
{
$viewFactoryData = new ViewFactoryData(
templateRootPaths: ['EXT:myExt/Resources/Private/Templates'],
partialRootPaths: ['EXT:myExt/Resources/Private/Partials'],
layoutRootPaths: ['EXT:myExt/Resources/Private/Layouts'],
request: $request,
);
$view = $this->viewFactory->create($viewFactoryData);
$view->assign('myData', 'myData');
return $view->render('path/to/template');
}
}
Note Extbase-based extensions create a view instance based on this factory
by default and are accessible as :php:`$this->view`.
.. index:: Fluid, PHP-API, ext:core
@@ -0,0 +1,60 @@
.. include:: /Includes.rst.txt
.. _feature-104789-1725194699:
========================================================================
Feature: #104789 - Support for contentArgumentName in AbstractViewHelper
========================================================================
See :issue:`104789`
Description
===========
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.
Example:
.. code-block:: html
<!-- Tag syntax -->
<f:format.json value="{data}" />
<f:format.json>{data}</f:format.json>
<!-- Inline syntax -->
{f:format.json(value: data)}
{data -> f:format.json()}
Previously, this feature was only available to ViewHelpers using the trait
:php-short:`\TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithContentArgumentAndRenderStatic`.
It is now available to all ViewHelpers since it has been integrated into the
:php-short:`\TYPO3Fluid\Fluid\Core\ViewHelper\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:
Example:
.. code-block:: php
public function getContentArgumentName(): string
{
return 'value';
}
Impact
======
ViewHelpers using the trait
:php-short:`\TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithContentArgumentAndRenderStatic`
should be migrated to the new feature.
:php-short:`\TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithContentArgumentAndRenderStatic`
will continue to work in Fluid v4, but will log a deprecation level error message.
It will be removed in Fluid v5.
.. index:: Fluid, ext:fluid
@@ -0,0 +1,116 @@
.. include:: /Includes.rst.txt
.. _feature-104794-1725980585:
=================================================
Feature: #104794 - Introduce Site Settings Editor
=================================================
See :issue:`104794`
Description
===========
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 :guilabel:`Site Management > Settings`
provides an overview of sites which offer configurable settings and makes
them editable based on
:doc:`Site Set provided Settings Definitions <../13.1/Feature-103437-IntroduceSiteSets>`.
The editor shows a list of settings categories and respective settings. It will
persist all settings into :file:`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 :file:`settings.definitions.yaml`
next to the site set file :file:`config.yaml`.
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Sets/MySet/settings.definitions.yaml
categories:
myCategory:
label: 'My Category'
settings:
my.example.setting:
label: 'My example setting'
category: myCategory
type: string
default: ''
my.seoRelevantSetting:
label: 'My SEO relevant setting'
# show in EXT:seo provided category "seo"
category: seo
type: int
default: 5
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 :file:`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.
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Sets/MySet/settings.definitions.yaml
settings:
my.readonlySetting:
label: 'My readonly setting'
type: int
default: 5
readonly: true
Enumeration of strings
----------------------
Site settings can provide possible options via the `enum` specifier, that will
be selectable in the editor GUI:
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Sets/MySet/settings.definitions.yaml
settings:
my.enumSetting:
label: 'My setting with options'
type: string
enum:
valueA: 'Label of value A'
valueB: 'Label of value B'
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.
.. index:: Backend, Frontend, YAML, ext:backend
@@ -0,0 +1,128 @@
.. include:: /Includes.rst.txt
.. _feature-104814-1725444916:
===================================================================
Feature: #104814 - Automatically add system fields to content types
===================================================================
See :issue:`104814`
Description
===========
All content elements types (:php:`CType`) are usually equipped with the same
system fields (`language`, `hidden`, etc.) - see also :ref:`feature-104311-1720176189`.
Adding them to the editor form has previously been done by adding those fields
to each content types' :php:`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 :php:`ctrl` definition.
.. note::
The fields are added to the :php:`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 :guilabel:`General` tab with the `general` palette at the very beginning
* The :guilabel:`Language` tab with the `language` palette after custom fields
* The :guilabel:`Access` tab with the `hidden` and `access` palettes
* The :guilabel:`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 :php:`ctrl` section:
* The :php:`ctrl[type]` field (usually :php:`CType`)
* The :php:`colPos` field
* The :php:`ctrl[languageField]` (usually :php:`sys_language_uid`)
* The :php:`ctrl[editlock]` field (usually :php:`editlock`)
* The :php:`ctrl[enablecolumns][disabled]` field (usually :php:`hidden`)
* The :php:`ctrl[enablecolumns][starttime]` field (usually :php:`starttime`)
* The :php:`ctrl[enablecolumns][endtime]` field (usually :php:`endtime`)
* The :php:`ctrl[enablecolumns][fe_group]` field (usually :php:`fe_group`)
* The :php:`ctrl[descriptionColumn]` field (usually :php:`rowDescription`)
By default, all custom fields - the ones still defined in :php:`showitem` - are
added after the `general` palette and are therefore added to the
:guilabel:`General` tab, unless a custom tab (e.g. :guilabel:`Plugin`,
or :guilabel:`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
:php:`showitem`. In this case, the :guilabel:`General` tab will be omitted.
All those system fields, which are added based on the :php:`ctrl` section are
also automatically removed from any custom palette and from the customized
type's :php:`showitem` definition.
If the content element defines the :guilabel:`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
:php:`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 :php:`showitem` to just the element specific fields.
A usual migration will therefore look like the following:
Before:
.. code-block:: php
'slider' => [
'showitem' => '
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
--palette--;;general,
--palette--;;headers,
slider_elements,
bodytext;LLL:EXT:awesome_slider/Resources/Private/Language/locallang_ttc.xlf:bodytext.ALT.slider_description,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:appearance,
--palette--;;frames,
--palette--;;appearanceLinks,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,
--palette--;;language,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
--palette--;;hidden,
--palette--;;access,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories,
categories,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:notes,
rowDescription,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:extended,
',
],
After:
.. code-block:: php
'slider' => [
'showitem' => '
--palette--;;headers,
slider_elements,
bodytext;LLL:EXT:awesome_slider/Resources/Private/Language/locallang_ttc.xlf:bodytext.ALT.slider_description,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories,
categories,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:extended,
',
],
Since all fields, palettes and tabs, which are defined in the :php:`showitem`
are added after the :php:`general` palette, also the :guilabel:`Categories` tab
- if defined - is displayed before the system tabs / fields. The only special
case is the :guilabel:`Extended` tab, which is always added at the end.
.. important::
For consistency reasons, custom labels for system fields are no
longer preserved.
.. index:: PHP-API, TCA, ext:core
@@ -0,0 +1,56 @@
.. include:: /Includes.rst.txt
.. _feature-104832-1725537890:
==========================================================================
Feature: #104832 - PSR-14 Event to alter the results of PageTreeRepository
==========================================================================
See :issue:`104832`
Description
===========
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 :php:`\TYPO3\CMS\Backend\Tree\Repository\AfterRawPageRowPreparedEvent`
has been introduced.
Example
=======
The event listener class, using the PHP attribute :php:`#[AsEventListener]` for
registration, will remove any children for displaying for the page with the
UID 123:
.. code-block:: php
use TYPO3\CMS\Core\Attribute\AsEventListener;
use TYPO3\CMS\Backend\Tree\Repository\AfterRawPageRowPreparedEvent;
final class MyEventListener
{
#[AsEventListener]
public function __invoke(AfterRawPageRowPreparedEvent $event): void
{
$rawPage = $event->getRawPage();
if ((int)$rawPage['uid'] === 123) {
$rawPage['_children'] = [];
$event->setRawPage($rawPage);
}
}
}
Impact
======
Using the new PSR-14 event, it is now possible to modify the populated
:php:`page` properties or its children records.
.. index:: Backend, PHP-API, ext:backend
@@ -0,0 +1,25 @@
.. include:: /Includes.rst.txt
.. _feature-104844-1725617507:
====================================================================================
Feature: #104844 - Add widgets for listing all the sys_notes inside the TYPO3 system
====================================================================================
See :issue:`104844`
Description
===========
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 :guilabel:`Dashboard` module and are
granted access to the new widgets can now add and use these widgets.
.. index:: Backend, ext:dashboard
@@ -0,0 +1,97 @@
.. include:: /Includes.rst.txt
.. _feature-104846-1725631434:
===============================================================
Feature: #104846 - Custom field transformations for new records
===============================================================
See :issue:`104846`
Description
===========
With :issue:`103783` the new :php:`\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 :ref:`feature-103581-1723209131` the properties of those
:php-short:`\TYPO3\CMS\Core\Domain\Record`
objects are transformed / expanded from their raw database value into
"rich-flavored" values. Those values might be relations to e.g.
:php-short:`\TYPO3\CMS\Core\Domain\Record`,
:php-short:`\TYPO3\CMS\Core\Resource\FileReference`,
:php-short:`\TYPO3\CMS\Core\Resource\Folder` or :php:`\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 :php:`\TYPO3\CMS\Core\Domain\Event\RecordCreationEvent` has been
introduced. It is dispatched right before a
:php-short:`\TYPO3\CMS\Core\Domain\Record` is created and
therefore allows to fully manipulate any property, even the ones already
transformed by TYPO3.
The new event is stoppable (implementing :php-short:`\Psr\EventDispatcher\StoppableEventInterface`), which
allows listeners to actually create a :php-short:`\TYPO3\CMS\Core\Domain\Record` object completely on their
own.
.. important::
The event operates on the :php-short:`\TYPO3\CMS\Core\Domain\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:
* :php:`setRecord()` - Manually adds a :php-short:`\TYPO3\CMS\Core\Domain\RecordInterface`
object (stops the event propagation)
* :php:`hasProperty()` - Whether a property exists
* :php:`setProperty()` - Add or overwrite a property
* :php:`setProperties()` - Set properties for the :php-short:`\TYPO3\CMS\Core\Domain\RecordInterface`
* :php:`unsetProperty()` - Unset a single property
* :php:`getProperty()` - Get the value for a single property
* :php:`getProperties()` - Get all properties
* :php:`getRawRecord()` - Get the :php:`RawRecord` object
* :php:`getSystemProperties()` - Get the calculated :php:`SystemProperties`
* :php:`getContext()` - Get the current :php:`Context` (used to fetch the raw database row)
* :php:`isPropagationStopped()` - Whether the event propagation is stopped
Example
=======
The event listener class, using the PHP attribute :php:`#[AsEventListener]` for
registration, creates a :php:`Coordinates` object based on the field value of
the :php:`coordinates` field for the custom :php:`maps` content type.
.. code-block:: php
final class RecordCreationEventListener
{
#[AsEventListener]
public function __invoke(\TYPO3\CMS\Core\Domain\Event\RecordCreationEvent $event): void
{
$rawRecord = $event->getRawRecord();
if ($rawRecord->getMainType() === 'tt_content' && $rawRecord->getRecordType() === 'maps' && $event->hasProperty('coordinates')) {
$event->setProperty(
'coordinates',
new Coordinates($event->getProperty('coordinates'))
);
}
}
}
Impact
======
Using the new PSR-14 :php-short:`\TYPO3\CMS\Core\Domain\Event\RecordCreationEvent`,
extension authors are able to apply any field transformation to any property before a
:php-short:`\TYPO3\CMS\Core\Domain\Record` is created.
It is even possible to completely create a new
:php-short:`\TYPO3\CMS\Core\Domain\RecordInterface` object on their own.
.. index:: PHP-API, ext:core
@@ -0,0 +1,30 @@
.. include:: /Includes.rst.txt
.. _feature-104868-1725912804:
=============================================
Feature: #104868 - Add color scheme switching
=============================================
See :issue:`104868`
Description
===========
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 :typoscript:`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
:typoscript:`setup.fields.colorScheme.disabled = 1`!
It is now possible to switch to an automatic, light or dark color scheme for use in the backend.
.. index:: Backend, ext:backend
@@ -0,0 +1,28 @@
.. include:: /Includes.rst.txt
.. _feature-104878-1725993353:
===========================================================================
Feature: #104878 - Introduce dashboard widget for pages with latest changes
===========================================================================
See :issue:`104878`
Description
===========
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 :guilabel:`Dashboard` module and are
granted access to the new widgets can now add and use this widget.
.. index:: Backend, ext:dashboard
@@ -0,0 +1,62 @@
.. include:: /Includes.rst.txt
.. _feature-104896-1726046146:
================================================
Feature: #104896 - Raise Fluid Standalone to 4.0
================================================
See :issue:`104896`
Description
===========
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 <https://github.com/TYPO3/Fluid/releases/tag/4.0.0>`_.
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:
.. code-block:: html
<my:viewhelper async="{true}" />
Result: <tag async="async" />
<my:viewhelper async="{false}" />
Result: <tag />
Of course, any variable containing a boolean can be supplied as well:
.. code-block:: html
<my:viewhelper async="{isAsync}" />
This can also be used in combination with variable casting:
.. code-block:: html
<my:viewhelper async="{myString as boolean}" />
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.
.. index:: Fluid, ext:fluid
@@ -0,0 +1,31 @@
.. include:: /Includes.rst.txt
.. _feature-104904-1726049662:
===========================================================
Feature: #104904 - Ignore Fluid syntax error in <f:comment>
===========================================================
See :issue:`104904`
Description
===========
Fluid 4 brings a new template processor
:php:`\TYPO3Fluid\Fluid\Core\Parser\TemplateProcessor\RemoveCommentsTemplateProcessor`
which removes Fluid comments created with the
:ref:`Debug ViewHelper <f:debug> <t3viewhelper:typo3-fluid-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 :fluid:`<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.
.. index:: Fluid, ext:fluid
@@ -0,0 +1,88 @@
.. include:: /Includes.rst.txt
.. _feature-104914-1726075631:
=====================================================================================================
Feature: #104914 - Updated HTTP headers for frontend rendering and new TypoScript setting for proxies
=====================================================================================================
See :issue:`104914`
Description
===========
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 :typoscript:`config.sendCacheHeaders = 1` is set
via TypoScript.
In this case, TYPO3 sends the following HTTP Headers (example):
.. code-block:: plaintext
Expires: Thu, 26 Aug 2024 08:52:00 GMT
ETag: "d41d8cd98f00b204ecs00998ecf8427e"
Cache-Control: max-age=86400
Pragma: public
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, :typoscript:`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
:typoscript:`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 :typoscript:`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 :typoscript:`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.
.. index:: Frontend, TypoScript, ext:frontend
@@ -0,0 +1,27 @@
.. include:: /Includes.rst.txt
.. _feature-104935-1726135959:
==============================================================
Feature: #104935 - Allow moving content elements via page tree
==============================================================
See :issue:`104935`
Description
===========
To make managing content across pages easier, a backend user may now drag
content elements from the :guilabel:`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 :guilabel:`Web > Page` module into the
page tree to initiate the moving process.
.. index:: Backend, ext:backend
@@ -0,0 +1,49 @@
.. include:: /Includes.rst.txt
.. _feature-104973-1726393875:
=====================================================================
Feature: #104973 - Activate the shipped LintYaml executable for TYPO3
=====================================================================
See :issue:`104973`
Description
===========
The :bash:`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:
.. code-block:: bash
# 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
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 :bash:`typo3` executable.
.. index:: CLI, YAML
@@ -0,0 +1,43 @@
.. include:: /Includes.rst.txt
.. _feature-104990-1726495719:
===================================================
Feature: #104990 - Automatic frontend cache tagging
===================================================
See :issue:`104990`
Description
===========
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 :php:`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.
.. index:: Frontend, ext:core
@@ -0,0 +1,52 @@
.. include:: /Includes.rst.txt
.. _feature-83835-1711517686:
=====================================================
Feature: #83835 - Check more fields in Link Validator
=====================================================
See :issue:`83835`
Description
===========
Some additional fields were added to Page TSconfig
:typoscript:`mod.linkvalidator.searchFields`:
* :typoscript:`pages = canonical_link`
* :typoscript:`sys_redirect = target`
* :typoscript:`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:
* :typoscript:`pages = media` has TCA `type="file"`
* :typoscript:`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:
* :typoscript:`sys_webhook = url` (webhook should not be invoked)
* :typoscript:`tt_content = subheader` (has softref `email[subst]`
which is not a supported link type)
* :typoscript:`pages = tsconfig_includes` (system configuration)
* :typoscript:`sys_template = constants, include_static_file, config`
(system configuration)
* :typoscript:`tx_scheduler_task_group = groupName` (scheduler
system configuration)
Impact
======
Broken links in `sys_file_reference.link`, `sys_redirect.target` and
`pages.canonical_link` will now be checked.
Any enabled field will only be checked, if there is TCA configured,
so for example `pages.canonical_link` will only be checked if `EXT:seo` is
installed.
.. index:: ext:linkvalidator
@@ -0,0 +1,56 @@
.. include:: /Includes.rst.txt
.. _feature-93100-1710488213:
==================================================================
Feature: #93100 - Allow to directly declare static route variables
==================================================================
See :issue:`93100`
Description
===========
Instead of having to use custom route aspect mappers, implementing
:php:`\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
-------
.. code-block:: yaml
routeEnhancers:
Verification:
type: Simple
routePath: '/verify/{code}'
static:
code: true
requirements:
# 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 well
code: '[a-f0-9]{40}'
As a result, using the URI query parameters `&code=11f6ad8ec52a2984abaafd7c3b516503785c2072`
would generate the URL `https://example.org/verify/11f6ad8ec52a2984abaafd7c3b516503785c2072`.
.. index:: Frontend, YAML, ext:core
@@ -0,0 +1,23 @@
.. include:: /Includes.rst.txt
.. _feature-99418-1722544152:
============================================
Feature: #99418 - Enable recycler by default
============================================
See :issue:`99418`
Description
===========
The TYPO3 system extension :composer:`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.
.. index:: Backend, ext:recycler
@@ -0,0 +1,43 @@
.. include:: /Includes.rst.txt
.. _feature-99510-1716815124:
================================================================
Feature: #99510 - Add file embedding option to asset ViewHelpers
================================================================
See :issue:`99510`
Description
===========
The ViewHelpers :ref:`<f:asset.css> <t3viewhelper:typo3-fluid-asset-css>`
and :ref:`<f:asset.script> <t3viewhelper:typo3-fluid-asset-script>` have
been extended with a new argument :fluid:`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
:fluid:`href` / :fluid:`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 :fluid:`inline`
argument can be set. For example, to add above-the-fold styles, the
:fluid:`priority` option can be set, which will put the file contents of
:file:`EXT:sitepackage/Resources/Public/Css/my-hero.css` as inline styles
to the :html:`<head>` section.
.. code-block:: html
<f:asset.css identifier="my-hero" href="EXT:sitepackage/Resources/Public/Css/my-hero.css" inline="1" priority="1"/>
To add JavaScript:
.. code-block:: html
<f:asset.script identifier="my-hero" src="EXT:sitepackage/Resources/Public/Js/my-hero.js" inline="1" priority="1"/>
.. index:: Fluid, Frontend, ext:fluid
@@ -0,0 +1,36 @@
.. include:: /Includes.rst.txt
.. _important-101535-1726059919:
=============================================================
Important: #101535 - Unused DB fields from tt_content removed
=============================================================
See :issue:`101535`
Description
===========
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.
.. _BLE: https://typo3.org/article/typo3-receives-german-governmental-funding-for-accessibility-and-usability-project
.. index:: Database, PHP-API, ext:frontend
@@ -0,0 +1,34 @@
.. include:: /Includes.rst.txt
.. _important-104126-1714290385:
============================================================================================
Important: #104126 - Drop "typo3conf" directory from system status check and backend locking
============================================================================================
See :issue:`104126`
Description
===========
The directory :path:`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 :file:`vendor/`),
* the configuration files (which are now part of the :file:`config/` tree)
* language labels and some artifact states (now part of :file:`var/`)
* a "backend lock" file (:file:`LOCK_BACKEND`)
The location to this file can be adjusted via the new configuration setting
:php:`$GLOBALS['TYPO3_CONF_VARS']['BE']['lockBackendFile']`. See
:ref:`<feature-104126-1714290385>` for details on this setting and location.
By default, :file:`LOCK_BACKEND` is now located here:
* :path:`var/lock/` for Composer Mode
* :path:`config/` for Legacy Mode
.. index:: Backend, CLI, LocalConfiguration, ext:backend
@@ -0,0 +1,50 @@
.. include:: /Includes.rst.txt
.. _important-60357-1777301944:
==================================================================
Important: #60357 - CType and colPos locked for translated content
==================================================================
See :issue:`60357`
Description
===========
Starting with TYPO3 v13.3, the fields :sql:`CType` and :sql:`colPos` of
connected :sql:`tt_content` translations are locked to the values of their
default-language parent. Both fields are now configured with
:php:`'l10n_mode' => 'exclude'` and
:php:`'l10n_display' => 'defaultAsReadonly'`
in :file:`EXT:frontend/Configuration/TCA/tt_content.php`.
This prevents editors from accidentally assigning a different content element
type or column position to a translated record, which previously caused silent
rendering inconsistencies: when the default-language record changed its
:sql:`CType`, the translated overlay would keep the old type and could render
incorrectly or not at all.
Impact
======
In the TYPO3 backend, the :guilabel:`Type` and :guilabel:`Column` selectors
are now read-only when editing a translated content element in connected
translation mode.
An upgrade wizard (:php:`synchronizeColPosAndCTypeWithDefaultLanguage`)
is provided to synchronize connected :sql:`tt_content` translations
whose :sql:`CType` or :sql:`colPos` differs from their default-language
parent.
.. warning::
The upgrade wizard **overwrites** :sql:`CType` and :sql:`colPos` on
every connected translation that currently differs from its parent —
including records where the difference was intentional. Back up the
database and review affected records before executing the wizard.
Extensions or integrations with connected translations that deliberately
use different :sql:`CType` values should align their content to use the
same :sql:`CType` across languages.
.. index:: Database, TCA, ext:frontend
+52
View File
@@ -0,0 +1,52 @@
:template: changelogOverview.html
.. include:: /Includes.rst.txt
.. _changelog-13-3:
============
13.3 Changes
============
.. contents:: Table of contents
:local:
:depth: 1
Breaking Changes
================
None since TYPO3 v13.0 release.
.. attention::
After TYPO3 v13.0, only new functionality with a solid migration path
can be added on top, with aiming for as little as possible breaking changes
after the initial v13.0 release on the way to LTS.
Features
========
.. toctree::
:maxdepth: 1
:titlesonly:
:glob:
Feature-*
Deprecation
===========
.. toctree::
:maxdepth: 1
:titlesonly:
:glob:
Deprecation-*
Important
=========
.. toctree::
:maxdepth: 1
:titlesonly:
:glob:
Important-*