Upgrading from older Extbase versions
Note
This page is a work in progress. Content will be added as part of the Extbase documentation rewrite for TYPO3 v14.
This page lists breaking changes and migration steps for upgrading an Extbase extension to a newer TYPO3 version. Each entry details what has changed, which version introduced the change, and what to do.
Tip
Many migrations can be automated, and TYPO3 Rector ( ssch/typo3-rector ) provides rules to do so. The tool is actively maintained and updated for each TYPO3 version that is released.
On this page
Annotations replaced by PHP attributes (TYPO3 v12 / required from v14)
Changed in version 14.0
DocBlock annotation support was fully removed. Extbase ignores annotations silently — no error is thrown.
Native PHP attributes (introduced in PHP 8.0) replace the Doctrine-based DocBlock annotation syntax. Extbase has supported PHP attributes since TYPO3 v12. In TYPO3 v14 the annotation syntax was removed entirely.
| Old annotation (removed in v14) | New PHP attribute |
|---|---|
@Extbase\ORM\Lazy | #[Lazy] |
@Extbase\ORM\Cascade("remove") | #[Cascade('remove')] |
@Extbase\ORM\Transient | #[Transient] |
@Extbase\Validate(...) | #[Validate(...)] |
@Extbase\IgnoreValidation | #[IgnoreValidation] |
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
+use TYPO3\CMS\Extbase\Attribute\ORM\Lazy;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
class Entity extends AbstractEntity
{
- /**
- * @var ObjectStorage<ChildEntity>
- * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy
- */
+ #[Lazy]
protected ObjectStorage $property;
}
See also
Attribute namespace moved from Annotation to Attribute (TYPO3 v14)
Changed in version 14.0
The namespace
\TYPO3\ is deprecated. Class
aliases remain available in v14 but will be removed in v15. Update your
use statements to
\TYPO3\ when dropping
TYPO3 v13 support.
All Extbase attributes have been moved from
\TYPO3\ to
\TYPO3\.
Attribute array syntax deprecated (TYPO3 v14, removed in v15)
Changed in version 14.0
Passing a configuration array as the first argument to Extbase attributes is deprecated (Deprecation #97559). The array-based syntax still works in v14 but will be removed in v15.
| Old array syntax (deprecated in v14) | New named-argument syntax |
|---|---|
#[Cascade(['value' => 'remove'])] | #[Cascade('remove')] |
#[Validate(['validator' => 'NotEmpty'])] | #[Validate('NotEmpty')] |
Important
There is no attribute syntax that is compatible with both TYPO3 v13 and v14. PHP attributes are parsed statically and cannot be conditionally defined based on the TYPO3 version. Extensions supporting both versions in the same release must keep the array-based syntax and accept the deprecation warning in v14.
#[FileUpload] array syntax replaced by named arguments (TYPO3 v14)
Changed in version 14.0
The array-based configuration syntax for
# is deprecated
and will be removed in TYPO3 v15. Replace the array with named arguments.
In TYPO3 v13,
# accepted a single configuration array. In
v14 the attribute requires named arguments instead:
-#[FileUpload([
- 'validation' => [
- 'required' => true,
- 'maxFiles' => 1,
- 'fileSize' => ['minimum' => '10K', 'maximum' => '2M'],
- 'mimeType' => ['allowedMimeTypes' => ['image/jpeg', 'image/png']],
- 'fileExtension' => ['allowedFileExtensions' => ['jpg', 'jpeg', 'png']],
- ],
- 'uploadFolder' => '1:/user_upload/conference_logos/',
-])]
+#[FileUpload(
+ validation: [
+ 'required' => true,
+ 'maxFiles' => 1,
+ 'fileSize' => ['minimum' => '10K', 'maximum' => '2M'],
+ 'mimeType' => ['allowedMimeTypes' => ['image/jpeg', 'image/png']],
+ 'fileExtension' => ['allowedFileExtensions' => ['jpg', 'jpeg', 'png']],
+ ],
+ uploadFolder: '1:/user_upload/conference_logos/',
+)]
protected ?FileReference $logo = null;
Important
There is no syntax that is not deprecated in either TYPO3 v13 or v14. Extensions that support both versions in the same release must keep the array-based syntax and accept the deprecation warning in v14.
See also
- File uploads in Extbase domain models — full reference for the
#attribute and its named arguments.[File Upload]
#[Validate] and
#[IgnoreValidation] moved to parameter level (TYPO3 v14, removed in v15)
Changed in version 14.0
Placing
# and
# on the action
method with a named
$param /
$argument property is
deprecated and will be removed in TYPO3 v15.
Before TYPO3 v14, PHP attributes could only be attached to methods, so both attributes required a named property to identify which parameter they targeted. TYPO3 v14 introduced support for placing attributes directly on the parameter, meaning you can now position the attribute on the parameter itself:
-#[Validate(param: 'conference', validator: 'NotEmpty')]
-#[IgnoreValidation(argumentName: 'conference')]
public function editAction(
+ #[Validate(validator: 'NotEmpty')]
+ #[IgnoreValidation]
Conference $conference,
): ResponseInterface {
}
See also
Deprecation #108227 — full deprecation details and automated migration via Rector.
Magic findBy(), findOneBy(), countBy*() methods removed (TYPO3 v14)
Changed in version 14.0
Magic property-name methods were deprecated in TYPO3 v12.3 and removed in v14. Replace them with the explicit array-based signatures.
| Old (removed in v14) | New |
|---|---|
findByTitle($value) | findBy(['title' => $value]) |
findOneByTitle($value) | findOneBy(['title' => $value]) |
countByTitle($value) | count(['title' => $value]) |
find and
find are not affected and remain
available.
See also
Migration — the migration guide in the TYPO3 v13 branch of this manual.
StandaloneView removed (TYPO3 v14)
Changed in version 14.0
\TYPO3\ was deprecated in TYPO3 v13
and removed in v14. The replacement is
View together with
View.
Standalone was the historical way to render a Fluid template outside
of a controller, for example, inside a service class, a scheduler task, or an email
renderer. It is no longer available.
The new way injects
View
and creates a view by passing a
View value object:
use TYPO3\CMS\Core\View\ViewFactoryData;
use TYPO3\CMS\Core\View\ViewFactoryInterface;
readonly class MailService
{
public function __construct(
protected ViewFactoryInterface $viewFactory,
) {}
public function renderTemplate(ServerRequestInterface $request): string
{
$view = $this->viewFactory->create(new ViewFactoryData(
templateRootPaths: ['EXT:my_extension/Resources/Private/Templates/'],
partialRootPaths: ['EXT:my_extension/Resources/Private/Partials/'],
layoutRootPaths: ['EXT:my_extension/Resources/Private/Layouts/'],
request: $request,
));
$view->assign('data', $this->loadData());
return $view->render('Mail/Notification');
}
}
Pass the current
Server wherever possible. The view
factory uses it for request-aware rendering (language, base URI, etc.).
See also
- Deprecation: #104773 — Custom Fluid views and Extbase changelog entry with full migration notes.
list_type plugin removed; fifth parameter of configurePlugin() restricted (TYPO3 v14)
Changed in version 14.0
The
list_ / "General Plugin" content element was removed. All
plugins must be registered as dedicated
CType content elements. The
fifth parameter
$plugin of
Extension
now only accepts
'CType' (or being omitted); any other value throws an
\Invalid (Important #105538).
Older extensions could pass
Extension ('list_type') as the
fifth argument, or register their plugin as a list_type TCA entry. Both
approaches no longer work in TYPO3 v14.
What to do:
- Remove the fifth argument from
configureor passPlugin () Extension.Utility:: PLUGIN_ TYPE_ CONTENT_ ELEMENT - Provide an upgrade wizard for your extension that extends
\TYPO3\to migrate existing content records fromCMS\ Install\ Updates\ Abstract List Type To CType Update list_to the newtype CType. TYPO3 does not ship a wizard for extension-specific plugins. Each extension must provide its own (see Deprecation #105076 for a reference implementation).
See also
- Registering an Extbase frontend plugin for the current registration approach.
- Plugin registered with list_type no longer works for common pitfalls.
Translation domain syntax as shorter alternative to LLL:EXT: (TYPO3 v14)
New in version 14.0
A shorter domain-based syntax for label references was introduced as an
alternative to the legacy
LLL: file path syntax
(Feature #93334).
Legacy syntax remains fully supported and is not deprecated. Both forms resolve to the same translation entries and can be used interchangeably:
| Legacy syntax | Domain syntax (v14+) |
|---|---|
LLL:EXT:my_ext/Resources/Private/Language/locallang.xlf:key | my_ext.messages:key |
LLL:EXT:my_ext/Resources/Private/Language/locallang_db.xlf:key | my_ext.db:key |
LLL:EXT:my_ext/Resources/Private/Language/locallang_val.xlf:key | my_ext.val:key |
LLL:EXT:my_ext/Resources/Private/Language/Form/locallang.xlf:key | my_ext.form.messages:key |
The domain syntax follows the pattern
extension_.
The resource name is derived from the file name:
locallang.maps to the fixed resource namexlf messages.locallang_strips thesuffix. xlf locallang_prefix, leavingsuffix— solocallang_becomesdb. xlf db.- Subdirectories below
Resources/are prepended as dot-separated parts —Private/ Language/ Form/becomeslocallang. xlf form.messages.
See also
- Translation domain mapping for label reference for a full syntax reference and resolution
rules including the
language:CLI command.domain: list