Updated Rector to commit 912d0b7ecc78aae4cbc2f3df7992fab9b5c63014

912d0b7ecc [PhpParser] Remove regex check single line spaces before <?php on FileProcessor (#6525)
This commit is contained in:
Tomas Votruba 2024-12-01 16:55:27 +00:00
parent cce6781c15
commit f4499090a2
17 changed files with 463 additions and 66 deletions

View File

@ -2237,8 +2237,12 @@ return array(
'Rector\\Symfony\\DataProvider\\ServiceMapProvider' => $vendorDir . '/rector/rector-symfony/src/DataProvider/ServiceMapProvider.php',
'Rector\\Symfony\\DataProvider\\ServiceNameToTypeUniqueProvider' => $vendorDir . '/rector/rector-symfony/src/DataProvider/ServiceNameToTypeUniqueProvider.php',
'Rector\\Symfony\\DependencyInjection\\NodeDecorator\\CommandConstructorDecorator' => $vendorDir . '/rector/rector-symfony/rules/DependencyInjection/NodeDecorator/CommandConstructorDecorator.php',
'Rector\\Symfony\\DependencyInjection\\NodeFactory\\AutowireClassMethodFactory' => $vendorDir . '/rector/rector-symfony/rules/DependencyInjection/NodeFactory/AutowireClassMethodFactory.php',
'Rector\\Symfony\\DependencyInjection\\Rector\\Class_\\CommandGetByTypeToConstructorInjectionRector' => $vendorDir . '/rector/rector-symfony/rules/DependencyInjection/Rector/Class_/CommandGetByTypeToConstructorInjectionRector.php',
'Rector\\Symfony\\DependencyInjection\\Rector\\Class_\\ControllerGetByTypeToConstructorInjectionRector' => $vendorDir . '/rector/rector-symfony/rules/DependencyInjection/Rector/Class_/ControllerGetByTypeToConstructorInjectionRector.php',
'Rector\\Symfony\\DependencyInjection\\Rector\\Class_\\GetBySymfonyStringToConstructorInjectionRector' => $vendorDir . '/rector/rector-symfony/rules/DependencyInjection/Rector/Class_/GetBySymfonyStringToConstructorInjectionRector.php',
'Rector\\Symfony\\DependencyInjection\\Rector\\Trait_\\TraitGetByTypeToInjectRector' => $vendorDir . '/rector/rector-symfony/rules/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector.php',
'Rector\\Symfony\\DependencyInjection\\ThisGetTypeMatcher' => $vendorDir . '/rector/rector-symfony/rules/DependencyInjection/ThisGetTypeMatcher.php',
'Rector\\Symfony\\DowngradeSymfony70\\Rector\\Class_\\DowngradeSymfonyCommandAttributeRector' => $vendorDir . '/rector/rector-symfony/rules/DowngradeSymfony70/Rector/Class_/DowngradeSymfonyCommandAttributeRector.php',
'Rector\\Symfony\\Enum\\SensioAttribute' => $vendorDir . '/rector/rector-symfony/src/Enum/SensioAttribute.php',
'Rector\\Symfony\\Enum\\SymfonyAnnotation' => $vendorDir . '/rector/rector-symfony/src/Enum/SymfonyAnnotation.php',

View File

@ -2456,8 +2456,12 @@ class ComposerStaticInitc12d7e0a7ec6f5f877903ca571cd9ab7
'Rector\\Symfony\\DataProvider\\ServiceMapProvider' => __DIR__ . '/..' . '/rector/rector-symfony/src/DataProvider/ServiceMapProvider.php',
'Rector\\Symfony\\DataProvider\\ServiceNameToTypeUniqueProvider' => __DIR__ . '/..' . '/rector/rector-symfony/src/DataProvider/ServiceNameToTypeUniqueProvider.php',
'Rector\\Symfony\\DependencyInjection\\NodeDecorator\\CommandConstructorDecorator' => __DIR__ . '/..' . '/rector/rector-symfony/rules/DependencyInjection/NodeDecorator/CommandConstructorDecorator.php',
'Rector\\Symfony\\DependencyInjection\\NodeFactory\\AutowireClassMethodFactory' => __DIR__ . '/..' . '/rector/rector-symfony/rules/DependencyInjection/NodeFactory/AutowireClassMethodFactory.php',
'Rector\\Symfony\\DependencyInjection\\Rector\\Class_\\CommandGetByTypeToConstructorInjectionRector' => __DIR__ . '/..' . '/rector/rector-symfony/rules/DependencyInjection/Rector/Class_/CommandGetByTypeToConstructorInjectionRector.php',
'Rector\\Symfony\\DependencyInjection\\Rector\\Class_\\ControllerGetByTypeToConstructorInjectionRector' => __DIR__ . '/..' . '/rector/rector-symfony/rules/DependencyInjection/Rector/Class_/ControllerGetByTypeToConstructorInjectionRector.php',
'Rector\\Symfony\\DependencyInjection\\Rector\\Class_\\GetBySymfonyStringToConstructorInjectionRector' => __DIR__ . '/..' . '/rector/rector-symfony/rules/DependencyInjection/Rector/Class_/GetBySymfonyStringToConstructorInjectionRector.php',
'Rector\\Symfony\\DependencyInjection\\Rector\\Trait_\\TraitGetByTypeToInjectRector' => __DIR__ . '/..' . '/rector/rector-symfony/rules/DependencyInjection/Rector/Trait_/TraitGetByTypeToInjectRector.php',
'Rector\\Symfony\\DependencyInjection\\ThisGetTypeMatcher' => __DIR__ . '/..' . '/rector/rector-symfony/rules/DependencyInjection/ThisGetTypeMatcher.php',
'Rector\\Symfony\\DowngradeSymfony70\\Rector\\Class_\\DowngradeSymfonyCommandAttributeRector' => __DIR__ . '/..' . '/rector/rector-symfony/rules/DowngradeSymfony70/Rector/Class_/DowngradeSymfonyCommandAttributeRector.php',
'Rector\\Symfony\\Enum\\SensioAttribute' => __DIR__ . '/..' . '/rector/rector-symfony/src/Enum/SensioAttribute.php',
'Rector\\Symfony\\Enum\\SymfonyAnnotation' => __DIR__ . '/..' . '/rector/rector-symfony/src/Enum/SymfonyAnnotation.php',

View File

@ -1868,12 +1868,12 @@
"source": {
"type": "git",
"url": "https:\/\/github.com\/rectorphp\/rector-symfony.git",
"reference": "617b3aff39d3ae14e5ea24ad5150fb4d0fc4a05e"
"reference": "1138f045e2a27f9b069a3e512a04e6d49e04a596"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-symfony\/zipball\/617b3aff39d3ae14e5ea24ad5150fb4d0fc4a05e",
"reference": "617b3aff39d3ae14e5ea24ad5150fb4d0fc4a05e",
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-symfony\/zipball\/1138f045e2a27f9b069a3e512a04e6d49e04a596",
"reference": "1138f045e2a27f9b069a3e512a04e6d49e04a596",
"shasum": ""
},
"require": {
@ -1898,7 +1898,7 @@
"tomasvotruba\/class-leak": "^1.0",
"tracy\/tracy": "^2.10"
},
"time": "2024-12-01T14:07:35+00:00",
"time": "2024-12-01T16:51:24+00:00",
"default-branch": true,
"type": "rector-extension",
"extra": {

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,7 @@ namespace Rector\RectorInstaller;
*/
final class GeneratedConfig
{
public const EXTENSIONS = array('rector/rector-doctrine' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => NULL, 'version' => 'dev-main 02ae401'), 'rector/rector-downgrade-php' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-downgrade-php', 'relative_install_path' => '../../rector-downgrade-php', 'extra' => NULL, 'version' => 'dev-main 7bb52fb'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => NULL, 'version' => 'dev-main a506b2c'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => NULL, 'version' => 'dev-main 617b3af'));
public const EXTENSIONS = array('rector/rector-doctrine' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => NULL, 'version' => 'dev-main 02ae401'), 'rector/rector-downgrade-php' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-downgrade-php', 'relative_install_path' => '../../rector-downgrade-php', 'extra' => NULL, 'version' => 'dev-main 7bb52fb'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => NULL, 'version' => 'dev-main a506b2c'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => NULL, 'version' => 'dev-main 1138f04'));
private function __construct()
{
}

View File

@ -4,16 +4,20 @@ declare (strict_types=1);
namespace RectorPrefix202412;
use Rector\Config\RectorConfig;
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;
use Rector\Symfony\Symfony42\Rector\MethodCall\ContainerGetToConstructorInjectionRector;
return static function (RectorConfig $rectorConfig) : void {
$rectorConfig->rules([
// modern step-by-step narrow approach
\Rector\Symfony\DependencyInjection\Rector\Class_\ControllerGetByTypeToConstructorInjectionRector::class,
\Rector\Symfony\DependencyInjection\Rector\Class_\CommandGetByTypeToConstructorInjectionRector::class,
ControllerGetByTypeToConstructorInjectionRector::class,
CommandGetByTypeToConstructorInjectionRector::class,
GetBySymfonyStringToConstructorInjectionRector::class,
TraitGetByTypeToInjectRector::class,
// legacy rules that require container fetch
ContainerGetToConstructorInjectionRector::class,
ContainerGetNameToTypeInTestsRector::class,
GetToConstructorInjectionRector::class,
]);

View File

@ -16,7 +16,6 @@ use Rector\Removing\ValueObject\ArgumentRemover;
use Rector\Renaming\Rector\MethodCall\RenameMethodRector;
use Rector\Renaming\Rector\Name\RenameClassRector;
use Rector\Renaming\ValueObject\MethodCallRename;
use Rector\Symfony\Symfony42\Rector\MethodCall\ContainerGetToConstructorInjectionRector;
use Rector\Symfony\Symfony42\Rector\New_\RootNodeTreeBuilderRector;
use Rector\Symfony\Symfony42\Rector\New_\StringToArrayArgumentProcessRector;
use Rector\Transform\Rector\ClassMethod\WrapReturnRector;
@ -39,11 +38,11 @@ return static function (RectorConfig $rectorConfig) : void {
'Symfony\\Bundle\\FrameworkBundle\\Command\\ContainerAwareCommand' => 'Symfony\\Component\\Console\\Command\\Command',
'Symfony\\Component\\Translation\\TranslatorInterface' => 'Symfony\\Contracts\\Translation\\TranslatorInterface',
]);
# related to "Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand" deprecation, @see https://github.com/rectorphp/rector/issues/1629
$rectorConfig->rule(ContainerGetToConstructorInjectionRector::class);
$rectorConfig->rules([
# https://symfony.com/blog/new-in-symfony-4-2-important-deprecations
$rectorConfig->rule(StringToArrayArgumentProcessRector::class);
$rectorConfig->rule(RootNodeTreeBuilderRector::class);
StringToArrayArgumentProcessRector::class,
RootNodeTreeBuilderRector::class,
]);
$rectorConfig->ruleWithConfiguration(ArgumentAdderRector::class, [new ArgumentAdder('Symfony\\Component\\DomCrawler\\Crawler', 'children', 0, null, null, null, ArgumentAddingScope::SCOPE_METHOD_CALL), new ArgumentAdder('Symfony\\Component\\Finder\\Finder', 'sortByName', 0, null, \false, null, ArgumentAddingScope::SCOPE_METHOD_CALL), new ArgumentAdder('Symfony\\Bridge\\Monolog\\Processor\\DebugProcessor', 'getLogs', 0, null, null, null, ArgumentAddingScope::SCOPE_METHOD_CALL), new ArgumentAdder('Symfony\\Bridge\\Monolog\\Processor\\DebugProcessor', 'countErrors', 0, 'default_value', null, null, ArgumentAddingScope::SCOPE_METHOD_CALL), new ArgumentAdder('Symfony\\Bridge\\Monolog\\Logger', 'getLogs', 0, 'default_value', null, null, ArgumentAddingScope::SCOPE_METHOD_CALL), new ArgumentAdder('Symfony\\Bridge\\Monolog\\Logger', 'countErrors', 0, 'default_value', null, null, ArgumentAddingScope::SCOPE_METHOD_CALL), new ArgumentAdder('Symfony\\Component\\Serializer\\Normalizer', 'handleCircularReference', 1, null, null, null, ArgumentAddingScope::SCOPE_METHOD_CALL), new ArgumentAdder('Symfony\\Component\\Serializer\\Normalizer', 'handleCircularReference', 2, null, null, null, ArgumentAddingScope::SCOPE_METHOD_CALL)]);
$rectorConfig->ruleWithConfiguration(RenameMethodRector::class, [new MethodCallRename('Symfony\\Component\\Cache\\CacheItem', 'getPreviousTags', 'getMetadata'), new MethodCallRename('Symfony\\Component\\Form\\AbstractTypeExtension', 'getExtendedType', 'getExtendedTypes')]);
$iterableType = new IterableType(new MixedType(), new MixedType());

View File

@ -13,6 +13,9 @@ use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\ValueObject\MethodName;
final class CommandConstructorDecorator
{
/**
* @readonly
*/
private NodeTypeResolver $nodeTypeResolver;
public function __construct(NodeTypeResolver $nodeTypeResolver)
{

View File

@ -0,0 +1,59 @@
<?php
declare (strict_types=1);
namespace Rector\Symfony\DependencyInjection\NodeFactory;
use PhpParser\Comment\Doc;
use PhpParser\Modifiers;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Trait_;
use PHPStan\Type\ObjectType;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\PostRector\ValueObject\PropertyMetadata;
final class AutowireClassMethodFactory
{
/**
* @readonly
*/
private NodeNameResolver $nodeNameResolver;
public function __construct(NodeNameResolver $nodeNameResolver)
{
$this->nodeNameResolver = $nodeNameResolver;
}
/**
* @param PropertyMetadata[] $propertyMetadatas
*/
public function create(Trait_ $trait, array $propertyMetadatas) : ClassMethod
{
$traitName = $this->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;
}
}

View File

@ -4,7 +4,6 @@ declare (strict_types=1);
namespace Rector\Symfony\DependencyInjection\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Reflection\ClassReflection;
@ -15,6 +14,7 @@ use Rector\PostRector\ValueObject\PropertyMetadata;
use Rector\Rector\AbstractRector;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
use Rector\Symfony\DependencyInjection\NodeDecorator\CommandConstructorDecorator;
use Rector\Symfony\DependencyInjection\ThisGetTypeMatcher;
use Rector\Symfony\Enum\SymfonyClass;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -35,11 +35,16 @@ final class CommandGetByTypeToConstructorInjectionRector extends AbstractRector
* @readonly
*/
private CommandConstructorDecorator $commandConstructorDecorator;
public function __construct(ClassDependencyManipulator $classDependencyManipulator, PropertyNaming $propertyNaming, CommandConstructorDecorator $commandConstructorDecorator)
/**
* @readonly
*/
private ThisGetTypeMatcher $thisGetTypeMatcher;
public function __construct(ClassDependencyManipulator $classDependencyManipulator, PropertyNaming $propertyNaming, CommandConstructorDecorator $commandConstructorDecorator, ThisGetTypeMatcher $thisGetTypeMatcher)
{
$this->classDependencyManipulator = $classDependencyManipulator;
$this->propertyNaming = $propertyNaming;
$this->commandConstructorDecorator = $commandConstructorDecorator;
$this->thisGetTypeMatcher = $thisGetTypeMatcher;
}
public function getRuleDefinition() : RuleDefinition
{
@ -91,27 +96,7 @@ CODE_SAMPLE
if (!$node instanceof MethodCall) {
return null;
}
if ($node->isFirstClassCallable()) {
return null;
}
if (!$this->isName($node->name, 'get')) {
return null;
}
if (!$this->isName($node->var, 'this')) {
return null;
}
if (\count($node->getArgs()) !== 1) {
return null;
}
$firstArg = $node->getArgs()[0];
if (!$firstArg->value instanceof ClassConstFetch) {
return null;
}
// must be class const fetch
if (!$this->isName($firstArg->value->name, 'class')) {
return null;
}
$className = $this->getName($firstArg->value->class);
$className = $this->thisGetTypeMatcher->match($node);
if (!\is_string($className)) {
return null;
}

View File

@ -4,7 +4,6 @@ declare (strict_types=1);
namespace Rector\Symfony\DependencyInjection\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Reflection\ClassReflection;
@ -14,6 +13,7 @@ use Rector\PHPStan\ScopeFetcher;
use Rector\PostRector\ValueObject\PropertyMetadata;
use Rector\Rector\AbstractRector;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
use Rector\Symfony\DependencyInjection\ThisGetTypeMatcher;
use Rector\Symfony\Enum\SymfonyClass;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -30,10 +30,15 @@ final class ControllerGetByTypeToConstructorInjectionRector extends AbstractRect
* @readonly
*/
private PropertyNaming $propertyNaming;
public function __construct(ClassDependencyManipulator $classDependencyManipulator, PropertyNaming $propertyNaming)
/**
* @readonly
*/
private ThisGetTypeMatcher $thisGetTypeMatcher;
public function __construct(ClassDependencyManipulator $classDependencyManipulator, PropertyNaming $propertyNaming, ThisGetTypeMatcher $thisGetTypeMatcher)
{
$this->classDependencyManipulator = $classDependencyManipulator;
$this->propertyNaming = $propertyNaming;
$this->thisGetTypeMatcher = $thisGetTypeMatcher;
}
public function getRuleDefinition() : RuleDefinition
{
@ -85,27 +90,7 @@ CODE_SAMPLE
if (!$node instanceof MethodCall) {
return null;
}
if ($node->isFirstClassCallable()) {
return null;
}
if (!$this->isName($node->name, 'get')) {
return null;
}
if (!$this->isName($node->var, 'this')) {
return null;
}
if (\count($node->getArgs()) !== 1) {
return null;
}
$firstArg = $node->getArgs()[0];
if (!$firstArg->value instanceof ClassConstFetch) {
return null;
}
// must be class const fetch
if (!$this->isName($firstArg->value->name, 'class')) {
return null;
}
$className = $this->getName($firstArg->value->class);
$className = $this->thisGetTypeMatcher->match($node);
if (!\is_string($className)) {
return null;
}

View File

@ -0,0 +1,129 @@
<?php
declare (strict_types=1);
namespace Rector\Symfony\DependencyInjection\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Reflection\ClassReflection;
use Rector\Naming\Naming\PropertyNaming;
use Rector\NodeManipulator\ClassDependencyManipulator;
use Rector\PHPStan\ScopeFetcher;
use Rector\PostRector\ValueObject\PropertyMetadata;
use Rector\Rector\AbstractRector;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
use Rector\Symfony\DependencyInjection\ThisGetTypeMatcher;
use Rector\Symfony\Enum\SymfonyClass;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Symfony\Tests\DependencyInjection\Rector\Class_\GetBySymfonyStringToConstructorInjectionRector\GetBySymfonyStringToConstructorInjectionRectorTest
*/
final class GetBySymfonyStringToConstructorInjectionRector extends AbstractRector
{
/**
* @readonly
*/
private ClassDependencyManipulator $classDependencyManipulator;
/**
* @readonly
*/
private ThisGetTypeMatcher $thisGetTypeMatcher;
/**
* @readonly
*/
private PropertyNaming $propertyNaming;
/**
* @var array<string, string>
*/
private const SYMFONY_NAME_TO_TYPE_MAP = ['validator' => SymfonyClass::VALIDATOR_INTERFACE, 'event_dispatcher' => SymfonyClass::EVENT_DISPATCHER_INTERFACE, 'logger' => SymfonyClass::LOGGER_INTERFACE, 'jms_serializer' => SymfonyClass::SERIALIZER_INTERFACE];
public function __construct(ClassDependencyManipulator $classDependencyManipulator, ThisGetTypeMatcher $thisGetTypeMatcher, PropertyNaming $propertyNaming)
{
$this->classDependencyManipulator = $classDependencyManipulator;
$this->thisGetTypeMatcher = $thisGetTypeMatcher;
$this->propertyNaming = $propertyNaming;
}
public function getRuleDefinition() : RuleDefinition
{
return new RuleDefinition('Converts typical Symfony services like $this->get("validator") in commands/controllers to constructor injection (step 3/x)', [new CodeSample(<<<'CODE_SAMPLE'
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
final class SomeController extends Controller
{
public function someMethod()
{
$someType = $this->get('validator');
}
}
CODE_SAMPLE
, <<<'CODE_SAMPLE'
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Validator\Validator\ValidatorInterface;
final class SomeController extends Controller
{
public function __construct(private ValidatorInterface $validator)
public function someMethod()
{
$someType = $this->validator;
}
}
CODE_SAMPLE
)]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes() : array
{
return [Class_::class];
}
/**
* @param Class_ $node
*/
public function refactor(Node $node) : ?Node
{
if ($this->shouldSkipClass($node)) {
return null;
}
$propertyMetadatas = [];
$this->traverseNodesWithCallable($node, function (Node $node) use(&$propertyMetadatas) : ?Node {
if (!$node instanceof MethodCall) {
return null;
}
$serviceName = $this->thisGetTypeMatcher->matchString($node);
if (!\is_string($serviceName)) {
return null;
}
$serviceType = self::SYMFONY_NAME_TO_TYPE_MAP[$serviceName] ?? null;
if ($serviceType === null) {
return null;
}
$propertyName = $this->propertyNaming->fqnToVariableName($serviceType);
$propertyMetadata = new PropertyMetadata($propertyName, new FullyQualifiedObjectType($serviceType));
$propertyMetadatas[] = $propertyMetadata;
return $this->nodeFactory->createPropertyFetch('this', $propertyMetadata->getName());
});
if ($propertyMetadatas === []) {
return null;
}
foreach ($propertyMetadatas as $propertyMetadata) {
$this->classDependencyManipulator->addConstructorDependency($node, $propertyMetadata);
}
return $node;
}
private function shouldSkipClass(Class_ $class) : bool
{
$scope = ScopeFetcher::fetch($class);
$classReflection = $scope->getClassReflection();
if (!$classReflection instanceof ClassReflection) {
return \true;
}
if ($classReflection->isSubclassOf(SymfonyClass::CONTAINER_AWARE_COMMAND)) {
return \false;
}
return !$classReflection->isSubclassOf(SymfonyClass::CONTROLLER);
}
}

View File

@ -0,0 +1,132 @@
<?php
declare (strict_types=1);
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\Param;
use PhpParser\Node\PropertyItem;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\Trait_;
use PHPStan\Type\ObjectType;
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
*/
final class TraitGetByTypeToInjectRector extends AbstractRector
{
/**
* @readonly
*/
private PropertyNaming $propertyNaming;
/**
* @readonly
*/
private ThisGetTypeMatcher $thisGetTypeMatcher;
/**
* @readonly
*/
private AutowireClassMethodFactory $autowireClassMethodFactory;
public function __construct(PropertyNaming $propertyNaming, ThisGetTypeMatcher $thisGetTypeMatcher, AutowireClassMethodFactory $autowireClassMethodFactory)
{
$this->propertyNaming = $propertyNaming;
$this->thisGetTypeMatcher = $thisGetTypeMatcher;
$this->autowireClassMethodFactory = $autowireClassMethodFactory;
}
public function getRuleDefinition() : RuleDefinition
{
return new RuleDefinition('From `$this->get(SomeType::class)` in traits, to autowired method with @required', [new CodeSample(<<<'CODE_SAMPLE'
// must be used in old Controller class
trait SomeInjects
{
public function someMethod()
{
return $this->get(SomeType::class);
}
}
CODE_SAMPLE
, <<<'CODE_SAMPLE'
trait SomeInjects
{
private SomeType $someType;
/**
* @required
*/
public function autowireSomeInjects(SomeType $someType): void
{
$this->someType = $someType;
}
public function someMethod()
{
return $this->someType;
}
}
CODE_SAMPLE
)]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes() : array
{
return [Trait_::class];
}
/**
* @param Trait_ $node
*/
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;
}
}

View File

@ -0,0 +1,70 @@
<?php
declare (strict_types=1);
namespace Rector\Symfony\DependencyInjection;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Scalar\String_;
use Rector\NodeNameResolver\NodeNameResolver;
final class ThisGetTypeMatcher
{
/**
* @readonly
*/
private NodeNameResolver $nodeNameResolver;
public function __construct(NodeNameResolver $nodeNameResolver)
{
$this->nodeNameResolver = $nodeNameResolver;
}
public function matchString(MethodCall $methodCall) : ?string
{
$getExpr = $this->matchGetExpr($methodCall);
if (!$getExpr instanceof String_) {
return null;
}
return $getExpr->value;
}
public function match(MethodCall $methodCall) : ?string
{
$getExpr = $this->matchGetExpr($methodCall);
if (!$getExpr instanceof ClassConstFetch) {
return null;
}
// must be class const fetch
if (!$this->nodeNameResolver->isName($getExpr->name, 'class')) {
return null;
}
return $this->nodeNameResolver->getName($getExpr->class);
}
private function isValidContainerCall(MethodCall $methodCall) : bool
{
if ($methodCall->var instanceof MethodCall && $this->nodeNameResolver->isName($methodCall->var->name, 'getContainer')) {
return \true;
}
if ($methodCall->var instanceof Variable && $this->nodeNameResolver->isName($methodCall->var, 'this')) {
return \true;
}
return $methodCall->var instanceof PropertyFetch && $this->nodeNameResolver->isName($methodCall->var->var, 'this') && $this->nodeNameResolver->isName($methodCall->var->name, 'container');
}
private function matchGetExpr(MethodCall $methodCall) : ?Expr
{
if ($methodCall->isFirstClassCallable()) {
return null;
}
if (!$this->nodeNameResolver->isName($methodCall->name, 'get')) {
return null;
}
if (!$this->isValidContainerCall($methodCall)) {
return null;
}
if (\count($methodCall->getArgs()) !== 1) {
return null;
}
$firstArg = $methodCall->getArgs()[0];
return $firstArg->value;
}
}

View File

@ -8,6 +8,7 @@ use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Type\ObjectType;
use Rector\Configuration\Deprecation\Contract\DeprecatedInterface;
use Rector\NodeManipulator\ClassDependencyManipulator;
use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer;
use Rector\PostRector\ValueObject\PropertyMetadata;
@ -19,9 +20,9 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* Ref: https://github.com/symfony/symfony/blob/master/UPGRADE-4.0.md#console
*
* @see \Rector\Symfony\Tests\Symfony42\Rector\MethodCall\ContainerGetToConstructorInjectionRector\ContainerGetToConstructorInjectionRectorTest
* @deprecated This rule is deprecated as too vague and causing too many changes. Use more granular @see \Rector\Symfony\Set\SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION instead
*/
final class ContainerGetToConstructorInjectionRector extends AbstractRector
final class ContainerGetToConstructorInjectionRector extends AbstractRector implements DeprecatedInterface
{
/**
* @readonly

View File

@ -34,7 +34,10 @@ final class ConvertRenderTemplateShortNotationToBundleSyntaxRector extends Abstr
public function getRuleDefinition() : RuleDefinition
{
return new RuleDefinition('Change Twig template short name to bundle syntax in render calls from controllers', [new CodeSample(<<<'CODE_SAMPLE'
class BaseController extends Controller {
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class BaseController extends Controller
{
function indexAction()
{
$this->render('appBundle:Landing\Main:index.html.twig');
@ -42,7 +45,10 @@ class BaseController extends Controller {
}
CODE_SAMPLE
, <<<'CODE_SAMPLE'
class BaseController extends Controller {
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class BaseController extends Controller
{
function indexAction()
{
$this->render('@app/Landing/Main/index.html.twig');

View File

@ -21,4 +21,20 @@ final class SymfonyClass
* @var string
*/
public const CONTAINER_AWARE_COMMAND = 'Symfony\\Bundle\\FrameworkBundle\\Command\\ContainerAwareCommand';
/**
* @var string
*/
public const EVENT_DISPATCHER_INTERFACE = 'Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface';
/**
* @var string
*/
public const VALIDATOR_INTERFACE = 'Symfony\\Component\\Validator\\Validator\\ValidatorInterface';
/**
* @var string
*/
public const LOGGER_INTERFACE = 'Psr\\Log\\LoggerInterface';
/**
* @var string
*/
public const SERIALIZER_INTERFACE = 'JMS\\Serializer\\SerializerInterface';
}