Upgrade to Symplify not using symfony/http-kernel (#1119)

* trigger CI

* upgrade to symplify configs instead of bundles

* update config files infos to config files

* use ConfigureCallMerginLoaderFactory

* remove symfony/http-kernel

* remove symplify/phpstan-twig-rules
This commit is contained in:
Tomas Votruba 2021-11-01 14:20:45 +01:00 committed by GitHub
parent 1c27c6e3bb
commit 20291b25c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 256 additions and 272 deletions

View File

@ -9,7 +9,7 @@ use Rector\Core\Configuration\Option;
use Rector\Core\Console\ConsoleApplication;
use Rector\Core\Console\Style\SymfonyStyleFactory;
use Rector\Core\DependencyInjection\RectorContainerFactory;
use Rector\Core\HttpKernel\RectorKernel;
use Rector\Core\Kernel\RectorKernel;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArgvInput;
use Symplify\PackageBuilder\Reflection\PrivatesCaller;

View File

@ -27,15 +27,14 @@
"rector/rector-doctrine": "^0.11.26",
"rector/rector-laravel": "^0.11.8",
"rector/rector-nette": "^0.11.31",
"rector/rector-phpoffice": "^0.11.4",
"rector/rector-phpunit": "^0.11.14",
"rector/rector-phpoffice": "^0.11.6",
"rector/rector-phpunit": "^0.11.16",
"rector/rector-symfony": "^0.11.31",
"sebastian/diff": "^4.0.4",
"ssch/typo3-rector": "^0.11.26",
"symfony/console": "^5.3.7",
"symfony/dependency-injection": "^5.3.7",
"symfony/finder": "^5.3.7",
"symfony/http-kernel": "^5.3.9",
"symfony/process": "^5.3.7",
"symfony/yaml": "^5.3.6",
"symplify/astral": "^9.5",
@ -65,7 +64,6 @@
"symplify/easy-testing": "^9.5",
"symplify/monorepo-builder": "^9.5",
"symplify/phpstan-extensions": "^9.5",
"symplify/phpstan-twig-rules": "^9.5",
"symplify/phpstan-rules": "^9.5",
"symplify/rule-doc-generator": "^9.5"
},

View File

@ -63,7 +63,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
__DIR__ . '/../src/Exception',
__DIR__ . '/../src/DependencyInjection/CompilerPass',
__DIR__ . '/../src/DependencyInjection/Loader',
__DIR__ . '/../src/HttpKernel',
__DIR__ . '/../src/Kernel',
__DIR__ . '/../src/ValueObject',
__DIR__ . '/../src/Bootstrap',
__DIR__ . '/../src/Enum',

View File

@ -14,7 +14,6 @@ use Rector\BetterPhpDocParser\ValueObject\Parser\BetterTokenIterator;
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
use Rector\BetterPhpDocParser\ValueObject\StartAndEnd;
use Rector\BetterPhpDocParser\ValueObject\Type\BracketsAwareUnionTypeNode;
use Rector\Core\Exception\ShouldNotHappenException;
use Symplify\SimplePhpDocParser\PhpDocNodeVisitor\AbstractPhpDocNodeVisitor;
final class UnionTypeNodePhpDocNodeVisitor extends AbstractPhpDocNodeVisitor implements BasePhpDocNodeVisitorInterface
@ -38,7 +37,7 @@ final class UnionTypeNodePhpDocNodeVisitor extends AbstractPhpDocNodeVisitor imp
// unwrap with parent array type...
$startAndEnd = $node->getAttribute(PhpDocAttributeKey::START_AND_END);
if (! $startAndEnd instanceof StartAndEnd) {
throw new ShouldNotHappenException();
return null;
}
$betterTokenProvider = $this->currentTokenIteratorProvider->provide();

View File

