[CodeQuality] Use #[Required] autowire() instead of constructor when parent has one in ControllerMethodInjectionToConstructorRector - #1006
Merged
Conversation
…r when parent class has a constructor in ControllerMethodInjectionToConstructorRector
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When a controller extends a parent that already has a constructor, adding a promoted constructor dependency forces the child to repeat every parent parameter and call
parent::__construct()with all of them:This PR makes the rule use
#[Required]setter injection in that case instead, so the parent constructor is left alone.Before / after
Parent class has a constructor:
final class ChildOfParentWithPrivatePromotedProperty extends ParentControllerWithPrivatePromotedProperty { + private \Psr\Log\LoggerInterface $logger; + #[Route('/example', name: 'example')] - public function example(LoggerInterface $logger) + public function example() { - $logger->log('level', 'value'); + $this->logger->log('level', 'value'); + } + + #[\Symfony\Contracts\Service\Attribute\Required] + public function autowire(\Psr\Log\LoggerInterface $logger): void + { + $this->logger = $logger; } }No parent constructor — unchanged, still promoted constructor:
final class SomeControllerWithMethodInjection extends AbstractController { + public function __construct(private readonly \Psr\Log\LoggerInterface $logger) + { + } + #[Route('/some-action', name: 'some_action')] public function someAction( \Symfony\Component\HttpFoundation\Request $request, - \Psr\Log\LoggerInterface $logger ) { - $logger->log('level', 'value'); + $this->logger->log('level', 'value'); } }Notes
autowire()method, one property assignment each.autowire(), the generated method is namedautowireServices()instead, so parent injection is not silently overridden.autowire()method rather than creating a second one.Previously the child got its own
__construct()with noparent::__construct()call at all, which broke the parent's dependencies at runtime — see the updatedchild_of_parent_with_private_promoted_property.php.incfixture.