Updated Rector to commit 390730a9c40cfad8ca6a089e2dee1b7e158e076e

390730a9c4 Remove propperty to add collector, add them directly or as a constructor dependency (#4131)
This commit is contained in:
Tomas Votruba 2023-06-09 10:52:53 +00:00
parent c0ebeabf68
commit ad74348451
25 changed files with 257 additions and 341 deletions

View File

@ -12,7 +12,6 @@ use Rector\PostRector\Contract\Rector\PostRectorDependencyInterface;
use Rector\PostRector\Contract\Rector\PostRectorInterface;
use Rector\PostRector\Rector\ClassRenamingPostRector;
use Rector\PostRector\Rector\NameImportingPostRector;
use Rector\PostRector\Rector\PropertyAddingPostRector;
use Rector\PostRector\Rector\UnusedImportRemovingPostRector;
use Rector\PostRector\Rector\UseAddingPostRector;
use Rector\Skipper\Skipper\Skipper;
@ -44,7 +43,6 @@ final class PostFileProcessor
// set order here
UseAddingPostRector $useAddingPostRector,
NameImportingPostRector $nameImportingPostRector,
PropertyAddingPostRector $propertyAddingPostRector,
ClassRenamingPostRector $classRenamingPostRector,
UnusedImportRemovingPostRector $unusedImportRemovingPostRector
)
@ -53,8 +51,6 @@ final class PostFileProcessor
$this->currentFileProvider = $currentFileProvider;
$this->currentRectorProvider = $currentRectorProvider;
$this->postRectors = [
// priority: 900
$propertyAddingPostRector,
// priority: 650
$classRenamingPostRector,
// priority: 600

View File

@ -1,46 +0,0 @@
<?php
declare (strict_types=1);
namespace Rector\PostRector\Collector;
use PhpParser\Node\Stmt\Class_;
use Rector\ChangesReporting\Collector\RectorChangeCollector;
use Rector\PostRector\Contract\Collector\NodeCollectorInterface;
use Rector\PostRector\ValueObject\PropertyMetadata;
/**
* @deprecated Use directly in the class
*/
final class PropertyToAddCollector implements NodeCollectorInterface
{
/**
* @readonly
* @var \Rector\ChangesReporting\Collector\RectorChangeCollector
*/
private $rectorChangeCollector;
/**
* @var array<string, PropertyMetadata[]>
*/
private $propertiesByClass = [];
public function __construct(RectorChangeCollector $rectorChangeCollector)
{
$this->rectorChangeCollector = $rectorChangeCollector;
}
public function isActive() : bool
{
return $this->propertiesByClass !== [];
}
public function addPropertyToClass(Class_ $class, PropertyMetadata $propertyMetadata) : void
{
$uniqueHash = \spl_object_hash($class);
$this->propertiesByClass[$uniqueHash][] = $propertyMetadata;
$this->rectorChangeCollector->notifyNodeFileInfo($class);
}
/**
* @return PropertyMetadata[]
*/
public function getPropertiesByClass(Class_ $class) : array
{
$classHash = \spl_object_hash($class);
return $this->propertiesByClass[$classHash] ?? [];
}
}

View File

@ -1,80 +0,0 @@
<?php
declare (strict_types=1);
namespace Rector\PostRector\Rector;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use Rector\Core\NodeAnalyzer\ClassAnalyzer;
use Rector\Core\NodeManipulator\ClassDependencyManipulator;
use Rector\PostRector\Collector\PropertyToAddCollector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* Adds new private properties to class + to constructor
*/
final class PropertyAddingPostRector extends \Rector\PostRector\Rector\AbstractPostRector
{
/**
* @readonly
* @var \Rector\Core\NodeManipulator\ClassDependencyManipulator
*/
private $classDependencyManipulator;
/**
* @readonly
* @var \Rector\PostRector\Collector\PropertyToAddCollector
*/
private $propertyToAddCollector;
/**
* @readonly
* @var \Rector\Core\NodeAnalyzer\ClassAnalyzer
*/
private $classAnalyzer;
public function __construct(ClassDependencyManipulator $classDependencyManipulator, PropertyToAddCollector $propertyToAddCollector, ClassAnalyzer $classAnalyzer)
{
$this->classDependencyManipulator = $classDependencyManipulator;
$this->propertyToAddCollector = $propertyToAddCollector;
$this->classAnalyzer = $classAnalyzer;
}
public function enterNode(Node $node) : ?Node
{
if (!$node instanceof Class_) {
return null;
}
if ($this->classAnalyzer->isAnonymousClass($node)) {
return null;
}
$this->addProperties($node);
return $node;
}
public function getRuleDefinition() : RuleDefinition
{
return new RuleDefinition('Add dependency properties', [new CodeSample(<<<'CODE_SAMPLE'
class SomeClass
{
public function run()
{
return $this->value;
}
}
CODE_SAMPLE
, <<<'CODE_SAMPLE'
class SomeClass
{
private $value;
public function run()
{
return $this->value;
}
}
CODE_SAMPLE
)]);
}
private function addProperties(Class_ $class) : void
{
$propertiesMetadatas = $this->propertyToAddCollector->getPropertiesByClass($class);
foreach ($propertiesMetadatas as $propertyMetadata) {
$this->classDependencyManipulator->addConstructorDependency($class, $propertyMetadata);
}
}
}

View File

@ -3,6 +3,7 @@
declare (strict_types=1);
namespace Rector\PostRector\ValueObject;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Type\Type;
final class PropertyMetadata
{
@ -20,8 +21,8 @@ final class PropertyMetadata
* @readonly
* @var int
*/
private $flags;
public function __construct(string $name, ?Type $type, int $flags)
private $flags = Class_::MODIFIER_PRIVATE;
public function __construct(string $name, ?Type $type, int $flags = Class_::MODIFIER_PRIVATE)
{
$this->name = $name;
$this->type = $type;

View File

@ -180,7 +180,7 @@ CODE_SAMPLE
if ($classReflection->hasProperty($propertyToComplete)) {
continue;
}
$propertyMetadata = new PropertyMetadata($propertyToComplete, new ObjectType($className), Class_::MODIFIER_PRIVATE);
$propertyMetadata = new PropertyMetadata($propertyToComplete, new ObjectType($className));
$hasClassContextProperty = $this->propertyPresenceChecker->hasClassContextProperty($class, $propertyMetadata);
if ($hasClassContextProperty) {
continue;

View File

@ -11,10 +11,10 @@ use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PHPStan\Type\ObjectType;
use Rector\Core\NodeManipulator\ClassDependencyManipulator;
use Rector\Core\PhpParser\Node\NodeFactory;
use Rector\Naming\Naming\PropertyNaming;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\PostRector\Collector\PropertyToAddCollector;
use Rector\PostRector\ValueObject\PropertyMetadata;
use Rector\Transform\NodeFactory\PropertyFetchFactory;
use Rector\Transform\NodeTypeAnalyzer\TypeProvidingExprFromClassResolver;
@ -47,17 +47,17 @@ final class FuncCallStaticCallToMethodCallAnalyzer
private $propertyFetchFactory;
/**
* @readonly
* @var \Rector\PostRector\Collector\PropertyToAddCollector
* @var \Rector\Core\NodeManipulator\ClassDependencyManipulator
*/
private $propertyToAddCollector;
public function __construct(TypeProvidingExprFromClassResolver $typeProvidingExprFromClassResolver, PropertyNaming $propertyNaming, NodeNameResolver $nodeNameResolver, NodeFactory $nodeFactory, PropertyFetchFactory $propertyFetchFactory, PropertyToAddCollector $propertyToAddCollector)
private $classDependencyManipulator;
public function __construct(TypeProvidingExprFromClassResolver $typeProvidingExprFromClassResolver, PropertyNaming $propertyNaming, NodeNameResolver $nodeNameResolver, NodeFactory $nodeFactory, PropertyFetchFactory $propertyFetchFactory, ClassDependencyManipulator $classDependencyManipulator)
{
$this->typeProvidingExprFromClassResolver = $typeProvidingExprFromClassResolver;
$this->propertyNaming = $propertyNaming;
$this->nodeNameResolver = $nodeNameResolver;
$this->nodeFactory = $nodeFactory;
$this->propertyFetchFactory = $propertyFetchFactory;
$this->propertyToAddCollector = $propertyToAddCollector;
$this->classDependencyManipulator = $classDependencyManipulator;
}
/**
* @return \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\PropertyFetch|\PhpParser\Node\Expr\Variable
@ -72,8 +72,7 @@ final class FuncCallStaticCallToMethodCallAnalyzer
return $expr;
}
$propertyName = $this->propertyNaming->fqnToVariableName($objectType);
$propertyMetadata = new PropertyMetadata($propertyName, $objectType, Class_::MODIFIER_PRIVATE);
$this->propertyToAddCollector->addPropertyToClass($class, $propertyMetadata);
$this->classDependencyManipulator->addConstructorDependency($class, new PropertyMetadata($propertyName, $objectType));
return $this->propertyFetchFactory->createFromType($objectType);
}
/**

View File

@ -9,7 +9,6 @@ use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Analyser\Scope;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Exception\ShouldNotHappenException;
@ -78,40 +77,46 @@ CODE_SAMPLE
*/
public function getNodeTypes() : array
{
return [StaticCall::class];
return [Class_::class];
}
/**
* @param StaticCall $node
* @param Class_ $node
*/
public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
$classLike = $this->betterNodeFinder->findParentType($node, Class_::class);
if (!$classLike instanceof Class_) {
return null;
$class = $node;
$hasChanged = \false;
foreach ($node->getMethods() as $classMethod) {
$this->traverseNodesWithCallable($classMethod, function (Node $node) use($class, $classMethod, &$hasChanged) {
if (!$node instanceof StaticCall) {
return null;
}
foreach ($this->staticCallsToMethodCalls as $staticCallToMethodCall) {
if (!$staticCallToMethodCall->isStaticCallMatch($node)) {
continue;
}
if ($classMethod->isStatic()) {
return $this->refactorToInstanceCall($node, $staticCallToMethodCall);
}
$expr = $this->funcCallStaticCallToMethodCallAnalyzer->matchTypeProvidingExpr($class, $classMethod, $staticCallToMethodCall->getClassObjectType());
if ($staticCallToMethodCall->getMethodName() === '*') {
$methodName = $this->getName($node->name);
} else {
$methodName = $staticCallToMethodCall->getMethodName();
}
if (!\is_string($methodName)) {
throw new ShouldNotHappenException();
}
$hasChanged = \true;
return new MethodCall($expr, $methodName, $node->args);
}
return $node;
});
}
$classMethod = $this->betterNodeFinder->findParentType($node, ClassMethod::class);
if (!$classMethod instanceof ClassMethod) {
return null;
if ($hasChanged) {
return $node;
}
foreach ($this->staticCallsToMethodCalls as $staticCallToMethodCall) {
if (!$staticCallToMethodCall->isStaticCallMatch($node)) {
continue;
}
if ($classMethod->isStatic()) {
return $this->refactorToInstanceCall($node, $staticCallToMethodCall);
}
$expr = $this->funcCallStaticCallToMethodCallAnalyzer->matchTypeProvidingExpr($classLike, $classMethod, $staticCallToMethodCall->getClassObjectType());
if ($staticCallToMethodCall->getMethodName() === '*') {
$methodName = $this->getName($node->name);
} else {
$methodName = $staticCallToMethodCall->getMethodName();
}
if (!\is_string($methodName)) {
throw new ShouldNotHappenException();
}
return new MethodCall($expr, $methodName, $node->args);
}
return $node;
return null;
}
/**
* @param mixed[] $configuration

View File

@ -19,12 +19,12 @@ final class VersionResolver
* @api
* @var string
*/
public const PACKAGE_VERSION = '2d13bc9773c3b7b91598312087c236c14b002d28';
public const PACKAGE_VERSION = '390730a9c40cfad8ca6a089e2dee1b7e158e076e';
/**
* @api
* @var string
*/
public const RELEASE_DATE = '2023-06-08 23:22:53';
public const RELEASE_DATE = '2023-06-09 11:49:08';
/**
* @var int
*/

View File

@ -15,7 +15,7 @@ final class RectorKernel
/**
* @var string
*/
private const CACHE_KEY = 'v77';
private const CACHE_KEY = 'v79';
/**
* @var \Symfony\Component\DependencyInjection\ContainerInterface|null
*/

2
vendor/autoload.php vendored
View File

@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) {
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitb5c263e2bdede23be55119fc17d4c292::getLoader();
return ComposerAutoloaderInit25989da06050fec2f81e0b951ae55419::getLoader();

View File

@ -2417,7 +2417,6 @@ return array(
'Rector\\PhpDocParser\\TypeAnalyzer\\ClassMethodReturnTypeResolver' => $baseDir . '/packages/PhpDocParser/TypeAnalyzer/ClassMethodReturnTypeResolver.php',
'Rector\\PhpDocParser\\ValueObject\\AttributeKey' => $baseDir . '/packages/PhpDocParser/ValueObject/AttributeKey.php',
'Rector\\PostRector\\Application\\PostFileProcessor' => $baseDir . '/packages/PostRector/Application/PostFileProcessor.php',
'Rector\\PostRector\\Collector\\PropertyToAddCollector' => $baseDir . '/packages/PostRector/Collector/PropertyToAddCollector.php',
'Rector\\PostRector\\Collector\\UseNodesToAddCollector' => $baseDir . '/packages/PostRector/Collector/UseNodesToAddCollector.php',
'Rector\\PostRector\\Contract\\Collector\\NodeCollectorInterface' => $baseDir . '/packages/PostRector/Contract/Collector/NodeCollectorInterface.php',
'Rector\\PostRector\\Contract\\Rector\\ComplementaryRectorInterface' => $baseDir . '/packages/PostRector/Contract/Rector/ComplementaryRectorInterface.php',
@ -2426,7 +2425,6 @@ return array(
'Rector\\PostRector\\Rector\\AbstractPostRector' => $baseDir . '/packages/PostRector/Rector/AbstractPostRector.php',
'Rector\\PostRector\\Rector\\ClassRenamingPostRector' => $baseDir . '/packages/PostRector/Rector/ClassRenamingPostRector.php',
'Rector\\PostRector\\Rector\\NameImportingPostRector' => $baseDir . '/packages/PostRector/Rector/NameImportingPostRector.php',
'Rector\\PostRector\\Rector\\PropertyAddingPostRector' => $baseDir . '/packages/PostRector/Rector/PropertyAddingPostRector.php',
'Rector\\PostRector\\Rector\\UnusedImportRemovingPostRector' => $baseDir . '/packages/PostRector/Rector/UnusedImportRemovingPostRector.php',
'Rector\\PostRector\\Rector\\UseAddingPostRector' => $baseDir . '/packages/PostRector/Rector/UseAddingPostRector.php',
'Rector\\PostRector\\ValueObject\\PropertyMetadata' => $baseDir . '/packages/PostRector/ValueObject/PropertyMetadata.php',

View File

@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitb5c263e2bdede23be55119fc17d4c292
class ComposerAutoloaderInit25989da06050fec2f81e0b951ae55419
{
private static $loader;
@ -22,17 +22,17 @@ class ComposerAutoloaderInitb5c263e2bdede23be55119fc17d4c292
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitb5c263e2bdede23be55119fc17d4c292', 'loadClassLoader'), true, true);
spl_autoload_register(array('ComposerAutoloaderInit25989da06050fec2f81e0b951ae55419', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInitb5c263e2bdede23be55119fc17d4c292', 'loadClassLoader'));
spl_autoload_unregister(array('ComposerAutoloaderInit25989da06050fec2f81e0b951ae55419', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitb5c263e2bdede23be55119fc17d4c292::getInitializer($loader));
call_user_func(\Composer\Autoload\ComposerStaticInit25989da06050fec2f81e0b951ae55419::getInitializer($loader));
$loader->setClassMapAuthoritative(true);
$loader->register(true);
$filesToLoad = \Composer\Autoload\ComposerStaticInitb5c263e2bdede23be55119fc17d4c292::$files;
$filesToLoad = \Composer\Autoload\ComposerStaticInit25989da06050fec2f81e0b951ae55419::$files;
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;

View File

@ -4,7 +4,7 @@
namespace Composer\Autoload;
class ComposerStaticInitb5c263e2bdede23be55119fc17d4c292
class ComposerStaticInit25989da06050fec2f81e0b951ae55419
{
public static $files = array (
'ad155f8f1cf0d418fe49e248db8c661b' => __DIR__ . '/..' . '/react/promise/src/functions_include.php',
@ -2668,7 +2668,6 @@ class ComposerStaticInitb5c263e2bdede23be55119fc17d4c292
'Rector\\PhpDocParser\\TypeAnalyzer\\ClassMethodReturnTypeResolver' => __DIR__ . '/../..' . '/packages/PhpDocParser/TypeAnalyzer/ClassMethodReturnTypeResolver.php',
'Rector\\PhpDocParser\\ValueObject\\AttributeKey' => __DIR__ . '/../..' . '/packages/PhpDocParser/ValueObject/AttributeKey.php',
'Rector\\PostRector\\Application\\PostFileProcessor' => __DIR__ . '/../..' . '/packages/PostRector/Application/PostFileProcessor.php',
'Rector\\PostRector\\Collector\\PropertyToAddCollector' => __DIR__ . '/../..' . '/packages/PostRector/Collector/PropertyToAddCollector.php',
'Rector\\PostRector\\Collector\\UseNodesToAddCollector' => __DIR__ . '/../..' . '/packages/PostRector/Collector/UseNodesToAddCollector.php',
'Rector\\PostRector\\Contract\\Collector\\NodeCollectorInterface' => __DIR__ . '/../..' . '/packages/PostRector/Contract/Collector/NodeCollectorInterface.php',
'Rector\\PostRector\\Contract\\Rector\\ComplementaryRectorInterface' => __DIR__ . '/../..' . '/packages/PostRector/Contract/Rector/ComplementaryRectorInterface.php',
@ -2677,7 +2676,6 @@ class ComposerStaticInitb5c263e2bdede23be55119fc17d4c292
'Rector\\PostRector\\Rector\\AbstractPostRector' => __DIR__ . '/../..' . '/packages/PostRector/Rector/AbstractPostRector.php',
'Rector\\PostRector\\Rector\\ClassRenamingPostRector' => __DIR__ . '/../..' . '/packages/PostRector/Rector/ClassRenamingPostRector.php',
'Rector\\PostRector\\Rector\\NameImportingPostRector' => __DIR__ . '/../..' . '/packages/PostRector/Rector/NameImportingPostRector.php',
'Rector\\PostRector\\Rector\\PropertyAddingPostRector' => __DIR__ . '/../..' . '/packages/PostRector/Rector/PropertyAddingPostRector.php',
'Rector\\PostRector\\Rector\\UnusedImportRemovingPostRector' => __DIR__ . '/../..' . '/packages/PostRector/Rector/UnusedImportRemovingPostRector.php',
'Rector\\PostRector\\Rector\\UseAddingPostRector' => __DIR__ . '/../..' . '/packages/PostRector/Rector/UseAddingPostRector.php',
'Rector\\PostRector\\ValueObject\\PropertyMetadata' => __DIR__ . '/../..' . '/packages/PostRector/ValueObject/PropertyMetadata.php',
@ -3136,9 +3134,9 @@ class ComposerStaticInitb5c263e2bdede23be55119fc17d4c292
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitb5c263e2bdede23be55119fc17d4c292::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitb5c263e2bdede23be55119fc17d4c292::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitb5c263e2bdede23be55119fc17d4c292::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInit25989da06050fec2f81e0b951ae55419::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit25989da06050fec2f81e0b951ae55419::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit25989da06050fec2f81e0b951ae55419::$classMap;
}, null, ClassLoader::class);
}

View File

@ -1921,12 +1921,12 @@
"source": {
"type": "git",
"url": "https:\/\/github.com\/rectorphp\/rector-doctrine.git",
"reference": "08503e7da4f587cb27211ecc3f0726a6ac367998"
"reference": "ca0179995eceabd2acae03c60665bc73494c36ec"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-doctrine\/zipball\/08503e7da4f587cb27211ecc3f0726a6ac367998",
"reference": "08503e7da4f587cb27211ecc3f0726a6ac367998",
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-doctrine\/zipball\/ca0179995eceabd2acae03c60665bc73494c36ec",
"reference": "ca0179995eceabd2acae03c60665bc73494c36ec",
"shasum": ""
},
"require": {
@ -1951,7 +1951,7 @@
"tomasvotruba\/type-coverage": "^0.2",
"tomasvotruba\/unused-public": "^0.1"
},
"time": "2023-06-05T09:07:54+00:00",
"time": "2023-06-09T10:43:45+00:00",
"default-branch": true,
"type": "rector-extension",
"extra": {
@ -2125,12 +2125,12 @@
"source": {
"type": "git",
"url": "https:\/\/github.com\/rectorphp\/rector-symfony.git",
"reference": "59b8f1ede5dfa2f78617328cf18ee8374a5e2980"
"reference": "65e2e8dd71093b38fdf1c150aa79faaac5831c88"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-symfony\/zipball\/59b8f1ede5dfa2f78617328cf18ee8374a5e2980",
"reference": "59b8f1ede5dfa2f78617328cf18ee8374a5e2980",
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-symfony\/zipball\/65e2e8dd71093b38fdf1c150aa79faaac5831c88",
"reference": "65e2e8dd71093b38fdf1c150aa79faaac5831c88",
"shasum": ""
},
"require": {
@ -2160,7 +2160,7 @@
"tomasvotruba\/type-coverage": "^0.2",
"tomasvotruba\/unused-public": "^0.1"
},
"time": "2023-06-08T23:14:37+00:00",
"time": "2023-06-09T10:36:08+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/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main 08503e7'), 'rector/rector-downgrade-php' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-downgrade-php', 'relative_install_path' => '../../rector-downgrade-php', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main 762ba3b'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main a842ca4'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main 59b8f1e'));
public const EXTENSIONS = array('rector/rector-doctrine' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main ca01799'), 'rector/rector-downgrade-php' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-downgrade-php', 'relative_install_path' => '../../rector-downgrade-php', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main 762ba3b'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main a842ca4'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main 65e2e8d'));
private function __construct()
{
}

View File

@ -20,7 +20,6 @@ use Rector\Doctrine\NodeFactory\RepositoryNodeFactory;
use Rector\Doctrine\Type\RepositoryTypeFactory;
use Rector\Naming\Naming\PropertyNaming;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PostRector\Collector\PropertyToAddCollector;
use Rector\PostRector\ValueObject\PropertyMetadata;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -42,11 +41,6 @@ final class ServiceEntityRepositoryParentCallToDIRector extends AbstractRector
* @var \Rector\Doctrine\Type\RepositoryTypeFactory
*/
private $repositoryTypeFactory;
/**
* @readonly
* @var \Rector\PostRector\Collector\PropertyToAddCollector
*/
private $propertyToAddCollector;
/**
* @readonly
* @var \Rector\Core\NodeManipulator\ClassDependencyManipulator
@ -57,11 +51,10 @@ final class ServiceEntityRepositoryParentCallToDIRector extends AbstractRector
* @var \Rector\Naming\Naming\PropertyNaming
*/
private $propertyNaming;
public function __construct(RepositoryNodeFactory $repositoryNodeFactory, RepositoryTypeFactory $repositoryTypeFactory, PropertyToAddCollector $propertyToAddCollector, ClassDependencyManipulator $classDependencyManipulator, PropertyNaming $propertyNaming)
public function __construct(RepositoryNodeFactory $repositoryNodeFactory, RepositoryTypeFactory $repositoryTypeFactory, ClassDependencyManipulator $classDependencyManipulator, PropertyNaming $propertyNaming)
{
$this->repositoryNodeFactory = $repositoryNodeFactory;
$this->repositoryTypeFactory = $repositoryTypeFactory;
$this->propertyToAddCollector = $propertyToAddCollector;
$this->classDependencyManipulator = $classDependencyManipulator;
$this->propertyNaming = $propertyNaming;
}
@ -147,8 +140,9 @@ CODE_SAMPLE
$this->addRepositoryProperty($node, $entityReferenceExpr);
// 5. add param + add property, dependency
$propertyName = $this->propertyNaming->fqnToVariableName($entityManagerObjectType);
$propertyMetadata = new PropertyMetadata($propertyName, $entityManagerObjectType, Class_::MODIFIER_PRIVATE);
$this->propertyToAddCollector->addPropertyToClass($node, $propertyMetadata);
// add property as first element
$propertyMetadata = new PropertyMetadata($propertyName, $entityManagerObjectType);
$this->classDependencyManipulator->addConstructorDependency($node, $propertyMetadata);
return $node;
}
private function removeParentConstructAndCollectEntityReference(ClassMethod $classMethod) : ?Expr
@ -183,6 +177,6 @@ CODE_SAMPLE
}
$genericObjectType = $this->repositoryTypeFactory->createRepositoryPropertyType($entityReferenceExpr);
$property = $this->nodeFactory->createPrivatePropertyFromNameAndType('repository', $genericObjectType);
\array_splice($class->stmts, 0, 0, [$property]);
$class->stmts = \array_merge([$property], $class->stmts);
}
}

View File

@ -10,7 +10,6 @@ use PhpParser\Node\Stmt\Property;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\ObjectType;
use Rector\Core\NodeManipulator\ClassDependencyManipulator;
use Rector\Core\NodeManipulator\ClassInsertManipulator;
use Rector\Core\Rector\AbstractRector;
use Rector\Doctrine\NodeAnalyzer\EntityObjectTypeResolver;
use Rector\Doctrine\NodeFactory\RepositoryAssignFactory;
@ -26,11 +25,6 @@ final class MoveRepositoryFromParentToConstructorRector extends AbstractRector
* @var \Rector\Core\NodeManipulator\ClassDependencyManipulator
*/
private $classDependencyManipulator;
/**
* @readonly
* @var \Rector\Core\NodeManipulator\ClassInsertManipulator
*/
private $classInsertManipulator;
/**
* @readonly
* @var \Rector\Doctrine\NodeFactory\RepositoryAssignFactory
@ -41,10 +35,9 @@ final class MoveRepositoryFromParentToConstructorRector extends AbstractRector
* @var \Rector\Doctrine\NodeAnalyzer\EntityObjectTypeResolver
*/
private $entityObjectTypeResolver;
public function __construct(ClassDependencyManipulator $classDependencyManipulator, ClassInsertManipulator $classInsertManipulator, RepositoryAssignFactory $repositoryAssignFactory, EntityObjectTypeResolver $entityObjectTypeResolver)
public function __construct(ClassDependencyManipulator $classDependencyManipulator, RepositoryAssignFactory $repositoryAssignFactory, EntityObjectTypeResolver $entityObjectTypeResolver)
{
$this->classDependencyManipulator = $classDependencyManipulator;
$this->classInsertManipulator = $classInsertManipulator;
$this->repositoryAssignFactory = $repositoryAssignFactory;
$this->entityObjectTypeResolver = $entityObjectTypeResolver;
}
@ -105,7 +98,8 @@ CODE_SAMPLE
$genericObjectType = new GenericObjectType('Doctrine\\ORM\\EntityRepository', [$subtractableType]);
// add $repository property
if (!$node->getProperty('repository') instanceof Property) {
$this->classInsertManipulator->addPropertyToClass($node, 'repository', $genericObjectType);
$repositoryProperty = $this->nodeFactory->createPrivatePropertyFromNameAndType('repository', $genericObjectType);
$node->stmts = \array_merge([$repositoryProperty], $node->stmts);
}
// add $entityManager and assign to constuctor
$repositoryAssign = $this->repositoryAssignFactory->create($node);

View File

@ -11,8 +11,8 @@ use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Type\ObjectType;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\NodeManipulator\ClassDependencyManipulator;
use Rector\Core\Rector\AbstractRector;
use Rector\PostRector\Collector\PropertyToAddCollector;
use Rector\PostRector\ValueObject\PropertyMetadata;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -23,16 +23,16 @@ final class ReplaceParentRepositoryCallsByRepositoryPropertyRector extends Abstr
{
/**
* @readonly
* @var \Rector\PostRector\Collector\PropertyToAddCollector
* @var \Rector\Core\NodeManipulator\ClassDependencyManipulator
*/
private $propertyToAddCollector;
private $classDependencyManipulator;
/**
* @var string[]
*/
private const ENTITY_REPOSITORY_PUBLIC_METHODS = ['createQueryBuilder', 'createResultSetMappingBuilder', 'clear', 'find', 'findBy', 'findAll', 'findOneBy', 'count', 'getClassName', 'matching'];
public function __construct(PropertyToAddCollector $propertyToAddCollector)
public function __construct(ClassDependencyManipulator $classDependencyManipulator)
{
$this->propertyToAddCollector = $propertyToAddCollector;
$this->classDependencyManipulator = $classDependencyManipulator;
}
public function getRuleDefinition() : RuleDefinition
{
@ -65,28 +65,40 @@ CODE_SAMPLE
*/
public function getNodeTypes() : array
{
return [MethodCall::class];
return [Class_::class];
}
/**
* @param MethodCall $node
* @param Class_ $node
*/
public function refactor(Node $node) : ?Node
{
if (!$this->isObjectType($node->var, new ObjectType('Doctrine\\ORM\\EntityRepository'))) {
return null;
$hasChanged = \false;
$class = $node;
$this->traverseNodesWithCallable($node->getMethods(), function (Node $node) use(&$hasChanged, $class) {
if (!$node instanceof MethodCall) {
return null;
}
if (!$this->isObjectType($node->var, new ObjectType('Doctrine\\ORM\\EntityRepository'))) {
return null;
}
if (!$this->isNames($node->name, self::ENTITY_REPOSITORY_PUBLIC_METHODS)) {
return null;
}
if ($node->isFirstClassCallable()) {
return null;
}
$hasChanged = \true;
// is it getRepository(), replace it with DI property
if ($node->var instanceof MethodCall && $this->isName($node->var->name, 'getRepository')) {
return $this->refactorGetRepositoryMethodCall($class, $node);
}
$node->var = $this->nodeFactory->createPropertyFetch('this', 'repository');
});
if ($hasChanged) {
// @todo add constructor property here
return $node;
}
if (!$this->isNames($node->name, self::ENTITY_REPOSITORY_PUBLIC_METHODS)) {
return null;
}
if ($node->isFirstClassCallable()) {
return null;
}
// is it getRepository(), replace it with DI property
if ($node->var instanceof MethodCall && $this->isName($node->var->name, 'getRepository')) {
return $this->refactorGetRepositoryMethodCall($node);
}
$node->var = $this->nodeFactory->createPropertyFetch('this', 'repository');
return $node;
return null;
}
private function resolveRepositoryName(Expr $expr) : string
{
@ -97,40 +109,35 @@ CODE_SAMPLE
$lastNamePart = (string) Strings::after($entityReferenceName, '\\', -1);
return \lcfirst($lastNamePart) . 'Repository';
}
private function guessRepositoryType(Expr $expr) : string
private function guessRepositoryType(Expr $expr) : ObjectType
{
if ($expr instanceof ClassConstFetch) {
$entityClass = $this->getName($expr->class);
if ($entityClass === null) {
return 'Unknown_Repository_Class';
return new ObjectType('Unknown_Repository_Class');
}
$entityClassNamespace = (string) Strings::before($entityClass, '\\', -2);
$lastNamePart = (string) Strings::after($entityClass, '\\', -1);
return $entityClassNamespace . '\\Repository\\' . $lastNamePart . 'Repository';
return new ObjectType($entityClassNamespace . '\\Repository\\' . $lastNamePart . 'Repository');
}
return 'Unknown_Repository_Class';
return new ObjectType('Unknown_Repository_Class');
}
private function refactorGetRepositoryMethodCall(MethodCall $methodCall) : ?MethodCall
private function refactorGetRepositoryMethodCall(Class_ $class, MethodCall $methodCall) : ?MethodCall
{
/** @var MethodCall $parentMethodCall */
$parentMethodCall = $methodCall->var;
if (\count($parentMethodCall->args) === 1) {
$class = $this->betterNodeFinder->findParentType($methodCall, Class_::class);
if (!$class instanceof Class_) {
return null;
}
if ($this->isObjectType($class, new ObjectType('Doctrine\\ORM\\EntityRepository'))) {
return null;
}
$firstArgValue = $parentMethodCall->getArgs()[0]->value;
$repositoryPropertyName = $this->resolveRepositoryName($firstArgValue);
$repositoryType = $this->guessRepositoryType($firstArgValue);
$objectType = new ObjectType($repositoryType);
$propertyMetadata = new PropertyMetadata($repositoryPropertyName, $objectType, Class_::MODIFIER_PRIVATE);
$this->propertyToAddCollector->addPropertyToClass($class, $propertyMetadata);
$methodCall->var = $this->nodeFactory->createPropertyFetch('this', $repositoryPropertyName);
return $methodCall;
if (\count($parentMethodCall->args) !== 1) {
return null;
}
return null;
if ($this->isObjectType($class, new ObjectType('Doctrine\\ORM\\EntityRepository'))) {
return null;
}
$firstArgValue = $parentMethodCall->getArgs()[0]->value;
$repositoryPropertyName = $this->resolveRepositoryName($firstArgValue);
$repositoryType = $this->guessRepositoryType($firstArgValue);
$propertyMetadata = new PropertyMetadata($repositoryPropertyName, $repositoryType);
$this->classDependencyManipulator->addConstructorDependency($class, $propertyMetadata);
$methodCall->var = $this->nodeFactory->createPropertyFetch('this', $repositoryPropertyName);
return $methodCall;
}
}

View File

@ -18,7 +18,6 @@ use Rector\Symfony\Rector\Class_\LogoutSuccessHandlerToLogoutEventSubscriberRect
use Rector\Symfony\Rector\ClassMethod\CommandConstantReturnCodeRector;
use Rector\Symfony\Rector\ClassMethod\RouteCollectionBuilderToRoutingConfiguratorRector;
use Rector\Transform\Rector\StaticCall\StaticCallToNewRector;
use Rector\Transform\ValueObject\NewArgToMethodCall;
use Rector\Transform\ValueObject\StaticCallToNew;
use Rector\TypeDeclaration\Rector\ClassMethod\AddParamTypeDeclarationRector;
use Rector\TypeDeclaration\ValueObject\AddParamTypeDeclaration;

View File

@ -4,17 +4,13 @@ declare (strict_types=1);
namespace Rector\Symfony\NodeAnalyzer;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
use PHPStan\Type\ObjectType;
use Rector\Core\NodeManipulator\PropertyManipulator;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\PhpParser\Node\NodeFactory;
use Rector\Naming\Naming\PropertyNaming;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\Php80\NodeAnalyzer\PromotedPropertyResolver;
use Rector\PostRector\Collector\PropertyToAddCollector;
use Rector\PostRector\ValueObject\PropertyMetadata;
final class DependencyInjectionMethodCallAnalyzer
{
@ -28,21 +24,6 @@ final class DependencyInjectionMethodCallAnalyzer
* @var \Rector\Symfony\NodeAnalyzer\ServiceTypeMethodCallResolver
*/
private $serviceTypeMethodCallResolver;
/**
* @readonly
* @var \Rector\Core\PhpParser\Node\NodeFactory
*/
private $nodeFactory;
/**
* @readonly
* @var \Rector\PostRector\Collector\PropertyToAddCollector
*/
private $propertyToAddCollector;
/**
* @readonly
* @var \Rector\Core\PhpParser\Node\BetterNodeFinder
*/
private $betterNodeFinder;
/**
* @readonly
* @var \Rector\Php80\NodeAnalyzer\PromotedPropertyResolver
@ -58,27 +39,20 @@ final class DependencyInjectionMethodCallAnalyzer
* @var \Rector\Core\NodeManipulator\PropertyManipulator
*/
private $propertyManipulator;
public function __construct(PropertyNaming $propertyNaming, \Rector\Symfony\NodeAnalyzer\ServiceTypeMethodCallResolver $serviceTypeMethodCallResolver, NodeFactory $nodeFactory, PropertyToAddCollector $propertyToAddCollector, BetterNodeFinder $betterNodeFinder, PromotedPropertyResolver $promotedPropertyResolver, NodeNameResolver $nodeNameResolver, PropertyManipulator $propertyManipulator)
public function __construct(PropertyNaming $propertyNaming, \Rector\Symfony\NodeAnalyzer\ServiceTypeMethodCallResolver $serviceTypeMethodCallResolver, PromotedPropertyResolver $promotedPropertyResolver, NodeNameResolver $nodeNameResolver, PropertyManipulator $propertyManipulator)
{
$this->propertyNaming = $propertyNaming;
$this->serviceTypeMethodCallResolver = $serviceTypeMethodCallResolver;
$this->nodeFactory = $nodeFactory;
$this->propertyToAddCollector = $propertyToAddCollector;
$this->betterNodeFinder = $betterNodeFinder;
$this->promotedPropertyResolver = $promotedPropertyResolver;
$this->nodeNameResolver = $nodeNameResolver;
$this->propertyManipulator = $propertyManipulator;
}
public function replaceMethodCallWithPropertyFetchAndDependency(MethodCall $methodCall) : ?PropertyFetch
public function replaceMethodCallWithPropertyFetchAndDependency(Class_ $class, MethodCall $methodCall) : ?PropertyMetadata
{
$serviceType = $this->serviceTypeMethodCallResolver->resolve($methodCall);
if (!$serviceType instanceof ObjectType) {
return null;
}
$class = $this->betterNodeFinder->findParentType($methodCall, Class_::class);
if (!$class instanceof Class_) {
return null;
}
$resolvedPropertyNameByType = $this->propertyManipulator->resolveExistingClassPropertyNameByType($class, $serviceType);
if (\is_string($resolvedPropertyNameByType)) {
$propertyName = $resolvedPropertyNameByType;
@ -86,9 +60,7 @@ final class DependencyInjectionMethodCallAnalyzer
$propertyName = $this->propertyNaming->fqnToVariableName($serviceType);
$propertyName = $this->resolveNewPropertyNameWhenExists($class, $propertyName, $propertyName);
}
$propertyMetadata = new PropertyMetadata($propertyName, $serviceType, Class_::MODIFIER_PRIVATE);
$this->propertyToAddCollector->addPropertyToClass($class, $propertyMetadata);
return $this->nodeFactory->createPropertyFetch('this', $propertyName);
return new PropertyMetadata($propertyName, $serviceType);
}
private function resolveNewPropertyNameWhenExists(Class_ $class, string $originalPropertyName, string $propertyName, int $count = 1) : string
{

View File

@ -5,9 +5,12 @@ namespace Rector\Symfony\Rector\MethodCall;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Type\ObjectType;
use Rector\Core\NodeManipulator\ClassDependencyManipulator;
use Rector\Core\Rector\AbstractRector;
use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer;
use Rector\PostRector\ValueObject\PropertyMetadata;
use Rector\Symfony\NodeAnalyzer\DependencyInjectionMethodCallAnalyzer;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -28,10 +31,16 @@ final class ContainerGetToConstructorInjectionRector extends AbstractRector
* @var \Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer
*/
private $testsNodeAnalyzer;
public function __construct(DependencyInjectionMethodCallAnalyzer $dependencyInjectionMethodCallAnalyzer, TestsNodeAnalyzer $testsNodeAnalyzer)
/**
* @readonly
* @var \Rector\Core\NodeManipulator\ClassDependencyManipulator
*/
private $classDependencyManipulator;
public function __construct(DependencyInjectionMethodCallAnalyzer $dependencyInjectionMethodCallAnalyzer, TestsNodeAnalyzer $testsNodeAnalyzer, ClassDependencyManipulator $classDependencyManipulator)
{
$this->dependencyInjectionMethodCallAnalyzer = $dependencyInjectionMethodCallAnalyzer;
$this->testsNodeAnalyzer = $testsNodeAnalyzer;
$this->classDependencyManipulator = $classDependencyManipulator;
}
public function getRuleDefinition() : RuleDefinition
{
@ -69,22 +78,41 @@ CODE_SAMPLE
*/
public function getNodeTypes() : array
{
return [MethodCall::class];
return [Class_::class];
}
/**
* @param MethodCall $node
* @param Class_ $node
*/
public function refactor(Node $node) : ?Node
{
if (!$this->isName($node->name, 'get')) {
return null;
}
if (!$this->isObjectType($node->var, new ObjectType('Symfony\\Component\\DependencyInjection\\ContainerInterface'))) {
return null;
}
if ($this->testsNodeAnalyzer->isInTestClass($node)) {
return null;
}
return $this->dependencyInjectionMethodCallAnalyzer->replaceMethodCallWithPropertyFetchAndDependency($node);
$class = $node;
$propertyMetadatas = [];
$this->traverseNodesWithCallable($class, function (Node $node) use($class, &$propertyMetadatas) : ?Node {
if (!$node instanceof MethodCall) {
return null;
}
if (!$this->isName($node->name, 'get')) {
return null;
}
if (!$this->isObjectType($node->var, new ObjectType('Symfony\\Component\\DependencyInjection\\ContainerInterface'))) {
return null;
}
$propertyMetadata = $this->dependencyInjectionMethodCallAnalyzer->replaceMethodCallWithPropertyFetchAndDependency($class, $node);
if (!$propertyMetadata instanceof PropertyMetadata) {
return null;
}
$propertyMetadatas[] = $propertyMetadata;
return $this->nodeFactory->createPropertyFetch('this', $propertyMetadata->getName());
});
if ($propertyMetadatas === []) {
return null;
}
foreach ($propertyMetadatas as $propertyMetadata) {
$this->classDependencyManipulator->addConstructorDependency($class, $propertyMetadata);
}
return $node;
}
}

View File

@ -10,9 +10,9 @@ use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Type\ObjectType;
use Rector\Core\NodeManipulator\ClassDependencyManipulator;
use Rector\Core\Rector\AbstractRector;
use Rector\Naming\Naming\PropertyNaming;
use Rector\PostRector\Collector\PropertyToAddCollector;
use Rector\PostRector\ValueObject\PropertyMetadata;
use Rector\Symfony\TypeAnalyzer\ControllerAnalyzer;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@ -32,18 +32,18 @@ final class GetHelperControllerToServiceRector extends AbstractRector
private $controllerAnalyzer;
/**
* @readonly
* @var \Rector\PostRector\Collector\PropertyToAddCollector
* @var \Rector\Core\NodeManipulator\ClassDependencyManipulator
*/
private $propertyToAddCollector;
private $classDependencyManipulator;
/**
* @readonly
* @var \Rector\Naming\Naming\PropertyNaming
*/
private $propertyNaming;
public function __construct(ControllerAnalyzer $controllerAnalyzer, PropertyToAddCollector $propertyToAddCollector, PropertyNaming $propertyNaming)
public function __construct(ControllerAnalyzer $controllerAnalyzer, ClassDependencyManipulator $classDependencyManipulator, PropertyNaming $propertyNaming)
{
$this->controllerAnalyzer = $controllerAnalyzer;
$this->propertyToAddCollector = $propertyToAddCollector;
$this->classDependencyManipulator = $classDependencyManipulator;
$this->propertyNaming = $propertyNaming;
}
public function getRuleDefinition() : RuleDefinition
@ -83,51 +83,59 @@ CODE_SAMPLE
*/
public function getNodeTypes() : array
{
return [MethodCall::class];
return [Class_::class];
}
/**
* @param MethodCall $node
* @param Class_ $node
*/
public function refactor(Node $node) : ?Node
{
if (!$this->controllerAnalyzer->isController($node->var)) {
if (!$this->controllerAnalyzer->isController($node)) {
return null;
}
$class = $this->betterNodeFinder->findParentType($node, Class_::class);
if (!$class instanceof Class_) {
$propertyMetadatas = [];
$this->traverseNodesWithCallable($node, function (Node $node) use(&$propertyMetadatas) {
if (!$node instanceof MethodCall) {
return null;
}
if (!$this->isName($node->var, 'this')) {
return null;
}
if ($this->isName($node->name, 'getDoctrine')) {
$entityManagerPropertyMetadata = $this->createManagerRegistryPropertyMetadata();
$propertyMetadatas[] = $entityManagerPropertyMetadata;
return $this->nodeFactory->createPropertyFetch('this', $entityManagerPropertyMetadata->getName());
}
if ($this->isName($node->name, 'dispatchMessage')) {
$eventDispatcherPropertyMetadata = $this->createMessageBusPropertyMetadata();
$propertyMetadatas[] = $eventDispatcherPropertyMetadata;
$thisVariable = new Variable('this');
$node->var = new PropertyFetch($thisVariable, new Identifier($eventDispatcherPropertyMetadata->getName()));
$node->name = new Identifier('dispatch');
return $node;
}
return null;
});
if ($propertyMetadatas === []) {
return null;
}
if ($this->isName($node->name, 'getDoctrine')) {
return $this->refactorGetDoctrine($class);
foreach ($propertyMetadatas as $propertyMetadata) {
$this->classDependencyManipulator->addConstructorDependency($node, $propertyMetadata);
}
if ($this->isName($node->name, 'dispatchMessage')) {
return $this->refactorDispatchMessage($class, $node);
}
return null;
return $node;
}
/**
* @return \PhpParser\Node|\PhpParser\Node\Expr\MethodCall
*/
private function refactorDispatchMessage(Class_ $class, MethodCall $methodCall)
private function createMessageBusPropertyMetadata() : PropertyMetadata
{
$propertyName = $this->propertyNaming->fqnToVariableName('Symfony\\Component\\Messenger\\MessageBusInterface');
// add dependency
$propertyObjectType = new ObjectType('Symfony\\Component\\Messenger\\MessageBusInterface');
$propertyMetadata = new PropertyMetadata($propertyName, $propertyObjectType, Class_::MODIFIER_PRIVATE);
$this->propertyToAddCollector->addPropertyToClass($class, $propertyMetadata);
$thisVariable = new Variable('this');
$methodCall->var = new PropertyFetch($thisVariable, $propertyName);
$methodCall->name = new Identifier('dispatch');
return $methodCall;
return new PropertyMetadata($propertyName, $propertyObjectType);
}
private function refactorGetDoctrine(Class_ $class) : PropertyFetch
private function createManagerRegistryPropertyMetadata() : PropertyMetadata
{
$propertyName = $this->propertyNaming->fqnToVariableName('Doctrine\\Persistence\\ManagerRegistry');
// add dependency
$propertyObjectType = new ObjectType('Doctrine\\Persistence\\ManagerRegistry');
$propertyMetadata = new PropertyMetadata($propertyName, $propertyObjectType, Class_::MODIFIER_PRIVATE);
$this->propertyToAddCollector->addPropertyToClass($class, $propertyMetadata);
$thisVariable = new Variable('this');
return new PropertyFetch($thisVariable, $propertyName);
return new PropertyMetadata($propertyName, $propertyObjectType);
}
}

View File

@ -5,7 +5,10 @@ namespace Rector\Symfony\Rector\MethodCall;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Class_;
use Rector\Core\NodeManipulator\ClassDependencyManipulator;
use Rector\Core\Rector\AbstractRector;
use Rector\PostRector\ValueObject\PropertyMetadata;
use Rector\Symfony\NodeAnalyzer\DependencyInjectionMethodCallAnalyzer;
use Rector\Symfony\TypeAnalyzer\ContainerAwareAnalyzer;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@ -25,10 +28,16 @@ final class GetToConstructorInjectionRector extends AbstractRector
* @var \Rector\Symfony\TypeAnalyzer\ContainerAwareAnalyzer
*/
private $containerAwareAnalyzer;
public function __construct(DependencyInjectionMethodCallAnalyzer $dependencyInjectionMethodCallAnalyzer, ContainerAwareAnalyzer $containerAwareAnalyzer)
/**
* @readonly
* @var \Rector\Core\NodeManipulator\ClassDependencyManipulator
*/
private $classDependencyManipulator;
public function __construct(DependencyInjectionMethodCallAnalyzer $dependencyInjectionMethodCallAnalyzer, ContainerAwareAnalyzer $containerAwareAnalyzer, ClassDependencyManipulator $classDependencyManipulator)
{
$this->dependencyInjectionMethodCallAnalyzer = $dependencyInjectionMethodCallAnalyzer;
$this->containerAwareAnalyzer = $containerAwareAnalyzer;
$this->classDependencyManipulator = $classDependencyManipulator;
}
public function getRuleDefinition() : RuleDefinition
{
@ -67,19 +76,38 @@ CODE_SAMPLE
*/
public function getNodeTypes() : array
{
return [MethodCall::class];
return [Class_::class];
}
/**
* @param MethodCall $node
* @param Class_ $node
*/
public function refactor(Node $node) : ?Node
{
if (!$this->isName($node->name, 'get')) {
$class = $node;
$propertyMetadatas = [];
$this->traverseNodesWithCallable($class, function (Node $node) use($class, &$propertyMetadatas) : ?Node {
if (!$node instanceof MethodCall) {
return null;
}
if (!$this->isName($node->name, 'get')) {
return null;
}
if (!$this->containerAwareAnalyzer->isGetMethodAwareType($node->var)) {
return null;
}
$propertyMetadata = $this->dependencyInjectionMethodCallAnalyzer->replaceMethodCallWithPropertyFetchAndDependency($class, $node);
if (!$propertyMetadata instanceof PropertyMetadata) {
return null;
}
$propertyMetadatas[] = $propertyMetadata;
return $this->nodeFactory->createPropertyFetch('this', $propertyMetadata->getName());
});
if ($propertyMetadatas === []) {
return null;
}
if (!$this->containerAwareAnalyzer->isGetMethodAwareType($node->var)) {
return null;
foreach ($propertyMetadatas as $propertyMetadata) {
$this->classDependencyManipulator->addConstructorDependency($node, $propertyMetadata);
}
return $this->dependencyInjectionMethodCallAnalyzer->replaceMethodCallWithPropertyFetchAndDependency($node);
return $node;
}
}

View File

@ -5,6 +5,7 @@ namespace Rector\Symfony\TypeAnalyzer;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Type\ObjectType;
@ -23,14 +24,20 @@ final class ControllerAnalyzer
{
$this->reflectionResolver = $reflectionResolver;
}
public function isController(Expr $expr) : bool
/**
* @param \PhpParser\Node\Expr|\PhpParser\Node\Stmt\Class_ $node
*/
public function isController($node) : bool
{
$scope = $expr->getAttribute(AttributeKey::SCOPE);
if ($node instanceof Class_) {
return $this->isControllerClass($node);
}
$scope = $node->getAttribute(AttributeKey::SCOPE);
// might be missing in a trait
if (!$scope instanceof Scope) {
return \false;
}
$nodeType = $scope->getType($expr);
$nodeType = $scope->getType($node);
if (!$nodeType instanceof TypeWithClassName) {
return \false;
}
@ -61,4 +68,12 @@ final class ControllerAnalyzer
}
return $classReflection->isSubclassOf('Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController');
}
private function isControllerClass(Class_ $class) : bool
{
$classReflection = $this->reflectionResolver->resolveClassReflection($class);
if (!$classReflection instanceof ClassReflection) {
return \false;
}
return $this->isControllerClassReflection($classReflection);
}
}