From 591ba88815d66afc9d01054feda8754d1bb77697 Mon Sep 17 00:00:00 2001 From: Sebastian Schreiber Date: Tue, 17 Nov 2020 22:33:04 +0100 Subject: [PATCH] [TASK] Add custom container and kernel (#1610) Resolves: #1609 --- bin/typo3-rector | 4 +- composer.json | 4 +- config/services.php | 2 + .../Typo3RectorContainerFactory.php | 53 ++++++++ src/HttpKernel/Typo3RectorKernel.php | 121 ++++++++++++++++++ src/Set/Typo3RectorSetProvider.php | 2 +- 6 files changed, 181 insertions(+), 5 deletions(-) create mode 100644 src/DependencyInjection/Typo3RectorContainerFactory.php create mode 100644 src/HttpKernel/Typo3RectorKernel.php diff --git a/bin/typo3-rector b/bin/typo3-rector index eb2009077..7f4f58992 100755 --- a/bin/typo3-rector +++ b/bin/typo3-rector @@ -13,7 +13,7 @@ use Rector\Core\Configuration\MinimalVersionChecker\ComposerJsonReader; use Ssch\TYPO3Rector\Bootstrap\Typo3RectorConfigsResolver; use Ssch\TYPO3Rector\Console\Application; use Rector\Core\Console\Style\SymfonyStyleFactory; -use Rector\Core\DependencyInjection\RectorContainerFactory; +use Ssch\TYPO3Rector\DependencyInjection\Typo3RectorContainerFactory; use Rector\Core\Exception\NoRectorsLoadedException; use Symplify\SetConfigResolver\Bootstrap\InvalidSetReporter; use Symplify\PackageBuilder\Console\ShellCode; @@ -51,7 +51,7 @@ try { $configFileInfos = $rectorConfigsResolver->provide(); // Build DI container - $rectorContainerFactory = new RectorContainerFactory(); + $rectorContainerFactory = new Typo3RectorContainerFactory([]); // shift configs as last so parameters with main config have higher priority $configShifter = new ConfigShifter(); diff --git a/composer.json b/composer.json index 2b0ffdb39..feb791297 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,8 @@ }, "autoload": { "psr-4": { - "Ssch\\TYPO3Rector\\": "src" + "Ssch\\TYPO3Rector\\": "src", + "Ssch\\TYPO3Rector\\PHPStan\\": "utils/phpstan/src" } }, "bin": [ @@ -31,7 +32,6 @@ "autoload-dev": { "psr-4": { "Ssch\\TYPO3Rector\\Tests\\": "tests", - "Ssch\\TYPO3Rector\\PHPStan\\": "utils/phpstan/src", "Ssch\\TYPO3Rector\\PHPStan\\Tests\\": "utils/phpstan/tests" }, "exclude-from-classmap": ["**.php.inc"] diff --git a/config/services.php b/config/services.php index 47ccbd03e..e7325ebae 100644 --- a/config/services.php +++ b/config/services.php @@ -26,6 +26,8 @@ __DIR__ . '/../src/Rector', __DIR__ . '/../src/Set', __DIR__ . '/../src/Bootstrap', + __DIR__ . '/../src/DependencyInjection', + __DIR__ . '/../src/HttpKernel', __DIR__ . '/../src/Compiler', ] ); diff --git a/src/DependencyInjection/Typo3RectorContainerFactory.php b/src/DependencyInjection/Typo3RectorContainerFactory.php new file mode 100644 index 000000000..30fa9ecdb --- /dev/null +++ b/src/DependencyInjection/Typo3RectorContainerFactory.php @@ -0,0 +1,53 @@ +unpackRealPathsFromFileInfos($configFileInfos); + $rectorKernel->setConfigs($configFilePaths); + } + + $stubLoader = new StubLoader(); + $stubLoader->loadStubs(); + + $rectorKernel->boot(); + + return $rectorKernel->getContainer(); + } + + /** + * @param SmartFileInfo[] $configFileInfos + * @return string[] + */ + private function unpackRealPathsFromFileInfos(array $configFileInfos): array + { + $configFilePaths = []; + foreach ($configFileInfos as $configFileInfo) { + // getRealPath() cannot be used, as it breaks in phar + $configFilePaths[] = $configFileInfo->getRealPath() ?: $configFileInfo->getPathname(); + } + + return $configFilePaths; + } +} diff --git a/src/HttpKernel/Typo3RectorKernel.php b/src/HttpKernel/Typo3RectorKernel.php new file mode 100644 index 000000000..aa2ed4b18 --- /dev/null +++ b/src/HttpKernel/Typo3RectorKernel.php @@ -0,0 +1,121 @@ +configureCallValuesCollector = new ConfigureCallValuesCollector(); + + parent::__construct($environment, $debug); + } + + public function getCacheDir(): string + { + // manually configured, so it can be replaced in phar + return sys_get_temp_dir() . '/_rector'; + } + + public function getLogDir(): string + { + // manually configured, so it can be replaced in phar + return sys_get_temp_dir() . '/_rector_log'; + } + + public function registerContainerConfiguration(LoaderInterface $loader): void + { + $loader->load(__DIR__ . '/../../vendor/rector/rector/config/config.php'); + $loader->load(__DIR__ . '/../../config/services.php'); + + foreach ($this->configs as $config) { + $loader->load($config); + } + } + + /** + * @param string[] $configs + */ + public function setConfigs(array $configs): void + { + $this->configs = $configs; + } + + /** + * @return BundleInterface[] + */ + public function registerBundles(): array + { + return [new ConsoleColorDiffBundle(), new PhpConfigPrinterBundle(), new ComposerJsonManipulatorBundle()]; + } + + protected function build(ContainerBuilder $containerBuilder): void + { + $containerBuilder->addCompilerPass(new AutowireArrayParameterCompilerPass()); + + // autowire Rectors by default (mainly for 3rd party code) + $containerBuilder->addCompilerPass(new AutowireInterfacesCompilerPass([RectorInterface::class])); + + $containerBuilder->addCompilerPass(new MakeRectorsPublicCompilerPass()); + + // add all merged arguments of Rector services + $containerBuilder->addCompilerPass( + new MergeImportedRectorConfigureCallValuesCompilerPass($this->configureCallValuesCollector) + ); + } + + /** + * This allows to use "%vendor%" variables in imports + */ + protected function getContainerLoader(ContainerInterface $container): DelegatingLoader + { + $fileLocator = new FileLocator($this); + + $loaders = [new GlobFileLoader($fileLocator)]; + + if ($container instanceof ContainerBuilder) { + $loaders[] = new ConfigurableCallValuesCollectingPhpFileLoader( + $container, + $fileLocator, + $this->configureCallValuesCollector + ); + } + + $loaderResolver = new LoaderResolver($loaders); + + return new DelegatingLoader($loaderResolver); + } +} diff --git a/src/Set/Typo3RectorSetProvider.php b/src/Set/Typo3RectorSetProvider.php index dfe2b5a0e..7adb41923 100644 --- a/src/Set/Typo3RectorSetProvider.php +++ b/src/Set/Typo3RectorSetProvider.php @@ -52,7 +52,7 @@ public function provideByName(string $desiredSetName): ?Set return $foundSet; } - // sencond approach by set path + // second approach by set path foreach ($this->sets as $set) { if (! file_exists($desiredSetName)) { continue;