| name | typo3-extension-upgrade |
| description | Systematic TYPO3 extension upgrades to newer LTS versions. Covers Extension Scanner, Rector, Fractor, PHPStan, and testing. Use when working with extension, upgrade, fractor, rector, migration. |
| compatibility | TYPO3 13.0 - 14.x |
| metadata | {"version":"1.0.0"} |
TYPO3 Extension Upgrade Skill
Systematic framework for upgrading TYPO3 extensions to newer LTS versions.
TYPO3 API First: Always use TYPO3's built-in APIs, core features, and established conventions before creating custom implementations. Do not reinvent what TYPO3 already provides. Always verify that the APIs and methods you use exist and are not deprecated in your target TYPO3 version (v13 or v14) by checking the official TYPO3 documentation.
Scope: Extension code upgrades only. NOT for TYPO3 project/core upgrades.
Upgrade Toolkit
| Tool | Purpose | Files |
|---|
| Extension Scanner | Diagnose deprecated APIs | TYPO3 Backend |
| Rector | Automated PHP migrations | .php |
| Fractor | Non-PHP migrations | FlexForms, TypoScript, YAML, Fluid |
| PHPStan | Static analysis | .php |
Planning Phase (Required)
Before ANY code changes for major upgrades:
- List all files with hardcoded versions (composer.json, CI, Docker, Rector)
- Document scope - how many places need changes?
- Present plan to user for approval
- Track progress with todo list
Pre-Upgrade Checklist
Upgrade Workflow
1. Prepare Environment
ddev snapshot --name=before-upgrade
git status
git checkout -b feature/typo3-14-upgrade
2. Update Version Constraints
{
"require": {
"php": "^8.2",
"typo3/cms-core": "^13.0 || ^14.0"
}
}
$EM_CONF[$_EXTKEY] = [
'constraints' => [
'depends' => [
'typo3' => '13.0.0-14.99.99',
'php' => '8.2.0-8.4.99',
],
],
];
3. Run Rector
Rector handles PHP code migrations automatically.
Configuration
<?php
declare(strict_types=1);
use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\LevelSetList;
use Ssch\TYPO3Rector\Set\Typo3LevelSetList;
use Ssch\TYPO3Rector\Set\Typo3SetList;
return RectorConfig::configure()
->withPaths([
__DIR__ . '/Classes',
__DIR__ . '/Configuration',
__DIR__ . '/Tests',
])
->withSkip([
__DIR__ . '/Resources',
])
->withSets([
// PHP version upgrades
LevelSetList::UP_TO_PHP_82,
// TYPO3 upgrades
Typo3LevelSetList::UP_TO_TYPO3_13,
Typo3SetList::TYPO3_13,
])
->withImportNames();
Run Rector
vendor/bin/rector process --dry-run
vendor/bin/rector process
git diff
4. Run Fractor
Fractor handles non-PHP file migrations (FlexForms, TypoScript, YAML).
Configuration
<?php
declare(strict_types=1);
use a]9r\Fractor\Configuration\FractorConfiguration;
use a9f\Typo3Fractor\Set\Typo3LevelSetList;
return FractorConfiguration::configure()
->withPaths([
__DIR__ . '/Configuration',
__DIR__ . '/Resources',
])
->withSets([
Typo3LevelSetList::UP_TO_TYPO3_13,
]);
Run Fractor
vendor/bin/fractor process --dry-run
vendor/bin/fractor process
5. Fix Code Style
vendor/bin/php-cs-fixer fix
vendor/bin/php-cs-fixer fix --dry-run
6. Run PHPStan
vendor/bin/phpstan analyse
7. Run Tests
vendor/bin/phpunit -c Tests/UnitTests.xml
vendor/bin/phpunit -c Tests/FunctionalTests.xml
8. Manual Testing
ddev composer require "typo3/cms-core:^14.0" --no-update
ddev composer update
ddev typo3 cache:flush
Common Migration Patterns
ViewFactory (Replaces StandaloneView)
use TYPO3\CMS\Fluid\View\StandaloneView;
$view = GeneralUtility::makeInstance(StandaloneView::class);
$view->setTemplatePathAndFilename('...');
use TYPO3\CMS\Core\View\ViewFactoryInterface;
use TYPO3\CMS\Core\View\ViewFactoryData;
public function __construct(
private readonly ViewFactoryInterface $viewFactory,
) {}
public function render(ServerRequestInterface $request): string
{
$viewFactoryData = new ViewFactoryData(
templateRootPaths: ['EXT:my_ext/Resources/Private/Templates'],
request: $request,
);
$view = $this->viewFactory->create($viewFactoryData);
->(, );
->();
}
Controller ResponseInterface
public function listAction(): void
{
$this->view->assign('items', $items);
}
public function listAction(): ResponseInterface
{
$this->view->assign('items', $items);
return $this->htmlResponse();
}
PSR-14 Events (Replace Hooks)
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['...']['hook'][] = MyHook::class;
services:
Vendor\MyExt\EventListener\MyListener:
tags:
- name: event.listener
identifier: 'myext/my-listener'
#[AsEventListener(identifier: 'myext/my-listener')]
final class MyListener
{
public function __invoke(SomeEvent $event): void
{
}
}
Static TCA (No Runtime Modifications)
$GLOBALS['TCA']['tt_content']['columns']['myfield'] = [...];
$GLOBALS['TCA']['tt_content']['columns']['myfield'] = [...];
Backend Module Registration
ExtensionUtility::registerModule(...);
return [
'web_mymodule' => [
'parent' => 'web',
'access' => 'user,group',
'iconIdentifier' => 'myext-module',
'labels' => 'LLL:EXT:my_ext/Resources/Private/Language/locallang_mod.xlf',
'extensionName' => 'MyExt',
'controllerActions' => [
MyController::class => ['index', 'list'],
],
],
];
API Changes Reference
TYPO3 v13 Breaking Changes
| Removed/Changed | Replacement |
|---|
StandaloneView | ViewFactoryInterface |
ObjectManager | Constructor injection |
TSFE->fe_user->user | Request attribute |
| Various hooks | PSR-14 events |
TYPO3 v14 Breaking Changes
| Removed/Changed | Replacement |
|---|
| Runtime TCA changes | Static TCA only |
| Legacy backend modules | Modules.php |
$GLOBALS['TYPO3_DB'] | QueryBuilder |
Troubleshooting
Rector Fails
rm -rf .rector_cache/
vendor/bin/rector process --dry-run -vvv
->withSkip([
\Ssch\TYPO3Rector\SomeRule::class,
])
PHPStan Errors
vendor/bin/phpstan analyse --generate-baseline
includes:
- phpstan-baseline.neon
Extension Not Found
ddev composer dump-autoload
ddev typo3 cache:flush
rm -rf var/cache/*
ddev typo3 extension:setup
Database Issues
ddev typo3 database:updateschema --verbose
ddev typo3 database:updateschema "*.add,*.change"
Success Criteria
Before considering upgrade complete:
Resources
Credits & Attribution
Thanks to Netresearch DTT GmbH for their contributions to the TYPO3 community.