@ -11,43 +11,43 @@ use Symfony\Component\Config\Loader\LoaderResolver;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\GlobFileLoader;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symplify\SmartFileSystem\SmartFileInfo;
/**
* Inspired by https://github.com/symplify/easy-coding-standard/blob/e598ab54686e416788f28fcfe007fd08e0f371d9/packages/changed-files-detector/src/FileHashComputer.php
*/
final class FileHashComputer
{
public function compute(SmartFileInfo $fileInfo): string
public function compute(string $filePath): string
{
$this->ensureIsPhp($fileInfo);
$this->ensureIsPhp($filePath);
$containerBuilder = new ContainerBuilder();
$fileLoader = $this->createFileLoader($fileInfo, $containerBuilder);
$fileLoader->load($fileInfo->getRealPath());
$fileLoader = $this->createFileLoader($filePath, $containerBuilder);
$fileLoader->load($filePath);
$parameterBag = $containerBuilder->getParameterBag();
return $this->arrayToHash($containerBuilder->getDefinitions()) . $this->arrayToHash($parameterBag->all());
}
private function ensureIsPhp(SmartFileInfo $fileInfo): void
private function ensureIsPhp(string $filePath): void
{
if ($fileInfo->hasSuffixes(['php'])) {
$fileExtension = pathinfo($filePath, PATHINFO_EXTENSION);
if ($fileExtension === 'php') {
return;
}
throw new ShouldNotHappenException(sprintf(
// getRealPath() cannot be used, as it breaks in phar
'Provide only PHP file, ready for Symfony Dependency Injection. "%s" given',
$fileInfo->getRelativeFilePath()
$filePath
));
}
private function createFileLoader(SmartFileInfo $fileInfo, ContainerBuilder $containerBuilder): LoaderInterface
private function createFileLoader(string $filePath, ContainerBuilder $containerBuilder): LoaderInterface
{
$fileLocator = new FileLocator([$fileInfo->getPath()]);
$fileLocator = new FileLocator([$filePath]);
$fileLoaders = [
new GlobFileLoader($containerBuilder, $fileLocator),
@ -55,7 +55,7 @@ final class FileHashComputer
];
$loaderResolver = new LoaderResolver($fileLoaders);
$loader = $loaderResolver->resolve($fileInfo->getRealPath());
$loader = $loaderResolver->resolve($filePath);
if (! $loader) {
throw new ShouldNotHappenException();
}

View File

@ -85,11 +85,11 @@ final class ChangedFilesDetector
/**
* @api
*/
public function setFirstResolvedConfigFileInfo(SmartFileInfo $fileInfo): void
public function setFirstResolvedConfigFileInfo(string $filePath): void
{
// the first config is core to all → if it was changed, just invalidate it
$configHash = $this->fileHashComputer->compute($fileInfo);
$this->storeConfigurationDataHash($fileInfo, $configHash);
$configHash = $this->fileHashComputer->compute($filePath);
$this->storeConfigurationDataHash($filePath, $configHash);
}
private function getFileInfoCacheKey(SmartFileInfo $smartFileInfo): string
@ -102,9 +102,9 @@ final class ChangedFilesDetector
return (string) sha1_file($smartFileInfo->getRealPath());
}
private function storeConfigurationDataHash(SmartFileInfo $fileInfo, string $configurationHash): void
private function storeConfigurationDataHash(string $filePath, string $configurationHash): void
{
$key = CacheKey::CONFIGURATION_HASH_KEY . '_' . Strings::webalize($fileInfo->getRealPath());
$key = CacheKey::CONFIGURATION_HASH_KEY . '_' . Strings::webalize($filePath);
$this->invalidateCacheIfConfigurationChanged($key, $configurationHash);
$this->cache->save($key, CacheKey::CONFIGURATION_HASH_KEY, $configurationHash);

View File

@ -52,8 +52,8 @@ abstract class AbstractRectorTestCase extends AbstractTestCase implements Rector
require_once __DIR__ . '/../../../preload.php';
}
$configFileInfo = new SmartFileInfo($this->provideConfigFilePath());
$this->bootFromConfigFileInfos([$configFileInfo]);
$configFile = $this->provideConfigFilePath();
$this->bootFromConfigFiles([$configFile]);
$this->applicationFileProcessor = $this->getService(ApplicationFileProcessor::class);
$this->parameterProvider = $this->getService(ParameterProvider::class);

View File

@ -5,10 +5,10 @@ declare(strict_types=1);
namespace Rector\Testing\PHPUnit;
use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\HttpKernel\RectorKernel;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symplify\SmartFileSystem\SmartFileInfo;
use Rector\Core\Kernel\RectorKernel;
use Webmozart\Assert\Assert;
abstract class AbstractTestCase extends TestCase
{
@ -21,25 +21,25 @@ abstract class AbstractTestCase extends TestCase
protected function boot(): void
{
$this->bootFromConfigFileInfos([]);
$this->bootFromConfigFiles([]);
}
/**
* @param SmartFileInfo[] $configFileInfos
* @param string[] $configFiles
*/
protected function bootFromConfigFileInfos(array $configFileInfos): void
protected function bootFromConfigFiles(array $configFiles): void
{
$configsHash = $this->createConfigsHash($configFileInfos);
$configsHash = $this->createConfigsHash($configFiles);
if (isset(self::$kernelsByHash[$configsHash])) {
$rectorKernel = self::$kernelsByHash[$configsHash];
self::$currentContainer = $rectorKernel->getContainer();
} else {
$rectorKernel = new RectorKernel('test_' . $configsHash, true, $configFileInfos);
$rectorKernel->boot();
$rectorKernel = new RectorKernel();
$container = $rectorKernel->createFromConfigs($configFiles);
self::$kernelsByHash[$configsHash] = $rectorKernel;
self::$currentContainer = $rectorKernel->getContainer();
self::$currentContainer = $container;
}
}
@ -66,13 +66,16 @@ abstract class AbstractTestCase extends TestCase
}
/**
* @param SmartFileInfo[] $configFileInfos
* @param string[] $configFiles
*/
private function createConfigsHash(array $configFileInfos): string
private function createConfigsHash(array $configFiles): string
{
Assert::allFile($configFiles);
Assert::allString($configFiles);
$configHash = '';
foreach ($configFileInfos as $configFileInfo) {
$configHash .= md5_file($configFileInfo->getRealPath());
foreach ($configFiles as $configFile) {
$configHash .= md5_file($configFile);
}
return $configHash;

View File

@ -18,6 +18,5 @@
<php>
<ini name="memory_limit" value="-1" />
<env name="XDEBUG_MODE" value="coverage"/>
<env name="KERNEL_CACHE_DIRECTORY" value="tmp/rector/cache"/>
</php>
</phpunit>

View File

@ -7,26 +7,25 @@ namespace Rector\Core\Bootstrap;
use Rector\Core\ValueObject\Bootstrap\BootstrapConfigs;
use Symfony\Component\Console\Input\ArgvInput;
use Symplify\SmartFileSystem\Exception\FileNotFoundException;
use Symplify\SmartFileSystem\SmartFileInfo;
final class RectorConfigsResolver
{
public function provide(): BootstrapConfigs
{
$argvInput = new ArgvInput();
$mainConfigFileInfo = $this->resolveFromInputWithFallback($argvInput, 'rector.php');
$mainConfigFile = $this->resolveFromInputWithFallback($argvInput, 'rector.php');
$rectorRecipeConfigFileInfo = $this->resolveRectorRecipeConfig($argvInput);
$rectorRecipeConfigFile = $this->resolveRectorRecipeConfig($argvInput);
$configFileInfos = [];
if ($rectorRecipeConfigFileInfo !== null) {
$configFileInfos[] = $rectorRecipeConfigFileInfo;
$configFiles = [];
if ($rectorRecipeConfigFile !== null) {
$configFiles[] = $rectorRecipeConfigFile;
}
return new BootstrapConfigs($mainConfigFileInfo, $configFileInfos);
return new BootstrapConfigs($mainConfigFile, $configFiles);
}
private function resolveRectorRecipeConfig(ArgvInput $argvInput): ?SmartFileInfo
private function resolveRectorRecipeConfig(ArgvInput $argvInput): ?string
{
if ($argvInput->getFirstArgument() !== 'generate') {
return null;
@ -38,25 +37,25 @@ final class RectorConfigsResolver
return null;
}
return new SmartFileInfo($rectorRecipeFilePath);
return $rectorRecipeFilePath;
}
private function resolveFromInput(ArgvInput $argvInput): ?SmartFileInfo
private function resolveFromInput(ArgvInput $argvInput): ?string
{
$configValue = $this->getOptionValue($argvInput, ['--config', '-c']);
if ($configValue === null) {
$configFile = $this->getOptionValue($argvInput, ['--config', '-c']);
if ($configFile === null) {
return null;
}
if (! file_exists($configValue)) {
$message = sprintf('File "%s" was not found', $configValue);
if (! file_exists($configFile)) {
$message = sprintf('File "%s" was not found', $configFile);
throw new FileNotFoundException($message);
}
return new SmartFileInfo($configValue);
return $configFile;
}
private function resolveFromInputWithFallback(ArgvInput $argvInput, string $fallbackFile): ?SmartFileInfo
private function resolveFromInputWithFallback(ArgvInput $argvInput, string $fallbackFile): ?string
{
$configFileInfo = $this->resolveFromInput($argvInput);
if ($configFileInfo !== null) {
@ -66,14 +65,14 @@ final class RectorConfigsResolver
return $this->createFallbackFileInfoIfFound($fallbackFile);
}
private function createFallbackFileInfoIfFound(string $fallbackFile): ?SmartFileInfo
private function createFallbackFileInfoIfFound(string $fallbackFile): ?string
{
$rootFallbackFile = getcwd() . DIRECTORY_SEPARATOR . $fallbackFile;
if (! is_file($rootFallbackFile)) {
return null;
}
return new SmartFileInfo($rootFallbackFile);
return $rootFallbackFile;
}
/**

View File

@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace Rector\Core\Config\Loader;
use Rector\Core\DependencyInjection\Collector\ConfigureCallValuesCollector;
use Rector\Core\DependencyInjection\Loader\ConfigurableCallValuesCollectingPhpFileLoader;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\Loader\DelegatingLoader;
use Symfony\Component\Config\Loader\GlobFileLoader;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\Loader\LoaderResolver;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symplify\SymfonyContainerBuilder\Contract\Config\LoaderFactoryInterface;
final class ConfigureCallMergingLoaderFactory implements LoaderFactoryInterface
{
public function __construct(
private ConfigureCallValuesCollector $configureCallValuesCollector
) {
}
public function create(ContainerBuilder $containerBuilder, string $currentWorkingDirectory): LoaderInterface
{
$fileLocator = new FileLocator([$currentWorkingDirectory]);
$loaderResolver = new LoaderResolver([
new GlobFileLoader($fileLocator),
new ConfigurableCallValuesCollectingPhpFileLoader(
$containerBuilder,
$fileLocator,
$this->configureCallValuesCollector
),
]);
return new DelegatingLoader($loaderResolver);
}
}

View File

@ -4,53 +4,39 @@ declare(strict_types=1);
namespace Rector\Core\DependencyInjection;
use Psr\Container\ContainerInterface;
use Rector\Caching\Detector\ChangedFilesDetector;
use Rector\Core\HttpKernel\RectorKernel;
use Rector\Core\Kernel\RectorKernel;
use Rector\Core\Stubs\PHPStanStubLoader;
use Rector\Core\ValueObject\Bootstrap\BootstrapConfigs;
use Rector\Core\ValueObject\Configuration;
use Rector\Testing\PHPUnit\StaticPHPUnitEnvironment;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symplify\PackageBuilder\Console\Input\StaticInputDetector;
use Symplify\SmartFileSystem\SmartFileInfo;
final class RectorContainerFactory
{
/**
* @param SmartFileInfo[] $configFileInfos
* @param string[] $configFiles
* @api
*/
public function createFromConfigs(array $configFileInfos): ContainerInterface
public function createFromConfigs(array $configFiles): ContainerInterface
{
// to override the configs without clearing cache
$isDebug = StaticInputDetector::isDebug();
$environment = $this->createEnvironment($configFileInfos);
// mt_rand is needed to invalidate container cache in case of class changes to be registered as services
$isPHPUnitRun = StaticPHPUnitEnvironment::isPHPUnitRun();
if (! $isPHPUnitRun) {
$environment .= random_int(0, 10000);
}
// $isDebug = StaticInputDetector::isDebug();
$phpStanStubLoader = new PHPStanStubLoader();
$phpStanStubLoader->loadStubs();
$rectorKernel = new RectorKernel($environment, $isDebug, $configFileInfos);
$rectorKernel->boot();
return $rectorKernel->getContainer();
$rectorKernel = new RectorKernel();
return $rectorKernel->createFromConfigs($configFiles);
}
public function createFromBootstrapConfigs(BootstrapConfigs $bootstrapConfigs): ContainerInterface
{
$container = $this->createFromConfigs($bootstrapConfigs->getConfigFileInfos());
$container = $this->createFromConfigs($bootstrapConfigs->getConfigFiles());
$mainConfigFileInfo = $bootstrapConfigs->getMainConfigFileInfo();
if ($mainConfigFileInfo !== null) {
$mainConfigFile = $bootstrapConfigs->getMainConfigFile();
if ($mainConfigFile !== null) {
/** @var ChangedFilesDetector $changedFilesDetector */
$changedFilesDetector = $container->get(ChangedFilesDetector::class);
$changedFilesDetector->setFirstResolvedConfigFileInfo($mainConfigFileInfo);
$changedFilesDetector->setFirstResolvedConfigFileInfo($mainConfigFile);
}
return $container;
@ -58,16 +44,6 @@ final class RectorContainerFactory
/**
* @see https://symfony.com/doc/current/components/dependency_injection/compilation.html#dumping-the-configuration-for-performance
* @param SmartFileInfo[] $configFileInfos
* @param string[] $configFiles
*/
private function createEnvironment(array $configFileInfos): string
{
$configHashes = [];
foreach ($configFileInfos as $configFileInfo) {
$configHashes[] = md5_file($configFileInfo->getRealPath());
}
$configHashString = implode('', $configHashes);
return sha1($configHashString);
}
}

View File

@ -1,132 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Core\HttpKernel;
use Rector\Core\Contract\Rector\RectorInterface;
use Rector\Core\DependencyInjection\Collector\ConfigureCallValuesCollector;
use Rector\Core\DependencyInjection\CompilerPass\MakeRectorsPublicCompilerPass;
use Rector\Core\DependencyInjection\CompilerPass\MergeImportedRectorConfigureCallValuesCompilerPass;
use Rector\Core\DependencyInjection\CompilerPass\RemoveSkippedRectorsCompilerPass;
use Rector\Core\DependencyInjection\CompilerPass\VerifyRectorServiceExistsCompilerPass;
use Rector\Core\DependencyInjection\Loader\ConfigurableCallValuesCollectingPhpFileLoader;
use Symfony\Component\Config\Loader\DelegatingLoader;
use Symfony\Component\Config\Loader\GlobFileLoader;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\Loader\LoaderResolver;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
use Symfony\Component\HttpKernel\Config\FileLocator;
use Symfony\Component\HttpKernel\Kernel;
use Symplify\Astral\Bundle\AstralBundle;
use Symplify\AutowireArrayParameter\DependencyInjection\CompilerPass\AutowireArrayParameterCompilerPass;
use Symplify\ComposerJsonManipulator\Bundle\ComposerJsonManipulatorBundle;
use Symplify\ConsoleColorDiff\Bundle\ConsoleColorDiffBundle;
use Symplify\PackageBuilder\DependencyInjection\CompilerPass\AutowireInterfacesCompilerPass;
use Symplify\SimplePhpDocParser\Bundle\SimplePhpDocParserBundle;
use Symplify\Skipper\Bundle\SkipperBundle;
use Symplify\SmartFileSystem\SmartFileInfo;
/**
* @todo possibly remove symfony/http-kernel and use the container build only
*/
final class RectorKernel extends Kernel
{
private ConfigureCallValuesCollector $configureCallValuesCollector;
/**
* @param SmartFileInfo[] $configFileInfos
*/
public function __construct(
string $environment,
bool $debug,
private array $configFileInfos
) {
$this->configureCallValuesCollector = new ConfigureCallValuesCollector();
parent::__construct($environment, $debug);
}
public function getCacheDir(): string
{
$cacheDirectory = $_ENV['KERNEL_CACHE_DIRECTORY'] ?? null;
if ($cacheDirectory !== null) {
return $cacheDirectory . '/' . $this->environment;
}
// manually configured, so it can be replaced in phar
return sys_get_temp_dir() . '/rector/cache';
}
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__ . '/../../config/config.php');
foreach ($this->configFileInfos as $configFileInfo) {
$loader->load($configFileInfo->getRealPath());
}
}
/**
* @return iterable<BundleInterface>
*/
public function registerBundles(): iterable
{
return [
new ConsoleColorDiffBundle(),
new ComposerJsonManipulatorBundle(),
new SkipperBundle(),
new SimplePhpDocParserBundle(),
new AstralBundle(),
];
}
protected function build(ContainerBuilder $containerBuilder): void
{
// @see https://symfony.com/blog/new-in-symfony-4-4-dependency-injection-improvements-part-1
$containerBuilder->setParameter('container.dumper.inline_factories', true);
// to fix reincluding files again
$containerBuilder->setParameter('container.dumper.inline_class_loader', false);
// must run before AutowireArrayParameterCompilerPass, as the autowired array cannot contain removed services
$containerBuilder->addCompilerPass(new RemoveSkippedRectorsCompilerPass());
$containerBuilder->addCompilerPass(new AutowireArrayParameterCompilerPass());
// autowire Rectors by default (mainly for tests)
$containerBuilder->addCompilerPass(new AutowireInterfacesCompilerPass([RectorInterface::class]));
$containerBuilder->addCompilerPass(new MakeRectorsPublicCompilerPass());
// add all merged arguments of Rector services
$containerBuilder->addCompilerPass(
new MergeImportedRectorConfigureCallValuesCompilerPass($this->configureCallValuesCollector)
);
$containerBuilder->addCompilerPass(new VerifyRectorServiceExistsCompilerPass());
}
/**
* This allows to use "%vendor%" variables in imports
*/
protected function getContainerLoader(ContainerInterface $container): DelegatingLoader
{
$fileLocator = new FileLocator($this);
$loaderResolver = new LoaderResolver([
new GlobFileLoader($fileLocator),
new ConfigurableCallValuesCollectingPhpFileLoader(
$container,
$fileLocator,
$this->configureCallValuesCollector
),
]);
return new DelegatingLoader($loaderResolver);
}
}

113
src/Kernel/RectorKernel.php Normal file
View File

@ -0,0 +1,113 @@
<?php
declare(strict_types=1);
namespace Rector\Core\Kernel;
use Rector\Core\Config\Loader\ConfigureCallMergingLoaderFactory;
use Rector\Core\Contract\Rector\RectorInterface;
use Rector\Core\DependencyInjection\Collector\ConfigureCallValuesCollector;
use Rector\Core\DependencyInjection\CompilerPass\MakeRectorsPublicCompilerPass;
use Rector\Core\DependencyInjection\CompilerPass\MergeImportedRectorConfigureCallValuesCompilerPass;
use Rector\Core\DependencyInjection\CompilerPass\RemoveSkippedRectorsCompilerPass;
use Rector\Core\DependencyInjection\CompilerPass\VerifyRectorServiceExistsCompilerPass;
use Rector\Core\Exception\ShouldNotHappenException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symplify\Astral\ValueObject\AstralConfig;
use Symplify\AutowireArrayParameter\DependencyInjection\CompilerPass\AutowireArrayParameterCompilerPass;
use Symplify\ComposerJsonManipulator\ValueObject\ComposerJsonManipulatorConfig;
use Symplify\ConsoleColorDiff\ValueObject\ConsoleColorDiffConfig;
use Symplify\PackageBuilder\DependencyInjection\CompilerPass\AutowireInterfacesCompilerPass;
use Symplify\SimplePhpDocParser\ValueObject\SimplePhpDocParserConfig;
use Symplify\Skipper\ValueObject\SkipperConfig;
use Symplify\SymfonyContainerBuilder\ContainerBuilderFactory;
use Symplify\SymplifyKernel\Contract\LightKernelInterface;
final class RectorKernel implements LightKernelInterface
{
private ConfigureCallValuesCollector $configureCallValuesCollector;
private ContainerInterface|null $container = null;
public function __construct()
{
$this->configureCallValuesCollector = new ConfigureCallValuesCollector();
}
/**
* @param string[] $configFiles
*/
public function createFromConfigs(array $configFiles): ContainerInterface
{
$defaultConfigFiles = $this->createDefaultConfigFiles();
$configFiles = array_merge($defaultConfigFiles, $configFiles);
$compilerPasses = $this->createCompilerPasses();
$configureCallMergingLoaderFactory = new ConfigureCallMergingLoaderFactory($this->configureCallValuesCollector);
$containerBuilderFactory = new ContainerBuilderFactory($configureCallMergingLoaderFactory);
$containerBuilder = $containerBuilderFactory->create([], $compilerPasses, $configFiles);
// @see https://symfony.com/blog/new-in-symfony-4-4-dependency-injection-improvements-part-1
$containerBuilder->setParameter('container.dumper.inline_factories', true);
// to fix reincluding files again
$containerBuilder->setParameter('container.dumper.inline_class_loader', false);
$containerBuilder->compile();
$this->container = $containerBuilder;
return $containerBuilder;
}
public function getContainer(): ContainerInterface
{
if ($this->container === null) {
throw new ShouldNotHappenException();
}
return $this->container;
}
/**
* @return CompilerPassInterface[]
*/
private function createCompilerPasses(): array
{
$compilerPasses = [];
// must run before AutowireArrayParameterCompilerPass, as the autowired array cannot contain removed services
$compilerPasses[] = new RemoveSkippedRectorsCompilerPass();
// autowire Rectors by default (mainly for tests)
$compilerPasses[] = new AutowireInterfacesCompilerPass([RectorInterface::class]);
$compilerPasses[] = new MakeRectorsPublicCompilerPass();
// add all merged arguments of Rector services
$compilerPasses[] = new MergeImportedRectorConfigureCallValuesCompilerPass($this->configureCallValuesCollector);
$compilerPasses[] = new VerifyRectorServiceExistsCompilerPass();
$compilerPasses[] = new AutowireArrayParameterCompilerPass();
return $compilerPasses;
}
/**
* @return string[]
*/
private function createDefaultConfigFiles(): array
{
$configFiles = [];
$configFiles[] = __DIR__ . '/../../config/config.php';
$configFiles[] = AstralConfig::FILE_PATH;
$configFiles[] = ComposerJsonManipulatorConfig::FILE_PATH;
$configFiles[] = ConsoleColorDiffConfig::FILE_PATH;
$configFiles[] = SimplePhpDocParserConfig::FILE_PATH;
$configFiles[] = SkipperConfig::FILE_PATH;
return $configFiles;
}
}

View File

@ -4,34 +4,32 @@ declare(strict_types=1);
namespace Rector\Core\ValueObject\Bootstrap;
use Symplify\SmartFileSystem\SmartFileInfo;
final class BootstrapConfigs
{
/**
* @param SmartFileInfo[] $setConfigFileInfos
* @param string[] $setConfigFiles
*/
public function __construct(
private ?SmartFileInfo $mainConfigFileInfo,
private array $setConfigFileInfos
private ?string $mainConfigFile,
private array $setConfigFiles
) {
}
public function getMainConfigFileInfo(): ?SmartFileInfo
public function getMainConfigFile(): ?string
{
return $this->mainConfigFileInfo;
return $this->mainConfigFile;
}
/**
* @return SmartFileInfo[]
* @return string[]
*/
public function getConfigFileInfos(): array
public function getConfigFiles(): array
{
$configFileInfos = [];
if ($this->mainConfigFileInfo !== null) {
$configFileInfos[] = $this->mainConfigFileInfo;
$configFiles = [];
if ($this->mainConfigFile !== null) {
$configFiles[] = $this->mainConfigFile;
}
return array_merge($configFileInfos, $this->setConfigFileInfos);
return array_merge($configFiles, $this->setConfigFiles);
}
}

View File

@ -75,11 +75,12 @@ final class Configuration
return null;
}
$mainConfigFileInfo = $this->bootstrapConfigs->getMainConfigFileInfo();
if (! $mainConfigFileInfo instanceof SmartFileInfo) {
$mainConfigFile = $this->bootstrapConfigs->getMainConfigFile();
if (! is_string($mainConfigFile)) {
return null;
}
$mainConfigFileInfo = new SmartFileInfo($mainConfigFile);
return $mainConfigFileInfo->getRelativeFilePathFromCwd();
}
}

View File

@ -9,7 +9,6 @@ use Rector\Core\ValueObject\Configuration;
use Rector\Core\ValueObjectFactory\Application\FileFactory;
use Rector\Core\ValueObjectFactory\ProcessResultFactory;
use Rector\Testing\PHPUnit\AbstractTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class ApplicationFileProcessorTest extends AbstractTestCase
{
@ -21,7 +20,7 @@ final class ApplicationFileProcessorTest extends AbstractTestCase
protected function setUp(): void
{
$this->bootFromConfigFileInfos([new SmartFileInfo(__DIR__ . '/config/configured_rule.php')]);
$this->bootFromConfigFiles([__DIR__ . '/config/configured_rule.php']);
$this->applicationFileProcessor = $this->getService(ApplicationFileProcessor::class);
$this->fileFactory = $this->getService(FileFactory::class);

View File

@ -8,7 +8,6 @@ use Iterator;
use Rector\Core\Configuration\RenamedClassesDataCollector;
use Rector\Renaming\Rector\Name\RenameClassRector;
use Rector\Testing\PHPUnit\AbstractTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class ConfigurableRectorImportConfigCallsMergeTest extends AbstractTestCase
{
@ -16,10 +15,9 @@ final class ConfigurableRectorImportConfigCallsMergeTest extends AbstractTestCas
* @dataProvider provideData()
* @param array<string, string> $expectedConfiguration
*/
public function testMainConfigValues(string $config, array $expectedConfiguration): void
public function testMainConfigValues(string $configFile, array $expectedConfiguration): void
{
$configFileInfos = [new SmartFileInfo($config)];
$this->bootFromConfigFileInfos($configFileInfos);
$this->bootFromConfigFiles([$configFile]);
// to invoke configure() method call
$this->getService(RenameClassRector::class);

View File

@ -6,13 +6,12 @@ namespace Rector\Core\Tests\FileSystem\FilesFinder\ExcludePaths;
use Rector\Core\FileSystem\FilesFinder;
use Rector\Testing\PHPUnit\AbstractTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class ExcludePathsTest extends AbstractTestCase
{
public function testShouldFail(): void
{
$this->bootFromConfigFileInfos([new SmartFileInfo(__DIR__ . '/config/config-with-excluded-paths.php')]);
$this->bootFromConfigFiles([__DIR__ . '/config/config-with-excluded-paths.php']);
$filesFinder = $this->getService(FilesFinder::class);

View File

@ -23,7 +23,7 @@ final class ClassWithPublicPropertiesFactoryTest extends AbstractTestCase
protected function setUp(): void
{
$this->bootFromConfigFileInfos([new SmartFileInfo(__DIR__ . '/../../../config/config.php')]);
$this->bootFromConfigFiles([__DIR__ . '/../../../config/config.php']);
$this->classWithPublicPropertiesFactory = $this->getService(ClassWithPublicPropertiesFactory::class);
$this->betterStandardPrinter = $this->getService(BetterStandardPrinter::class);
}

View File

@ -8,7 +8,6 @@ use Iterator;
use Rector\Core\Exception\Configuration\InvalidConfigurationException;
use Rector\Core\Php\PhpVersionProvider;
use Rector\Testing\PHPUnit\AbstractTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class PhpVersionProviderTest extends AbstractTestCase
{
@ -16,44 +15,44 @@ final class PhpVersionProviderTest extends AbstractTestCase
* @doesNotPerformAssertions
* @dataProvider provideValidConfigData()
*/
public function testValidInput(SmartFileInfo $invalidFileInfo): void
public function testValidInput(string $invalidFilePath): void
{
$this->bootFromConfigFileInfos([$invalidFileInfo]);
$this->bootFromConfigFiles([$invalidFilePath]);
$phpVersionProvider = $this->getService(PhpVersionProvider::class);
$phpVersionProvider->provide();
}
/**
* @return Iterator<SmartFileInfo[]>
* @return Iterator<string[]>
*/
public function provideValidConfigData(): Iterator
{
yield [new SmartFileInfo(__DIR__ . '/config/valid_explicit_value.php')];
yield [new SmartFileInfo(__DIR__ . '/config/valid_minus_value.php')];
yield [__DIR__ . '/config/valid_explicit_value.php'];
yield [__DIR__ . '/config/valid_minus_value.php'];
}
/**
* @dataProvider provideInvalidConfigData()
*/
public function testInvalidInput(SmartFileInfo $invalidFileInfo): void
public function testInvalidInput(string $invalidFilePath): void
{
$this->expectException(InvalidConfigurationException::class);
$this->bootFromConfigFileInfos([$invalidFileInfo]);
$this->bootFromConfigFiles([$invalidFilePath]);
$phpVersionProvider = $this->getService(PhpVersionProvider::class);
$phpVersionProvider->provide();
}
/**
* @return Iterator<SmartFileInfo[]>
* @return Iterator<string[]>
*/
public function provideInvalidConfigData(): Iterator
{
yield [new SmartFileInfo(__DIR__ . '/config/invalid_input.php')];
yield [new SmartFileInfo(__DIR__ . '/config/invalid_string_input.php')];
yield [new SmartFileInfo(__DIR__ . '/config/invalid_number_input.php')];
yield [new SmartFileInfo(__DIR__ . '/config/invalid_php_4_number.php')];
yield [__DIR__ . '/config/invalid_input.php'];
yield [__DIR__ . '/config/invalid_string_input.php'];
yield [__DIR__ . '/config/invalid_number_input.php'];
yield [__DIR__ . '/config/invalid_php_4_number.php'];
}
}

View File

@ -7,7 +7,6 @@ namespace Rector\Core\Tests\Validation\Collector\EmptyConfigurableRectorCollecto
use Rector\Core\Validation\Collector\EmptyConfigurableRectorCollector;
use Rector\Php80\Rector\Class_\AnnotationToAttributeRector;
use Rector\Testing\PHPUnit\AbstractTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
/**
* array configurable with has values config will be passed
@ -18,7 +17,7 @@ final class ConfigurableArrayHasValuesTest extends AbstractTestCase
protected function setUp(): void
{
$this->bootFromConfigFileInfos([new SmartFileInfo(__DIR__ . '/config/configurable_array_has_values.php')]);
$this->bootFromConfigFiles([__DIR__ . '/config/configurable_array_has_values.php']);
$this->collector = $this->getService(EmptyConfigurableRectorCollector::class);
}

View File

@ -7,7 +7,6 @@ namespace Rector\Core\Tests\Validation\Collector\EmptyConfigurableRectorCollecto
use Rector\Core\Validation\Collector\EmptyConfigurableRectorCollector;
use Rector\Php80\Rector\Class_\AnnotationToAttributeRector;
use Rector\Testing\PHPUnit\AbstractTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
/**
* array configurable with missing values config will show warning
@ -18,7 +17,7 @@ final class ConfigurableArrayMissingTest extends AbstractTestCase
protected function setUp(): void
{
$this->bootFromConfigFileInfos([new SmartFileInfo(__DIR__ . '/config/configurable_array_missing.php')]);
$this->bootFromConfigFiles([__DIR__ . '/config/configurable_array_missing.php']);
$this->collector = $this->getService(EmptyConfigurableRectorCollector::class);
}

View File

@ -7,7 +7,6 @@ namespace Rector\Core\Tests\Validation\Collector\EmptyConfigurableRectorCollecto
use Rector\Core\Validation\Collector\EmptyConfigurableRectorCollector;
use Rector\Php74\Rector\Property\TypedPropertyRector;
use Rector\Testing\PHPUnit\AbstractTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
/**
* Not array configurable, eg:
@ -20,7 +19,7 @@ final class ConfigurableNotArrayTest extends AbstractTestCase
protected function setUp(): void
{
$this->bootFromConfigFileInfos([new SmartFileInfo(__DIR__ . '/config/configurable_not_array.php')]);
$this->bootFromConfigFiles([__DIR__ . '/config/configurable_not_array.php']);
$this->collector = $this->getService(EmptyConfigurableRectorCollector::class);
}

View File

@ -7,7 +7,6 @@ namespace Rector\Core\Tests\Validation\Collector\EmptyConfigurableRectorCollecto
use Rector\Core\Validation\Collector\EmptyConfigurableRectorCollector;
use Rector\Privatization\Rector\Class_\ChangeLocalPropertyToVariableRector;
use Rector\Testing\PHPUnit\AbstractTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
/**
* Not configurable will be passed
@ -18,7 +17,7 @@ final class NotConfigurableRectorTest extends AbstractTestCase
protected function setUp(): void
{
$this->bootFromConfigFileInfos([new SmartFileInfo(__DIR__ . '/config/not_configurable.php')]);
$this->bootFromConfigFiles([__DIR__ . '/config/not_configurable.php']);
$this->collector = $this->getService(EmptyConfigurableRectorCollector::class);
}