diff --git a/config/v11/typo3-115.php b/config/v11/typo3-115.php index 6b3b23392..b1a37b5d8 100644 --- a/config/v11/typo3-115.php +++ b/config/v11/typo3-115.php @@ -38,4 +38,7 @@ $services->set(\Ssch\TYPO3Rector\Rector\v11\v5\ReplaceTSFEATagParamsCallOnGlobalsRector::class); $services->set(\Ssch\TYPO3Rector\Rector\v11\v5\HandleCObjRendererATagParamsMethodRector::class); $services->set(\Ssch\TYPO3Rector\Rector\v11\v5\SubstituteBackendTemplateViewWithModuleTemplateRector::class); + $services->set( + \Ssch\TYPO3Rector\Rector\v11\v5\SubstituteGetIconFactoryAndGetPageRendererFromModuleTemplateRector::class + ); }; diff --git a/src/Rector/v11/v5/SubstituteGetIconFactoryAndGetPageRendererFromModuleTemplateRector.php b/src/Rector/v11/v5/SubstituteGetIconFactoryAndGetPageRendererFromModuleTemplateRector.php new file mode 100644 index 000000000..202e9985b --- /dev/null +++ b/src/Rector/v11/v5/SubstituteGetIconFactoryAndGetPageRendererFromModuleTemplateRector.php @@ -0,0 +1,181 @@ +> + */ + public function getNodeTypes(): array + { + return [Class_::class]; + } + + /** + * @param Class_ $node + */ + public function refactor(Node $node): ?Node + { + $iconFactoryMethodCalls = $this->findModuleTemplateMethodCallsByName($node, 'getIconFactory'); + $pageRendererMethodCalls = $this->findModuleTemplateMethodCallsByName($node, 'getPageRenderer'); + + if ([] === $iconFactoryMethodCalls && [] === $pageRendererMethodCalls) { + return null; + } + + if ([] !== $iconFactoryMethodCalls) { + $this->addIconFactoryToConstructor($node); + + foreach ($iconFactoryMethodCalls as $iconFactoryMethodCall) { + $this->nodesToReplaceCollector->addReplaceNodeWithAnotherNode( + $iconFactoryMethodCall, + $this->nodeFactory->createPropertyFetch('this', 'iconFactory') + ); + } + } + + if ([] !== $pageRendererMethodCalls) { + $this->addPageRendererToConstructor($node); + + foreach ($pageRendererMethodCalls as $pageRendererMethodCall) { + $this->nodesToReplaceCollector->addReplaceNodeWithAnotherNode( + $pageRendererMethodCall, + $this->nodeFactory->createPropertyFetch('this', 'pageRenderer') + ); + } + } + + // change the node + return $node; + } + + /** + * @codeCoverageIgnore + */ + public function getRuleDefinition(): RuleDefinition + { + return new RuleDefinition( + 'Use PageRenderer and IconFactory directly instead of getting them from the ModuleTemplate', + [ + new CodeSample( + <<<'CODE_SAMPLE' +class MyController extends ActionController +{ + protected ModuleTemplateFactory $moduleTemplateFactory; + + public function __construct(ModuleTemplateFactory $moduleTemplateFactory) + { + $this->moduleTemplateFactory = $moduleTemplateFactory; + } + + public function myAction(): ResponseInterface + { + $moduleTemplate = $this->moduleTemplateFactory->create($this->request); + $moduleTemplate->getPageRenderer()->loadRequireJsModule('Vendor/Extension/MyJsModule'); + $moduleTemplate->setContent($moduleTemplate->getIconFactory()->getIcon('some-icon', Icon::SIZE_SMALL)->render()); + return $this->htmlResponse($moduleTemplate->renderContent()); + } +} +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +class MyController extends ActionController +{ + protected ModuleTemplateFactory $moduleTemplateFactory; + protected IconFactory $iconFactory; + protected PageRenderer $pageRenderer; + + public function __construct( + ModuleTemplateFactory $moduleTemplateFactory, + IconFactory $iconFactory, + PageRenderer $pageRenderer + ) { + $this->moduleTemplateFactory = $moduleTemplateFactory; + $this->iconFactory = $iconFactory; + $this->pageRenderer = $pageRenderer; + } + + public function myAction(): ResponseInterface + { + $moduleTemplate = $this->moduleTemplateFactory->create($this->request); + $this->pageRenderer->loadRequireJsModule('Vendor/Extension/MyJsModule'); + $moduleTemplate->setContent($this->iconFactory->getIcon('some-icon', Icon::SIZE_SMALL)->render()); + return $this->htmlResponse($moduleTemplate->renderContent()); + } +} +CODE_SAMPLE + ), + + ] + ); + } + + /** + * @return Node[] + */ + private function findModuleTemplateMethodCallsByName(Class_ $node, string $methodCallName): array + { + return $this->betterNodeFinder->find($node->stmts, function (Node $node) use ($methodCallName) { + if (! $node instanceof MethodCall) { + return false; + } + + if (! $this->nodeTypeResolver->isMethodStaticCallOrClassMethodObjectType( + $node, + new ObjectType('TYPO3\CMS\Backend\Template\ModuleTemplate') + )) { + return false; + } + + return $this->nodeNameResolver->isName($node->name, $methodCallName); + }); + } + + private function addIconFactoryToConstructor(Class_ $node): void + { + $this->classDependencyManipulator->addConstructorDependency( + $node, + new PropertyMetadata( + 'iconFactory', + new ObjectType('TYPO3\CMS\Core\Imaging\IconFactory'), + Class_::MODIFIER_PRIVATE + ) + ); + } + + private function addPageRendererToConstructor(Class_ $node): void + { + $this->classDependencyManipulator->addConstructorDependency( + $node, + new PropertyMetadata( + 'pageRenderer', + new ObjectType('TYPO3\CMS\Core\Page\PageRenderer'), + Class_::MODIFIER_PRIVATE + ) + ); + } +} diff --git a/tests/Rector/v11/v5/SubstituteGetIconFactoryAndGetPageRendererFromModuleTemplateRector/Fixture/my_action_controller.php.inc b/tests/Rector/v11/v5/SubstituteGetIconFactoryAndGetPageRendererFromModuleTemplateRector/Fixture/my_action_controller.php.inc new file mode 100644 index 000000000..374421806 --- /dev/null +++ b/tests/Rector/v11/v5/SubstituteGetIconFactoryAndGetPageRendererFromModuleTemplateRector/Fixture/my_action_controller.php.inc @@ -0,0 +1,61 @@ +moduleTemplateFactory = $moduleTemplateFactory; + } + + public function myAction(): ResponseInterface + { + $moduleTemplate = $this->moduleTemplateFactory->create($this->request); + $moduleTemplate->getPageRenderer()->loadRequireJsModule('Vendor/Extension/MyJsModule'); + $moduleTemplate->setContent($moduleTemplate->getIconFactory()->getIcon('some-icon', Icon::SIZE_SMALL)->render()); + return $this->htmlResponse($moduleTemplate->renderContent()); + } +} + +?> +----- +moduleTemplateFactory = $moduleTemplateFactory; + $this->iconFactory = $iconFactory; + $this->pageRenderer = $pageRenderer; + } + + public function myAction(): ResponseInterface + { + $moduleTemplate = $this->moduleTemplateFactory->create($this->request); + $this->pageRenderer->loadRequireJsModule('Vendor/Extension/MyJsModule'); + $moduleTemplate->setContent($this->iconFactory->getIcon('some-icon', Icon::SIZE_SMALL)->render()); + return $this->htmlResponse($moduleTemplate->renderContent()); + } +} + +?> diff --git a/tests/Rector/v11/v5/SubstituteGetIconFactoryAndGetPageRendererFromModuleTemplateRector/SubstituteGetIconFactoryAndGetPageRendererFromModuleTemplateRectorTest.php b/tests/Rector/v11/v5/SubstituteGetIconFactoryAndGetPageRendererFromModuleTemplateRector/SubstituteGetIconFactoryAndGetPageRendererFromModuleTemplateRectorTest.php new file mode 100644 index 000000000..1b9badfdb --- /dev/null +++ b/tests/Rector/v11/v5/SubstituteGetIconFactoryAndGetPageRendererFromModuleTemplateRector/SubstituteGetIconFactoryAndGetPageRendererFromModuleTemplateRectorTest.php @@ -0,0 +1,33 @@ +doTestFileInfo($fileInfo); + } + + /** + * @return Iterator + */ + public function provideData(): Iterator + { + return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/tests/Rector/v11/v5/SubstituteGetIconFactoryAndGetPageRendererFromModuleTemplateRector/config/configured_rule.php b/tests/Rector/v11/v5/SubstituteGetIconFactoryAndGetPageRendererFromModuleTemplateRector/config/configured_rule.php new file mode 100644 index 000000000..30c4fe3f2 --- /dev/null +++ b/tests/Rector/v11/v5/SubstituteGetIconFactoryAndGetPageRendererFromModuleTemplateRector/config/configured_rule.php @@ -0,0 +1,19 @@ +parameters(); + $parameters->set(Option::PHP_VERSION_FEATURES, PhpVersion::PHP_74); + + $containerConfigurator->import(__DIR__ . '/../../../../../../config/config_test.php'); + + $services = $containerConfigurator->services(); + $services->set(SubstituteGetIconFactoryAndGetPageRendererFromModuleTemplateRector::class); +};