[Decouple] Remove set, rather job for PHPStorm (#4521)

* [Decouple] Remove set, rather PHPStorm job

* update docs
This commit is contained in:
Tomas Votruba 2020-10-31 08:54:00 +01:00 committed by GitHub
parent 18d2ea2d31
commit 9751b9a1e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 1 additions and 1136 deletions

View File

@ -98,7 +98,6 @@
"Rector\\ConsoleDiffer\\": "packages/console-differ/src",
"Rector\\Core\\": "src",
"Rector\\DeadCode\\": "rules/dead-code/src",
"Rector\\Decouple\\": "rules/decouple/src",
"Rector\\DoctrineAnnotationGenerated\\": "packages/doctrine-annotation-generated/src",
"Rector\\DoctrineCodeQuality\\": "rules/doctrine-code-quality/src",
"Rector\\DoctrineGedmoToKnplabs\\": "rules/doctrine-gedmo-to-knplabs/src",
@ -227,7 +226,6 @@
"Rector\\Compiler\\Tests\\": "compiler/tests",
"Rector\\Core\\Tests\\": "tests",
"Rector\\DeadCode\\Tests\\": "rules/dead-code/tests",
"Rector\\Decouple\\Tests\\": "rules/decouple/tests",
"Rector\\DoctrineCodeQuality\\Tests\\": "rules/doctrine-code-quality/tests",
"Rector\\DoctrineGedmoToKnplabs\\Tests\\": "rules/doctrine-gedmo-to-knplabs/tests",
"Rector\\Doctrine\\Tests\\": "rules/doctrine/tests",

View File

@ -1,4 +1,4 @@
# All 600 Rectors Overview
# All 599 Rectors Overview
- [Projects](#projects)
---
@ -11,7 +11,6 @@
- [CodeQuality](#codequality) (61)
- [CodingStyle](#codingstyle) (33)
- [DeadCode](#deadcode) (41)
- [Decouple](#decouple) (1)
- [Defluent](#defluent) (8)
- [Doctrine](#doctrine) (17)
- [DoctrineCodeQuality](#doctrinecodequality) (9)
@ -3479,76 +3478,6 @@ Change ternary of bool : false to && bool
<br><br>
## Decouple
### `DecoupleClassMethodToOwnClassRector`
- class: [`Rector\Decouple\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector`](/rules/decouple/src/Rector/ClassMethod/DecoupleClassMethodToOwnClassRector.php)
- [test fixtures](/rules/decouple/tests/Rector/ClassMethod/DecoupleClassMethodToOwnClassRector/Fixture)
Move class method with its all dependencies to own class by method name
```php
<?php
declare(strict_types=1);
use Rector\Decouple\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(DecoupleClassMethodToOwnClassRector::class)
->call('configure', [[
DecoupleClassMethodToOwnClassRector::METHOD_NAMES_BY_CLASS => [
'SomeClass' => [
'someMethod' => [
'class' => 'NewDecoupledClass',
'method' => 'someRenamedMethod',
'parent_class' => 'AddedParentClass',
],
],
],
]]);
};
```
```diff
class SomeClass
{
- public function someMethod()
- {
- $this->alsoCallThis();
- }
-
- private function alsoCallThis()
- {
- }
}
```
**New file**
```php
<?php declare(strict_types=1);
class NewDecoupledClass extends AddedParentClass
{
public function someRenamedMethod(): void
{
$this->alsoCallThis();
}
private function alsoCallThis(): void
{
}
}
```
<br><br>
## Defluent
### `DefluentReturnMethodCallRector`

View File

@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->defaults()
->autowire()
->public()
->autoconfigure();
$services->load('Rector\Decouple\\', __DIR__ . '/../src')
->exclude([__DIR__ . '/../src/Rector', __DIR__ . '/../src/ValueObject']);
};

View File

@ -1,61 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Decouple\Matcher;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Decouple\ValueObject\DecoupleClassMethodMatch;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
final class DecoupledClassMethodMatcher
{
/**
* @var NodeNameResolver
*/
private $nodeNameResolver;
/**
* @var NodeTypeResolver
*/
private $nodeTypeResolver;
public function __construct(NodeNameResolver $nodeNameResolver, NodeTypeResolver $nodeTypeResolver)
{
$this->nodeNameResolver = $nodeNameResolver;
$this->nodeTypeResolver = $nodeTypeResolver;
}
/**
* @param array<string, array<mixed>> $methodNamesByClass
*/
public function matchDecoupled(ClassMethod $classMethod, array $methodNamesByClass): ?DecoupleClassMethodMatch
{
$classLike = $classMethod->getAttribute(AttributeKey::CLASS_NODE);
if ($classLike === null) {
return null;
}
foreach ($methodNamesByClass as $className => $configuration) {
if (! $this->nodeTypeResolver->isObjectType($classLike, $className)) {
continue;
}
foreach ($configuration as $methodName => $newClassConfiguration) {
if (! $this->nodeNameResolver->isName($classMethod->name, $methodName)) {
continue;
}
return new DecoupleClassMethodMatch(
$newClassConfiguration['class'],
$newClassConfiguration['method'],
$newClassConfiguration['parent_class'] ?? null
);
}
}
return null;
}
}

View File

@ -1,56 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Decouple\NodeFactory;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
use Rector\Core\PhpParser\Builder\MethodBuilder;
use Rector\Core\PhpParser\Builder\ParamBuilder;
use Rector\Core\ValueObject\MethodName;
final class ConstructorClassMethodFactory
{
/**
* @param array<string, Property> $properties
*/
public function create(array $properties): ?ClassMethod
{
if ($properties === []) {
return null;
}
$methodBuilder = new MethodBuilder(MethodName::CONSTRUCT);
$methodBuilder->makePublic();
foreach ($properties as $propertyName => $property) {
/** @var string $propertyName */
$paramBuilder = new ParamBuilder($propertyName);
/** @var Property $property */
if ($property->type !== null) {
$paramBuilder->setType($property->type);
}
$methodBuilder->addParam($paramBuilder->getNode());
// add assign
$assign = $this->createAssign($propertyName);
$methodBuilder->addStmt($assign);
}
return $methodBuilder->getNode();
}
private function createAssign(string $propertyName): Assign
{
$localPropertyFetch = new PropertyFetch(new Variable('this'), $propertyName);
return new Assign($localPropertyFetch, new Variable($propertyName));
}
}

View File

@ -1,61 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Decouple\NodeFactory;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Namespace_;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\Builder\ClassBuilder;
use Rector\Decouple\ValueObject\DecoupleClassMethodMatch;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class NamespaceFactory
{
/**
* @param Stmt[] $classStmts
*/
public function createNamespacedClassByNameAndStmts(
Class_ $class,
DecoupleClassMethodMatch $decoupleClassMethodMatch,
array $classStmts
): Namespace_ {
/** @var Namespace_|null $namespace */
$namespace = $class->getAttribute(AttributeKey::NAMESPACE_NODE);
if ($namespace === null) {
throw new ShouldNotHappenException();
}
foreach ($namespace->stmts as $key => $stmt) {
if (! $stmt instanceof Class_) {
continue;
}
$namespace->stmts[$key] = $this->createNewClass($decoupleClassMethodMatch, $classStmts);
}
$this->createNewClass($decoupleClassMethodMatch, $classStmts);
return $namespace;
}
/**
* @param Stmt[] $classStmts
*/
private function createNewClass(DecoupleClassMethodMatch $decoupleClassMethodMatch, array $classStmts): Class_
{
$classBuilder = new ClassBuilder($decoupleClassMethodMatch->getClassName());
$classBuilder->addStmts($classStmts);
$classBuilder->makeFinal();
$parentClassName = $decoupleClassMethodMatch->getParentClassName();
if ($parentClassName !== null) {
$classBuilder->extend(new FullyQualified($parentClassName));
}
return $classBuilder->getNode();
}
}

View File

@ -1,230 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Decouple\Rector\ClassMethod;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\ConfiguredCodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\Decouple\Matcher\DecoupledClassMethodMatcher;
use Rector\Decouple\NodeFactory\ConstructorClassMethodFactory;
use Rector\Decouple\NodeFactory\NamespaceFactory;
use Rector\Decouple\UsedNodesExtractor\UsedClassConstsExtractor;
use Rector\Decouple\UsedNodesExtractor\UsedClassMethodsExtractor;
use Rector\Decouple\UsedNodesExtractor\UsedClassPropertyExtractor;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\SmartFileSystem\SmartFileInfo;
/**
* @sponsor Thanks https://amateri.com for sponsoring this rule - visit them on https://www.startupjobs.cz/startup/scrumworks-s-r-o
*
* @see \Rector\Decouple\Tests\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector\DecoupleClassMethodToOwnClassRectorTest
*/
final class DecoupleClassMethodToOwnClassRector extends AbstractRector implements ConfigurableRectorInterface
{
/**
* @var string
*/
public const METHOD_NAMES_BY_CLASS = '$methodNamesByClass';
/**
* @var array<string, string[]>
*/
private $methodNamesByClass = [];
/**
* @var NamespaceFactory
*/
private $namespaceFactory;
/**
* @var UsedClassMethodsExtractor
*/
private $usedClassMethodsExtractor;
/**
* @var UsedClassConstsExtractor
*/
private $usedClassConstsExtractor;
/**
* @var UsedClassPropertyExtractor
*/
private $usedClassPropertyExtractor;
/**
* @var DecoupledClassMethodMatcher
*/
private $decoupledClassMethodMatcher;
/**
* @var ConstructorClassMethodFactory
*/
private $constructorClassMethodFactory;
public function __construct(
NamespaceFactory $namespaceFactory,
UsedClassMethodsExtractor $usedClassMethodsExtractor,
UsedClassConstsExtractor $usedClassConstsExtractor,
UsedClassPropertyExtractor $usedClassPropertyExtractor,
DecoupledClassMethodMatcher $decoupledClassMethodMatcher,
ConstructorClassMethodFactory $constructorClassMethodFactory
) {
$this->namespaceFactory = $namespaceFactory;
$this->usedClassMethodsExtractor = $usedClassMethodsExtractor;
$this->usedClassConstsExtractor = $usedClassConstsExtractor;
$this->usedClassPropertyExtractor = $usedClassPropertyExtractor;
$this->decoupledClassMethodMatcher = $decoupledClassMethodMatcher;
$this->constructorClassMethodFactory = $constructorClassMethodFactory;
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [ClassMethod::class];
}
/**
* @param ClassMethod $node
*/
public function refactor(Node $node): ?Node
{
$decoupleClassMethodMatch = $this->decoupledClassMethodMatcher->matchDecoupled(
$node,
$this->methodNamesByClass
);
if ($decoupleClassMethodMatch === null) {
return null;
}
$mainClassMethod = clone $node;
$mainClassMethod->name = new Identifier($decoupleClassMethodMatch->getMethodName());
$this->makePublic($mainClassMethod);
// 2. get related class constants in the same class
$usedClassConsts = $this->usedClassConstsExtractor->extract($node);
// 3. get class method related methods call in the same class
$usedClassMethods = $this->usedClassMethodsExtractor->extractFromClassMethod(
$node,
$decoupleClassMethodMatch->getParentClassName()
);
// 4. get class method related property fetches in the same class - add to constructor
$classMethods = array_merge($usedClassMethods, [$node]);
$usedProperties = $this->usedClassPropertyExtractor->extractFromClassMethods(
$classMethods,
$decoupleClassMethodMatch->getParentClassName()
);
// 5. add constructor dependencies $requiredLocalPropertyFetches
/** @var Class_ $classLike */
$classLike = $node->getAttribute(AttributeKey::CLASS_NODE);
$constructClassMethod = $this->constructorClassMethodFactory->create($usedProperties);
// 6. build a class
$usedClassStmts = array_merge(
$usedClassConsts,
$usedProperties,
$constructClassMethod !== null ? [$constructClassMethod] : [],
[$mainClassMethod],
$usedClassMethods
);
$namespace = $this->namespaceFactory->createNamespacedClassByNameAndStmts(
$classLike,
$decoupleClassMethodMatch,
$usedClassStmts
);
$newClassLocation = $this->createNewClassLocation($node, $decoupleClassMethodMatch->getClassName());
$this->printNodesToFilePath([$namespace], $newClassLocation);
// 7. cleanup this class method
$this->removeNode($node);
return null;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Move class method with its all dependencies to own class by method name', [
new ConfiguredCodeSample(
<<<'CODE_SAMPLE'
class SomeClass
{
public function someMethod()
{
$this->alsoCallThis();
}
private function alsoCallThis()
{
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
class SomeClass
{
}
CODE_SAMPLE
,
[
self::METHOD_NAMES_BY_CLASS => [
'SomeClass' => [
'someMethod' => [
'class' => 'NewDecoupledClass',
'method' => 'someRenamedMethod',
'parent_class' => 'AddedParentClass',
],
],
],
],
<<<'CODE_SAMPLE'
<?php
class NewDecoupledClass extends AddedParentClass
{
public function someRenamedMethod()
{
$this->alsoCallThis();
}
private function alsoCallThis()
{
}
}
CODE_SAMPLE
),
]);
}
/**
* @param mixed[] $configuration
*/
public function configure(array $configuration): void
{
$this->methodNamesByClass = $configuration[self::METHOD_NAMES_BY_CLASS] ?? [];
}
private function createNewClassLocation(ClassMethod $classMethod, string $newClassName): string
{
/** @var SmartFileInfo|null $fileInfo */
$fileInfo = $classMethod->getAttribute(AttributeKey::FILE_INFO);
if ($fileInfo === null) {
throw new ShouldNotHappenException();
}
return $fileInfo->getPath() . DIRECTORY_SEPARATOR . $newClassName . '.php';
}
}

View File

@ -1,93 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Decouple\UsedNodesExtractor;
use function implode;
use PhpParser\Node;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassConst;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use function sprintf;
final class UsedClassConstsExtractor
{
/**
* @var CallableNodeTraverser
*/
private $callableNodeTraverser;
/**
* @var NodeNameResolver
*/
private $nodeNameResolver;
public function __construct(CallableNodeTraverser $callableNodeTraverser, NodeNameResolver $nodeNameResolver)
{
$this->callableNodeTraverser = $callableNodeTraverser;
$this->nodeNameResolver = $nodeNameResolver;
}
/**
* @return ClassConst[]
*/
public function extract(ClassMethod $classMethod): array
{
$classConsts = [];
/** @var Class_ $classLike */
$classLike = $classMethod->getAttribute(AttributeKey::CLASS_NODE);
$this->callableNodeTraverser->traverseNodesWithCallable((array) $classMethod->stmts, function (Node $node) use (
&$classConsts,
$classLike
) {
if (! $node instanceof ClassConstFetch) {
return null;
}
if (! $this->nodeNameResolver->isName($node->class, 'self')) {
return null;
}
$classConstName = $this->nodeNameResolver->getName($node->name);
if ($classConstName === null) {
return null;
}
$classConsts[$classConstName] = $this->getClassConstByName($classLike, $classConstName);
});
return $classConsts;
}
private function getClassConstByName(Class_ $class, string $classConstName): ClassConst
{
$classConstantNames = [];
foreach ($class->getConstants() as $classConst) {
$classConstantNames[] = $this->nodeNameResolver->getName($classConst);
if (! $this->nodeNameResolver->isName($classConst, $classConstName)) {
continue;
}
return $classConst;
}
$className = $this->nodeNameResolver->getName($class);
$message = sprintf(
'Cannot find "%s::%s" constant. Pick one of: %s',
$className,
$classConstName,
implode(', ', $classConstantNames)
);
throw new ShouldNotHappenException($message);
}
}

View File

@ -1,138 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Decouple\UsedNodesExtractor;
use function array_keys;
use function array_merge;
use function in_array;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use ReflectionClass;
final class UsedClassMethodsExtractor
{
/**
* @var CallableNodeTraverser
*/
private $callableNodeTraverser;
/**
* @var NodeNameResolver
*/
private $nodeNameResolver;
public function __construct(CallableNodeTraverser $callableNodeTraverser, NodeNameResolver $nodeNameResolver)
{
$this->callableNodeTraverser = $callableNodeTraverser;
$this->nodeNameResolver = $nodeNameResolver;
}
/**
* @return ClassMethod[]
*/
public function extractFromClassMethod(ClassMethod $classMethod, ?string $parentClassName = null): array
{
/** @var Class_ $classLike */
$classLike = $classMethod->getAttribute(AttributeKey::CLASS_NODE);
$classMethods = [];
$this->callableNodeTraverser->traverseNodesWithCallable((array) $classMethod->stmts, function (Node $node) use (
&$classMethods,
$classLike
) {
if (! $node instanceof MethodCall) {
return null;
}
if (! $this->isThisPropertyFetch($node->var)) {
return null;
}
/** @var string $methodName */
$methodName = $this->nodeNameResolver->getName($node->name);
$classMethod = $classLike->getMethod($methodName);
if ($classMethod === null) {
throw new ShouldNotHappenException();
}
$classMethods[$methodName] = $classMethod;
});
// 2nd nesting method calls
foreach ($classMethods as $nestedClassMethod) {
$classMethods = array_merge($classMethods, $this->extractFromClassMethod($nestedClassMethod));
}
$uniqueClassMethods = $this->makeClassesMethodsUnique($classMethods);
if ($parentClassName !== null) {
return $this->filterOutParentClassMethods($uniqueClassMethods, $parentClassName);
}
return $uniqueClassMethods;
}
private function isThisPropertyFetch(Node $node): bool
{
if ($node instanceof MethodCall) {
return false;
}
if ($node instanceof StaticCall) {
return false;
}
return $this->nodeNameResolver->isName($node, 'this');
}
/**
* @param ClassMethod[] $classMethods
* @return ClassMethod[]
*/
private function makeClassesMethodsUnique(array $classMethods): array
{
$uniqueClassMethods = [];
foreach ($classMethods as $classMethod) {
/** @var string $classMethodName */
$classMethodName = $this->nodeNameResolver->getName($classMethod);
$uniqueClassMethods[$classMethodName] = $classMethod;
}
return $uniqueClassMethods;
}
/**
* @param ClassMethod[] $classMethods
* @return ClassMethod[]
*/
private function filterOutParentClassMethods(array $classMethods, string $parentClassName): array
{
$reflectionClass = new ReflectionClass($parentClassName);
$parentClassMethodNames = [];
foreach ($reflectionClass->getMethods() as $reflectionMethod) {
$parentClassMethodNames[] = $reflectionMethod->getName();
}
foreach (array_keys($classMethods) as $methodName) {
if (! in_array($methodName, $parentClassMethodNames, true)) {
continue;
}
unset($classMethods[$methodName]);
}
return $classMethods;
}
}

View File

@ -1,135 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Decouple\UsedNodesExtractor;
use function array_keys;
use function array_merge;
use function in_array;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use ReflectionClass;
final class UsedClassPropertyExtractor
{
/**
* @var CallableNodeTraverser
*/
private $callableNodeTraverser;
/**
* @var NodeNameResolver
*/
private $nodeNameResolver;
public function __construct(CallableNodeTraverser $callableNodeTraverser, NodeNameResolver $nodeNameResolver)
{
$this->callableNodeTraverser = $callableNodeTraverser;
$this->nodeNameResolver = $nodeNameResolver;
}
/**
* @param ClassMethod[] $classMethods
* @return Property[] <int|string, \PhpParser\Node\Stmt\Property>
*/
public function extractFromClassMethods(array $classMethods, ?string $parentClassName = null): array
{
$properties = [];
foreach ($classMethods as $classMethod) {
$properties = array_merge($properties, $this->extract($classMethod));
}
if ($parentClassName !== null) {
return $this->filterOutParentClassProperties($properties, $parentClassName);
}
return $properties;
}
/**
* @return Property[]
*/
private function extract(ClassMethod $classMethod): array
{
$properties = [];
/** @var Class_ $classLike */
$classLike = $classMethod->getAttribute(AttributeKey::CLASS_NODE);
$this->callableNodeTraverser->traverseNodesWithCallable((array) $classMethod->stmts, function (Node $node) use (
&$properties,
$classLike
) {
if (! $node instanceof PropertyFetch) {
return null;
}
if (! $this->isThisPropertyFetch($node->var)) {
return null;
}
$propertyName = $this->nodeNameResolver->getName($node->name);
if ($propertyName === null) {
throw new ShouldNotHappenException();
}
/** @var Property|null $property */
$property = $classLike->getProperty($propertyName);
if ($property === null) {
throw new ShouldNotHappenException();
}
$properties[$propertyName] = $property;
});
return $properties;
}
/**
* @param Property[] $classProperties
* @return Property[]
*/
private function filterOutParentClassProperties(array $classProperties, string $parentClassName): array
{
$reflectionClass = new ReflectionClass($parentClassName);
$parentClassPropertyNames = [];
foreach ($reflectionClass->getProperties() as $reflectionProperty) {
$parentClassPropertyNames[] = $reflectionProperty->getName();
}
foreach (array_keys($classProperties) as $propertyName) {
if (! in_array($propertyName, $parentClassPropertyNames, true)) {
continue;
}
unset($classProperties[$propertyName]);
}
return $classProperties;
}
private function isThisPropertyFetch(Node $node): bool
{
if ($node instanceof MethodCall) {
return false;
}
if ($node instanceof StaticCall) {
return false;
}
return $this->nodeNameResolver->isName($node, 'this');
}
}

View File

@ -1,45 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Decouple\ValueObject;
final class DecoupleClassMethodMatch
{
/**
* @var string
*/
private $className;
/**
* @var string
*/
private $methodName;
/**
* @var string|null
*/
private $parentClassName;
public function __construct(string $className, string $methodName, ?string $parentClassName = null)
{
$this->className = $className;
$this->parentClassName = $parentClassName;
$this->methodName = $methodName;
}
public function getClassName(): string
{
return $this->className;
}
public function getParentClassName(): ?string
{
return $this->parentClassName;
}
public function getMethodName(): string
{
return $this->methodName;
}
}

View File

@ -1,71 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Decouple\Tests\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\Decouple\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector;
use Rector\Decouple\Tests\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector\Source\AbstractFather;
use Symplify\SmartFileSystem\SmartFileInfo;
final class DecoupleClassMethodToOwnClassRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo, string $expectedFilePath, string $expectedContentFilePath): void
{
$this->doTestFileInfo($fileInfo);
$this->assertFileExists($expectedFilePath);
$this->assertFileEquals($expectedContentFilePath, $expectedFilePath);
}
public function provideData(): Iterator
{
yield [
new SmartFileInfo(__DIR__ . '/Fixture/basic.php.inc'),
// expected new file location
$this->getTempPath() . '/ExtraClassName.php',
// expected new file content
__DIR__ . '/Source/ExpectedExtraClassName.php',
];
yield [
new SmartFileInfo(__DIR__ . '/Fixture/with_property_dependency.php.inc'),
// expected new file location
$this->getTempPath() . '/ExtraUsingProperty.php',
// expected new file content
__DIR__ . '/Source/ExpectedExtraUsingProperty.php',
];
}
/**
* @return array<string, mixed[]>
*/
protected function getRectorsWithConfiguration(): array
{
return [
DecoupleClassMethodToOwnClassRector::class => [
DecoupleClassMethodToOwnClassRector::METHOD_NAMES_BY_CLASS => [
'Rector\Decouple\Tests\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector\Fixture\Basic' => [
'someMethod' => [
'method' => 'newMethodName',
'class' => 'ExtraClassName',
// optionally: "parent_class" =>
],
],
'Rector\Decouple\Tests\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector\Fixture\WithPropertyDependency' => [
'usingProperty' => [
'method' => 'newUsingProperty',
'class' => 'ExtraUsingProperty',
'parent_class' => AbstractFather::class,
],
],
],
],
];
}
}

View File

@ -1,46 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Decouple\Tests\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector\Fixture;
final class Basic
{
/**
* @var string
*/
public const VALUE = 'value';
public function another()
{
return $this->someMethod();
}
private function someMethod()
{
return self::VALUE;
}
}
?>
-----
<?php
declare(strict_types=1);
namespace Rector\Decouple\Tests\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector\Fixture;
final class Basic
{
/**
* @var string
*/
public const VALUE = 'value';
public function another()
{
return $this->someMethod();
}
}
?>

View File

@ -1,50 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Decouple\Tests\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector\Fixture;
use Rector\Decouple\Tests\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector\Source\EventManager;
final class WithPropertyDependency
{
/**
* @var EventManager
*/
private $eventManager;
public function __construct(EventManager $eventManager)
{
$this->eventManager = $eventManager;
}
public function usingProperty()
{
return $this->eventManager->runEvent();
}
}
?>
-----
<?php
declare(strict_types=1);
namespace Rector\Decouple\Tests\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector\Fixture;
use Rector\Decouple\Tests\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector\Source\EventManager;
final class WithPropertyDependency
{
/**
* @var EventManager
*/
private $eventManager;
public function __construct(EventManager $eventManager)
{
$this->eventManager = $eventManager;
}
}
?>

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Decouple\Tests\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector\Source;
abstract class AbstractFather
{
}

View File

@ -1,14 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Decouple\Tests\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector\Source;
final class EventManager
{
public function runEvent()
{
}
}

View File

@ -1,15 +0,0 @@
<?php
namespace Rector\Decouple\Tests\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector\Fixture;
final class ExtraClassName
{
/**
* @var string
*/
public const VALUE = 'value';
public function newMethodName()
{
return self::VALUE;
}
}

View File

@ -1,20 +0,0 @@
<?php
namespace Rector\Decouple\Tests\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector\Fixture;
use Rector\Decouple\Tests\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector\Source\EventManager;
final class ExtraUsingProperty extends \Rector\Decouple\Tests\Rector\ClassMethod\DecoupleClassMethodToOwnClassRector\Source\AbstractFather
{
/**
* @var EventManager
*/
private $eventManager;
public function __construct($eventManager)
{
$this->eventManager = $eventManager;
}
public function newUsingProperty()
{
return $this->eventManager->runEvent();
}
}