typo3-rector

TYPO3 upgrade patterns using Rector, including automated refactoring rules and dual-version compatibility strategies for v13/v14. Use when working with rector, upgrade, migration, refactoring, deprecation.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "typo3-rector" with this command: npx skills add dirnbauer/webconsulting-skills/dirnbauer-webconsulting-skills-typo3-rector

TYPO3 Rector Upgrade Patterns

Compatibility: TYPO3 v13.x and v14.x (v14 preferred) This skill covers patterns for writing code that works on both v13 and v14.

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.

1. Introduction to TYPO3 Rector

Rector is an automated refactoring tool that helps migrate TYPO3 PHP code between major versions. It applies predefined rules to update deprecated code patterns. For non-PHP migrations (FlexForms, TypoScript, Fluid, YAML), use Fractor -- see the typo3-fractor skill.

Installation

composer require --dev ssch/typo3-rector
# or with DDEV:
ddev composer require --dev ssch/typo3-rector

Important: Rector loads your project's autoloader. For TYPO3 v14 projects, Rector must run on PHP 8.2+ because TYPO3 v14 packages use readonly classes and other PHP 8.2 syntax. If your local PHP is older, always use DDEV or a container: ddev exec vendor/bin/rector process --dry-run

Always run Rector, never skip it. Manual replacements (e.g. strpos -> str_starts_with) miss edge cases that Rector rules handle correctly. Rector also catches deprecated TYPO3 namespace changes and method signature updates that are hard to find manually.

Basic Configuration for Dual-Version Support

Create rector.php in your project root:

<?php
declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\LevelSetList;
use Rector\ValueObject\PhpVersion;
use Ssch\TYPO3Rector\Set\Typo3LevelSetList;

return RectorConfig::configure()
    ->withPaths([
        __DIR__ . '/packages',
        __DIR__ . '/public/typo3conf/ext',
    ])
    ->withSkip([
        __DIR__ . '/public/typo3conf/ext/*/Resources/',
        __DIR__ . '/public/typo3conf/ext/*/Tests/',
    ])
    ->withPhpVersion(PhpVersion::PHP_82)
    ->withSets([
        // PHP upgrades
        LevelSetList::UP_TO_PHP_82,
        
        // TYPO3 v13 minimum (works on v14 too)
        Typo3LevelSetList::UP_TO_TYPO3_13,
    ])
    ->withImportNames();

2. Running Rector

Dry Run (Preview Changes)

# Show what would be changed
ddev exec vendor/bin/rector process --dry-run

# For specific extension
ddev exec vendor/bin/rector process packages/my_extension --dry-run

Apply Changes

# Apply all changes
ddev exec vendor/bin/rector process

# Apply to specific path
ddev exec vendor/bin/rector process packages/my_extension

Clear Cache After

ddev typo3 cache:flush
ddev composer dump-autoload

3. Dual-Version Compatible Patterns

Version Constraints

For extensions that must work on both v13 and v14:

<?php
// ext_emconf.php
$EM_CONF[$_EXTKEY] = [
    'title' => 'My Extension',
    'version' => '2.0.0',
    'state' => 'stable',
    'constraints' => [
        'depends' => [
            'typo3' => '13.0.0-14.99.99',
            'php' => '8.2.0-8.4.99',
        ],
        'conflicts' => [],
        'suggests' => [],
    ],
];
// composer.json
{
    "require": {
        "php": "^8.2",
        "typo3/cms-core": "^13.0 || ^14.0"
    }
}

Rector Configuration for v13/v14 Dual Support

<?php
declare(strict_types=1);

use Rector\Config\RectorConfig;
use Ssch\TYPO3Rector\Set\Typo3LevelSetList;
use Ssch\TYPO3Rector\Set\Typo3SetList;

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/packages'])
    ->withSets([
        // Target v13 minimum - these patterns also work on v14
        Typo3LevelSetList::UP_TO_TYPO3_13,
        Typo3SetList::TYPO3_13,
    ]);

4. Key Migration Patterns (v13/v14 Compatible)

Fluid ViewFactory (Replaces StandaloneView)

The ViewFactory approach works on both v13 and v14:

<?php
declare(strict_types=1);

namespace Vendor\Extension\Service;

use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\View\ViewFactoryData;
use TYPO3\CMS\Core\View\ViewFactoryInterface;

final class RenderingService
{
    public function __construct(
        private readonly ViewFactoryInterface $viewFactory,
    ) {}

