From 96a51e3f586ead3bb6009dbbeced653184de1fe4 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 3 Aug 2026 19:24:33 +0200 Subject: [PATCH] Turn ReplaceServiceArgumentRector into hardcoded ContainerInterfaceServiceToServiceContainerRector The rule only ever handled one Symfony 6.0 BC break: the removal of the Psr\Container\ContainerInterface and Symfony\Component\DependencyInjection\ContainerInterface aliases of the "service_container" service. Hardcode both values, drop the configuration and its value object, and bond the rule to symfony/dependency-injection >=6.0 via ComposerPackageConstraintInterface. --- config/sets/symfony/composer-based.php | 14 ++--- .../symfony60-dependency-injection.php | 12 +---- ...ceServiceToServiceContainerRectorTest.php} | 4 +- .../Fixture/fixture.php.inc | 4 +- .../Fixture/skip_different_value.php.inc | 2 +- .../config/configured_rule.php | 10 ++++ .../config/configured_rule.php | 16 ------ ...erfaceServiceToServiceContainerRector.php} | 51 ++++++++++--------- src/Enum/SymfonyClass.php | 4 ++ src/ValueObject/ReplaceServiceArgument.php | 26 ---------- 10 files changed, 51 insertions(+), 92 deletions(-) rename rules-tests/Symfony60/Rector/FuncCall/{ReplaceServiceArgumentRector/ReplaceServiceArgumentRectorTest.php => ContainerInterfaceServiceToServiceContainerRector/ContainerInterfaceServiceToServiceContainerRectorTest.php} (72%) rename rules-tests/Symfony60/Rector/FuncCall/{ReplaceServiceArgumentRector => ContainerInterfaceServiceToServiceContainerRector}/Fixture/fixture.php.inc (60%) rename rules-tests/Symfony60/Rector/FuncCall/{ReplaceServiceArgumentRector => ContainerInterfaceServiceToServiceContainerRector}/Fixture/skip_different_value.php.inc (51%) create mode 100644 rules-tests/Symfony60/Rector/FuncCall/ContainerInterfaceServiceToServiceContainerRector/config/configured_rule.php delete mode 100644 rules-tests/Symfony60/Rector/FuncCall/ReplaceServiceArgumentRector/config/configured_rule.php rename rules/Symfony60/Rector/FuncCall/{ReplaceServiceArgumentRector.php => ContainerInterfaceServiceToServiceContainerRector.php} (54%) delete mode 100644 src/ValueObject/ReplaceServiceArgument.php diff --git a/config/sets/symfony/composer-based.php b/config/sets/symfony/composer-based.php index 00d5fe26c..c4412d92f 100644 --- a/config/sets/symfony/composer-based.php +++ b/config/sets/symfony/composer-based.php @@ -2,7 +2,6 @@ declare(strict_types=1); -use PhpParser\Node\Scalar\String_; use PHPStan\Type\ArrayType; use PHPStan\Type\BooleanType; use PHPStan\Type\Constant\ConstantBooleanType; @@ -87,7 +86,7 @@ use Rector\Symfony\Symfony52\Rector\New_\PropertyPathMapperToDataMapperRector; use Rector\Symfony\Symfony52\Rector\StaticCall\BinaryFileResponseCreateToNewInstanceRector; use Rector\Symfony\Symfony53\Rector\StaticPropertyFetch\KernelTestCaseContainerPropertyDeprecationRector; -use Rector\Symfony\Symfony60\Rector\FuncCall\ReplaceServiceArgumentRector; +use Rector\Symfony\Symfony60\Rector\FuncCall\ContainerInterfaceServiceToServiceContainerRector; use Rector\Symfony\Symfony60\Rector\MethodCall\GetHelperControllerToServiceRector; use Rector\Symfony\Symfony61\Rector\Class_\CommandConfigureToAttributeRector; use Rector\Symfony\Symfony61\Rector\Class_\CommandPropertyToAttributeRector; @@ -113,7 +112,6 @@ use Rector\Symfony\Symfony81\Rector\MethodCall\RenameCopyOnWindowsOptionToFollowSymlinksRector; use Rector\Symfony\Symfony81\Rector\New_\RemoveEraseCredentialsFromAuthenticatorManagerRector; use Rector\Symfony\Symfony81\Rector\StaticCall\AddFormatArgumentToIsValidRector; -use Rector\Symfony\ValueObject\ReplaceServiceArgument; use Rector\Transform\Rector\Attribute\AttributeKeyToClassConstFetchRector; use Rector\Transform\Rector\ClassMethod\WrapReturnRector; use Rector\Transform\Rector\StaticCall\StaticCallToNewRector; @@ -253,6 +251,9 @@ // symfony/framework-bundle 5.3 KernelTestCaseContainerPropertyDeprecationRector::class, + // symfony/dependency-injection 6.0 + ContainerInterfaceServiceToServiceContainerRector::class, + // symfony/framework-bundle 6.0 GetHelperControllerToServiceRector::class, @@ -2016,13 +2017,6 @@ new UnionType($scalarTypes) ), ], 'symfony/dependency-injection', '>=6.0'); - $rectorConfig->ruleWithConfigurationComposerVersionBound(ReplaceServiceArgumentRector::class, [ - new ReplaceServiceArgument('Psr\Container\ContainerInterface', new String_('service_container')), - new ReplaceServiceArgument( - 'Symfony\Component\DependencyInjection\ContainerInterface', - new String_('service_container') - ), - ], 'symfony/dependency-injection', '>=6.0'); // symfony/doctrine-bridge 6.0 $rectorConfig->ruleWithConfigurationComposerVersionBound(RenameMethodRector::class, [ diff --git a/config/sets/symfony/symfony6/symfony60/symfony60-dependency-injection.php b/config/sets/symfony/symfony6/symfony60/symfony60-dependency-injection.php index e156ca702..45a25147d 100644 --- a/config/sets/symfony/symfony6/symfony60/symfony60-dependency-injection.php +++ b/config/sets/symfony/symfony6/symfony60/symfony60-dependency-injection.php @@ -2,7 +2,6 @@ declare(strict_types=1); -use PhpParser\Node\Scalar\String_; use PHPStan\Type\ArrayType; use PHPStan\Type\BooleanType; use PHPStan\Type\Constant\ConstantBooleanType; @@ -15,19 +14,12 @@ use PHPStan\Type\StringType; use PHPStan\Type\UnionType; use Rector\Config\RectorConfig; -use Rector\Symfony\Symfony60\Rector\FuncCall\ReplaceServiceArgumentRector; -use Rector\Symfony\ValueObject\ReplaceServiceArgument; +use Rector\Symfony\Symfony60\Rector\FuncCall\ContainerInterfaceServiceToServiceContainerRector; use Rector\TypeDeclaration\Rector\ClassMethod\AddReturnTypeDeclarationRector; use Rector\TypeDeclaration\ValueObject\AddReturnTypeDeclaration; return static function (RectorConfig $rectorConfig): void { - $rectorConfig->ruleWithConfiguration(ReplaceServiceArgumentRector::class, [ - new ReplaceServiceArgument('Psr\Container\ContainerInterface', new String_('service_container')), - new ReplaceServiceArgument( - 'Symfony\Component\DependencyInjection\ContainerInterface', - new String_('service_container') - ), - ]); + $rectorConfig->rule(ContainerInterfaceServiceToServiceContainerRector::class); $configurationType = new ObjectType('Symfony\Component\Config\Definition\ConfigurationInterface'); diff --git a/rules-tests/Symfony60/Rector/FuncCall/ReplaceServiceArgumentRector/ReplaceServiceArgumentRectorTest.php b/rules-tests/Symfony60/Rector/FuncCall/ContainerInterfaceServiceToServiceContainerRector/ContainerInterfaceServiceToServiceContainerRectorTest.php similarity index 72% rename from rules-tests/Symfony60/Rector/FuncCall/ReplaceServiceArgumentRector/ReplaceServiceArgumentRectorTest.php rename to rules-tests/Symfony60/Rector/FuncCall/ContainerInterfaceServiceToServiceContainerRector/ContainerInterfaceServiceToServiceContainerRectorTest.php index ab9b1679c..0bb0c164b 100644 --- a/rules-tests/Symfony60/Rector/FuncCall/ReplaceServiceArgumentRector/ReplaceServiceArgumentRectorTest.php +++ b/rules-tests/Symfony60/Rector/FuncCall/ContainerInterfaceServiceToServiceContainerRector/ContainerInterfaceServiceToServiceContainerRectorTest.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace Rector\Symfony\Tests\Symfony60\Rector\FuncCall\ReplaceServiceArgumentRector; +namespace Rector\Symfony\Tests\Symfony60\Rector\FuncCall\ContainerInterfaceServiceToServiceContainerRector; use Iterator; use PHPUnit\Framework\Attributes\DataProvider; use Rector\Testing\PHPUnit\AbstractRectorTestCase; -final class ReplaceServiceArgumentRectorTest extends AbstractRectorTestCase +final class ContainerInterfaceServiceToServiceContainerRectorTest extends AbstractRectorTestCase { #[DataProvider('provideData')] public function test(string $filePath): void diff --git a/rules-tests/Symfony60/Rector/FuncCall/ReplaceServiceArgumentRector/Fixture/fixture.php.inc b/rules-tests/Symfony60/Rector/FuncCall/ContainerInterfaceServiceToServiceContainerRector/Fixture/fixture.php.inc similarity index 60% rename from rules-tests/Symfony60/Rector/FuncCall/ReplaceServiceArgumentRector/Fixture/fixture.php.inc rename to rules-tests/Symfony60/Rector/FuncCall/ContainerInterfaceServiceToServiceContainerRector/Fixture/fixture.php.inc index 781820e2d..1133beb07 100644 --- a/rules-tests/Symfony60/Rector/FuncCall/ReplaceServiceArgumentRector/Fixture/fixture.php.inc +++ b/rules-tests/Symfony60/Rector/FuncCall/ContainerInterfaceServiceToServiceContainerRector/Fixture/fixture.php.inc @@ -1,6 +1,6 @@ rule(ContainerInterfaceServiceToServiceContainerRector::class); +}; diff --git a/rules-tests/Symfony60/Rector/FuncCall/ReplaceServiceArgumentRector/config/configured_rule.php b/rules-tests/Symfony60/Rector/FuncCall/ReplaceServiceArgumentRector/config/configured_rule.php deleted file mode 100644 index 764c8a4d5..000000000 --- a/rules-tests/Symfony60/Rector/FuncCall/ReplaceServiceArgumentRector/config/configured_rule.php +++ /dev/null @@ -1,16 +0,0 @@ -ruleWithConfiguration( - ReplaceServiceArgumentRector::class, - [new ReplaceServiceArgument(ContainerInterface::class, new String_('service_container'))] - ); -}; diff --git a/rules/Symfony60/Rector/FuncCall/ReplaceServiceArgumentRector.php b/rules/Symfony60/Rector/FuncCall/ContainerInterfaceServiceToServiceContainerRector.php similarity index 54% rename from rules/Symfony60/Rector/FuncCall/ReplaceServiceArgumentRector.php rename to rules/Symfony60/Rector/FuncCall/ContainerInterfaceServiceToServiceContainerRector.php index ccbebe8d7..48c354cbb 100644 --- a/rules/Symfony60/Rector/FuncCall/ReplaceServiceArgumentRector.php +++ b/rules/Symfony60/Rector/FuncCall/ContainerInterfaceServiceToServiceContainerRector.php @@ -8,36 +8,48 @@ use PhpParser\Node\Arg; use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Scalar\String_; -use Rector\Contract\Rector\ConfigurableRectorInterface; use Rector\PhpParser\Node\Value\ValueResolver; use Rector\Rector\AbstractRector; +use Rector\Symfony\Enum\SymfonyClass; use Rector\Symfony\Enum\SymfonyFunctionName; -use Rector\Symfony\ValueObject\ReplaceServiceArgument; -use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample; +use Rector\VersionBonding\Contract\ComposerPackageConstraintInterface; +use Rector\VersionBonding\ValueObject\ComposerPackageConstraint; +use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; -use Webmozart\Assert\Assert; /** - * @see \Rector\Symfony\Tests\Symfony60\Rector\FuncCall\ReplaceServiceArgumentRector\ReplaceServiceArgumentRectorTest + * @changelog https://github.com/symfony/symfony/pull/42149 + * + * @see \Rector\Symfony\Tests\Symfony60\Rector\FuncCall\ContainerInterfaceServiceToServiceContainerRector\ContainerInterfaceServiceToServiceContainerRectorTest */ -final class ReplaceServiceArgumentRector extends AbstractRector implements ConfigurableRectorInterface +final class ContainerInterfaceServiceToServiceContainerRector extends AbstractRector implements ComposerPackageConstraintInterface { /** - * @var ReplaceServiceArgument[] + * @var string[] */ - private array $replaceServiceArguments = []; + private const array CONTAINER_INTERFACES = [ + SymfonyClass::PSR_CONTAINER_INTERFACE, + SymfonyClass::DEPENDENCY_INJECTION_CONTAINER_INTERFACE, + ]; + + private const string SERVICE_CONTAINER = 'service_container'; public function __construct( private readonly ValueResolver $valueResolver ) { } + public function provideComposerPackageConstraint(): ComposerPackageConstraint + { + return new ComposerPackageConstraint('symfony/dependency-injection', '>=6.0'); + } + public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( - 'Replace defined service() argument in Symfony PHP config', + 'Replace removed ContainerInterface alias with "service_container" service id in service() call', [ - new ConfiguredCodeSample( + new CodeSample( <<<'CODE_SAMPLE' use function Symfony\Component\DependencyInjection\Loader\Configurator\service; @@ -49,8 +61,6 @@ public function getRuleDefinition(): RuleDefinition return service('service_container'); CODE_SAMPLE - , - [new ReplaceServiceArgument('ContainerInterface', new String_('service_container'))] ), ] ); @@ -73,29 +83,20 @@ public function refactor(Node $node): ?FuncCall return null; } - $firstArg = $node->args[0]; + $firstArg = $node->args[0] ?? null; if (! $firstArg instanceof Arg) { return null; } - foreach ($this->replaceServiceArguments as $replaceServiceArgument) { - if (! $this->valueResolver->isValue($firstArg->value, $replaceServiceArgument->getOldValue())) { + foreach (self::CONTAINER_INTERFACES as $containerInterface) { + if (! $this->valueResolver->isValue($firstArg->value, $containerInterface)) { continue; } - $node->args[0] = new Arg($replaceServiceArgument->getNewValueExpr()); + $node->args[0] = new Arg(new String_(self::SERVICE_CONTAINER)); return $node; } return null; } - - /** - * @param mixed[] $configuration - */ - public function configure(array $configuration): void - { - Assert::allIsAOf($configuration, ReplaceServiceArgument::class); - $this->replaceServiceArguments = $configuration; - } } diff --git a/src/Enum/SymfonyClass.php b/src/Enum/SymfonyClass.php index 1bb23823d..b1c5d9df1 100644 --- a/src/Enum/SymfonyClass.php +++ b/src/Enum/SymfonyClass.php @@ -14,6 +14,10 @@ final class SymfonyClass public const string CONTAINER_AWARE_COMMAND = 'Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand'; + public const string PSR_CONTAINER_INTERFACE = 'Psr\Container\ContainerInterface'; + + public const string DEPENDENCY_INJECTION_CONTAINER_INTERFACE = 'Symfony\Component\DependencyInjection\ContainerInterface'; + public const string EVENT_DISPATCHER_INTERFACE = 'Symfony\Contracts\EventDispatcher\EventDispatcherInterface'; public const string VALIDATOR_INTERFACE = 'Symfony\Component\Validator\Validator\ValidatorInterface'; diff --git a/src/ValueObject/ReplaceServiceArgument.php b/src/ValueObject/ReplaceServiceArgument.php deleted file mode 100644 index eaa0d0df4..000000000 --- a/src/ValueObject/ReplaceServiceArgument.php +++ /dev/null @@ -1,26 +0,0 @@ -oldValue; - } - - public function getNewValueExpr(): Expr - { - return $this->newValueExpr; - } -}