ssch/typo3-rector
TYPO3 Rector applies instant upgrades and refactoring to TYPO3 website and extension code, easing migrations between releases and removing deprecations. Extending Rector, it supports PHP 5.3+ and requires PHP 7.4+. Always run on development environments under version control, never production.
Installation:
composer require --dev ssch/typo3-rector
Initialize Config:
vendor/bin/typo3-init
This generates a rector.php file in your project root.
First Dry Run (to preview changes):
vendor/bin/rector process src --dry-run
Run a TYPO3 version-specific migration (e.g., TYPO3 v12 → v13):
vendor/bin/rector process src --set TYPO313
Verify changes with Git diff before committing.
Pin the tool in composer.json and treat upgrades as their own commit so rule changes are easy to bisect:
composer update ssch/typo3-rector --with-dependencies
vendor/bin/rector process src --dry-run > rector-upgrade.diff
From v3.16.0 onward the bundled sets also enable the upstream CodeQuality preset (via structarmed ^0.17), so an upgrade dry run will surface additional, non-TYPO3-specific cleanup suggestions — review them separately from migration changes.
Use setters in rector.php to target specific TYPO3 versions:
return static::configure()
->withSets([
TYPO312::class, // Migrate from v11 to v12
TYPO313::class, // Migrate from v12 to v13
]);
Convert GeneralUtility::makeInstance() to constructor injection:
return static::configure()
->withRules([
GeneralUtilityMakeInstanceToConstructorPropertyRector::class,
]);
Move ExtensionManagementUtility calls to Configuration/TCA/Overrides/:
return static::configure()
->withRules([
MoveExtensionManagementUtilityAddStaticFileIntoTCAOverridesRector::class,
]);
Migrate imports/usages from TYPO3\CMS\Extbase\Annotation\* to the renamed TYPO3\CMS\Extbase\Attribute\* classes:
return static::configure()
->withRules([
RenameExtbaseAnnotationToAttributeRector::class,
]);
Run this before your usual PHP-CS-Fixer/ECS pass so attribute syntax and import ordering settle in one go.
Mark commands that must not be exposed to the scheduler with the #[AsNonSchedulableCommand] attribute:
return static::configure()
->withRules([
AddAsNonSchedulableCommandAttributeRector::class,
]);
This is typically a per-extension decision — review the dry-run diff and drop the rule for commands that genuinely should be schedulable.
For a major TYPO3 jump, chain passes in dependency order and commit between each step:
vendor/bin/rector process src --dry-run # 1. review everything
vendor/bin/rector process src --only='*Annotation*' # 2. narrow slices
vendor/bin/rector process src # 3. apply
vendor/bin/ecs check src --fix # 4. normalise style
Slicing by --only keeps each commit reviewable and makes a bad rule easy to revert.
Add a pre-commit hook or GitHub Action to auto-fix deprecations:
# .github/workflows/rector.yml
name: TYPO3 Rector
on: [push]
jobs:
rector:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: composer install --no-interaction
- run: vendor/bin/rector process src --dry-run
Pin the Rector version in CI (composer require --dev ssch/typo3-rector:^3.16) so a new release doesn't silently change what CI enforces.
Ensure code formatting after Rector runs:
vendor/bin/rector process src && vendor/bin/ecs check src
No Production Runs
--dry-run first. Rector modifies files irreversibly.vendor/bin/rector process --dry-run > rector-changes.diff
Coding Standards
composer require --dev symplify/easy-coding-standard
vendor/bin/ecs check src
Symfony Container Dependency
AddAutoconfigureAttributeToClassRector require a debug container:
// rector.php
->withSymfonyContainerXml(__DIR__ . '/var/cache/dev/App_KernelDevDebugContainer.xml')
vendor/bin/typo3 cache:flush in TYPO3 dev mode.Partial Rule Application
ExtEmConfRector) require manual configuration in rector.php:
->withRules([
ExtEmConfRector::class,
])
->withRuleArguments([
ExtEmConfRector::class => [
'extensionKey' => 'your_extension',
],
]);
CodeQuality Preset Noise (v3.16.0+)
return static::configure()
->withSets([TYPO313::class])
->withSkip([
\Rector\CodeQuality\Rector\ClassMethod\InlineArrayReturnAssignRector::class,
]);
Attribute Renames Break String References
TYPO3\CMS\Extbase\Annotation\* → TYPO3\CMS\Extbase\Attribute\* only rewrites PHP code. Class names inside YAML, FlexForms, ext_conf_template.txt, DB records, or JS will not be touched — grep for the old namespace after the run:
grep -rn "Extbase\\\\Annotation" --include="*.yaml" --include="*.typoscript" .
Log Changes Redirect output to a file:
vendor/bin/rector process src --dry-run > rector.log
Skip Problematic Files
Exclude files/folders in rector.php:
->withPaths([
__DIR__ . '/src',
])
->withExcludedPaths([
__DIR__ . '/vendor',
__DIR__ . '/Tests',
]);
Test Incrementally Run Rector on one file first:
vendor/bin/rector process src/My/Class.php --dry-run
Re-run After Bugfixes
Rule bugs get fixed regularly — v3.16.0 corrects MigrateLabelReferenceToDomainSyntaxRector. If you previously skipped a rule or hand-patched the output, re-run just that rule to confirm the generated TCA matches what you wrote manually:
vendor/bin/rector process Configuration/TCA --only=MigrateLabelReferenceToDomainSyntaxRector --dry-run
Custom Rules Extend Rector with custom rules for project-specific migrations:
// CustomRector.php
use Rector\Core\Contract\Rector\RectorInterface;
use PhpParser\Node;
class MyCustomRector implements RectorInterface {
public function refactor(Node $node): ?Node {
// Your logic here
}
}
Register in rector.php:
->withRules([
MyCustomRector::class,
]);
Rule Configuration
Override default rule behavior via withRuleArguments:
->withRuleArguments([
RenameClassMapAliasRector::class => [
'mapping' => [
't3lib_div' => 'TYPO3\CMS\Core\Utility\GeneralUtility',
],
],
]);
Parallel Processing Speed up large codebases with parallel execution:
vendor/bin/rector process src --parallel
How can I help you explore Laravel packages today?