From 1b2c3cbd329a0c86ceee843010864c6a71c53b1c Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 3 Aug 2026 23:34:01 +0200 Subject: [PATCH] [DependencyInjection] Deprecate TraitGetByTypeToInjectRector A trait has no context about the class it is used in, so the $this->get() call cannot be safely resolved to a constructor/autowired injection. The rule was built for a single custom project and does not generalize. Also removes the now-unused AutowireClassMethodFactory and drops the rule from the symfony-constructor-injection set. --- .../symfony/symfony-constructor-injection.php | 2 - .../Fixture/trait_get_type.php.inc | 39 --------- .../Source/SomeService.php | 7 -- .../TraitGetByTypeToInjectRectorTest.php | 28 ------- .../config/configured_rule.php | 10 --- .../AutowireClassMethodFactory.php | 69 --------------- .../Trait_/TraitGetByTypeToInjectRector.php | 84 ++----------------- 7 files changed, 7 insertions(+), 232 deletions(-) delete mode 100644 rules-tests/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector/Fixture/trait_get_type.php.inc delete mode 100644 rules-tests/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector/Source/SomeService.php delete mode 100644 rules-tests/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector/TraitGetByTypeToInjectRectorTest.php delete mode 100644 rules-tests/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector/config/configured_rule.php delete mode 100644 rules/DependencyInjection/NodeFactory/AutowireClassMethodFactory.php diff --git a/config/sets/symfony/symfony-constructor-injection.php b/config/sets/symfony/symfony-constructor-injection.php index ac31ffc46..85385c136 100644 --- a/config/sets/symfony/symfony-constructor-injection.php +++ b/config/sets/symfony/symfony-constructor-injection.php @@ -6,7 +6,6 @@ use Rector\Symfony\DependencyInjection\Rector\Class_\CommandGetByTypeToConstructorInjectionRector; use Rector\Symfony\DependencyInjection\Rector\Class_\ControllerGetByTypeToConstructorInjectionRector; use Rector\Symfony\DependencyInjection\Rector\Class_\GetBySymfonyStringToConstructorInjectionRector; -use Rector\Symfony\DependencyInjection\Rector\Trait_\TraitGetByTypeToInjectRector; use Rector\Symfony\Symfony28\Rector\MethodCall\GetToConstructorInjectionRector; use Rector\Symfony\Symfony34\Rector\Closure\ContainerGetNameToTypeInTestsRector; @@ -16,7 +15,6 @@ ControllerGetByTypeToConstructorInjectionRector::class, CommandGetByTypeToConstructorInjectionRector::class, GetBySymfonyStringToConstructorInjectionRector::class, - TraitGetByTypeToInjectRector::class, // legacy rules that require container fetch ContainerGetNameToTypeInTestsRector::class, diff --git a/rules-tests/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector/Fixture/trait_get_type.php.inc b/rules-tests/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector/Fixture/trait_get_type.php.inc deleted file mode 100644 index 3474ffbb6..000000000 --- a/rules-tests/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector/Fixture/trait_get_type.php.inc +++ /dev/null @@ -1,39 +0,0 @@ -get(SomeService::class); - } -} - -?> ------ -someService = $someService; - } - public function configure() - { - $someType = $this->someService; - } -} - -?> diff --git a/rules-tests/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector/Source/SomeService.php b/rules-tests/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector/Source/SomeService.php deleted file mode 100644 index 453494d69..000000000 --- a/rules-tests/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector/Source/SomeService.php +++ /dev/null @@ -1,7 +0,0 @@ -doTestFile($filePath); - } - - public static function provideData(): Iterator - { - return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); - } - - public function provideConfigFilePath(): string - { - return __DIR__ . '/config/configured_rule.php'; - } -} diff --git a/rules-tests/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector/config/configured_rule.php b/rules-tests/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector/config/configured_rule.php deleted file mode 100644 index 1f622e667..000000000 --- a/rules-tests/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector/config/configured_rule.php +++ /dev/null @@ -1,10 +0,0 @@ -rule(TraitGetByTypeToInjectRector::class); -}; diff --git a/rules/DependencyInjection/NodeFactory/AutowireClassMethodFactory.php b/rules/DependencyInjection/NodeFactory/AutowireClassMethodFactory.php deleted file mode 100644 index ffe545a95..000000000 --- a/rules/DependencyInjection/NodeFactory/AutowireClassMethodFactory.php +++ /dev/null @@ -1,69 +0,0 @@ -nodeNameResolver->getShortName($trait); - - $autowireClassMethod = new ClassMethod('autowire' . $traitName); - $autowireClassMethod->flags |= Modifiers::PUBLIC; - $autowireClassMethod->returnType = new Identifier('void'); - $autowireClassMethod->setDocComment(new Doc("/**\n * @required\n */")); - - foreach ($propertyMetadatas as $propertyMetadata) { - $param = $this->createAutowiredParam($propertyMetadata); - $autowireClassMethod->params[] = $param; - - $createPropertyAssign = new Assign( - new PropertyFetch(new Variable('this'), new Identifier($propertyMetadata->getName())), - new Variable($propertyMetadata->getName()) - ); - $autowireClassMethod->stmts[] = new Expression($createPropertyAssign); - } - - return $autowireClassMethod; - } - - private function createAutowiredParam(PropertyMetadata $propertyMetadata): Param - { - $param = new Param(new Variable($propertyMetadata->getName())); - $objectType = $propertyMetadata->getType(); - if (! $objectType instanceof ObjectType) { - throw new ShouldNotHappenException(); - } - - $param->type = new FullyQualified($objectType->getClassName()); - - return $param; - } -} diff --git a/rules/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector.php b/rules/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector.php index febf5e273..b83ceeed3 100644 --- a/rules/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector.php +++ b/rules/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector.php @@ -4,36 +4,19 @@ namespace Rector\Symfony\DependencyInjection\Rector\Trait_; -use PhpParser\Modifiers; use PhpParser\Node; -use PhpParser\Node\Expr\MethodCall; -use PhpParser\Node\Name\FullyQualified; -use PhpParser\Node\PropertyItem; -use PhpParser\Node\Stmt\Property; use PhpParser\Node\Stmt\Trait_; -use PHPStan\Type\ObjectType; +use Rector\Configuration\Deprecation\Contract\DeprecatedInterface; use Rector\Exception\ShouldNotHappenException; -use Rector\Naming\Naming\PropertyNaming; -use Rector\PostRector\ValueObject\PropertyMetadata; use Rector\Rector\AbstractRector; -use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType; -use Rector\Symfony\DependencyInjection\NodeFactory\AutowireClassMethodFactory; -use Rector\Symfony\DependencyInjection\ThisGetTypeMatcher; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** - * @see \Rector\Symfony\Tests\DependencyInjection\Rector\Trait_\TraitGetByTypeToInjectRector\TraitGetByTypeToInjectRectorTest + * @deprecated A trait has no context about the class it is used in, so the `$this->get()` call cannot be safely resolved. This rule was made for a single custom project and does not generalize. */ -final class TraitGetByTypeToInjectRector extends AbstractRector +final class TraitGetByTypeToInjectRector extends AbstractRector implements DeprecatedInterface { - public function __construct( - private readonly PropertyNaming $propertyNaming, - private readonly ThisGetTypeMatcher $thisGetTypeMatcher, - private readonly AutowireClassMethodFactory $autowireClassMethodFactory, - ) { - } - public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( @@ -88,62 +71,9 @@ public function getNodeTypes(): array */ public function refactor(Node $node): ?Node { - $propertyMetadatas = []; - - $this->traverseNodesWithCallable($node, function (Node $node) use (&$propertyMetadatas): ?Node { - if (! $node instanceof MethodCall) { - return null; - } - - $className = $this->thisGetTypeMatcher->match($node); - if (! is_string($className)) { - return null; - } - - $propertyName = $this->propertyNaming->fqnToVariableName($className); - $propertyMetadata = new PropertyMetadata($propertyName, new FullyQualifiedObjectType($className)); - - $propertyMetadatas[] = $propertyMetadata; - return $this->nodeFactory->createPropertyFetch('this', $propertyMetadata->getName()); - }); - - if ($propertyMetadatas === []) { - return null; - } - - // create local properties - - $autowiredProperties = $this->createAutowiredProperties($propertyMetadatas); - $autowireClassMethod = $this->autowireClassMethodFactory->create($node, $propertyMetadatas); - - $node->stmts = array_merge($autowiredProperties, [$autowireClassMethod], $node->stmts); - - return $node; - } - - /** - * @param PropertyMetadata[] $propertyMetadatas - * @return Property[] - */ - private function createAutowiredProperties(array $propertyMetadatas): array - { - $autowiredProperties = []; - - foreach ($propertyMetadatas as $propertyMetadata) { - $propertyType = $propertyMetadata->getType(); - if (! $propertyType instanceof ObjectType) { - throw new ShouldNotHappenException(); - } - - // create property - $autowiredProperties[] = new Property( - Modifiers::PRIVATE, - [new PropertyItem($propertyMetadata->getName())], - [], - new FullyQualified($propertyType->getClassName()) - ); - } - - return $autowiredProperties; + throw new ShouldNotHappenException(sprintf( + '"%s" is deprecated, as a trait has no context about the class it is used in. Handle the `$this->get()` calls in the using class instead.', + self::class + )); } }