Skip to content

Commit

Permalink
[TASK] Add custom TYPO3 init config command (#4072)
Browse files Browse the repository at this point in the history
  • Loading branch information
sabbelasichon committed Feb 12, 2024
1 parent 24a51ea commit c4fba5a
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 185 deletions.
3 changes: 2 additions & 1 deletion .gitattributes
Expand Up @@ -12,7 +12,8 @@
.github export-ignore
.gitignore export-ignore
.phpstorm.meta.php export-ignore
/bin export-ignore
/bin/typo3-rector export-ignore
/bin/typo3-rector.php export-ignore
/stubs export-ignore
LICENSE export-ignore
ecs.php export-ignore
Expand Down
4 changes: 4 additions & 0 deletions bin/typo3-init
@@ -0,0 +1,4 @@
#!/usr/bin/env php
<?php

require_once __DIR__ . '/typo3-init.php';
51 changes: 51 additions & 0 deletions bin/typo3-init.php
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

use Nette\Utils\FileSystem;
use Rector\FileSystem\InitFilePathsResolver;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\SingleCommandApplication;

include_once __DIR__ . '/../vendor/autoload.php';

(new SingleCommandApplication())
->setName('Initialize TYPO3-Rector configuration')
->setVersion('2.0.0')
->setCode(function (InputInterface $input, OutputInterface $output): int {
$projectDirectory = getcwd();

if ($projectDirectory === false) {
$output->writeln('<error>Could not determine current working directory!</error>');
return Command::FAILURE;
}

$commonRectorConfigPath = $projectDirectory . '/rector.php';

if (file_exists($commonRectorConfigPath)) {
$output->writeln('Configuration already exists.');
return Command::FAILURE;
}

$configContents = FileSystem::read(__DIR__ . '/../templates/rector.php.dist');
$iniFilePathsResolver = new InitFilePathsResolver();
$projectPhpDirectories = $iniFilePathsResolver->resolve($projectDirectory);
// fallback to default 'src' in case of empty one
if ($projectPhpDirectories === []) {
$projectPhpDirectories[] = 'src';
}
$projectPhpDirectoriesContents = '';
foreach ($projectPhpDirectories as $projectPhpDirectory) {
$projectPhpDirectoriesContents .= " __DIR__ . '/" . $projectPhpDirectory . "'," . \PHP_EOL;
}
$projectPhpDirectoriesContents = \rtrim($projectPhpDirectoriesContents);
$configContents = \str_replace('__PATHS__', $projectPhpDirectoriesContents, $configContents);

$output->writeln('<info>The config is added now. Re-run command to make Rector do the work!</info>');
FileSystem::write($commonRectorConfigPath, $configContents, null);

return Command::SUCCESS;
})
->run();
7 changes: 5 additions & 2 deletions composer.json
Expand Up @@ -31,6 +31,7 @@
"nikic/php-parser": "^4.18.0",
"phpstan/phpstan": "^1.10.56",
"rector/rector": "^1.0",
"symfony/console": "^5.4 || ^6.4 || ^7.0",
"symfony/filesystem": "^5.4 || ^6.4 || ^7.0",
"symfony/finder": "^5.4 || ^6.4 || ^7.0",
"symfony/polyfill-php80": "^1.28.0",
Expand All @@ -49,8 +50,7 @@
"symfony/dependency-injection": "^5.4.34 || ^6.4.2 || ^7.0.2",
"symfony/http-kernel": "^5.4.34 || ^6.4.2 || ^7.0.2",
"symplify/easy-coding-standard": "^12.1.8",
"webmozart/assert": "^1.11.0",
"symfony/console": "^5.4 || ^6.4 || ^7.0"
"webmozart/assert": "^1.11.0"
},
"suggest": {
"ssch/typo3-debug-dump-pass": "^0.0.1"
Expand All @@ -77,6 +77,9 @@
"**.php.inc"
]
},
"bin": [
"bin/typo3-init"
],
"config": {
"allow-plugins": {
"ergebnis/composer-normalize": true,
Expand Down
113 changes: 2 additions & 111 deletions docs/configuration_and_processing.md
Expand Up @@ -12,16 +12,8 @@
This library ships already with a bunch of configuration files organized by TYPO3 version.
To get you started quickly, run the following command inside the root directory of your project:

### For ssch/typo3-rector (PHP 7.4>= dependency)

```bash
cp vendor/ssch/typo3-rector/templates/rector.php.dist rector.php
```

#### For rector/rector 0.13.4 (<PHP 7.4 dependency)

```bash
vendor/bin/rector init --template-type=typo3
vendor/bin/typo3-init
```

The command generates a basic configuration skeleton which you can adapt to your needs.
Expand All @@ -30,110 +22,9 @@ The file is full of comments, so you can follow along what is going on.
Also have a look at the class [Typo3SetList](https://github.com/sabbelasichon/typo3-rector/blob/main/src/Set/Typo3SetList.php).
There you can find all the available sets you can configure in the configuration file.

To mitigate one of the most boring but also most tedious tasks, the TCA configuration, we offer dedicated sets for it.
Let's say you want to migrate the TCA from a TYPO3 7 project to the latest TYPO3 version 11 add the following sets to your configuration file:

```php
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;use Rector\Core\Configuration\Option;use Rector\Core\ValueObject\PhpVersion;use Rector\PostRector\Rector\NameImportingPostRector;use Rector\Set\ValueObject\LevelSetList;use Ssch\TYPO3Rector\CodeQuality\General\ConvertImplicitVariablesToExplicitGlobalsRector;use Ssch\TYPO3Rector\CodeQuality\General\ExtEmConfRector;use Ssch\TYPO3Rector\Configuration\Typo3Option;use Ssch\TYPO3Rector\Set\Extension\TYPO3TestingFrameworkSetList;use Ssch\TYPO3Rector\Set\Typo3LevelSetList;

return static function (RectorConfig $rectorConfig): void {

// If you want to override the number of spaces for your typoscript files you can define it here, the default value is 4
// $parameters = $rectorConfig->parameters();
// $parameters->set(Typo3Option::TYPOSCRIPT_INDENT_SIZE, 2);

$rectorConfig->sets([
LevelSetList::UP_TO_PHP_81,
Typo3LevelSetList::UP_TO_TYPO3_12,
// https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/Configuration/Icons.html
// Typo3SetList::REGISTER_ICONS_TO_ICON,
// If you use the TYPO3 Testing Framework and want to migrate to Version 7, then use this set list:
// TYPO3TestingFrameworkSetList::TYPO3_TESTING_FRAMEWORK_7
]);

// Register a single rule. Single rules don't load the main config file, therefore the config file needs to be loaded manually.
// $rectorConfig->import(__DIR__ . '/vendor/ssch/typo3-rector/config/config.php');
// $rectorConfig->rule(\Ssch\TYPO3Rector\Rector\v9\v0\InjectAnnotationRector::class);

// To have a better analysis from phpstan, we teach it here some more things
$rectorConfig->phpstanConfig(Typo3Option::PHPSTAN_FOR_RECTOR_PATH);

// FQN classes are not imported by default. If you don't do it manually after every Rector run, enable it by:
$rectorConfig->importNames();

// this will not import root namespace classes, like \DateTime or \Exception
$rectorConfig->importShortClasses(false);

// Define your target version which you want to support
$rectorConfig->phpVersion(PhpVersion::PHP_81);

// If you only want to process one/some TYPO3 extension(s), you can specify its path(s) here.
// If you use the option --config change __DIR__ to getcwd()
// $rectorConfig->paths([
// __DIR__ . '/packages/acme_demo/',
// ]);

// When you use rector, there are rules that require some more actions like creating UpgradeWizards for outdated TCA types.
// To fully support you, we added some warnings. So watch out for them.

// If you use importNames(), you should consider excluding some TYPO3 files.
$rectorConfig->skip([
// @see https://github.com/sabbelasichon/typo3-rector/issues/2536
__DIR__ . '/**/Configuration/ExtensionBuilder/*',
__DIR__ . '/vendor/*',
__DIR__ . '/Build/*',
__DIR__ . '/public/*',
__DIR__ . '/.github/*',
__DIR__ . '/.Build/*',
NameImportingPostRector::class => [
'ext_localconf.php',
'ext_tables.php',
'ClassAliasMap.php',
__DIR__ . '/**/Configuration/*.php',
__DIR__ . '/**/Configuration/**/*.php',
]
]);

// If you have trouble that rector cannot run because some TYPO3 constants are not defined, add an additional constants file
// @see https://github.com/sabbelasichon/typo3-rector/blob/main/typo3.constants.php
// @see https://getrector.com/documentation/static-reflection-and-autoload#include-files
// $rectorConfig->bootstrapFiles([
// __DIR__ . '/typo3.constants.php'
// ]);

/**
* Useful rule from RectorPHP itself to transform i.e. GeneralUtility::makeInstance('TYPO3\CMS\Core\Log\LogManager')
* to GeneralUtility::makeInstance(\TYPO3\CMS\Core\Log\LogManager::class) calls.
* But be warned, sometimes it produces false positives (edge cases), so watch out
*/
// $rectorConfig->rule(\Rector\Php55\Rector\String_\StringClassNameToClassConstantRector::class);

// Optional non-php file functionalities:
// @see https://github.com/sabbelasichon/typo3-rector/blob/main/docs/beyond_php_file_processors.md

// Rewrite your extbase persistence class mapping from typoscript into php according to official docs.
// This processor will create a summarized file with all the typoscript rewrites combined into a single file.
/* $rectorConfig->ruleWithConfiguration(\Ssch\TYPO3Rector\FileProcessor\TypoScript\Rector\v10\v0\ExtbasePersistenceTypoScriptRector::class, [
\Ssch\TYPO3Rector\FileProcessor\TypoScript\Rector\v10\v0\ExtbasePersistenceTypoScriptRector::FILENAME => __DIR__ . '/packages/acme_demo/Configuration/Extbase/Persistence/Classes.php',
]); */
// Add some general TYPO3 rules
$rectorConfig->rule(ConvertImplicitVariablesToExplicitGlobalsRector::class);
$rectorConfig->ruleWithConfiguration(ExtEmConfRector::class, [
ExtEmConfRector::ADDITIONAL_VALUES_TO_BE_REMOVED => []
]);

// Modernize your TypoScript include statements for files and move from <INCLUDE /> to @import use the FileIncludeToImportStatementVisitor (introduced with TYPO3 9.0)
// $rectorConfig->rule(\Ssch\TYPO3Rector\FileProcessor\TypoScript\Rector\v9\v0\FileIncludeToImportStatementTypoScriptRector::class);
};
```

For more configuration options see [Rector README](https://github.com/rectorphp/rector#configuration).

After your adopt the configuration to your needs, run typo3-rector to simulate (hence the option `--dry-run`) the future code fixes:
After your adopt the configuration to your needs, run vendor/bin/rector --dry-run to simulate (hence the option `--dry-run`) the future code fixes:

```bash
vendor/bin/rector process packages/my_custom_extension --dry-run
Expand Down
2 changes: 1 addition & 1 deletion ecs.php
Expand Up @@ -33,7 +33,7 @@
__DIR__ . '/rules',
__DIR__ . '/ecs.php',
__DIR__ . '/rector.php',
__DIR__ . '/bin/typo3-rector.php',
__DIR__ . '/bin',
__DIR__ . '/config',
__DIR__ . '/utils',
]);
Expand Down
5 changes: 3 additions & 2 deletions phpstan.neon
Expand Up @@ -9,10 +9,11 @@ parameters:
level: 8

paths:
- bin
- config
- rector.php
- src
- rules
- config
- src
- tests
- utils

Expand Down
33 changes: 18 additions & 15 deletions rector.php
Expand Up @@ -8,20 +8,17 @@
use Rector\Set\ValueObject\LevelSetList;
use Rector\Set\ValueObject\SetList;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->phpstanConfig(__DIR__ . '/phpstan.neon');

$rectorConfig->paths([__DIR__ . '/utils', __DIR__ . '/src', __DIR__ . '/tests', __DIR__ . '/rules']);

$rectorConfig->sets([
LevelSetList::UP_TO_PHP_74,
SetList::PRIVATIZATION,
SetList::CODING_STYLE,
SetList::CODE_QUALITY,
SetList::DEAD_CODE,
]);

$rectorConfig->skip([
return RectorConfig::configure()
->withPaths([
__DIR__ . '/config',
__DIR__ . '/rules',
__DIR__ . '/src',
__DIR__ . '/tests',
__DIR__ . '/bin',
__DIR__ . '/utils',
])
->withPHPStanConfigs([__DIR__ . '/phpstan.neon'])
->withSkip([
RemoveUnusedVariableAssignRector::class,
__DIR__ . '/utils/generator/templates',
StringClassNameToClassConstantRector::class,
Expand All @@ -32,5 +29,11 @@
'*/Source/*',
'*/Source*',
'*/Expected/*',
])
->withSets([
LevelSetList::UP_TO_PHP_74,
SetList::PRIVATIZATION,
SetList::CODING_STYLE,
SetList::CODE_QUALITY,
SetList::DEAD_CODE,
]);
};
Expand Up @@ -53,11 +53,11 @@ public function getRuleDefinition(): RuleDefinition
protected function refactorColumn(Expr $columnName, Expr $columnTca): void
{
$configArray = $this->extractSubArrayByKey($columnTca, self::CONFIG);
if (!$configArray instanceof Array_) {
if (! $configArray instanceof Array_) {
return;
}

if (!$this->configIsOfRenderType($configArray, 'selectMultipleSideBySide')) {
if (! $this->configIsOfRenderType($configArray, 'selectMultipleSideBySide')) {
return;
}

Expand Down
72 changes: 21 additions & 51 deletions templates/rector.php.dist
Expand Up @@ -11,65 +11,35 @@ use Ssch\TYPO3Rector\CodeQuality\General\ExtEmConfRector;
use Ssch\TYPO3Rector\Configuration\Typo3Option;
use Ssch\TYPO3Rector\Set\Typo3LevelSetList;

return static function (RectorConfig $rectorConfig): void {

$rectorConfig->sets([
return RectorConfig::configure()
->withConfiguredRule(ExtEmConfRector::class, [
ExtEmConfRector::ADDITIONAL_VALUES_TO_BE_REMOVED => []
])
->withPaths([
__PATHS__
])
->withPhpSets(
LevelSetList::UP_TO_PHP_81,
Typo3LevelSetList::UP_TO_TYPO3_12,
]);

// Register a single rule. Single rules don't load the main config file, therefore the config file needs to be loaded manually.
// $rectorConfig->import(__DIR__ . '/vendor/ssch/typo3-rector/config/config.php');

// To have a better analysis from phpstan, we teach it here some more things
$rectorConfig->phpstanConfig(Typo3Option::PHPSTAN_FOR_RECTOR_PATH);

// FQN classes are not imported by default. If you don't do it manually after every Rector run, enable it by:
$rectorConfig->importNames();

// this will not import root namespace classes, like \DateTime or \Exception
$rectorConfig->importShortClasses(false);

// Define your target version which you want to support
$rectorConfig->phpVersion(PhpVersion::PHP_81);

// If you only want to process one/some TYPO3 extension(s), you can specify its path(s) here.
// If you use the option --config change __DIR__ to getcwd()
// $rectorConfig->paths([
// __DIR__ . '/packages/acme_demo/',
// ]);

// When you use rector, there are rules that require some more actions like creating UpgradeWizards for outdated TCA types.
// To fully support you, we added some warnings. So watch out for them.

// If you use importNames(), you should consider excluding some TYPO3 files.
$rectorConfig->skip([
)
# To have a better analysis from PHPStan, we teach it here some more things
->withPHPStanConfigs([
Typo3Option::PHPSTAN_FOR_RECTOR_PATH
])
->withPhpVersion(PhpVersion::PHP_81)
->withRules([
ConvertImplicitVariablesToExplicitGlobalsRector::class,
])
# If you use importNames(), you should consider excluding some TYPO3 files.
->withSkip([
// @see https://github.com/sabbelasichon/typo3-rector/issues/2536
__DIR__ . '/**/Configuration/ExtensionBuilder/*',
// We skip those directories on purpose as there might be node_modules or similar
// that include typescript which would result in false positive processing
__DIR__ . '/**/Resources/**/node_modules/*',
__DIR__ . '/**/Resources/**/NodeModules/*',
__DIR__ . '/**/Resources/**/BowerComponents/*',
__DIR__ . '/**/Resources/**/bower_components/*',
__DIR__ . '/**/Resources/**/build/*',
__DIR__ . '/vendor/*',
__DIR__ . '/Build/*',
__DIR__ . '/public/*',
__DIR__ . '/.github/*',
__DIR__ . '/.Build/*',
NameImportingPostRector::class => [
'ext_localconf.php',
'ext_tables.php',
'ClassAliasMap.php',
__DIR__ . '/**/Configuration/*.php',
__DIR__ . '/**/Configuration/**/*.php',
]
]);

// Add some general TYPO3 rules
$rectorConfig->rule(ConvertImplicitVariablesToExplicitGlobalsRector::class);
$rectorConfig->ruleWithConfiguration(ExtEmConfRector::class, [
ExtEmConfRector::ADDITIONAL_VALUES_TO_BE_REMOVED => []
]);
};
])
;

0 comments on commit c4fba5a

Please sign in to comment.