home / skills / dirnbauer / webconsulting-skills / typo3-rector

typo3-rector skill

/skills/typo3-rector

npx playbooks add skill dirnbauer/webconsulting-skills --skill typo3-rector

Review the files below or copy the command above to add this skill to your agents.

Files (3)
SKILL.md
12.2 KB
---
name: typo3-rector
description: TYPO3 upgrade patterns using Rector, including automated refactoring rules and dual-version compatibility strategies for v13/v14.
version: 2.0.0
typo3_compatibility: "13.0 - 14.x"
triggers:
  - rector
  - upgrade
  - migration
  - refactoring
  - deprecation
---

# 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.

## 1. Introduction to TYPO3 Rector

Rector is an automated refactoring tool that helps migrate TYPO3 extensions between major versions. It applies predefined rules to update deprecated code patterns.

### Installation

```bash
ddev composer require --dev ssch/typo3-rector
```

### Basic Configuration for Dual-Version Support

Create `rector.php` in your project root:

```php
<?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)

```bash
# 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

```bash
# 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

```bash
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
<?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' => [],
    ],
];
```

```json
// composer.json
{
    "require": {
        "php": "^8.2",
        "typo3/cms-core": "^13.0 || ^14.0"
    }
}
```

### Rector Configuration for v13/v14 Dual Support

```php
<?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
<?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
<?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
<?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
<?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)

```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
<?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

| Feature | TYPO3 v13 | TYPO3 v14 | Notes |
|---------|-----------|-----------|-------|
| PHP 8.2 | Required | Required | Minimum for both |
| PHP 8.3 | Supported | Supported | Recommended |
| PHP 8.4 | Supported | Supported | Available |
| Symfony 7 | 7.1 | 7.2 | Minor differences |
| PSR-14 Events | Full | Full | Preferred pattern |
| Legacy Hooks | Working | Deprecated | Migrate to events |
| ViewFactory | Available | Available | Use this approach |
| StandaloneView | Deprecated | Removed | Migrate now |
| Content Blocks | Available | Enhanced | New features in v14 |
| TCA Runtime Changes | Deprecated | Forbidden | Use static TCA only |

## 7. Step-by-Step Migration Process

### 1. Prepare

```bash
# 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
<?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

```bash
# 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

```bash
# 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

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

## 8. Troubleshooting

### Rector Fails

```bash
# 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:

```bash
ddev composer outdated
ddev composer show -l
```

Search for v13/v14-compatible alternatives on:
- https://extensions.typo3.org
- https://packagist.org

### Database Issues

```bash
# 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
<?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
<?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

- **TYPO3 Rector**: https://github.com/sabbelasichon/typo3-rector
- **Upgrade Guide**: https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/Upgrading/Index.html
- **v13 Changelog**: https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog-13/Index.html
- **v14 Changelog**: https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog-14/Index.html

---

## Credits & Attribution

This skill is based on the excellent TYPO3 best practices and methodology developed by
**[Netresearch DTT GmbH](https://www.netresearch.de/)**. We are deeply grateful for their
outstanding contributions to the TYPO3 community and their commitment to sharing knowledge.

Netresearch has been a leading force in TYPO3 development, and their expertise has been
invaluable in shaping these guidelines. Thank you, Netresearch, for your exceptional work!

**Copyright (c) Netresearch DTT GmbH** - Methodology and best practices  
Adapted by webconsulting.at for this skill collection