diff --git a/rules-tests/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector/Fixture/fixture.php.inc b/rules-tests/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector/Fixture/fixture.php.inc new file mode 100644 index 00000000000..4fc297bacff --- /dev/null +++ b/rules-tests/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector/Fixture/fixture.php.inc @@ -0,0 +1,35 @@ +setName('John') + ->setSurname('Doe'); + } +} + +?> +----- +setSurname('Doe'); + $someSetterClass->setName('John'); + } +} + +?> diff --git a/rules-tests/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector/Fixture/skip_sole_setter.php.inc b/rules-tests/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector/Fixture/skip_sole_setter.php.inc new file mode 100644 index 00000000000..9a8d204d64e --- /dev/null +++ b/rules-tests/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector/Fixture/skip_sole_setter.php.inc @@ -0,0 +1,14 @@ +setName('John'); + } +} diff --git a/rules-tests/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector/FluentSettersToStandaloneCallMethodRectorTest.php b/rules-tests/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector/FluentSettersToStandaloneCallMethodRectorTest.php new file mode 100644 index 00000000000..0a20edee79e --- /dev/null +++ b/rules-tests/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector/FluentSettersToStandaloneCallMethodRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector/Source/SomeSetterClass.php b/rules-tests/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector/Source/SomeSetterClass.php new file mode 100644 index 00000000000..7b0ff3a3afa --- /dev/null +++ b/rules-tests/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector/Source/SomeSetterClass.php @@ -0,0 +1,22 @@ +name = $name; + return $this; + } + + public function setSurname(?string $surname): self + { + $this->surname = $surname; + return $this; + } +} diff --git a/rules-tests/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector/config/configured_rule.php b/rules-tests/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector/config/configured_rule.php new file mode 100644 index 00000000000..1250f10ccec --- /dev/null +++ b/rules-tests/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector/config/configured_rule.php @@ -0,0 +1,9 @@ +withRules([FluentSettersToStandaloneCallMethodRector::class]); diff --git a/rules/Naming/Naming/PropertyNaming.php b/rules/Naming/Naming/PropertyNaming.php index 29c3e364975..4dff3f8d39a 100644 --- a/rules/Naming/Naming/PropertyNaming.php +++ b/rules/Naming/Naming/PropertyNaming.php @@ -5,6 +5,7 @@ namespace Rector\Naming\Naming; use Nette\Utils\Strings; +use PhpParser\Node\Name; use PHPStan\Type\Generic\GenericObjectType; use PHPStan\Type\ObjectType; use PHPStan\Type\StaticType; @@ -116,8 +117,12 @@ public function getExpectedNameFromType(Type $type): ?ExpectedName return new ExpectedName($originalName, $this->rectorNamingInflector->singularize($originalName)); } - public function fqnToVariableName(ThisType | ObjectType | string $objectType): string + public function fqnToVariableName(ThisType | ObjectType | Name | string $objectType): string { + if ($objectType instanceof Name) { + $objectType = $objectType->toString(); + } + if ($objectType instanceof ThisType) { $objectType = $objectType->getStaticObjectType(); } diff --git a/rules/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector.php b/rules/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector.php new file mode 100644 index 00000000000..cd53d7ccce9 --- /dev/null +++ b/rules/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector.php @@ -0,0 +1,140 @@ +setName('John') + ->setAge(30); + } +} +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +class SomeClass +{ + public function run() + { + $someFluentClass = new SomeFluentClass(); + $someFluentClass->setName('John'); + $someFluentClass->setAge(30); + + return $someFluentClass; + } +} +CODE_SAMPLE + ), + ] + ); + } + + /** + * @return array> + */ + public function getNodeTypes(): array + { + return [Expression::class, Return_::class]; + } + + /** + * @param Expression|Return_ $node + */ + public function refactor(Node $node): ?array + { + if (! $node->expr instanceof MethodCall) { + return null; + } + + $firstMethodCall = $node->expr; + + // must be nested method call, so we avoid only single one + if (! $firstMethodCall->var instanceof MethodCall) { + return null; + } + + /** @var MethodCall[] $methodCalls */ + $methodCalls = []; + + $currentMethodCall = $firstMethodCall; + while ($currentMethodCall instanceof MethodCall) { + $methodCalls[] = $currentMethodCall; + $currentMethodCall = $currentMethodCall->var; + } + + // at least 2 method calls + if (count($methodCalls) < 1) { + return null; + } + + $rootExpr = $currentMethodCall; + + $variableName = $this->resolveVariableName($rootExpr); + $someVariable = new Variable($variableName); + + $firstAssign = new Assign($someVariable, $rootExpr); + $stmts = [new Expression($firstAssign)]; + + foreach ($methodCalls as $methodCall) { + $methodCall->var = $someVariable; + // inlines indent and removes () around first expr + $methodCall->setAttribute(AttributeKey::ORIGINAL_NODE, null); + $stmts[] = new Expression($methodCall); + } + + $node->expr = $someVariable; + + return $stmts; + } + + private function resolveVariableName(Expr $expr): string + { + if (! $expr instanceof New_) { + return 'someVariable'; + } + + if ($expr->class instanceof Name) { + return $this->propertyNaming->fqnToVariableName($expr->class); + } + + return 'someVariable'; + } +} diff --git a/stubs/Doctrine/ORM/QueryBuilder.php b/stubs/Doctrine/ORM/QueryBuilder.php index d86b9be270c..51dbefc6ca2 100644 --- a/stubs/Doctrine/ORM/QueryBuilder.php +++ b/stubs/Doctrine/ORM/QueryBuilder.php @@ -10,5 +10,4 @@ class QueryBuilder { - }