Merge pull request #2470 from rectorphp/argument-merge

merge Rector arguments on import
This commit is contained in:
Tomáš Votruba 2019-12-23 14:09:24 +01:00 committed by GitHub
commit 3735fd15f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 166 additions and 19 deletions

View File

@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace Rector\DependencyInjection\Collector;
use Nette\Utils\Strings;
use Rector\Contract\Rector\RectorInterface;
use Symplify\PackageBuilder\Yaml\ParametersMerger;
final class RectorServiceArgumentCollector
{
/**
* @var ParametersMerger
*/
private $parametersMerger;
/**
* @var mixed[]
*/
private $cachedRectorServiceKeyArguments = [];
public function __construct()
{
$this->parametersMerger = new ParametersMerger();
}
public function getClassArgumentValue(string $serviceClass): array
{
return $this->cachedRectorServiceKeyArguments[$serviceClass] ?? [];
}
public function collectFromServiceAndRectorClass(array $service, string $className): void
{
if (! is_a($className, RectorInterface::class, true)) {
return;
}
foreach ($service as $argumentName => $argumentValue) {
// is that argument?
if (! Strings::startsWith($argumentName, '$')) {
continue;
}
$this->addArgumentValue($className, $argumentName, $argumentValue);
}
}
private function addArgumentValue(string $serviceClassName, string $argumentName, $argumentValue): void
{
if (! isset($this->cachedRectorServiceKeyArguments[$serviceClassName][$argumentName])) {
$this->cachedRectorServiceKeyArguments[$serviceClassName][$argumentName] = $argumentValue;
} else {
$mergedParameters = $this->parametersMerger->merge(
$this->cachedRectorServiceKeyArguments[$serviceClassName][$argumentName],
$argumentValue
);
$this->cachedRectorServiceKeyArguments[$serviceClassName][$argumentName] = $mergedParameters;
}
}
}

View File

@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace Rector\DependencyInjection\CompilerPass;
use Rector\DependencyInjection\Collector\RectorServiceArgumentCollector;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
final class MergeImportedRectorServiceArgumentsCompilerPass implements CompilerPassInterface
{
/**
* @var RectorServiceArgumentCollector
*/
private $rectorServiceArgumentCollector;
public function __construct(RectorServiceArgumentCollector $rectorServiceArgumentCollector)
{
$this->rectorServiceArgumentCollector = $rectorServiceArgumentCollector;
}
public function process(ContainerBuilder $containerBuilder): void
{
foreach ($containerBuilder->getDefinitions() as $id => $definition) {
$this->completeCollectedArguments($id, $definition);
}
}
private function completeCollectedArguments(string $serviceClass, Definition $definition): void
{
$cachedServiceKeyArguments = $this->rectorServiceArgumentCollector->getClassArgumentValue($serviceClass);
if ($cachedServiceKeyArguments === []) {
return;
}
// prevent argument override
foreach ($cachedServiceKeyArguments as $argumentName => $argumentValue) {
$definition->setArgument($argumentName, $argumentValue);
}
}
}

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Rector\DependencyInjection\Loader;
use Rector\Contract\Rector\RectorInterface;
use Rector\DependencyInjection\Collector\RectorServiceArgumentCollector;
use Symfony\Component\Config\FileLocatorInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symplify\PackageBuilder\Yaml\FileLoader\AbstractParameterMergingYamlFileLoader;
@ -21,10 +23,19 @@ final class TolerantRectorYamlFileLoader extends AbstractParameterMergingYamlFil
*/
private $classExistenceValidator;
public function __construct(ContainerBuilder $containerBuilder, FileLocatorInterface $fileLocator)
{
/**
* @var RectorServiceArgumentCollector
*/
private $rectorServiceArgumentCollector;
public function __construct(
ContainerBuilder $containerBuilder,
FileLocatorInterface $fileLocator,
RectorServiceArgumentCollector $rectorServiceArgumentCollector
) {
$this->parameterInImportResolver = new ParameterInImportResolver();
$this->classExistenceValidator = new ClassExistenceValidator();
$this->rectorServiceArgumentCollector = $rectorServiceArgumentCollector;
parent::__construct($containerBuilder, $fileLocator);
}
@ -41,19 +52,35 @@ final class TolerantRectorYamlFileLoader extends AbstractParameterMergingYamlFil
return [];
}
// @todo: merge service arguments as well
foreach ($configuration['services'] ?? [] as $service) {
if (! isset($service['arguments'])) {
continue;
}
// dump($service['arguments']);
}
$this->collectRectorServiceArguments($configuration);
$this->classExistenceValidator->ensureClassesAreValid($configuration, $file);
// $configuration = $this->rectorServiceParametersShifter->process($configuration, $file);
return $this->parameterInImportResolver->process($configuration);
}
private function collectRectorServiceArguments(array $configuration): void
{
if (! isset($configuration['services'])) {
return;
}
// merge service arguments as well
foreach ($configuration['services'] as $className => $service) {
if (! is_string($className)) {
continue;
}
// skip non-rectors
if (! is_a($className, RectorInterface::class, true)) {
continue;
}
if (! is_array($service)) {
continue;
}
$this->rectorServiceArgumentCollector->collectFromServiceAndRectorClass($service, $className);
}
}
}

