diff --git a/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/child_of_parent_with_private_promoted_property.php.inc b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/child_of_parent_with_private_promoted_property.php.inc index a8f935aa6..cd135c182 100644 --- a/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/child_of_parent_with_private_promoted_property.php.inc +++ b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/child_of_parent_with_private_promoted_property.php.inc @@ -38,7 +38,7 @@ final class ChildOfParentWithPrivatePromotedProperty extends ParentControllerWit $this->logger->log('level', 'value'); } #[\Symfony\Contracts\Service\Attribute\Required] - public function autowire(\Psr\Log\LoggerInterface $logger): void + public function autowireChildOfParentWithPrivatePromotedProperty(\Psr\Log\LoggerInterface $logger): void { $this->logger = $logger; } diff --git a/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/parent_constructor_multiple_services.php.inc b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/parent_constructor_multiple_services.php.inc index de28db64a..bf34dff0e 100644 --- a/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/parent_constructor_multiple_services.php.inc +++ b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/parent_constructor_multiple_services.php.inc @@ -41,7 +41,7 @@ final class ParentConstructorMultipleServices extends ParentControllerWithPrivat $this->logger->log('level', $this->translator->trans('value')); } #[\Symfony\Contracts\Service\Attribute\Required] - public function autowire(\Psr\Log\LoggerInterface $logger, \Symfony\Contracts\Translation\TranslatorInterface $translator): void + public function autowireParentConstructorMultipleServices(\Psr\Log\LoggerInterface $logger, \Symfony\Contracts\Translation\TranslatorInterface $translator): void { $this->logger = $logger; $this->translator = $translator; diff --git a/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/parent_with_autowire_method.php.inc b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/parent_with_autowire_method.php.inc index b0736d5e9..94d0c19aa 100644 --- a/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/parent_with_autowire_method.php.inc +++ b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/parent_with_autowire_method.php.inc @@ -38,7 +38,7 @@ final class ParentWithAutowireMethod extends ParentControllerWithAutowireMethod $this->logger->log('level', 'value'); } #[\Symfony\Contracts\Service\Attribute\Required] - public function autowireServices(\Psr\Log\LoggerInterface $logger): void + public function autowireParentWithAutowireMethod(\Psr\Log\LoggerInterface $logger): void { $this->logger = $logger; } diff --git a/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/FixtureTypeGuarded/non_guarded_controller.php.inc b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/FixtureTypeGuarded/non_guarded_controller.php.inc new file mode 100644 index 000000000..0d5388d33 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/FixtureTypeGuarded/non_guarded_controller.php.inc @@ -0,0 +1,44 @@ +log('level', 'value'); + } +} + +?> +----- +logger->log('level', 'value'); + } +} + +?> diff --git a/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/FixtureTypeGuarded/skip_type_guarded_controller.php.inc b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/FixtureTypeGuarded/skip_type_guarded_controller.php.inc new file mode 100644 index 000000000..14d7946a1 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/FixtureTypeGuarded/skip_type_guarded_controller.php.inc @@ -0,0 +1,18 @@ +log('level', 'value'); + } +} diff --git a/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Source/AbstractCustomController.php b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Source/AbstractCustomController.php new file mode 100644 index 000000000..24349aaeb --- /dev/null +++ b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Source/AbstractCustomController.php @@ -0,0 +1,11 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/FixtureTypeGuarded'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/type_guarded_rule.php'; + } +} diff --git a/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/config/type_guarded_rule.php b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/config/type_guarded_rule.php new file mode 100644 index 000000000..fd4d9746a --- /dev/null +++ b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/config/type_guarded_rule.php @@ -0,0 +1,11 @@ +withRules([ControllerMethodInjectionToConstructorRector::class]) + ->withTypeGuardedClasses([AbstractCustomController::class]); diff --git a/rules/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector.php b/rules/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector.php index d45796faf..f2f6e226e 100644 --- a/rules/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector.php +++ b/rules/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector.php @@ -53,12 +53,7 @@ final class ControllerMethodInjectionToConstructorRector extends AbstractRector */ private const array COMMON_ENTITY_CONTAINS_SUBNAMESPACES = ["\\Entity\\", "\\Document\\", "\\Model\\"]; - private const string AUTOWIRE_METHOD_NAME = 'autowire'; - - /** - * Used when a parent class already defines autowire(), to avoid overriding it - */ - private const string FALLBACK_AUTOWIRE_METHOD_NAME = 'autowireServices'; + private const string AUTOWIRE_METHOD_NAME_PREFIX = 'autowire'; public function __construct( private readonly ControllerAnalyzer $controllerAnalyzer, @@ -75,7 +70,7 @@ public function __construct( public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( - 'Change Symfony controller method injection to direct constructor dependency, to separate params and services clearly. If a parent class has a constructor, use #[Required] autowire() method instead, to avoid repeating all parent params', + 'Change Symfony controller method injection to direct constructor dependency, to separate params and services clearly. If a parent class has a constructor, use #[Required] autowire() method instead, to avoid repeating all parent params', [ new CodeSample( <<<'CODE_SAMPLE' @@ -145,7 +140,7 @@ public function someAction() } #[Required] - public function autowire(SomeService $someService): void + public function autowireSomeController(SomeService $someService): void { $this->someService = $someService; } @@ -177,6 +172,11 @@ public function refactor(Node $node): ?Node return null; } + // removing action params would break child classes of user-guarded classes + if ($this->parentClassMethodTypeOverrideGuard->isTypeGuardedClass($node)) { + return null; + } + $propertyMetadatas = []; $constructParamVariables = []; @@ -495,20 +495,14 @@ private function addRequiredAutowireClassMethod(Class_ $class, array $propertyMe } } + /** + * Suffix with the short class name, to keep the method unique in case of inheritance + */ private function resolveAutowireMethodName(Class_ $class): string { - $classReflection = $this->reflectionResolver->resolveClassReflection($class); - if (! $classReflection instanceof ClassReflection) { - return self::AUTOWIRE_METHOD_NAME; - } - - foreach ($classReflection->getParents() as $parentClassReflection) { - if ($parentClassReflection->hasNativeMethod(self::AUTOWIRE_METHOD_NAME)) { - return self::FALLBACK_AUTOWIRE_METHOD_NAME; - } - } + $shortClassName = $class->name instanceof Identifier ? $class->name->toString() : ''; - return self::AUTOWIRE_METHOD_NAME; + return self::AUTOWIRE_METHOD_NAME_PREFIX . ucfirst($shortClassName); } private function hasParentConstructor(Class_ $class): bool