    public function render(ServerRequestInterface $request): string
    {
        $viewFactoryData = 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 = $this->viewFactory->create($viewFactoryData);
        $view->assign('data', ['key' => 'value']);
        $view->assignMultiple([
            'items' => [],
            'settings' => [],
        ]);
        
        return $view->render('MyTemplate');
    }
}

ExtBase Controller Response (Required in v13+)

<?php
declare(strict_types=1);

namespace Vendor\Extension\Controller;

use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;

final class ItemController extends ActionController
{
    // ✅ Correct: Return ResponseInterface (required v13+)
    public function listAction(): ResponseInterface
    {
        $items = $this->itemRepository->findAll();
        $this->view->assign('items', $items);
        return $this->htmlResponse();
    }

    // ✅ Correct: JSON response
    public function apiAction(): ResponseInterface
    {
        $data = ['success' => true];
        return $this->jsonResponse(json_encode($data));
    }

    // ✅ Correct: Redirect
    public function createAction(Item $item): ResponseInterface
    {
        $this->itemRepository->add($item);
        return $this->redirect('list');
    }
}

PSR-14 Events (Preferred over Hooks)

PSR-14 events work on both v13 and v14. Use them instead of legacy hooks:

<?php
declare(strict_types=1);

namespace Vendor\Extension\EventListener;

use TYPO3\CMS\Core\Attribute\AsEventListener;
use TYPO3\CMS\Frontend\Event\ModifyPageLinkConfigurationEvent;

#[AsEventListener(identifier: 'vendor-extension/modify-pagelink')]
final class ModifyPageLinkListener
{
    public function __invoke(ModifyPageLinkConfigurationEvent $event): void
    {
        $configuration = $event->getConfiguration();
        // Modify link configuration
        $event->setConfiguration($configuration);
    }
}

Backend Module Registration (v13/v14)

<?php
// Configuration/Backend/Modules.php
return [
    'web_myextension_mymodule' => [
        'parent' => 'web',
        'position' => ['after' => 'web_info'],
        'access' => 'user,group',
        'iconIdentifier' => 'myextension-module',
        'path' => '/module/web/myextension',
        'labels' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang_mod.xlf',
        'extensionName' => 'MyExtension',
        'controllerActions' => [
            \Vendor\MyExtension\Controller\ModuleController::class => [
                'index',
                'edit',
            ],
        ],
    ],
];

Service Configuration (Services.yaml)

# Configuration/Services.yaml
services:
  _defaults:
    autowire: true
    autoconfigure: true
    public: false

  Vendor\MyExtension\:
    resource: '../Classes/*'
    exclude:
      - '../Classes/Domain/Model/*'

5. TCA Best Practices (v13/v14)

Static TCA Only

In v14, $GLOBALS['TCA'] becomes read-only after loading. Always use static TCA files:

<?php
// Configuration/TCA/Overrides/tt_content.php
defined('TYPO3') or die();

// ✅ Correct: Static TCA configuration
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTcaSelectItem(
    'tt_content',
    'CType',
    [
        'label' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:mytype.title',
        'value' => 'myextension_mytype',
        'icon' => 'content-text',
        'group' => 'default',
    ]
);

$GLOBALS['TCA']['tt_content']['types']['myextension_mytype'] = [
    'showitem' => '
        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
            --palette--;;general,
            header;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:header_formlabel,
            bodytext,
        --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
            --palette--;;hidden,
            --palette--;;access,
    ',
    'columnsOverrides' => [
        'bodytext' => [
            'config' => [
                'enableRichtext' => true,
            ],
        ],
    ],
];

6. Version Compatibility Table

FeatureTYPO3 v13TYPO3 v14Notes
PHP 8.2RequiredRequiredMinimum for both
PHP 8.3SupportedSupportedRecommended
PHP 8.4SupportedSupportedAvailable
Symfony 77.17.2Minor differences
PSR-14 EventsFullFullPreferred pattern
Legacy HooksWorkingDeprecatedMigrate to events
ViewFactoryAvailableAvailableUse this approach
StandaloneViewDeprecatedRemovedMigrate now
Content BlocksAvailableEnhancedNew features in v14
TCA Runtime ChangesDeprecatedForbiddenUse static TCA only

7. Step-by-Step Migration Process

1. Prepare

# Create backup
ddev snapshot --name=before-migration

# Ensure tests pass
ddev exec vendor/bin/phpunit -c packages/my_extension/Tests/phpunit.xml

# Check deprecation log
tail -f var/log/typo3_deprecations_*.log

2. Configure Rector for Dual-Version

