-
-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FEATURE] Add MigratePluginContentElementAndPluginSubtypesRector
Closes: #4323
- Loading branch information
1 parent
2f5ab4b
commit 4eb57db
Showing
15 changed files
with
553 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
use Rector\Config\RectorConfig; | ||
use Ssch\TYPO3Rector\TYPO313\v4\MigratePluginContentElementAndPluginSubtypesRector; | ||
|
||
return static function (RectorConfig $rectorConfig): void { | ||
$rectorConfig->import(__DIR__ . '/../config.php'); | ||
$rectorConfig->rule(MigratePluginContentElementAndPluginSubtypesRector::class); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
200 changes: 200 additions & 0 deletions
200
rules/TYPO313/v4/MigratePluginContentElementAndPluginSubtypesRector.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Ssch\TYPO3Rector\TYPO313\v4; | ||
|
||
use PhpParser\Node; | ||
use PhpParser\Node\Arg; | ||
use PhpParser\Node\Expr\Array_; | ||
use PhpParser\Node\Expr\ClassConstFetch; | ||
use PhpParser\Node\Expr\StaticCall; | ||
use PhpParser\Node\Identifier; | ||
use PhpParser\Node\Name\FullyQualified; | ||
use PHPStan\Type\ObjectType; | ||
use Rector\PhpParser\Node\Value\ValueResolver; | ||
use Rector\Rector\AbstractRector; | ||
use Ssch\TYPO3Rector\ComposerPsr4Resolver; | ||
use Ssch\TYPO3Rector\Contract\FilesystemInterface; | ||
use Ssch\TYPO3Rector\Filesystem\FilesFinder; | ||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; | ||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; | ||
|
||
/** | ||
* @changelog https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/13.4/Deprecation-105076-PluginContentElementAndPluginSubTypes.html | ||
* @see \Ssch\TYPO3Rector\Tests\Rector\v13\v4\MigratePluginContentElementAndPluginSubtypesRector\MigratePluginContentElementAndPluginSubtypesRectorTest | ||
*/ | ||
final class MigratePluginContentElementAndPluginSubtypesRector extends AbstractRector | ||
{ | ||
/** | ||
* @readonly | ||
*/ | ||
private FilesFinder $filesFinder; | ||
|
||
/** | ||
* @readonly | ||
*/ | ||
private FilesystemInterface $filesystem; | ||
|
||
/** | ||
* @readonly | ||
*/ | ||
private ValueResolver $valueResolver; | ||
|
||
/** | ||
* @readonly | ||
*/ | ||
private ComposerPsr4Resolver $composerPsr4Resolver; | ||
|
||
public function __construct( | ||
FilesFinder $filesFinder, | ||
FilesystemInterface $filesystem, | ||
ValueResolver $valueResolver, | ||
ComposerPsr4Resolver $composerPsr4Resolver | ||
) { | ||
$this->filesFinder = $filesFinder; | ||
$this->filesystem = $filesystem; | ||
$this->valueResolver = $valueResolver; | ||
$this->composerPsr4Resolver = $composerPsr4Resolver; | ||
} | ||
|
||
public function getRuleDefinition(): RuleDefinition | ||
{ | ||
return new RuleDefinition('Migrate plugin content element and plugin subtypes (list_type)', [new CodeSample( | ||
<<<'CODE_SAMPLE' | ||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPlugin([], 'list_type', 'extension_key'); | ||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin('ExtensionName', 'PluginName', [], [], 'list_type'); | ||
CODE_SAMPLE | ||
, | ||
<<<'CODE_SAMPLE' | ||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPlugin([], 'CType', 'extension_key'); | ||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin('ExtensionName', 'PluginName', [], [], 'CType'); | ||
CODE_SAMPLE | ||
)]); | ||
} | ||
|
||
/** | ||
* @return array<class-string<Node>> | ||
*/ | ||
public function getNodeTypes(): array | ||
{ | ||
return [StaticCall::class]; | ||
} | ||
|
||
/** | ||
* @param StaticCall $node | ||
*/ | ||
public function refactor(Node $node): ?Node | ||
{ | ||
if ($this->shouldSkip($node)) { | ||
return null; | ||
} | ||
|
||
$type = 'list_type'; | ||
if ($this->nodeTypeResolver->isMethodStaticCallOrClassMethodObjectType( | ||
$node, | ||
new ObjectType('TYPO3\CMS\Core\Utility\ExtensionManagementUtility') | ||
)) { | ||
if (isset($node->args[1])) { | ||
$type = $this->valueResolver->getValue($node->args[1]->value); | ||
} | ||
|
||
if ($type === 'list_type') { | ||
$node->args[1] = new Arg(new ClassConstFetch(new FullyQualified( | ||
'TYPO3\CMS\Extbase\Utility\ExtensionUtility' | ||
), new Identifier('PLUGIN_TYPE_CONTENT_ELEMENT'))); | ||
} | ||
} else { | ||
if (isset($node->args[4])) { | ||
$type = $this->valueResolver->getValue($node->args[4]->value); | ||
} elseif (! isset($node->args[3])) { | ||
$node->args[3] = new Arg(new Array_()); | ||
} | ||
|
||
if ($type === 'list_type') { | ||
$node->args[4] = new Arg(new ClassConstFetch(new FullyQualified( | ||
'TYPO3\CMS\Extbase\Utility\ExtensionUtility' | ||
), new Identifier('PLUGIN_TYPE_CONTENT_ELEMENT'))); | ||
} | ||
} | ||
|
||
$psr4 = $this->composerPsr4Resolver->resolve($this->file); | ||
if ($psr4 !== null) { | ||
$filePath = $this->file->getFilePath(); | ||
$directoryName = $this->filesFinder->isInTCAOverridesFolder($filePath) | ||
? dirname($filePath, 4) | ||
: dirname($filePath); | ||
|
||
$namespaceParts = explode('\\', $psr4); | ||
$vendor = $namespaceParts[0]; | ||
$lowerCasedVendor = mb_strtolower($vendor); | ||
$extensionName = $namespaceParts[1]; | ||
|
||
$migrationFile = $directoryName . '/Classes/Updates/' . $vendor . $extensionName . 'CTypeMigration.php'; | ||
if (! $this->filesystem->fileExists($migrationFile)) { | ||
$content = <<<CODE | ||
<?php | ||
declare(strict_types=1); | ||
namespace {$psr4}Updates; | ||
use TYPO3\CMS\Install\Attribute\UpgradeWizard; | ||
use TYPO3\CMS\Install\Updates\AbstractListTypeToCTypeUpdate; | ||
#[UpgradeWizard('{$lowerCasedVendor}{$extensionName}CTypeMigration')] | ||
final class {$vendor}{$extensionName}CTypeMigration extends AbstractListTypeToCTypeUpdate | ||
{ | ||
public function getTitle(): string | ||
{ | ||
return 'Migrate "{$vendor} {$extensionName}" plugins to content elements.'; | ||
} | ||
public function getDescription(): string | ||
{ | ||
return 'The "{$vendor} {$extensionName}" plugins are now registered as content element. Update migrates existing records and backend user permissions.'; | ||
} | ||
/** | ||
* This must return an array containing the "list_type" to "CType" mapping | ||
* | ||
* Example: | ||
* | ||
* [ | ||
* 'pi_plugin1' => 'pi_plugin1', | ||
* 'pi_plugin2' => 'new_content_element', | ||
* ] | ||
* | ||
* @return array<string, string> | ||
*/ | ||
protected function getListTypeToCTypeMapping(): array | ||
{ | ||
return [ | ||
// TODO: Add this mapping yourself! | ||
]; | ||
} | ||
} | ||
CODE; | ||
$this->filesystem->write($migrationFile, $content); | ||
} | ||
} | ||
|
||
return $node; | ||
} | ||
|
||
private function shouldSkip(StaticCall $staticCall): bool | ||
{ | ||
if (! $this->nodeTypeResolver->isMethodStaticCallOrClassMethodObjectType( | ||
$staticCall, | ||
new ObjectType('TYPO3\CMS\Core\Utility\ExtensionManagementUtility') | ||
) && ! $this->nodeTypeResolver->isMethodStaticCallOrClassMethodObjectType( | ||
$staticCall, | ||
new ObjectType('TYPO3\CMS\Extbase\Utility\ExtensionUtility') | ||
)) { | ||
return true; | ||
} | ||
|
||
return ! $this->isNames($staticCall->name, ['addPlugin', 'configurePlugin']); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Ssch\TYPO3Rector; | ||
|
||
use Rector\ValueObject\Application\File; | ||
use Ssch\TYPO3Rector\Contract\FilesystemInterface; | ||
use Ssch\TYPO3Rector\Filesystem\FilesFinder; | ||
|
||
final class ComposerPsr4Resolver | ||
{ | ||
/** | ||
* @readonly | ||
*/ | ||
private FilesystemInterface $filesystem; | ||
|
||
/** | ||
* @readonly | ||
*/ | ||
private FilesFinder $filesFinder; | ||
|
||
public function __construct(FilesystemInterface $filesystem, FilesFinder $filesFinder) | ||
{ | ||
$this->filesystem = $filesystem; | ||
$this->filesFinder = $filesFinder; | ||
} | ||
|
||
public function resolve(File $file): ?string | ||
{ | ||
$filePath = $file->getFilePath(); | ||
if (! $this->filesFinder->isExtLocalConf($filePath) | ||
&& ! $this->filesFinder->isInTCAOverridesFolder($filePath) | ||
) { | ||
return null; | ||
} | ||
|
||
$directoryName = $this->filesFinder->isInTCAOverridesFolder($filePath) | ||
? dirname($filePath, 4) | ||
: dirname($filePath); | ||
|
||
$composerJsonFile = $directoryName . '/composer.json'; | ||
|
||
if (! $this->filesystem->fileExists($composerJsonFile)) { | ||
return null; | ||
} | ||
|
||
$composerJsonContent = $this->filesystem->read($composerJsonFile); | ||
|
||
$composerJsonContentDecoded = json_decode($composerJsonContent, true, 512, JSON_THROW_ON_ERROR); | ||
|
||
$autoLoadings = $composerJsonContentDecoded['autoload']['psr-4'] ?? []; | ||
foreach ($autoLoadings as $namespace => $path) { | ||
if (str_starts_with($path, 'Classes')) { | ||
return $namespace; | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
stubs/TYPO3/CMS/Install/Classes/Attribute/UpgradeWizard.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
namespace TYPO3\CMS\Install\Attribute; | ||
|
||
if (class_exists('TYPO3\CMS\Install\Attribute\UpgradeWizard')) { | ||
return; | ||
} | ||
|
||
class UpgradeWizard | ||
{ | ||
} |
28 changes: 28 additions & 0 deletions
28
stubs/TYPO3/CMS/Install/Updates/AbstractListTypeToCTypeUpdate.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?php | ||
|
||
namespace TYPO3\CMS\Install\Updates; | ||
|
||
if (class_exists('TYPO3\CMS\Install\Updates\AbstractListTypeToCTypeUpdate')) { | ||
return; | ||
} | ||
|
||
abstract class AbstractListTypeToCTypeUpdate | ||
{ | ||
/** | ||
* This must return an array containing the "list_type" to "CType" mapping | ||
* | ||
* Example: | ||
* | ||
* [ | ||
* 'pi_plugin1' => 'pi_plugin1', | ||
* 'pi_plugin2' => 'new_content_element', | ||
* ] | ||
* | ||
* @return array<string, string> | ||
*/ | ||
abstract protected function getListTypeToCTypeMapping(): array; | ||
|
||
abstract public function getTitle(): string; | ||
|
||
abstract public function getDescription(): string; | ||
} |
Oops, something went wrong.