View File

@ -5,6 +5,8 @@ declare(strict_types=1);
namespace Rector\HttpKernel;
use Rector\Contract\Rector\RectorInterface;
use Rector\DependencyInjection\Collector\RectorServiceArgumentCollector;
use Rector\DependencyInjection\CompilerPass\MergeImportedRectorServiceArgumentsCompilerPass;
use Rector\DependencyInjection\CompilerPass\RemoveExcludedRectorsCompilerPass;
use Rector\DependencyInjection\Loader\TolerantRectorYamlFileLoader;
use Symfony\Component\Config\Loader\DelegatingLoader;
@ -29,6 +31,18 @@ final class RectorKernel extends Kernel implements ExtraConfigAwareKernelInterfa
*/
private $configs = [];
/**
* @var RectorServiceArgumentCollector
*/
private $rectorServiceArgumentCollector;
public function __construct(string $environment, bool $debug)
{
$this->rectorServiceArgumentCollector = new RectorServiceArgumentCollector();
parent::__construct($environment, $debug);
}
public function getCacheDir(): string
{
// manually configured, so it can be replaced in phar
@ -77,6 +91,11 @@ final class RectorKernel extends Kernel implements ExtraConfigAwareKernelInterfa
$containerBuilder->addCompilerPass(new AutowireInterfacesCompilerPass([RectorInterface::class]));
$containerBuilder->addCompilerPass(new AutoBindParametersCompilerPass());
// add all merged arguments of Rector services
$containerBuilder->addCompilerPass(
new MergeImportedRectorServiceArgumentsCompilerPass($this->rectorServiceArgumentCollector)
);
}
/**
@ -89,7 +108,7 @@ final class RectorKernel extends Kernel implements ExtraConfigAwareKernelInterfa
$loaderResolver = new LoaderResolver([
new GlobFileLoader($kernelFileLocator),
new TolerantRectorYamlFileLoader($container, $kernelFileLocator),
new TolerantRectorYamlFileLoader($container, $kernelFileLocator, $this->rectorServiceArgumentCollector),
]);
return new DelegatingLoader($loaderResolver);

View File

@ -6,9 +6,8 @@ use Rector\Tests\Issues\Issue2451\Source\AbstractBaseHandler;
class Issue2451 extends AbstractBaseHandler
{
public function handle($params)
public function handle()
{
// do something
}
}
@ -22,9 +21,8 @@ use Rector\Tests\Issues\Issue2451\Source\AbstractBaseHandler;
class Issue2451 extends AbstractBaseHandler
{
public function handle($params): \Tomaj\NetteApi\Response\ResponseInterface
public function handle(): \Tomaj\NetteApi\Response\ResponseInterface
{
// do something
}
}

View File

@ -10,8 +10,6 @@ final class Issue2451Test extends AbstractRectorTestCase
{
public function test(): void
{
$this->markTestSkipped('Resolve after removing shifter');
$this->doTestFile(__DIR__ . '/Fixture/fixture2451.php.inc');
}