<?php
declare(strict_types=1);

use Rector\Config\RectorConfig;
use Ssch\TYPO3Rector\Set\Typo3LevelSetList;

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/packages/my_extension/Classes'])
    ->withSets([
        Typo3LevelSetList::UP_TO_TYPO3_13,
    ]);

3. Run Rector

# Dry run first
ddev exec vendor/bin/rector process --dry-run

# Apply changes
ddev exec vendor/bin/rector process

# Review changes
git diff

4. Manual Fixes

  • Review Rector output for skipped files
  • Check deprecation log for remaining issues
  • Update TCA configurations manually
  • Test all backend modules

5. Test on Both Versions

# Test on v13
ddev composer require "typo3/cms-core:^13.0" --no-update
ddev composer update
ddev typo3 cache:flush

# Run tests
ddev exec vendor/bin/phpunit

# Test on v14
ddev composer require "typo3/cms-core:^14.0" --no-update
ddev composer update
ddev typo3 cache:flush

# Run tests again
ddev exec vendor/bin/phpunit

6. Commit

git add -A
git commit -m "feat: Add TYPO3 v13/v14 dual-version support"

8. Troubleshooting

Rector Fails

# Clear Rector cache
rm -rf .rector_cache/

# Run with verbose output
ddev exec vendor/bin/rector process --dry-run -vvv

Extension Incompatibility

Check for updates:

ddev composer outdated
ddev composer show -l

Search for v13/v14-compatible alternatives on:

Database Issues

# Check schema differences
ddev typo3 database:updateschema --verbose

# Safe schema update (add only)
ddev typo3 database:updateschema "*.add,*.change"

# Full update (includes destructive)
ddev typo3 database:updateschema "*"

9. Common Rector Rules

Namespace Changes (Auto-Migrated)

Rector automatically handles namespace changes between versions.

Utility Method Changes

<?php
// ❌ Old (deprecated)
GeneralUtility::getIndpEnv('TYPO3_REQUEST_HOST');

// ✅ New (v13/v14 compatible)
$request = $GLOBALS['TYPO3_REQUEST'];
$normalizedParams = $request->getAttribute('normalizedParams');
$host = $normalizedParams->getRequestHost();

ObjectManager Removal

<?php
// ❌ Old (removed in v13+)
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$service = $objectManager->get(MyService::class);

// ✅ New (Dependency Injection)
public function __construct(
    private readonly MyService $myService,
) {}

10. Resources

v14-Only Rector Targets

The following patterns are v14-only migration targets for Rector. Use Typo3LevelSetList::UP_TO_TYPO3_14 when it becomes available, or apply these manually.

New Rector Migration Targets [v14 only]

Removed/ChangedMigration
TypoScriptFrontendControllerUse request attributes (frontend.page.information, language)
Extbase annotations (@validate, @ignorevalidation)Use PHP attributes (#[Validate], #[IgnoreValidation])
FlexFormService classMerged into FlexFormTools (#107945)
BackendUtility localization methodsUse new APIs (#106393)
MailMessage->send()Use Mailer::send()
GeneralUtility::createVersionNumberedFilename()Use System Resource API
PathUtility::getPublicResourceWebPath()Use System Resource API
PathUtility::getRelativePath() / getRelativePathTo()Use new path resolution
AbstractTypolinkBuilder->build()Use TypolinkBuilderInterface
DataHandler->userid / ->admin / ->storeLogMessagesRemoved, no replacement

v14.2 Deprecation Targets (prepare for v15 removal)

DeprecatedMigration
PageDoktypeRegistry config methodsMigrate to TCA allowedRecordTypes
PageRenderer->addInlineLanguageDomain()Use alternative API
ExtensionManagementUtility::addFieldsToUserSettingsUse TCA for user settings
ButtonBar/Menu/MenuRegistry make* methodsUse ComponentFactory
Scheduler task registration via SC_OPTIONSUse TCA-based registration
FormEngine "additionalHiddenFields" keyRemoved in v15
Localization parsers (XliffParser, etc.)Symfony Translation Component

Credits & Attribution

Thanks to Netresearch DTT GmbH for their contributions to the TYPO3 community.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

ai-search-optimization

No summary provided by upstream source.

Repository SourceNeeds Review
General

document-processing

No summary provided by upstream source.

Repository SourceNeeds Review
General

typo3-content-blocks

No summary provided by upstream source.

Repository SourceNeeds Review
General

php-modernization

No summary provided by upstream source.

Repository SourceNeeds Review