ssch/typo3-rector
Automated upgrades and refactoring for TYPO3 sites and extensions using Rector. Apply version migrations, remove deprecations, and modernize code safely in development with configurable rule sets for TYPO3 7–12+.
CodeQuality (13)
General (3)
TYPO310 (38)
TYPO311 (36)
TYPO312 (59)
TYPO313 (49)
TYPO314 (47)
TypeDeclaration (2)
Add Autoconfigure attribute for public or non-shared services
To run this rule, you need to do the following steps:
Require "ssch/typo3-debug-dump-pass": "^0.0.2" in your composer.json in the main TYPO3 project
Add ->withSymfonyContainerXml(__DIR__ . '/var/cache/development/App_KernelDevelopmentDebugContainer.xml') in your rector config file.
Clear the TYPO3 cache via cmd: vendor/bin/typo3 cache:flush to create the App_KernelDevelopmentDebugContainer.xml file.
Finally run Rector.
class: Ssch\TYPO3Rector\CodeQuality\General\AddAutoconfigureAttributeToClassRector
+use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
+
+#[Autoconfigure(public: true)]
class MyService
{
}
+use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
+
+#[Autoconfigure(public: true, shared: false)]
class NotSharedService
{
}
Add timestamp error code to exceptions
-throw new \RuntimeException('my message');
+throw new \RuntimeException('my message', 1729021897);
Convert $TYPO3_CONF_VARS to $GLOBALS['TYPO3_CONF_VARS']
-$TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['postUserLookUp']['foo'] = 'FooBarBaz->handle';
+$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['postUserLookUp']['foo'] = 'FooBarBaz->handle';
Refactor file ext_emconf.php
:wrench: configure it!
$EM_CONF[$_EXTKEY] = [
'title' => 'Package Extension',
'description' => 'Package Extension',
'category' => 'fe',
- 'shy' => 0,
'version' => '2.0.1',
- 'dependencies' => '',
- 'conflicts' => '',
- 'priority' => '',
- 'loadOrder' => '',
- 'module' => '',
'state' => 'stable',
- 'uploadfolder' => 0,
- 'createDirs' => '',
- 'modify_tables' => '',
- 'clearcacheonload' => 0,
- 'lockType' => '',
'author' => 'Max Mustermann',
'author_email' => 'max.mustermann@mustermann.de',
'author_company' => 'Mustermann GmbH',
- 'CGLcompliance' => '',
- 'CGLcompliance_note' => '',
'constraints' => [
'depends' => [
'php' => '5.6.0-0.0.0',
'typo3' => '7.6.0-8.99.99',
],
'conflicts' => [],
'suggests' => [],
],
'autoload' => [
'psr-4' => [
'Foo\\Bar\\' => 'Classes/',
],
],
- '_md5_values_when_last_written' => 'a:0:{}',
];
Move GeneralUtility::makeInstance calls to constructor injection
:wrench: configure it!
use TYPO3\CMS\Core\Context\Context;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
class Service
{
+ private Context $context;
+
+ public function __construct(Context $context)
+ {
+ $this->context = $context;
+ }
+
public function myMethod(): void
{
- GeneralUtility::makeInstance(Context::class)->getAspect('frontend.user');
+ $this->context->getAspect('frontend.user');
}
}
Replace inject method to constructor injection
use TYPO3\CMS\Core\Cache\CacheManager;
class Service
{
private CacheManager $cacheManager;
- public function injectCacheManager(CacheManager $cacheManager): void
+ public function __construct(CacheManager $cacheManager)
{
$this->cacheManager = $cacheManager;
}
}
Use GeneralUtility::makeInstance() instead of getInstance call
:wrench: configure it!
-$instance = TYPO3\CMS\Core\Resource\Index\ExtractorRegistry::getInstance();
+use TYPO3\CMS\Core\Resource\Index\ExtractorRegistry;
+
+$instance = GeneralUtility::makeInstance(ExtractorRegistry::class);
Move ExtensionManagementUtility::addStaticFile() into Configuration/TCA/Overrides/sys_template.php
-\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile('extensionKey', 'Configuration/TypoScript', 'Title');
+// Move to file Configuration/TCA/Overrides/sys_template.php
Move ExtensionManagementUtility::addToAllTCAtypes() into table specific Configuration/TCA/Overrides file
-\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes('table', 'new_field', '', 'after:existing_field');
+// Move to table specific Configuration/TCA/Overrides/table.php file
Move ExtensionUtility::registerPlugin() into Configuration/TCA/Overrides/tt_content.php
Ssch\TYPO3Rector\CodeQuality\General\MoveExtensionUtilityRegisterPluginIntoTCAOverridesRector-\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin('extension_key', 'Pi1', 'Title');
+// Move to file Configuration/TCA/Overrides/tt_content.php
Remove Typo3Version checks for older TYPO3 versions
:wrench: configure it!
-if ((new Typo3Version())->getMajorVersion() >= 13) {
- // do something for TYPO3 13 and above
- $this->request->getAttribute('frontend.cache.collector')->addCacheTags(new CacheTag('tx_extension'));
-} else {
- // do something for older versions
- $typoScriptFrontendController->addCacheTags(['tx_extension']);
-}
+// do something for TYPO3 13 and above
+$this->request->getAttribute('frontend.cache.collector')->addCacheTags(new CacheTag('tx_extension'));
-$iconSize = (new Typo3Version())->getMajorVersion() >= 13 ? IconSize::SMALL : 'small';
+$iconSize = IconSize::SMALL;
Replace defined classes by new ones
:wrench: configure it!
namespace App;
-use t3lib_div;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
function someFunction()
{
- t3lib_div::makeInstance(\tx_cms_BackendLayout::class);
+ GeneralUtility::makeInstance(\TYPO3\CMS\Backend\View\BackendLayoutView::class);
}
Replace the second parameter of LocalizationUtility::translate() with the extension name
-LocalizationUtility::translate('key', 'extension_key');
+LocalizationUtility::translate('key', 'ExtensionName');
Migrate constants to enum class
:wrench: configure it!
-\TYPO3\CMS\Core\Imaging\Icon::SIZE_DEFAULT
-\TYPO3\CMS\Core\Imaging\Icon::SIZE_SMALL
-\TYPO3\CMS\Core\Imaging\Icon::SIZE_MEDIUM
-\TYPO3\CMS\Core\Imaging\Icon::SIZE_LARGE
-\TYPO3\CMS\Core\Imaging\Icon::SIZE_MEGA
+TYPO3\CMS\Core\Imaging\IconSize::DEFAULT
+TYPO3\CMS\Core\Imaging\IconSize::SMALL
+TYPO3\CMS\Core\Imaging\IconSize::MEDIUM
+TYPO3\CMS\Core\Imaging\IconSize::LARGE
+TYPO3\CMS\Core\Imaging\IconSize::MEGA
Migrate constants to enum class values
:wrench: configure it!
-\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_UNKNOWN
-\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_TEXT
-\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_IMAGE
-\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_AUDIO
-\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_VIDEO
-\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_APPLICATION
+\TYPO3\CMS\Core\Resource\FileType::UNKNOWN->value
+\TYPO3\CMS\Core\Resource\FileType::TEXT->value
+\TYPO3\CMS\Core\Resource\FileType::IMAGE->value
+\TYPO3\CMS\Core\Resource\FileType::AUDIO->value
+\TYPO3\CMS\Core\Resource\FileType::VIDEO->value
+\TYPO3\CMS\Core\Resource\FileType::APPLICATION->value
Rename Attribute
:wrench: configure it!
-#[Controller]
+#[AsController]
Migrate the method BackendUtility::editOnClick() to use UriBuilder API
$pid = 2;
$params = '&edit[pages][' . $pid . ']=new&returnNewPageId=1';
-$url = BackendUtility::editOnClick($params);
+$url = GeneralUtility::makeInstance(UriBuilder::class)->buildUriFromRoute('record_edit') . $params . '&returnUrl=' . rawurlencode(GeneralUtility::getIndpEnv('REQUEST_URI'));;
Refactor method call BackendUtility::getViewDomain() to PageRouter
-use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Site\SiteFinder;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
-$domain1 = BackendUtility::getViewDomain(1);
+$site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId(1);
+$domain1 = $site->getRouter()->generateUri(1);
Use new default cache names like core instead of cache_core)
$cacheManager = GeneralUtility::makeInstance(CacheManager::class);
-$cacheManager->getCache('cache_core');
-$cacheManager->getCache('cache_hash');
-$cacheManager->getCache('cache_pages');
-$cacheManager->getCache('cache_pagesection');
-$cacheManager->getCache('cache_runtime');
-$cacheManager->getCache('cache_rootline');
-$cacheManager->getCache('cache_imagesizes');
+$cacheManager->getCache('core');
+$cacheManager->getCache('hash');
+$cacheManager->getCache('pages');
+$cacheManager->getCache('pagesection');
+$cacheManager->getCache('runtime');
+$cacheManager->getCache('rootline');
+$cacheManager->getCache('imagesizes');
Add additional method getControllerConfiguration for AbstractConfigurationManager
final class MyExtbaseConfigurationManager extends AbstractConfigurationManager
{
protected function getSwitchableControllerActions($extensionName, $pluginName)
{
$switchableControllerActions = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['modules'][$pluginName]['controllers'] ?? false;
if ( ! is_array($switchableControllerActions)) {
$switchableControllerActions = [];
}
return $switchableControllerActions;
}
+
+ protected function getControllerConfiguration($extensionName, $pluginName): array
+ {
+ return $this->getSwitchableControllerActions($extensionName, $pluginName);
+ }
}
Change parameter $excludeServiceKeys explicitly to an array
-GeneralUtility::makeInstanceService('serviceType', 'serviceSubType', 'key1, key2');
-ExtensionManagementUtility::findService('serviceType', 'serviceSubType', 'key1, key2');
+GeneralUtility::makeInstanceService('serviceType', 'serviceSubType', ['key1', 'key2']);
+ExtensionManagementUtility::findService('serviceType', 'serviceSubType', ['key1', 'key2']);
Force template parsing in tsfe is replaced with context api and aspects
-$myVariable = $GLOBALS['TSFE']->forceTemplateParsing;
-$myVariable2 = $GLOBALS['TSFE']->tmpl->forceTemplateParsing;
+$myVariable = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Context\Context::class)->getPropertyFromAspect('typoscript', 'forcedTemplateParsing');
+$myVariable2 = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Context\Context::class)->getPropertyFromAspect('typoscript', 'forcedTemplateParsing');
-$GLOBALS['TSFE']->forceTemplateParsing = true;
-$GLOBALS['TSFE']->tmpl->forceTemplateParsing = true;
+\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Context\Context::class)->setAspect('typoscript', \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Context\TypoScriptAspect::class, true));
+\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Context\Context::class)->setAspect('typoscript', \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Context\TypoScriptAspect::class, true));
Inject EnvironmentService if needed in subclass of Response
class MyResponse extends Response
{
+ /**
+ * [@var](https://github.com/var) \TYPO3\CMS\Extbase\Service\EnvironmentService
+ */
+ protected $environmentService;
+
public function myMethod()
{
if ($this->environmentService->isEnvironmentInCliMode()) {
}
+ }
+
+ public function injectEnvironmentService(\TYPO3\CMS\Extbase\Service\EnvironmentService $environmentService)
+ {
+ $this->environmentService = $environmentService;
}
}
class MyOtherResponse extends Response
{
public function myMethod()
{
}
}
Migrate protected RecordHistory properties
use TYPO3\CMS\Core\History\RecordHistory;
$recordHistory = new RecordHistory();
-$changeLog = $recordHistory->changeLog;
-$lastEntry = $recordHistory->lastHistoryEntry;
+$changeLog = $recordHistory->getChangeLog();
+$lastEntry = $recordHistory->getLastHistoryEntryNumber();
Use Environment API to fetch application context
-GeneralUtility::getApplicationContext();
+Environment::getContext();
Refactor Internal public property cHash_array
-$cHash_array = $GLOBALS['TSFE']->cHash_array;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\HttpUtility;
+use TYPO3\CMS\Frontend\Page\CacheHashCalculator;
+
+$relevantParametersForCachingFromPageArguments = [];
+$pageArguments = $GLOBALS['REQUEST']->getAttribute('routing');
+$queryParams = $pageArguments->getDynamicArguments();
+if (!empty($queryParams) && ($pageArguments->getArguments()['cHash'] ?? false)) {
+ $queryParams['id'] = $pageArguments->getPageId();
+ $relevantParametersForCachingFromPageArguments = GeneralUtility::makeInstance(CacheHashCalculator::class)->getRelevantParameters(HttpUtility::buildQueryString($queryParams));
+}
+$cHash_array = $relevantParametersForCachingFromPageArguments;
Use native function idn_to_ascii instead of GeneralUtility::idnaEncode()
-$domain = GeneralUtility::idnaEncode('domain.com');
-$email = GeneralUtility::idnaEncode('email@domain.com');
+$domain = idn_to_ascii('domain.com', IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46);
+$email = 'email@' . idn_to_ascii('domain.com', IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46);
Refactor Internal public TSFE properties
-$domainStartPage = $GLOBALS['TSFE']->domainStartPage;
+$cHash = $GLOBALS['REQUEST']->getAttribute('routing')->getArguments()['cHash'];
Remove vendor name from registerPlugin call
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
- 'TYPO3.CMS.Form',
+ 'Form',
'Formframework',
'Form',
'content-form'
);
Remove "enableMultiSelectFilterTextfield" => true as its default from render type "selectMultipleSideBySide"
return [
'columns' => [
'foo' => [
'label' => 'foo',
'config' => [
'type' => 'select',
'renderType' => 'selectMultipleSideBySide',
- 'enableMultiSelectFilterTextfield' => true,
],
],
],
];
transOrigPointerField is not longer allowed to be excluded
return [
'ctrl' => [
'transOrigPointerField' => 'l10n_parent',
],
'columns' => [
'l10n_parent' => [
- 'exclude' => true,
'config' => [
'type' => 'select',
],
],
],
];
Remove constants FORMAT_PLAINTEXT and FORMAT_HTML of class TYPO3\CMS\Form\Domain\Finishers\EmailFinisher
-$this->setOption(self::FORMAT, EmailFinisher::FORMAT_HTML);
+$this->setOption('addHtmlPart', true);
Use method getControllerExtensionName() from $request property instead of removed property $extensionName
class MyCommandController extends CommandController
{
public function myMethod()
{
- if ($this->extensionName === 'whatever') {
+ if ($this->request->getControllerEx...
How can I help you explore Laravel packages today?