[Defluent] Refactoring to multiple rules (#4400)

* [Defluent] Refactoring to multiple rules

* [Defluent] Decouple defluent-only set, it deserved to have own domain

* cleanup

* [rector] cleanup

* [cs] cleanup

* fixup! cleanup

* static fixes

Co-authored-by: rector-bot <tomas@getrector.org>
This commit is contained in:
Tomas Votruba 2020-10-14 06:24:29 +02:00 committed by GitHub
parent d017e5417e
commit 8af70b5ac0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
163 changed files with 2931 additions and 965 deletions

View File

@ -44,6 +44,7 @@
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.16",
"nette/application": "^3.0",
"nette/di": "^3.0",
"nette/forms": "^3.0",
"ocramius/package-versions": "^1.9",
"php-parallel-lint/php-parallel-lint": "^1.2",
@ -109,6 +110,7 @@
"Rector\\NetteToSymfony\\": "rules/nette-to-symfony/src",
"Rector\\NetteUtilsCodeQuality\\": "rules/nette-utils-code-quality/src",
"Rector\\Nette\\": "rules/nette/src",
"Rector\\Defluent\\": "rules/defluent/src",
"Rector\\NodeCollector\\": "packages/node-collector/src",
"Rector\\NodeNameResolver\\": "packages/node-name-resolver/src",
"Rector\\NodeNestingScope\\": "packages/node-nesting-scope/src",
@ -194,7 +196,8 @@
"rules/type-declaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Source/MyBar.php",
"rules/type-declaration/tests/Rector/Property/CompleteVarDocTypePropertyRector/Source/EventDispatcher.php",
"stubs/Nette/Localization/ITranslation.php",
"vendor/symfony/dependency-injection/Loader/Configurator/ContainerConfigurator.php"
"vendor/symfony/dependency-injection/Loader/Configurator/ContainerConfigurator.php",
"tests/debug_functions.php"
],
"psr-4": {
"Rector\\Architecture\\Tests\\": "rules/architecture/tests",
@ -222,6 +225,7 @@
"Rector\\JMS\\Tests\\": "rules/jms/tests",
"Rector\\Laravel\\Tests\\": "rules/laravel/tests",
"Rector\\Legacy\\Tests\\": "rules/legacy/tests",
"Rector\\Defluent\\Tests\\": "rules/defluent/tests",
"Rector\\MagicDisclosure\\Tests\\": "rules/magic-disclosure/tests",
"Rector\\MockeryToProphecy\\Tests\\": "rules/mockery-to-prophecy/tests",
"Rector\\MockistaToMockery\\Tests\\": "rules/mockista-to-mockery/tests",

View File

@ -2,11 +2,14 @@
declare(strict_types=1);
use Rector\MagicDisclosure\Rector\ClassMethod\ReturnThisRemoveRector;
use Rector\MagicDisclosure\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector;
use Rector\MagicDisclosure\Rector\MethodCall\InArgFluentChainMethodCallToStandaloneMethodCallRector;
use Rector\MagicDisclosure\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector;
use Rector\MagicDisclosure\Rector\Return_\DefluentReturnMethodCallRector;
use Rector\Defluent\Rector\ClassMethod\ReturnThisRemoveRector;
use Rector\Defluent\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector;
use Rector\Defluent\Rector\MethodCall\InArgFluentChainMethodCallToStandaloneMethodCallRector;
use Rector\Defluent\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector;
use Rector\Defluent\Rector\MethodCall\NewFluentChainMethodCallToNonFluentRector;
use Rector\Defluent\Rector\Return_\DefluentReturnMethodCallRector;
use Rector\Defluent\Rector\Return_\ReturnFluentChainMethodCallToNormalMethodCallRector;
use Rector\Defluent\Rector\Return_\ReturnNewFluentChainMethodCallToNonFluentRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
// @see https://ocramius.github.io/blog/fluent-interfaces-are-evil/
@ -15,9 +18,16 @@ use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigura
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
// variable/property
$services->set(FluentChainMethodCallToNormalMethodCallRector::class);
$services->set(ReturnFluentChainMethodCallToNormalMethodCallRector::class);
// new
$services->set(NewFluentChainMethodCallToNonFluentRector::class);
$services->set(ReturnNewFluentChainMethodCallToNonFluentRector::class);
$services->set(ReturnThisRemoveRector::class);
$services->set(DefluentReturnMethodCallRector::class);
$services->set(FluentChainMethodCallToNormalMethodCallRector::class);
$services->set(MethodCallOnSetterMethodCallToStandaloneAssignRector::class);
$services->set(InArgFluentChainMethodCallToStandaloneMethodCallRector::class);
};

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
use Rector\MagicDisclosure\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector;
use Rector\Defluent\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector;
use Rector\Renaming\Rector\MethodCall\RenameMethodRector;
use Rector\Renaming\ValueObject\MethodCallRename;
use function Rector\SymfonyPhpConfig\inline_value_objects;
@ -16,7 +16,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
# both uses "%classes_to_defluent%
#diff-810cdcfdd8a6b9e1fc0d1e96d7786874
$services->set(FluentChainMethodCallToNormalMethodCallRector::class);
$configuration = [

View File

@ -1,4 +1,4 @@
# All 588 Rectors Overview
# All 592 Rectors Overview
- [Projects](#projects)
---
@ -12,6 +12,7 @@
- [CodingStyle](#codingstyle) (33)
- [DeadCode](#deadcode) (40)
- [Decouple](#decouple) (1)
- [Defluent](#defluent) (8)
- [Doctrine](#doctrine) (17)
- [DoctrineCodeQuality](#doctrinecodequality) (8)
- [DoctrineGedmoToKnplabs](#doctrinegedmotoknplabs) (7)
@ -26,7 +27,7 @@
- [JMS](#jms) (2)
- [Laravel](#laravel) (3)
- [Legacy](#legacy) (4)
- [MagicDisclosure](#magicdisclosure) (8)
- [MagicDisclosure](#magicdisclosure) (3)
- [MockeryToProphecy](#mockerytoprophecy) (2)
- [MockistaToMockery](#mockistatomockery) (2)
- [MysqlToMysqli](#mysqltomysqli) (4)
@ -3492,6 +3493,171 @@ class NewDecoupledClass extends AddedParentClass
<br><br>
## Defluent
### `DefluentReturnMethodCallRector`
- class: [`Rector\Defluent\Rector\Return_\DefluentReturnMethodCallRector`](/rules/defluent/src/Rector/Return_/DefluentReturnMethodCallRector.php)
- [test fixtures](/rules/defluent/tests/Rector/Return_/DefluentReturnMethodCallRector/Fixture)
Turns return of fluent, to standalone call line and return of value
```diff
$someClass = new SomeClass();
-return $someClass->someFunction();
+$someClass->someFunction();
+return $someClass;
```
<br><br>
### `FluentChainMethodCallToNormalMethodCallRector`
- class: [`Rector\Defluent\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector`](/rules/defluent/src/Rector/MethodCall/FluentChainMethodCallToNormalMethodCallRector.php)
- [test fixtures](/rules/defluent/tests/Rector/MethodCall/FluentChainMethodCallToNormalMethodCallRector/Fixture)
Turns fluent interface calls to classic ones.
```diff
$someClass = new SomeClass();
-$someClass->someFunction()
- ->otherFunction();
+$someClass->someFunction();
+$someClass->otherFunction();
```
<br><br>
### `InArgFluentChainMethodCallToStandaloneMethodCallRector`
- class: [`Rector\Defluent\Rector\MethodCall\InArgFluentChainMethodCallToStandaloneMethodCallRector`](/rules/defluent/src/Rector/MethodCall/InArgFluentChainMethodCallToStandaloneMethodCallRector.php)
Turns fluent interface calls to classic ones.
```diff
class UsedAsParameter
{
public function someFunction(FluentClass $someClass)
{
- $this->processFluentClass($someClass->someFunction()->otherFunction());
+ $someClass->someFunction();
+ $someClass->otherFunction();
+ $this->processFluentClass($someClass);
}
public function processFluentClass(FluentClass $someClass)
{
}
-}
+}
```
<br><br>
### `MethodCallOnSetterMethodCallToStandaloneAssignRector`
- class: [`Rector\Defluent\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector`](/rules/defluent/src/Rector/MethodCall/MethodCallOnSetterMethodCallToStandaloneAssignRector.php)
- [test fixtures](/rules/defluent/tests/Rector/MethodCall/MethodCallOnSetterMethodCallToStandaloneAssignRector/Fixture)
Change method call on setter to standalone assign before the setter
```diff
class SomeClass
{
public function some()
{
- $this->anotherMethod(new AnotherClass())
- ->someFunction();
+ $anotherClass = new AnotherClass();
+ $anotherClass->someFunction();
+ $this->anotherMethod($anotherClass);
}
public function anotherMethod(AnotherClass $anotherClass)
{
}
}
```
<br><br>
### `NewFluentChainMethodCallToNonFluentRector`
- class: [`Rector\Defluent\Rector\MethodCall\NewFluentChainMethodCallToNonFluentRector`](/rules/defluent/src/Rector/MethodCall/NewFluentChainMethodCallToNonFluentRector.php)
- [test fixtures](/rules/defluent/tests/Rector/MethodCall/NewFluentChainMethodCallToNonFluentRector/Fixture)
Turns fluent interface calls to classic ones.
```diff
-(new SomeClass())->someFunction()
- ->otherFunction();
+$someClass = new SomeClass();
+$someClass->someFunction();
+$someClass->otherFunction();
```
<br><br>
### `ReturnFluentChainMethodCallToNormalMethodCallRector`
- class: [`Rector\Defluent\Rector\Return_\ReturnFluentChainMethodCallToNormalMethodCallRector`](/rules/defluent/src/Rector/Return_/ReturnFluentChainMethodCallToNormalMethodCallRector.php)
- [test fixtures](/rules/defluent/tests/Rector/Return_/ReturnFluentChainMethodCallToNormalMethodCallRector/Fixture)
Turns fluent interface calls to classic ones.
```diff
$someClass = new SomeClass();
-return $someClass->someFunction()
- ->otherFunction();
+$someClass->someFunction();
+$someClass->otherFunction();
+return $someClass;
```
<br><br>
### `ReturnNewFluentChainMethodCallToNonFluentRector`
- class: [`Rector\Defluent\Rector\Return_\ReturnNewFluentChainMethodCallToNonFluentRector`](/rules/defluent/src/Rector/Return_/ReturnNewFluentChainMethodCallToNonFluentRector.php)
- [test fixtures](/rules/defluent/tests/Rector/Return_/ReturnNewFluentChainMethodCallToNonFluentRector/Fixture)
Turns fluent interface calls to classic ones.
```diff
-return (new SomeClass())->someFunction()
- ->otherFunction();
+$someClass = new SomeClass();
+$someClass->someFunction();
+$someClass->otherFunction();
+return $someClass;
```
<br><br>
### `ReturnThisRemoveRector`
- class: [`Rector\Defluent\Rector\ClassMethod\ReturnThisRemoveRector`](/rules/defluent/src/Rector/ClassMethod/ReturnThisRemoveRector.php)
- [test fixtures](/rules/defluent/tests/Rector/ClassMethod/ReturnThisRemoveRector/Fixture)
Removes "return `$this;"` from *fluent interfaces* for specified classes.
```diff
class SomeExampleClass
{
public function someFunction()
{
- return $this;
}
public function otherFunction()
{
- return $this;
}
}
```
<br><br>
## Doctrine
### `AddEntityIdByConditionRector`
@ -7118,39 +7284,6 @@ Remove includes (include, include_once, require, require_once) from source
## MagicDisclosure
### `DefluentReturnMethodCallRector`
- class: [`Rector\MagicDisclosure\Rector\Return_\DefluentReturnMethodCallRector`](/rules/magic-disclosure/src/Rector/Return_/DefluentReturnMethodCallRector.php)
- [test fixtures](/rules/magic-disclosure/tests/Rector/Return_/DefluentReturnMethodCallRector/Fixture)
Turns return of fluent, to standalone call line and return of value
```diff
$someClass = new SomeClass();
-return $someClass->someFunction();
+$someClass->someFunction();
+return $someClass;
```
<br><br>
### `FluentChainMethodCallToNormalMethodCallRector`
- class: [`Rector\MagicDisclosure\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector`](/rules/magic-disclosure/src/Rector/MethodCall/FluentChainMethodCallToNormalMethodCallRector.php)
- [test fixtures](/rules/magic-disclosure/tests/Rector/MethodCall/FluentChainMethodCallToNormalMethodCallRector/Fixture)
Turns fluent interface calls to classic ones.
```diff
$someClass = new SomeClass();
-$someClass->someFunction()
- ->otherFunction();
+$someClass->someFunction();
+$someClass->otherFunction();
```
<br><br>
### `GetAndSetToMethodCallRector`
- class: [`Rector\MagicDisclosure\Rector\Assign\GetAndSetToMethodCallRector`](/rules/magic-disclosure/src/Rector/Assign/GetAndSetToMethodCallRector.php)
@ -7219,83 +7352,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
<br><br>
### `InArgFluentChainMethodCallToStandaloneMethodCallRector`
- class: [`Rector\MagicDisclosure\Rector\MethodCall\InArgFluentChainMethodCallToStandaloneMethodCallRector`](/rules/magic-disclosure/src/Rector/MethodCall/InArgFluentChainMethodCallToStandaloneMethodCallRector.php)
Turns fluent interface calls to classic ones.
```diff
class UsedAsParameter
{
public function someFunction(FluentClass $someClass)
{
- $this->processFluentClass($someClass->someFunction()->otherFunction());
+ $someClass->someFunction();
+ $someClass->otherFunction();
+ $this->processFluentClass($someClass);
}
public function processFluentClass(FluentClass $someClass)
{
}
-}
+}
```
<br><br>
### `MethodCallOnSetterMethodCallToStandaloneAssignRector`
- class: [`Rector\MagicDisclosure\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector`](/rules/magic-disclosure/src/Rector/MethodCall/MethodCallOnSetterMethodCallToStandaloneAssignRector.php)
- [test fixtures](/rules/magic-disclosure/tests/Rector/MethodCall/MethodCallOnSetterMethodCallToStandaloneAssignRector/Fixture)
Change method call on setter to standalone assign before the setter
```diff
class SomeClass
{
public function some()
{
- $this->anotherMethod(new AnotherClass())
- ->someFunction();
+ $anotherClass = new AnotherClass();
+ $anotherClass->someFunction();
+ $this->anotherMethod($anotherClass);
}
public function anotherMethod(AnotherClass $anotherClass)
{
}
}
```
<br><br>
### `ReturnThisRemoveRector`
- class: [`Rector\MagicDisclosure\Rector\ClassMethod\ReturnThisRemoveRector`](/rules/magic-disclosure/src/Rector/ClassMethod/ReturnThisRemoveRector.php)
- [test fixtures](/rules/magic-disclosure/tests/Rector/ClassMethod/ReturnThisRemoveRector/Fixture)
Removes "return `$this;"` from *fluent interfaces* for specified classes.
```diff
class SomeExampleClass
{
public function someFunction()
{
- return $this;
}
public function otherFunction()
{
- return $this;
}
}
```
<br><br>
### `ToStringToMethodCallRector`
- class: [`Rector\MagicDisclosure\Rector\String_\ToStringToMethodCallRector`](/rules/magic-disclosure/src/Rector/String_/ToStringToMethodCallRector.php)
@ -8609,7 +8665,7 @@ Rename "*.phpt" file to "*Test.php" file
### `DeleteFactoryInterfaceRector`
- class: [`Rector\NetteToSymfony\Rector\Interface_\DeleteFactoryInterfaceRector`](/rules/nette-to-symfony/src/Rector/FileSystem/DeleteFactoryInterfaceRector.php)
- class: [`Rector\NetteToSymfony\Rector\Interface_\DeleteFactoryInterfaceRector`](/rules/nette-to-symfony/src/Rector/Interface_/DeleteFactoryInterfaceRector.php)
Interface factories are not needed in Symfony. Clear constructor injection is used instead
@ -13889,8 +13945,8 @@ Restore accidentally shortened class names to its fully qualified form.
### `UpdateFileNameByClassNameFileSystemRector`
- class: [`Rector\Restoration\Rector\ClassLike\UpdateFileNameByClassNameFileSystemRector`](/rules/restoration/src/Rector/FileSystem/UpdateFileNameByClassNameFileSystemRector.php)
- [test fixtures](/rules/restoration/tests/Rector/FileSystem/UpdateFileNameByClassNameFileSystemRector/Fixture)
- class: [`Rector\Restoration\Rector\ClassLike\UpdateFileNameByClassNameFileSystemRector`](/rules/restoration/src/Rector/ClassLike/UpdateFileNameByClassNameFileSystemRector.php)
- [test fixtures](/rules/restoration/tests/Rector/ClassLike/UpdateFileNameByClassNameFileSystemRector/Fixture)
Rename file to respect class name

View File

@ -5,15 +5,11 @@ declare(strict_types=1);
namespace Rector\NodeTypeResolver\Tests\PerNodeTypeResolver;
use PhpParser\Node;
use Rector\Core\Configuration\Option;
use Rector\Core\HttpKernel\RectorKernel;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\PhpParser\Parser\Parser;
use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator;
use Rector\Core\Testing\TestingParser\TestingParser;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Symplify\PackageBuilder\Parameter\ParameterProvider;
use Symplify\PackageBuilder\Tests\AbstractKernelTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
abstract class AbstractNodeTypeResolverTest extends AbstractKernelTestCase
{
@ -28,29 +24,17 @@ abstract class AbstractNodeTypeResolverTest extends AbstractKernelTestCase
private $betterNodeFinder;
/**
* @var Parser
* @var TestingParser
*/
private $parser;
/**
* @var NodeScopeAndMetadataDecorator
*/
private $nodeScopeAndMetadataDecorator;
/**
* @var ParameterProvider
*/
private $parameterProvider;
private $testingParser;
protected function setUp(): void
{
$this->bootKernel(RectorKernel::class);
$this->betterNodeFinder = self::$container->get(BetterNodeFinder::class);
$this->parameterProvider = self::$container->get(ParameterProvider::class);
$this->testingParser = self::$container->get(TestingParser::class);
$this->nodeTypeResolver = self::$container->get(NodeTypeResolver::class);
$this->parser = self::$container->get(Parser::class);
$this->nodeScopeAndMetadataDecorator = self::$container->get(NodeScopeAndMetadataDecorator::class);
}
/**
@ -58,22 +42,8 @@ abstract class AbstractNodeTypeResolverTest extends AbstractKernelTestCase
*/
protected function getNodesForFileOfType(string $file, string $type): array
{
$nodes = $this->getNodesForFile($file);
$nodes = $this->testingParser->parseFileToDecoratedNodes($file);
return $this->betterNodeFinder->findInstanceOf($nodes, $type);
}
/**
* @return Node[]
*/
private function getNodesForFile(string $file): array
{
$smartFileInfo = new SmartFileInfo($file);
$this->parameterProvider->changeParameter(Option::SOURCE, [$file]);
$nodes = $this->parser->parseFileInfo($smartFileInfo);
return $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile($nodes, $smartFileInfo);
}
}

View File

@ -892,3 +892,8 @@ parameters:
message: '#Multiple class/interface/trait is not allowed in a file#'
paths:
- src/PhpParser/NodeTraverser/CallableNodeTraverser.php
-
message: '#Function "dump\(\)" cannot be used/left in the code#'
paths:
- tests/debug_functions.php

View File

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

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\ConflictGuard;
namespace Rector\Defluent\ConflictGuard;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Reflection\ClassReflection;

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\Contract\ValueObject;
interface FirstCallFactoryAwareInterface
{
public function isFirstCallFactory(): bool;
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\Contract\ValueObject;
use PhpParser\Node\Expr;
interface RootExprAwareInterface
{
public function getRootExpr(): Expr;
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\NodeAnalyzer;
namespace Rector\Defluent\NodeAnalyzer;
use PhpParser\Node\Expr;
use PHPStan\Type\TypeWithClassName;

View File

@ -2,12 +2,11 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\NodeAnalyzer;
namespace Rector\Defluent\NodeAnalyzer;
use PhpParser\Node\Expr\MethodCall;
use Rector\MagicDisclosure\ValueObject\AssignAndRootExpr;
final class ChainCallsStaticTypeResolver
final class FluentCallStaticTypeResolver
{
/**
* @var ExprStringTypeResolver
@ -23,15 +22,17 @@ final class ChainCallsStaticTypeResolver
* @param MethodCall[] $chainMethodCalls
* @return string[]
*/
public function resolveCalleeUniqueTypes(AssignAndRootExpr $assignAndRootExpr, array $chainMethodCalls): array
public function resolveCalleeUniqueTypes(array $chainMethodCalls): array
{
$rootClassType = $this->exprStringTypeResolver->resolve($assignAndRootExpr->getRootExpr());
if ($rootClassType === null) {
return [];
}
$callerClassTypes = [];
$callerClassTypes[] = $rootClassType;
$lastMethodCallKey = array_key_last($chainMethodCalls);
$lastMethodCall = $chainMethodCalls[$lastMethodCallKey];
$rootType = $this->exprStringTypeResolver->resolve($lastMethodCall->var);
if ($rootType !== null) {
$callerClassTypes[] = $rootType;
}
// chain method calls are inversed
$lastChainMethodCallKey = array_key_first($chainMethodCalls);

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\NodeAnalyzer;
namespace Rector\Defluent\NodeAnalyzer;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
@ -177,7 +177,7 @@ final class FluentChainMethodCallNodeAnalyzer
->yes();
}
public function resolveRootVariable(MethodCall $methodCall): Node
public function resolveRootExpr(MethodCall $methodCall): Node
{
$callerNode = $methodCall->var;

View File

@ -2,31 +2,31 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\NodeManipulator;
namespace Rector\Defluent\NodeAnalyzer;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\MagicDisclosure\NodeAnalyzer\ExprStringTypeResolver;
use Rector\MagicDisclosure\ValueObject\AssignAndRootExpr;
use Rector\Defluent\ValueObject\AssignAndRootExpr;
use Rector\Defluent\ValueObject\FluentCallsKind;
use Rector\Naming\Naming\PropertyNaming;
use Rector\NetteKdyby\Naming\VariableNaming;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\PHPStan\Type\FullyQualifiedObjectType;
/**
* @see \Rector\Defluent\Tests\NodeFactory\FluentChainMethodCallRootExtractor\FluentChainMethodCallRootExtractorTest
*/
final class FluentChainMethodCallRootExtractor
{
/**
* @var string
*/
public const KIND_IN_ARGS = 'in_args';
/**
* @var PropertyNaming
*/
@ -52,18 +52,25 @@ final class FluentChainMethodCallRootExtractor
*/
private $exprStringTypeResolver;
/**
* @var NodeTypeResolver
*/
private $nodeTypeResolver;
public function __construct(
BetterNodeFinder $betterNodeFinder,
NodeNameResolver $nodeNameResolver,
PropertyNaming $propertyNaming,
VariableNaming $variableNaming,
ExprStringTypeResolver $exprStringTypeResolver
ExprStringTypeResolver $exprStringTypeResolver,
NodeTypeResolver $nodeTypeResolver
) {
$this->propertyNaming = $propertyNaming;
$this->betterNodeFinder = $betterNodeFinder;
$this->nodeNameResolver = $nodeNameResolver;
$this->variableNaming = $variableNaming;
$this->exprStringTypeResolver = $exprStringTypeResolver;
$this->nodeTypeResolver = $nodeTypeResolver;
}
/**
@ -71,15 +78,19 @@ final class FluentChainMethodCallRootExtractor
*/
public function extractFromMethodCalls(array $methodCalls, string $kind): ?AssignAndRootExpr
{
// we need at least 2 method call for fluent
if (count($methodCalls) < 2) {
return null;
}
foreach ($methodCalls as $methodCall) {
if ($methodCall->var instanceof Variable || $methodCall->var instanceof PropertyFetch) {
$isFirstCallFactory = $this->resolveIsFirstCallFactory($methodCall);
return new AssignAndRootExpr($methodCall->var, $methodCall->var, null, $isFirstCallFactory);
return $this->createAssignAndRootExprForVariableOrPropertyFetch($methodCall);
}
if ($methodCall->var instanceof New_) {
// direct = no parent
if ($kind === self::KIND_IN_ARGS) {
if ($kind === FluentCallsKind::IN_ARGS) {
return $this->resolveKindInArgs($methodCall);
}
@ -95,7 +106,7 @@ final class FluentChainMethodCallRootExtractor
* A. FLUENT: $cook->bake()->serve() // only "Cook"
* B. FACTORY: $food = $cook->bake()->warmUp(); // only "Food"
*/
private function resolveIsFirstCallFactory(MethodCall $methodCall): bool
public function resolveIsFirstMethodCallFactory(MethodCall $methodCall): bool
{
$variableStaticType = $this->exprStringTypeResolver->resolve($methodCall->var);
$calledMethodStaticType = $this->exprStringTypeResolver->resolve($methodCall);
@ -118,6 +129,26 @@ final class FluentChainMethodCallRootExtractor
return $variableStaticType !== $calledMethodStaticType;
}
private function createAssignAndRootExprForVariableOrPropertyFetch(MethodCall $methodCall): AssignAndRootExpr
{
$isFirstCallFactory = $this->resolveIsFirstMethodCallFactory($methodCall);
// the method call, does not belong to the
$staticType = $this->nodeTypeResolver->getStaticType($methodCall);
// no assign
if ($methodCall->getAttribute(AttributeKey::PARENT_NODE) instanceof Expression) {
$variableName = $this->propertyNaming->fqnToVariableName($staticType);
// the assign expresison must be break
// pesuero code bsaed on type
$variable = new Variable($variableName);
return new AssignAndRootExpr($methodCall->var, $methodCall->var, $variable, $isFirstCallFactory);
}
return new AssignAndRootExpr($methodCall->var, $methodCall->var, null, $isFirstCallFactory);
}
private function resolveKindInArgs(MethodCall $methodCall): AssignAndRootExpr
{
$variableName = $this->variableNaming->resolveFromNode($methodCall->var);

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\NodeAnalyzer;
use PhpParser\Node\Expr\MethodCall;
use Rector\NodeTypeResolver\NodeTypeResolver;
final class GetterMethodCallAnalyzer
{
/**
* @var NodeTypeResolver
*/
private $nodeTypeResolver;
public function __construct(NodeTypeResolver $nodeTypeResolver)
{
$this->nodeTypeResolver = $nodeTypeResolver;
}
public function isGetterMethodCall(MethodCall $methodCall): bool
{
if ($methodCall->var instanceof MethodCall) {
return false;
}
$methodCallStaticType = $this->nodeTypeResolver->getStaticType($methodCall);
$methodCallVarStaticType = $this->nodeTypeResolver->getStaticType($methodCall->var);
// getter short call type
return ! $methodCallStaticType->equals($methodCallVarStaticType);
}
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\NodeAnalyzer;
namespace Rector\Defluent\NodeAnalyzer;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;

View File

@ -0,0 +1,64 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\NodeAnalyzer;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Defluent\Contract\ValueObject\FirstCallFactoryAwareInterface;
use Rector\NodeCollector\NodeCollector\NodeRepository;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class SameClassMethodCallAnalyzer
{
/**
* @var NodeRepository
*/
private $nodeRepository;
public function __construct(NodeRepository $nodeRepository)
{
$this->nodeRepository = $nodeRepository;
}
/**
* @param MethodCall[] $chainMethodCalls
*/
public function haveSingleClass(array $chainMethodCalls): bool
{
// are method calls located in the same class?
$classOfClassMethod = [];
foreach ($chainMethodCalls as $chainMethodCall) {
$classMethod = $this->nodeRepository->findClassMethodByMethodCall($chainMethodCall);
if ($classMethod instanceof ClassMethod) {
$classOfClassMethod[] = $classMethod->getAttribute(AttributeKey::CLASS_NAME);
} else {
$classOfClassMethod[] = null;
}
}
$uniqueClasses = array_unique($classOfClassMethod);
return count($uniqueClasses) < 2;
}
/**
* @param string[] $calleeUniqueTypes
*/
public function isCorrectTypeCount(
array $calleeUniqueTypes,
FirstCallFactoryAwareInterface $firstCallFactoryAware
): bool {
if (count($calleeUniqueTypes) === 0) {
return false;
}
// in case of factory method, 2 methods are allowed
if ($firstCallFactoryAware->isFirstCallFactory()) {
return count($calleeUniqueTypes) === 2;
}
return count($calleeUniqueTypes) === 1;
}
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\NodeFactory;
namespace Rector\Defluent\NodeFactory;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
@ -12,9 +12,9 @@ use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\MagicDisclosure\NodeAnalyzer\FluentChainMethodCallNodeAnalyzer;
use Rector\MagicDisclosure\NodeManipulator\FluentChainMethodCallRootExtractor;
use Rector\MagicDisclosure\ValueObject\AssignAndRootExpr;
use Rector\Defluent\NodeAnalyzer\FluentChainMethodCallNodeAnalyzer;
use Rector\Defluent\ValueObject\AssignAndRootExpr;
use Rector\Defluent\ValueObject\FluentCallsKind;
use Rector\NetteKdyby\Naming\VariableNaming;
final class NonFluentChainMethodCallFactory
@ -73,7 +73,7 @@ final class NonFluentChainMethodCallFactory
public function createFromAssignObjectAndMethodCalls(
AssignAndRootExpr $assignAndRootExpr,
array $chainMethodCalls,
string $kind = 'normal'
string $kind
): array {
$nodesToAdd = [];
@ -90,7 +90,7 @@ final class NonFluentChainMethodCallFactory
$nodesToAdd = array_merge($nodesToAdd, $decoupledMethodCalls);
if ($assignAndRootExpr->getSilentVariable() !== null && $kind !== FluentChainMethodCallRootExtractor::KIND_IN_ARGS) {
if ($assignAndRootExpr->getSilentVariable() !== null && $kind !== FluentCallsKind::IN_ARGS) {
$nodesToAdd[] = $assignAndRootExpr->getReturnSilentVariable();
}

View File

@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\NodeFactory;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use Rector\Defluent\NodeAnalyzer\FluentChainMethodCallRootExtractor;
use Rector\Defluent\ValueObject\FirstAssignFluentCall;
use Rector\Defluent\ValueObject\FluentMethodCalls;
use Rector\Naming\Naming\PropertyNaming;
use Rector\NodeTypeResolver\NodeTypeResolver;
final class ReturnFluentMethodCallFactory
{
/**
* @var FluentChainMethodCallRootExtractor
*/
private $fluentChainMethodCallRootExtractor;
/**
* @var NodeTypeResolver
*/
private $nodeTypeResolver;
/**
* @var PropertyNaming
*/
private $propertyNaming;
public function __construct(
FluentChainMethodCallRootExtractor $fluentChainMethodCallRootExtractor,
NodeTypeResolver $nodeTypeResolver,
PropertyNaming $propertyNaming
) {
$this->fluentChainMethodCallRootExtractor = $fluentChainMethodCallRootExtractor;
$this->nodeTypeResolver = $nodeTypeResolver;
$this->propertyNaming = $propertyNaming;
}
public function createFromFluentMethodCalls(FluentMethodCalls $fluentMethodCalls): FirstAssignFluentCall
{
$rootMethodCall = $fluentMethodCalls->getRootMethodCall();
// this means the 1st method creates different object then it runs on
// e.g. $sheet->getRow(), creates a "Row" object
$isFirstMethodCallFactory = $this->fluentChainMethodCallRootExtractor->resolveIsFirstMethodCallFactory(
$rootMethodCall
);
$lastMethodCall = $fluentMethodCalls->getRootMethodCall();
if ($lastMethodCall->var instanceof PropertyFetch) {
$assignExpr = $lastMethodCall->var;
} else {
// we need a variable to assign the stuff into
// the method call, does not belong to the
$staticType = $this->nodeTypeResolver->getStaticType($rootMethodCall);
$variableName = $this->propertyNaming->fqnToVariableName($staticType);
$assignExpr = new Variable($variableName);
}
return new FirstAssignFluentCall(
$assignExpr,
$rootMethodCall,
$isFirstMethodCallFactory,
$fluentMethodCalls
);
}
}

View File

@ -0,0 +1,83 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\NodeFactory;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Stmt\Return_;
use Rector\Defluent\ValueObject\FirstAssignFluentCall;
use Rector\Defluent\ValueObject\FluentMethodCalls;
final class SeparateReturnMethodCallFactory
{
/**
* @return Node[]
*/
public function createReturnFromFirstAssignFluentCallAndFluentMethodCalls(
FirstAssignFluentCall $firstAssignFluentCall,
FluentMethodCalls $fluentMethodCalls
): array {
$nodesToAdd = [];
if (! $firstAssignFluentCall->getAssignExpr() instanceof PropertyFetch) {
$nodesToAdd[] = $firstAssignFluentCall->createFirstAssign();
}
$decoupledMethodCalls = $this->createNonFluentMethodCalls(
$fluentMethodCalls->getFluentMethodCalls(),
$firstAssignFluentCall,
true
);
$nodesToAdd = array_merge($nodesToAdd, $decoupledMethodCalls);
// return the first value
$nodesToAdd[] = new Return_($firstAssignFluentCall->getAssignExpr());
return $nodesToAdd;
}
/**
* @param MethodCall[] $chainMethodCalls
* @return MethodCall[]
*/
private function createNonFluentMethodCalls(
array $chainMethodCalls,
FirstAssignFluentCall $firstAssignFluentCall,
bool $isNewNodeNeeded
): array {
$decoupledMethodCalls = [];
$lastKey = array_key_last($chainMethodCalls);
foreach ($chainMethodCalls as $key => $chainMethodCall) {
// skip first, already handled
if ($key === $lastKey && $firstAssignFluentCall->isFirstCallFactory() && $isNewNodeNeeded) {
continue;
}
$chainMethodCall->var = $this->resolveMethodCallVar($firstAssignFluentCall, $key);
$decoupledMethodCalls[] = $chainMethodCall;
}
return array_reverse($decoupledMethodCalls);
}
private function resolveMethodCallVar(FirstAssignFluentCall $firstAssignFluentCall, int $key): Expr
{
if (! $firstAssignFluentCall->isFirstCallFactory()) {
return $firstAssignFluentCall->getCallerExpr();
}
// very first call
if ($key !== 0) {
return $firstAssignFluentCall->getCallerExpr();
}
return $firstAssignFluentCall->getFactoryAssignVariable();
}
}

View File

@ -0,0 +1,148 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\Rector;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\Rector\AbstractRector;
use Rector\Defluent\NodeAnalyzer\FluentChainMethodCallNodeAnalyzer;
use Rector\Defluent\NodeAnalyzer\FluentChainMethodCallRootExtractor;
use Rector\Defluent\NodeAnalyzer\SameClassMethodCallAnalyzer;
use Rector\Defluent\NodeFactory\NonFluentChainMethodCallFactory;
use Rector\Defluent\Skipper\FluentMethodCallSkipper;
use Rector\Defluent\ValueObject\AssignAndRootExprAndNodesToAdd;
use Rector\NodeTypeResolver\Node\AttributeKey;
abstract class AbstractFluentChainMethodCallRector extends AbstractRector
{
/**
* @var FluentChainMethodCallNodeAnalyzer
*/
protected $fluentChainMethodCallNodeAnalyzer;
/**
* @var NonFluentChainMethodCallFactory
*/
protected $nonFluentChainMethodCallFactory;
/**
* @var FluentChainMethodCallRootExtractor
*/
protected $fluentChainMethodCallRootExtractor;
/**
* @var SameClassMethodCallAnalyzer
*/
protected $sameClassMethodCallAnalyzer;
/**
* @var FluentMethodCallSkipper
*/
protected $fluentMethodCallSkipper;
/**
* @required
*/
public function autowireAbstractFluentChainMethodCallRector(
FluentChainMethodCallNodeAnalyzer $fluentChainMethodCallNodeAnalyzer,
FluentChainMethodCallRootExtractor $fluentChainMethodCallRootExtractor,
NonFluentChainMethodCallFactory $nonFluentChainMethodCallFactory,
SameClassMethodCallAnalyzer $sameClassMethodCallAnalyzer,
FluentMethodCallSkipper $fluentMethodCallSkipper
): void {
$this->fluentChainMethodCallNodeAnalyzer = $fluentChainMethodCallNodeAnalyzer;
$this->fluentChainMethodCallRootExtractor = $fluentChainMethodCallRootExtractor;
$this->nonFluentChainMethodCallFactory = $nonFluentChainMethodCallFactory;
$this->sameClassMethodCallAnalyzer = $sameClassMethodCallAnalyzer;
$this->fluentMethodCallSkipper = $fluentMethodCallSkipper;
}
protected function createStandaloneNodesToAddFromChainMethodCalls(
MethodCall $methodCall,
string $kind
): ?AssignAndRootExprAndNodesToAdd {
$chainMethodCalls = $this->fluentChainMethodCallNodeAnalyzer->collectAllMethodCallsInChain($methodCall);
if (! $this->sameClassMethodCallAnalyzer->haveSingleClass($chainMethodCalls)) {
return null;
}
$assignAndRootExpr = $this->fluentChainMethodCallRootExtractor->extractFromMethodCalls(
$chainMethodCalls,
$kind
);
if ($assignAndRootExpr === null) {
return null;
}
if ($this->fluentMethodCallSkipper->shouldSkipMethodCalls($assignAndRootExpr, $chainMethodCalls)) {
return null;
}
$nodesToAdd = $this->nonFluentChainMethodCallFactory->createFromAssignObjectAndMethodCalls(
$assignAndRootExpr,
$chainMethodCalls,
$kind
);
return new AssignAndRootExprAndNodesToAdd($assignAndRootExpr, $nodesToAdd);
}
/**
* @param MethodCall|Return_ $node
*/
protected function removeCurrentNode(Node $node): void
{
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
if ($parent instanceof Assign) {
$this->removeNode($parent);
return;
}
// part of method call
if ($parent instanceof Arg) {
$parentParent = $parent->getAttribute(AttributeKey::PARENT_NODE);
if ($parentParent instanceof MethodCall) {
$this->removeNode($parentParent);
}
return;
}
$this->removeNode($node);
}
protected function shouldSkipMethodCall(MethodCall $methodCall): bool
{
return $this->fluentMethodCallSkipper->shouldSkipRootMethodCall($methodCall);
}
protected function matchReturnMethodCall(Return_ $return): ?MethodCall
{
if ($return->expr === null) {
return null;
}
if (! $return->expr instanceof MethodCall) {
return null;
}
return $return->expr;
}
protected function shouldSkipMethodCallIncludingNew(MethodCall $methodCall): bool
{
if ($this->shouldSkipMethodCall($methodCall)) {
return true;
}
$chainRootExpr = $this->fluentChainMethodCallNodeAnalyzer->resolveRootExpr($methodCall);
return $chainRootExpr instanceof New_;
}
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Rector\ClassMethod;
namespace Rector\Defluent\Rector\ClassMethod;
use PhpParser\Node;
use PhpParser\Node\Identifier;
@ -14,11 +14,11 @@ use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\MagicDisclosure\ConflictGuard\ParentClassMethodTypeOverrideGuard;
use Rector\Defluent\ConflictGuard\ParentClassMethodTypeOverrideGuard;
use Rector\NodeTypeResolver\Node\AttributeKey;
/**
* @see \Rector\MagicDisclosure\Tests\Rector\ClassMethod\ReturnThisRemoveRector\ReturnThisRemoveRectorTest
* @see \Rector\Defluent\Tests\Rector\ClassMethod\ReturnThisRemoveRector\ReturnThisRemoveRectorTest
*/
final class ReturnThisRemoveRector extends AbstractRector
{

View File

@ -0,0 +1,91 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\Rector\MethodCall;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\Defluent\Rector\AbstractFluentChainMethodCallRector;
use Rector\Defluent\Rector\Return_\DefluentReturnMethodCallRector;
use Rector\Defluent\ValueObject\FluentCallsKind;
/**
* @see https://ocramius.github.io/blog/fluent-interfaces-are-evil/
* @see https://www.yegor256.com/2018/03/13/fluent-interfaces.html
*
* @see \Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\FluentChainMethodCallToNormalMethodCallRectorTest
*/
final class FluentChainMethodCallToNormalMethodCallRector extends AbstractFluentChainMethodCallRector
{
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Turns fluent interface calls to classic ones.', [
new CodeSample(
<<<'CODE_SAMPLE'
$someClass = new SomeClass();
$someClass->someFunction()
->otherFunction();
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
$someClass = new SomeClass();
$someClass->someFunction();
$someClass->otherFunction();
CODE_SAMPLE
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [MethodCall::class];
}
/**
* @param MethodCall $node
*/
public function refactor(Node $node): ?Node
{
if ($this->isHandledByAnotherRule($node)) {
return null;
}
if ($this->shouldSkipMethodCallIncludingNew($node)) {
return null;
}
$assignAndRootExprAndNodesToAdd = $this->createStandaloneNodesToAddFromChainMethodCalls(
$node,
FluentCallsKind::NORMAL
);
if ($assignAndRootExprAndNodesToAdd === null) {
return null;
}
$this->removeCurrentNode($node);
$this->addNodesAfterNode($assignAndRootExprAndNodesToAdd->getNodesToAdd(), $node);
return null;
}
/**
* Is handled by:
* @see DefluentReturnMethodCallRector
* @see InArgFluentChainMethodCallToStandaloneMethodCallRector
*
* @param MethodCall|Return_ $node
*/
private function isHandledByAnotherRule(Node $node): bool
{
return $this->hasParentTypes($node, [Return_::class, Arg::class]);
}
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Rector\MethodCall;
namespace Rector\Defluent\Rector\MethodCall;
use PhpParser\Node;
use PhpParser\Node\Arg;
@ -12,15 +12,16 @@ use PhpParser\Node\Expr\Variable;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\MagicDisclosure\NodeAnalyzer\NewFluentChainMethodCallNodeAnalyzer;
use Rector\MagicDisclosure\NodeManipulator\FluentChainMethodCallRootExtractor;
use Rector\Defluent\NodeAnalyzer\NewFluentChainMethodCallNodeAnalyzer;
use Rector\Defluent\Rector\AbstractFluentChainMethodCallRector;
use Rector\Defluent\ValueObject\FluentCallsKind;
use Rector\NetteKdyby\Naming\VariableNaming;
use Rector\NodeTypeResolver\Node\AttributeKey;
/**
* @sponsor Thanks https://amateri.com for sponsoring this rule - visit them on https://www.startupjobs.cz/startup/scrumworks-s-r-o
*
* @see \Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest
* @see \Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest
*/
final class InArgFluentChainMethodCallToStandaloneMethodCallRector extends AbstractFluentChainMethodCallRector
{
@ -113,7 +114,7 @@ CODE_SAMPLE
$assignAndRootExprAndNodesToAdd = $this->createStandaloneNodesToAddFromChainMethodCalls(
$node,
FluentChainMethodCallRootExtractor::KIND_IN_ARGS
FluentCallsKind::IN_ARGS
);
if ($assignAndRootExprAndNodesToAdd === null) {

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Rector\MethodCall;
namespace Rector\Defluent\Rector\MethodCall;
use PhpParser\Node;
use PhpParser\Node\Arg;
@ -12,13 +12,14 @@ use PhpParser\Node\Expr\Variable;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\MagicDisclosure\NodeAnalyzer\NewFluentChainMethodCallNodeAnalyzer;
use Rector\Defluent\NodeAnalyzer\NewFluentChainMethodCallNodeAnalyzer;
use Rector\Defluent\Rector\AbstractFluentChainMethodCallRector;
use Rector\NetteKdyby\Naming\VariableNaming;
/**
* @sponsor Thanks https://amateri.com for sponsoring this rule - visit them on https://www.startupjobs.cz/startup/scrumworks-s-r-o
*
* @see \Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\MethodCallOnSetterMethodCallToStandaloneAssignRectorTest
* @see \Rector\Defluent\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\MethodCallOnSetterMethodCallToStandaloneAssignRectorTest
*/
final class MethodCallOnSetterMethodCallToStandaloneAssignRector extends AbstractFluentChainMethodCallRector
{
@ -91,7 +92,7 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
if ($this->shouldSkip($node)) {
if ($this->shouldSkipMethodCall($node)) {
return null;
}
@ -115,15 +116,6 @@ CODE_SAMPLE
return $rootMethodCall;
}
private function shouldSkip(MethodCall $methodCall): bool
{
if (! $methodCall->var instanceof MethodCall) {
return true;
}
return ! $this->fluentChainMethodCallNodeAnalyzer->isLastChainMethodCall($methodCall);
}
private function crateVariableFromNew(New_ $new): Variable
{
$variableName = $this->variableNaming->resolveFromNode($new);

View File

@ -0,0 +1,78 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\Rector\MethodCall;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\Defluent\Rector\AbstractFluentChainMethodCallRector;
use Rector\Defluent\ValueObject\FluentCallsKind;
/**
* @see https://ocramius.github.io/blog/fluent-interfaces-are-evil/
* @see https://www.yegor256.com/2018/03/13/fluent-interfaces.html
*
* @see \Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\FluentChainMethodCallToNormalMethodCallRectorTest
* @see \Rector\Defluent\Tests\Rector\MethodCall\NewFluentChainMethodCallToNonFluentRector\NewFluentChainMethodCallToNonFluentRectorTest
*/
final class NewFluentChainMethodCallToNonFluentRector extends AbstractFluentChainMethodCallRector
{
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Turns fluent interface calls to classic ones.', [
new CodeSample(
<<<'CODE_SAMPLE'
(new SomeClass())->someFunction()
->otherFunction();
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
$someClass = new SomeClass();
$someClass->someFunction();
$someClass->otherFunction();
CODE_SAMPLE
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [MethodCall::class];
}
/**
* @param MethodCall $node
*/
public function refactor(Node $node): ?Node
{
// handled by another rule
if ($this->hasParentTypes($node, [Return_::class, Arg::class])) {
return null;
}
if ($this->shouldSkipMethodCall($node)) {
return null;
}
$assignAndRootExprAndNodesToAdd = $this->createStandaloneNodesToAddFromChainMethodCalls(
$node,
FluentCallsKind::NORMAL
);
if ($assignAndRootExprAndNodesToAdd === null) {
return null;
}
$this->removeCurrentNode($node);
$this->addNodesAfterNode($assignAndRootExprAndNodesToAdd->getNodesToAdd(), $node);
return null;
}
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Rector\Return_;
namespace Rector\Defluent\Rector\Return_;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
@ -10,12 +10,12 @@ use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\MagicDisclosure\Rector\MethodCall\AbstractFluentChainMethodCallRector;
use Rector\Defluent\Rector\AbstractFluentChainMethodCallRector;
/**
* @sponsor Thanks https://amateri.com for sponsoring this rule - visit them on https://www.startupjobs.cz/startup/scrumworks-s-r-o
*
* @see \Rector\MagicDisclosure\Tests\Rector\Return_\DefluentReturnMethodCallRector\DefluentReturnMethodCallRectorTest
* @see \Rector\Defluent\Tests\Rector\Return_\DefluentReturnMethodCallRector\DefluentReturnMethodCallRectorTest
*/
final class DefluentReturnMethodCallRector extends AbstractFluentChainMethodCallRector
{

View File

@ -0,0 +1,138 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\Rector\Return_;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\Defluent\NodeFactory\ReturnFluentMethodCallFactory;
use Rector\Defluent\NodeFactory\SeparateReturnMethodCallFactory;
use Rector\Defluent\Rector\AbstractFluentChainMethodCallRector;
use Rector\Defluent\ValueObjectFactory\FluentMethodCallsFactory;
/**
* @see https://ocramius.github.io/blog/fluent-interfaces-are-evil/
* @see https://www.yegor256.com/2018/03/13/fluent-interfaces.html
*
* @see \Rector\Defluent\Tests\Rector\Return_\ReturnFluentChainMethodCallToNormalMethodCallRector\ReturnFluentChainMethodCallToNormalMethodCallRectorTest
*/
final class ReturnFluentChainMethodCallToNormalMethodCallRector extends AbstractFluentChainMethodCallRector
{
/**
* @var ReturnFluentMethodCallFactory
*/
private $returnFluentMethodCallFactory;
/**
* @var FluentMethodCallsFactory
*/
private $fluentMethodCallsFactory;
/**
* @var SeparateReturnMethodCallFactory
*/
private $separateReturnMethodCallFactory;
public function __construct(
ReturnFluentMethodCallFactory $returnFluentMethodCallFactory,
FluentMethodCallsFactory $fluentMethodCallsFactory,
SeparateReturnMethodCallFactory $separateReturnMethodCallFactory
) {
$this->returnFluentMethodCallFactory = $returnFluentMethodCallFactory;
$this->fluentMethodCallsFactory = $fluentMethodCallsFactory;
$this->separateReturnMethodCallFactory = $separateReturnMethodCallFactory;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Turns fluent interface calls to classic ones.', [
new CodeSample(
<<<'CODE_SAMPLE'
$someClass = new SomeClass();
return $someClass->someFunction()
->otherFunction();
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
$someClass = new SomeClass();
$someClass->someFunction();
$someClass->otherFunction();
return $someClass;
CODE_SAMPLE
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [Return_::class];
}
/**
* @param Return_ $node
*/
public function refactor(Node $node): ?Node
{
$methodCall = $this->matchReturnMethodCall($node);
if ($methodCall === null) {
return null;
}
if ($this->shouldSkipMethodCallIncludingNew($methodCall)) {
return null;
}
$nodesToAdd = $this->createStandaloneNodesToAddFromReturnFluentMethodCalls($methodCall);
if ($nodesToAdd === []) {
return null;
}
$this->removeCurrentNode($node);
$this->addNodesAfterNode($nodesToAdd, $node);
return null;
}
protected function shouldSkipMethodCallIncludingNew(MethodCall $methodCall): bool
{
if ($this->shouldSkipMethodCall($methodCall)) {
return true;
}
$rootVariable = $this->fluentChainMethodCallNodeAnalyzer->resolveRootExpr($methodCall);
return $rootVariable instanceof New_;
}
/**
* @return Node[]
*/
private function createStandaloneNodesToAddFromReturnFluentMethodCalls(MethodCall $methodCall): array
{
$fluentMethodCalls = $this->fluentMethodCallsFactory->createFromLastMethodCall($methodCall);
if ($fluentMethodCalls === null) {
return [];
}
$firstAssignFluentCall = $this->returnFluentMethodCallFactory->createFromFluentMethodCalls(
$fluentMethodCalls
);
// should be skipped?
if ($this->fluentMethodCallSkipper->shouldSkipFirstAssignFluentCall($firstAssignFluentCall)) {
return [];
}
return $this->separateReturnMethodCallFactory->createReturnFromFirstAssignFluentCallAndFluentMethodCalls(
$firstAssignFluentCall,
$fluentMethodCalls
);
}
}

View File

@ -0,0 +1,78 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\Rector\Return_;
use PhpParser\Node;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\Defluent\Rector\AbstractFluentChainMethodCallRector;
use Rector\Defluent\ValueObject\FluentCallsKind;
/**
* @see https://ocramius.github.io/blog/fluent-interfaces-are-evil/
* @see https://www.yegor256.com/2018/03/13/fluent-interfaces.html
*
* @see \Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\FluentChainMethodCallToNormalMethodCallRectorTest
* @see \Rector\Defluent\Tests\Rector\Return_\ReturnNewFluentChainMethodCallToNonFluentRector\ReturnNewFluentChainMethodCallToNonFluentRectorTest
*/
final class ReturnNewFluentChainMethodCallToNonFluentRector extends AbstractFluentChainMethodCallRector
{
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Turns fluent interface calls to classic ones.', [
new CodeSample(
<<<'CODE_SAMPLE'
return (new SomeClass())->someFunction()
->otherFunction();
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
$someClass = new SomeClass();
$someClass->someFunction();
$someClass->otherFunction();
return $someClass;
CODE_SAMPLE
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [Return_::class];
}
/**
* @param Return_ $node
*/
public function refactor(Node $node): ?Node
{
$methodCall = $this->matchReturnMethodCall($node);
if ($methodCall === null) {
return null;
}
if ($this->shouldSkipMethodCall($methodCall)) {
return null;
}
$assignAndRootExprAndNodesToAdd = $this->createStandaloneNodesToAddFromChainMethodCalls(
$methodCall,
FluentCallsKind::NORMAL
);
if ($assignAndRootExprAndNodesToAdd === null) {
return null;
}
$this->removeCurrentNode($node);
$this->addNodesAfterNode($assignAndRootExprAndNodesToAdd->getNodesToAdd(), $node);
return null;
}
}

View File

@ -0,0 +1,143 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\Skipper;
use PhpParser\Node\Expr\MethodCall;
use Rector\Defluent\Contract\ValueObject\FirstCallFactoryAwareInterface;
use Rector\Defluent\NodeAnalyzer\FluentCallStaticTypeResolver;
use Rector\Defluent\NodeAnalyzer\FluentChainMethodCallNodeAnalyzer;
use Rector\Defluent\NodeAnalyzer\GetterMethodCallAnalyzer;
use Rector\Defluent\NodeAnalyzer\SameClassMethodCallAnalyzer;
use Rector\Defluent\ValueObject\AssignAndRootExpr;
use Rector\Defluent\ValueObject\FirstAssignFluentCall;
final class FluentMethodCallSkipper
{
/**
* Skip query and builder
* @see https://ocramius.github.io/blog/fluent-interfaces-are-evil/ "When does a fluent interface make sense?
*
* @var string[]
*/
private const ALLOWED_FLUENT_TYPES = [
'Symfony\Component\DependencyInjection\Loader\Configurator\AbstractConfigurator',
'Nette\Forms\Controls\BaseControl',
'Nette\DI\ContainerBuilder',
'Nette\DI\Definitions\Definition',
'Nette\DI\Definitions\ServiceDefinition',
'PHPStan\Analyser\Scope',
'DateTime',
'Nette\Utils\DateTime',
'DateTimeInterface',
'*Finder',
'*Builder',
'*Query',
];
/**
* @var FluentCallStaticTypeResolver
*/
private $fluentCallStaticTypeResolver;
/**
* @var SameClassMethodCallAnalyzer
*/
private $sameClassMethodCallAnalyzer;
/**
* @var FluentChainMethodCallNodeAnalyzer
*/
private $fluentChainMethodCallNodeAnalyzer;
/**
* @var GetterMethodCallAnalyzer
*/
private $getterMethodCallAnalyzer;
public function __construct(
FluentCallStaticTypeResolver $fluentCallStaticTypeResolver,
SameClassMethodCallAnalyzer $sameClassMethodCallAnalyzer,
FluentChainMethodCallNodeAnalyzer $fluentChainMethodCallNodeAnalyzer,
GetterMethodCallAnalyzer $getterMethodCallAnalyzer
) {
$this->fluentCallStaticTypeResolver = $fluentCallStaticTypeResolver;
$this->sameClassMethodCallAnalyzer = $sameClassMethodCallAnalyzer;
$this->fluentChainMethodCallNodeAnalyzer = $fluentChainMethodCallNodeAnalyzer;
$this->getterMethodCallAnalyzer = $getterMethodCallAnalyzer;
}
public function shouldSkipRootMethodCall(MethodCall $methodCall): bool
{
if (! $this->fluentChainMethodCallNodeAnalyzer->isLastChainMethodCall($methodCall)) {
return true;
}
return $this->getterMethodCallAnalyzer->isGetterMethodCall($methodCall);
}
public function shouldSkipFirstAssignFluentCall(FirstAssignFluentCall $firstAssignFluentCall): bool
{
$calleeUniqueTypes = $this->fluentCallStaticTypeResolver->resolveCalleeUniqueTypes(
$firstAssignFluentCall->getFluentMethodCalls()
->getFluentMethodCalls()
);
if (! $this->sameClassMethodCallAnalyzer->isCorrectTypeCount($calleeUniqueTypes, $firstAssignFluentCall)) {
return true;
}
$calleeUniqueType = $this->resolveCalleeUniqueType($firstAssignFluentCall, $calleeUniqueTypes);
return $this->isAllowedType($calleeUniqueType, self::ALLOWED_FLUENT_TYPES);
}
/**
* @param MethodCall[] $fluentMethodCalls
*/
public function shouldSkipMethodCalls(AssignAndRootExpr $assignAndRootExpr, array $fluentMethodCalls): bool
{
$calleeUniqueTypes = $this->fluentCallStaticTypeResolver->resolveCalleeUniqueTypes($fluentMethodCalls);
if (! $this->sameClassMethodCallAnalyzer->isCorrectTypeCount($calleeUniqueTypes, $assignAndRootExpr)) {
return true;
}
$calleeUniqueType = $this->resolveCalleeUniqueType($assignAndRootExpr, $calleeUniqueTypes);
return $this->isAllowedType($calleeUniqueType, self::ALLOWED_FLUENT_TYPES);
}
/**
* @param string[] $calleeUniqueTypes
*/
private function resolveCalleeUniqueType(
FirstCallFactoryAwareInterface $firstCallFactoryAware,
array $calleeUniqueTypes
): string {
if (! $firstCallFactoryAware->isFirstCallFactory()) {
return $calleeUniqueTypes[0];
}
return $calleeUniqueTypes[1] ?? $calleeUniqueTypes[0];
}
/**
* @param string[] $allowedTypes
*/
private function isAllowedType(string $currentType, array $allowedTypes): bool
{
foreach ($allowedTypes as $allowedType) {
if (is_a($currentType, $allowedType, true)) {
return true;
}
if (fnmatch($allowedType, $currentType, FNM_NOESCAPE)) {
return true;
}
}
return false;
}
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\ValueObject;
namespace Rector\Defluent\ValueObject;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
@ -11,9 +11,11 @@ use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Defluent\Contract\ValueObject\FirstCallFactoryAwareInterface;
use Rector\Defluent\Contract\ValueObject\RootExprAwareInterface;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class AssignAndRootExpr
final class AssignAndRootExpr implements RootExprAwareInterface, FirstCallFactoryAwareInterface
{
/**
* @var bool
@ -74,17 +76,10 @@ final class AssignAndRootExpr
public function createFirstAssign(): Assign
{
if ($this->isFirstCallFactory && $this->getFirstAssign() !== null) {
/** @var Assign $currentMethodCall */
$currentMethodCall = $this->getFirstAssign()
->expr;
while ($currentMethodCall->var instanceof MethodCall) {
$currentMethodCall = $currentMethodCall->var;
}
return new Assign($this->getFirstAssign()->var, $currentMethodCall);
return $this->createFactoryAssign();
}
return new Assign($this->assignExpr, $this->rootExpr);
return $this->createAssign($this->assignExpr, $this->rootExpr);
}
public function getCallerExpr(): Expr
@ -124,4 +119,41 @@ final class AssignAndRootExpr
return null;
}
private function createFactoryAssign(): Assign
{
/** @var Assign $firstAssign */
$firstAssign = $this->getFirstAssign();
$currentMethodCall = $firstAssign->expr;
if (! $currentMethodCall instanceof MethodCall) {
throw new ShouldNotHappenException();
}
$currentMethodCall = $this->resolveLastMethodCall($currentMethodCall);
// ensure var and expr are different
$assignVar = $firstAssign->var;
$assignExpr = $currentMethodCall;
return $this->createAssign($assignVar, $assignExpr);
}
private function createAssign(Expr $assignVar, Expr $assignExpr): Assign
{
if ($assignVar === $assignExpr) {
throw new ShouldNotHappenException();
}
return new Assign($assignVar, $assignExpr);
}
private function resolveLastMethodCall(MethodCall $currentMethodCall): MethodCall
{
while ($currentMethodCall->var instanceof MethodCall) {
$currentMethodCall = $currentMethodCall->var;
}
return $currentMethodCall;
}
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\ValueObject;
namespace Rector\Defluent\ValueObject;
use PhpParser\Node\Expr;
use PhpParser\Node\Stmt\Return_;

View File

@ -0,0 +1,135 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\ValueObject;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Expression;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Defluent\Contract\ValueObject\FirstCallFactoryAwareInterface;
use Rector\Defluent\Contract\ValueObject\RootExprAwareInterface;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class FirstAssignFluentCall implements RootExprAwareInterface, FirstCallFactoryAwareInterface
{
/**
* @var bool
*/
private $isFirstCallFactory = false;
/**
* @var Expr
*/
private $assignExpr;
/**
* @var Expr
*/
private $rootExpr;
/**
* @var FluentMethodCalls
*/
private $fluentMethodCalls;
public function __construct(
Expr $assignExpr,
Expr $rootExpr,
bool $isFirstCallFactory,
FluentMethodCalls $fluentMethodCalls
) {
$this->assignExpr = $assignExpr;
$this->rootExpr = $rootExpr;
$this->isFirstCallFactory = $isFirstCallFactory;
$this->fluentMethodCalls = $fluentMethodCalls;
}
public function getAssignExpr(): Expr
{
return $this->assignExpr;
}
public function getRootExpr(): Expr
{
return $this->rootExpr;
}
public function createFirstAssign(): Assign
{
if ($this->isFirstCallFactory && $this->getFirstAssign() !== null) {
return $this->createFactoryAssign();
}
return $this->createAssign($this->assignExpr, $this->rootExpr);
}
public function getCallerExpr(): Expr
{
return $this->assignExpr;
}
public function isFirstCallFactory(): bool
{
return $this->isFirstCallFactory;
}
public function getFactoryAssignVariable(): Expr
{
$firstAssign = $this->getFirstAssign();
if ($firstAssign === null) {
return $this->assignExpr;
}
return $firstAssign->var;
}
public function getFluentMethodCalls(): FluentMethodCalls
{
return $this->fluentMethodCalls;
}
private function getFirstAssign(): ?Assign
{
$currentStmt = $this->assignExpr->getAttribute(AttributeKey::CURRENT_STATEMENT);
if (! $currentStmt instanceof Expression) {
return null;
}
if ($currentStmt->expr instanceof Assign) {
return $currentStmt->expr;
}
return null;
}
private function createFactoryAssign(): Assign
{
/** @var Assign $firstAssign */
$firstAssign = $this->getFirstAssign();
$currentMethodCall = $firstAssign->expr;
if (! $currentMethodCall instanceof MethodCall) {
throw new ShouldNotHappenException();
}
$currentMethodCall = $this->fluentMethodCalls->getLastMethodCall();
// ensure var and expr are different
$assignVar = $firstAssign->var;
$assignExpr = $currentMethodCall;
return $this->createAssign($assignVar, $assignExpr);
}
private function createAssign(Expr $assignVar, Expr $assignExpr): Assign
{
if ($assignVar === $assignExpr) {
throw new ShouldNotHappenException();
}
return new Assign($assignVar, $assignExpr);
}
}

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\ValueObject;
final class FluentCallsKind
{
/**
* @var string
*/
public const NORMAL = 'normal';
/**
* @var string
*/
public const IN_ARGS = 'in_args';
}

View File

@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\ValueObject;
use PhpParser\Node\Expr\MethodCall;
final class FluentMethodCalls
{
/**
* @var MethodCall[]
*/
private $fluentMethodCalls = [];
/**
* @var MethodCall
*/
private $rootMethodCall;
/**
* @var MethodCall
*/
private $lastMethodCall;
/**
* @param MethodCall[] $fluentMethodCalls
*/
public function __construct(MethodCall $rootMethodCall, array $fluentMethodCalls, MethodCall $lastMethodCall)
{
$this->rootMethodCall = $rootMethodCall;
$this->fluentMethodCalls = $fluentMethodCalls;
$this->lastMethodCall = $lastMethodCall;
}
public function getRootMethodCall(): MethodCall
{
return $this->rootMethodCall;
}
/**
* @return MethodCall[]
*/
public function getFluentMethodCalls(): array
{
return $this->fluentMethodCalls;
}
public function getLastMethodCall(): MethodCall
{
return $this->lastMethodCall;
}
}

View File

@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\ValueObjectFactory;
use PhpParser\Node\Expr\MethodCall;
use Rector\Defluent\NodeAnalyzer\FluentChainMethodCallNodeAnalyzer;
use Rector\Defluent\NodeAnalyzer\SameClassMethodCallAnalyzer;
use Rector\Defluent\ValueObject\FluentMethodCalls;
final class FluentMethodCallsFactory
{
/**
* @var FluentChainMethodCallNodeAnalyzer
*/
private $fluentChainMethodCallNodeAnalyzer;
/**
* @var SameClassMethodCallAnalyzer
*/
private $sameClassMethodCallAnalyzer;
public function __construct(
FluentChainMethodCallNodeAnalyzer $fluentChainMethodCallNodeAnalyzer,
SameClassMethodCallAnalyzer $sameClassMethodCallAnalyzer
) {
$this->fluentChainMethodCallNodeAnalyzer = $fluentChainMethodCallNodeAnalyzer;
$this->sameClassMethodCallAnalyzer = $sameClassMethodCallAnalyzer;
}
public function createFromLastMethodCall(MethodCall $lastMethodCall): ?FluentMethodCalls
{
$chainMethodCalls = $this->fluentChainMethodCallNodeAnalyzer->collectAllMethodCallsInChain($lastMethodCall);
if (! $this->sameClassMethodCallAnalyzer->haveSingleClass($chainMethodCalls)) {
return null;
}
// we need at least 2 method call for fluent
if (count($chainMethodCalls) < 2) {
return null;
}
$rootMethodCall = $this->resolveRootMethodCall($chainMethodCalls);
return new FluentMethodCalls($rootMethodCall, $chainMethodCalls, $lastMethodCall);
}
/**
* @param MethodCall[] $chainMethodCalls
*/
private function resolveRootMethodCall(array $chainMethodCalls): MethodCall
{
$lastKey = array_key_last($chainMethodCalls);
return $chainMethodCalls[$lastKey];
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\Tests\NodeFactory\FluentChainMethodCallRootExtractor\Fixture;
use Rector\Defluent\Tests\NodeFactory\FluentChainMethodCallRootExtractor\Source\AnotherTypeFactory;
final class IsFactoryVariableDoubleMethodCall
{
public function run()
{
$mainVariable = new AnotherTypeFactory();
$someClassWithFluentMethods = $mainVariable->createSomeClassWithFluentMethods()->one();
}
}

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\Tests\NodeFactory\FluentChainMethodCallRootExtractor\Fixture;
use Rector\Defluent\Tests\NodeFactory\FluentChainMethodCallRootExtractor\Source\SomeClassWithFluentMethods;
final class ReturnNewDoubleMethodCall
{
public function run()
{
return (new SomeClassWithFluentMethods())->one()->two();
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\Tests\NodeFactory\FluentChainMethodCallRootExtractor\Fixture;
use Nette\DI\ContainerBuilder;
final class SkipNoNFluentNetteContainerBuilder
{
public function run()
{
$containerBuilder = new ContainerBuilder();
$containerBuilder->addDefinition('someClass');
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\Tests\NodeFactory\FluentChainMethodCallRootExtractor\Fixture;
use Rector\Defluent\Tests\NodeFactory\FluentChainMethodCallRootExtractor\Source\SomeClassWithFluentMethods;
final class VariableDoubleMethodCall
{
public function run()
{
$mainVariable = new SomeClassWithFluentMethods();
$mainVariable->one()->two();
}
}

View File

@ -0,0 +1,102 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\Tests\NodeFactory\FluentChainMethodCallRootExtractor;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\Variable;
use Rector\Core\HttpKernel\RectorKernel;
use Rector\Core\Testing\TestingParser\TestingParser;
use Rector\Defluent\NodeAnalyzer\FluentChainMethodCallRootExtractor;
use Rector\Defluent\ValueObject\AssignAndRootExpr;
use Rector\Defluent\ValueObject\FluentCallsKind;
use Symplify\PackageBuilder\Tests\AbstractKernelTestCase;
final class FluentChainMethodCallRootExtractorTest extends AbstractKernelTestCase
{
/**
* @var FluentChainMethodCallRootExtractor
*/
private $fluentChainMethodCallRootExtractor;
/**
* @var TestingParser
*/
private $testingParser;
protected function setUp(): void
{
$this->bootKernel(RectorKernel::class);
$this->fluentChainMethodCallRootExtractor = self::$container->get(FluentChainMethodCallRootExtractor::class);
$this->testingParser = self::$container->get(TestingParser::class);
}
public function test(): void
{
$assignAndRootExpr = $this->parseFileAndCreateAssignAndRootExprForSure(
__DIR__ . '/Fixture/variable_double_method_call.php.inc'
);
$this->assertFalse($assignAndRootExpr->isFirstCallFactory());
$this->assertNull($assignAndRootExpr->getSilentVariable());
}
public function testFactory(): void
{
$assignAndRootExpr = $this->parseFileAndCreateAssignAndRootExprForSure(
__DIR__ . '/Fixture/is_factory_variable_double_method_call.php.inc'
);
$this->assertTrue($assignAndRootExpr->isFirstCallFactory());
}
public function testNew(): void
{
$assignAndRootExpr = $this->parseFileAndCreateAssignAndRootExprForSure(
__DIR__ . '/Fixture/return_new_double_method_call.php.inc'
);
$this->assertFalse($assignAndRootExpr->isFirstCallFactory());
$silentVariable = $assignAndRootExpr->getSilentVariable();
/** @var Variable $silentVariable */
$this->assertInstanceOf(Variable::class, $silentVariable);
$this->assertIsString($silentVariable->name);
$this->assertSame('someClassWithFluentMethods', $silentVariable->name);
}
public function testSingleMethodCallNull(): void
{
$assignAndRootExpr = $this->parseFileAndCreateAssignAndRootExpr(
__DIR__ . '/Fixture/skip_non_fluent_nette_container_builder.php.inc'
);
$this->assertNull($assignAndRootExpr);
}
private function parseFileAndCreateAssignAndRootExprForSure(string $filePath): AssignAndRootExpr
{
$assignAndRootExpr = $this->parseFileAndCreateAssignAndRootExpr($filePath);
$this->assertInstanceOf(AssignAndRootExpr::class, $assignAndRootExpr);
/** @var AssignAndRootExpr $assignAndRootExpr */
return $assignAndRootExpr;
}
private function parseFileAndCreateAssignAndRootExpr(string $filePath): ?AssignAndRootExpr
{
/** @var MethodCall[] $methodCalls */
$methodCalls = $this->testingParser->parseFileToDecoratedNodesAndFindNodesByType(
$filePath,
MethodCall::class
);
return $this->fluentChainMethodCallRootExtractor->extractFromMethodCalls(
$methodCalls,
FluentCallsKind::NORMAL
);
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\Tests\NodeFactory\FluentChainMethodCallRootExtractor\Source;
final class AnotherTypeFactory
{
/**
* @return SomeClassWithFluentMethods
*/
public function createSomeClassWithFluentMethods()
{
return new SomeClassWithFluentMethods();
}
}

View File

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\Tests\NodeFactory\FluentChainMethodCallRootExtractor\Source;
final class SomeClassWithFluentMethods
{
/**
* @return self
*/
public function one()
{
return $this;
}
/**
* @return $this
*/
public function two()
{
return $this;
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Fixture;
namespace Rector\Defluent\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Fixture;
class ChildClassWithSameMethodName extends SomeParentClassWithSameMethod
{
@ -30,7 +30,7 @@ class SomeParentClassWithSameMethod
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Fixture;
namespace Rector\Defluent\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Fixture;
class ChildClassWithSameMethodName extends SomeParentClassWithSameMethod
{

View File

@ -1,6 +1,6 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Fixture;
namespace Rector\Defluent\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Fixture;
class AnyClass
{
@ -27,7 +27,7 @@ class AnyClass
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Fixture;
namespace Rector\Defluent\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Fixture;
class AnyClass
{

View File

@ -1,6 +1,6 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Fixture;
namespace Rector\Defluent\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Fixture;
class SomeMultiNested
{

View File

@ -1,8 +1,8 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Fixture;
namespace Rector\Defluent\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Source\ParentInVendor;
use Rector\Defluent\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Source\ParentInVendor;
class SkipParentInVendor extends ParentInVendor
{

View File

@ -2,11 +2,11 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\ClassMethod\ReturnThisRemoveRector;
namespace Rector\Defluent\Tests\Rector\ClassMethod\ReturnThisRemoveRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\MagicDisclosure\Rector\ClassMethod\ReturnThisRemoveRector;
use Rector\Defluent\Rector\ClassMethod\ReturnThisRemoveRector;
use Symplify\SmartFileSystem\SmartFileInfo;
final class ReturnThisRemoveRectorTest extends AbstractRectorTestCase

View File

@ -2,9 +2,9 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Source;
namespace Rector\Defluent\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Source;
use Rector\MagicDisclosure\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Fixture\SkipParentInVendor;
use Rector\Defluent\Tests\Rector\ClassMethod\ReturnThisRemoveRector\Fixture\SkipParentInVendor;
class ParentInVendor
{

View File

@ -0,0 +1,34 @@
<?php
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\Row;
final class AssignOfFluent
{
public function run(Row $row)
{
$cell = $row->addCell()->setName(2);
return $cell;
}
}
?>
-----
<?php
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\Row;
final class AssignOfFluent
{
public function run(Row $row)
{
$cell = $row->addCell();
$cell->setName(2);
return $cell;
}
}
?>

View File

@ -1,6 +1,6 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Throwable;
@ -34,7 +34,7 @@ class SomeAjaxPresenter
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Throwable;

View File

@ -1,8 +1,8 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\FluentInterfaceClass;
use Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\FluentInterfaceClass;
class ActionClass
{
@ -24,9 +24,9 @@ class ActionClass
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\FluentInterfaceClass;
use Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\FluentInterfaceClass;
class ActionClass
{

View File

@ -0,0 +1,35 @@
<?php
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\DifferentReturnValues;
class KeepLastDifferentType
{
public function run()
{
$differentReturnValues = new DifferentReturnValues();
$differentReturnValues->someFunction()
->otherFunction();
}
}
?>
-----
<?php
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\DifferentReturnValues;
class KeepLastDifferentType
{
public function run()
{
$differentReturnValues = new DifferentReturnValues();
$differentReturnValues->someFunction();
$differentReturnValues->otherFunction();
}
}
?>

View File

@ -0,0 +1,33 @@
<?php
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\FluentInterfaceClass;
class LastNormalCallOnFluent
{
public function someMethod(FluentInterfaceClass $fluentInterfaceClass)
{
$fluentInterfaceClass->someFunction()
->voidReturningMethod();
}
}
?>
-----
<?php
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\FluentInterfaceClass;
class LastNormalCallOnFluent
{
public function someMethod(FluentInterfaceClass $fluentInterfaceClass)
{
$fluentInterfaceClass->someFunction();
$fluentInterfaceClass->voidReturningMethod();
}
}
?>

View File

@ -1,6 +1,6 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Symfony\Component\Console\Command\Command;
@ -18,7 +18,7 @@ class MultipleSomeCommand extends Command
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Symfony\Component\Console\Command\Command;

View File

@ -1,8 +1,8 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\MagicDisclosure\Rector\ClassMethod\ReturnThisRemoveRector;
use Rector\Defluent\Rector\ClassMethod\ReturnThisRemoveRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
final class SkipContainerConfigurator

View File

@ -1,6 +1,6 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use DateTime;

View File

@ -1,6 +1,6 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use DateTime;

View File

@ -0,0 +1,15 @@
<?php
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\DifferentReturnValues;
class SkipDifferentType
{
public function run()
{
$differentReturnValues = new DifferentReturnValues();
$differentReturnValues->otherFunction()
->someFunction();
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Symfony\Component\Console\Command\Command;
class SkipFactoryCall extends Command
{
public function go()
{
$this->getApplication()
->setAutoExit(true);
}
}

View File

@ -1,8 +1,8 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\SomeResponse;
use Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\SomeResponse;
final class SkipGetterResponseHeader
{

View File

@ -1,6 +1,6 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Nette\Forms\Controls\TextInput;
use Nette\Forms\Form;

View File

@ -0,0 +1,15 @@
<?php
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Nette\DI\CompilerExtension;
final class SkipNetteDIBuilder extends CompilerExtension
{
public function build(): void
{
$containerBuilder = $this->getContainerBuilder();
$containerBuilder->addDefinition('one')
->setFactory('two');
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\FluentInterfaceClass;
class SkipNew
{
public function someFunction()
{
return (new FluentInterfaceClass())->someFunction()->otherFunction();
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use PHPStan\Type\MixedType;
class SkipPhpStanTrinary
{
public function run(MixedType $variableType)
{
return $variableType->isSuperTypeOf($variableType)->yes();
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\QueryBuilder;
class SkipQueryBuilder
{
public function someFunction()
{
$queryBuilder = new QueryBuilder();
$queryBuilder->addQuery()
->select();
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\Defluent\Rector\ClassMethod\ReturnThisRemoveRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
final class SkipReturn
{
public function run(ContainerConfigurator $containerConfigurator)
{
$services = $containerConfigurator->services();
return $services->set(ReturnThisRemoveRector::class)
->arg('key', 'value');
}
}

View File

@ -1,8 +1,8 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\FluentInterfaceClass;
use Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source\FluentInterfaceClass;
class UsedAsParameter
{

View File

@ -1,6 +1,6 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Symfony\Component\Console\Command\Command;
@ -18,7 +18,7 @@ class SomeCommand extends Command
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use Symfony\Component\Console\Command\Command;

View File

@ -2,11 +2,11 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\MagicDisclosure\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector;
use Rector\Defluent\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector;
use Symplify\SmartFileSystem\SmartFileInfo;
final class FluentChainMethodCallToNormalMethodCallRectorTest extends AbstractRectorTestCase

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source;
final class Cell
{

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source;
final class DifferentReturnValues implements FluentInterfaceClassInterface
{

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source;
final class FluentInterfaceClass extends InterFluentInterfaceClass
{

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source;
interface FluentInterfaceClassInterface
{
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source;
abstract class InterFluentInterfaceClass implements FluentInterfaceClassInterface
{

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source;
final class QueryBuilder
{

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source;
final class Row
{

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source;
namespace Rector\Defluent\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Source;
interface SomeResponse
{

View File

@ -1,9 +1,9 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\DummyUserProfile;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\DummyUserProvider;
use Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\DummyUserProfile;
use Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\DummyUserProvider;
class SomeClass
{
@ -27,10 +27,10 @@ class SomeClass
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\DummyUserProfile;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\DummyUserProvider;
use Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\DummyUserProfile;
use Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\DummyUserProvider;
class SomeClass
{

View File

@ -1,8 +1,8 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\FluentClass;
use Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\FluentClass;
class NewInArg
{
@ -20,9 +20,9 @@ class NewInArg
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\FluentClass;
use Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\FluentClass;
class NewInArg
{

View File

@ -1,10 +1,10 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
use DateTime;
use DateTimeZone;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\SetGetDateTime;
use Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\SetGetDateTime;
use Nette\Utils\DateTime as NetteDateTime;
final class SelfSelf

View File

@ -0,0 +1,14 @@
<?php
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
use Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\FluentClass;
class SkipNonArg
{
public function someFunction()
{
(new FluentClass())->otherFunction()
->someFunction();
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
use Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\NonFluentClass;
class SkipNonFluentNewInArg
{
public function someFunction()
{
$this->processFluentClass((new NonFluentClass())->number());
}
public function processFluentClass(int $number)
{
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
use Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\FluentClass;
class SkipSingleClass
{
public function someFunction(FluentClass $someClass)
{
$this->processFluentClass($someClass->someFunction());
}
public function processFluentClass(FluentClass $someClass)
{
}
}

View File

@ -1,8 +1,8 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\FluentClass;
use Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\FluentClass;
class UsedAsParameter
{
@ -20,9 +20,9 @@ class UsedAsParameter
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\FluentClass;
use Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\FluentClass;
class UsedAsParameter
{

View File

@ -1,8 +1,8 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\FluentClass;
use Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\FluentClass;
class WithArgs
{
@ -20,9 +20,9 @@ class WithArgs
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\FluentClass;
use Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source\FluentClass;
class WithArgs
{

View File

@ -2,11 +2,11 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest;
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\MagicDisclosure\Rector\MethodCall\InArgFluentChainMethodCallToStandaloneMethodCallRector;
use Rector\Defluent\Rector\MethodCall\InArgFluentChainMethodCallToStandaloneMethodCallRector;
use Symplify\SmartFileSystem\SmartFileInfo;
final class InArgChainFluentMethodCallToStandaloneMethodCallRectorTest extends AbstractRectorTestCase

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source;
final class DummyUser
{
public $id;
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source;
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source;
final class DummyUserProfile
{

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source;
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source;
final class DummyUserProvider
{

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source;
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source;
final class FluentClass
{

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source;
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source;
final class NonFluentClass
{

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source;
namespace Rector\Defluent\Tests\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source;
use Nette\Utils\DateTime;

View File

@ -1,8 +1,8 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
use Rector\Defluent\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
class SomeClass
{
@ -22,9 +22,9 @@ class SomeClass
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
use Rector\Defluent\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
class SomeClass
{

View File

@ -1,8 +1,8 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
use Rector\Defluent\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
class MultiChain
{
@ -23,9 +23,9 @@ class MultiChain
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
use Rector\Defluent\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
class MultiChain
{

View File

@ -1,8 +1,8 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
use Rector\Defluent\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
class WithArguments
{
@ -23,9 +23,9 @@ class WithArguments
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
use Rector\Defluent\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
class WithArguments
{

View File

@ -2,11 +2,11 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector;
namespace Rector\Defluent\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\MagicDisclosure\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector;
use Rector\Defluent\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector;
use Symplify\SmartFileSystem\SmartFileInfo;
final class MethodCallOnSetterMethodCallToStandaloneAssignRectorTest extends AbstractRectorTestCase

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source;
namespace Rector\Defluent\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source;
final class AnotherClass
{

View File

@ -1,6 +1,6 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
namespace Rector\Defluent\Tests\Rector\MethodCall\NewFluentChainMethodCallToNonFluentRector\Fixture;
use Symfony\Component\Finder\Finder;

View File

@ -0,0 +1,13 @@
<?php
namespace Rector\Defluent\Tests\Rector\MethodCall\NewFluentChainMethodCallToNonFluentRector\Fixture;
use Rector\Defluent\Tests\Rector\MethodCall\NewFluentChainMethodCallToNonFluentRector\Source\DifferentReturnValues;
class SkipGetterOnNew
{
public function run()
{
$differentReturnValues = (new DifferentReturnValues())->otherFunction();
}
}

Some files were not shown because too many files have changed in this diff Show More