StaticCall to MethodCall (#4085)

* drop MessageAsArrayRector, as only rule in guzzle

* [Transform] Move StaticCallToMethodCallRector to Transform

* merge FacadeStaticCallToConstructorInjectionRector to StaticCallToMethodCallRector

* add ArrayArgumentToDataProvider

* [Transform] Move PropertyAssignToMethodCallRector to Transform
This commit is contained in:
Tomas Votruba 2020-08-31 10:48:14 +02:00 committed by GitHub
parent 082f1c6294
commit b281fb1260
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 451 additions and 398 deletions

View File

@ -7,6 +7,9 @@ use function Rector\SymfonyPhpConfig\inline_value_objects;
use Rector\Transform\ValueObject\FuncCallToStaticCall;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
// @see https://medium.freecodecamp.org/moving-away-from-magic-or-why-i-dont-want-to-use-laravel-anymore-2ce098c979bd
// @see https://laravel.com/docs/5.7/facades#facades-vs-dependency-injection
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();

View File

@ -3,19 +3,189 @@
declare(strict_types=1);
use Rector\Generic\Rector\FuncCall\FuncCallToNewRector;
use Rector\Laravel\Rector\StaticCall\FacadeStaticCallToConstructorInjectionRector;
use Rector\Laravel\Rector\StaticCall\RequestStaticValidateToInjectRector;
use function Rector\SymfonyPhpConfig\inline_value_objects;
use Rector\Transform\Rector\FuncCall\ArgumentFuncCallToMethodCallRector;
use Rector\Transform\Rector\StaticCall\StaticCallToMethodCallRector;
use Rector\Transform\ValueObject\ArgumentFuncCallToMethodCall;
use Rector\Transform\ValueObject\ArrayFuncCallToMethodCall;
use Rector\Transform\ValueObject\StaticCallToMethodCall;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->import(__DIR__ . '/laravel-array-str-functions-to-static-call.php');
$services = $containerConfigurator->services();
$services->set(FacadeStaticCallToConstructorInjectionRector::class);
// https://laravel.com/docs/5.7/facades#facades-vs-dependency-injection
$services->set(StaticCallToMethodCallRector::class)
->call('configure', [[
StaticCallToMethodCallRector::STATIC_CALLS_TO_METHOD_CALLS => inline_value_objects([
new StaticCallToMethodCall(
'Illuminate\Support\Facades\App',
'*',
'Illuminate\Foundation\Application',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Artisan',
'*',
'Illuminate\Contracts\Console\Kernel',
'*'
),
new StaticCallToMethodCall('Illuminate\Support\Facades\Auth', '*', 'Illuminate\Auth\AuthManager', '*'),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Blade',
'*',
'Illuminate\View\Compilers\BladeCompiler',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Broadcast',
'*',
'Illuminate\Contracts\Broadcasting\Factory',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Bus',
'*',
'Illuminate\Contracts\Bus\Dispatcher',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Cache',
'*',
'Illuminate\Cache\CacheManager',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Config',
'*',
'Illuminate\Config\Repository',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Cookie',
'*',
'Illuminate\Cookie\CookieJar',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Crypt',
'*',
'Illuminate\Encryption\Encrypter',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\DB',
'*',
'Illuminate\Database\DatabaseManager',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Event',
'*',
'Illuminate\Events\Dispatcher',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\File',
'*',
'Illuminate\Filesystem\Filesystem',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Gate',
'*',
'Illuminate\Contracts\Auth\Access\Gate',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Hash',
'*',
'Illuminate\Contracts\Hashing\Hasher',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Lang',
'*',
'Illuminate\Translation\Translator',
'*'
),
new StaticCallToMethodCall('Illuminate\Support\Facades\Log', '*', 'Illuminate\Log\LogManager', '*'),
new StaticCallToMethodCall('Illuminate\Support\Facades\Mail', '*', 'Illuminate\Mail\Mailer', '*'),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Notification',
'*',
'Illuminate\Notifications\ChannelManager',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Password',
'*',
'Illuminate\Auth\Passwords\PasswordBrokerManager',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Queue',
'*',
'Illuminate\Queue\QueueManager',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Redirect',
'*',
'Illuminate\Routing\Redirector',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Redis',
'*',
'Illuminate\Redis\RedisManager',
'*'
),
new StaticCallToMethodCall('Illuminate\Support\Facades\Request', '*', 'Illuminate\Http\Request', '*'),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Response',
'*',
'Illuminate\Contracts\Routing\ResponseFactory',
'*'
),
new StaticCallToMethodCall('Illuminate\Support\Facades\Route', '*', 'Illuminate\Routing\Router', '*'),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Schema',
'*',
'Illuminate\Database\Schema\Builder',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Session',
'*',
'Illuminate\Session\SessionManager',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Storage',
'*',
'Illuminate\Filesystem\FilesystemManager',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\URL',
'*',
'Illuminate\Routing\UrlGenerator',
'*'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Validator',
'*',
'Illuminate\Validation\Factory',
'*'
),
new StaticCallToMethodCall('Illuminate\Support\Facades\View', '*', 'Illuminate\View\Factory', '*'),
]),
]]);
$services->set(RequestStaticValidateToInjectRector::class);
// @see https://github.com/laravel/framework/blob/78828bc779e410e03cc6465f002b834eadf160d2/src/Illuminate/Foundation/helpers.php#L959

View File

@ -1,4 +1,4 @@
# All 566 Rectors Overview
# All 565 Rectors Overview
- [Projects](#projects)
---
@ -18,9 +18,9 @@
- [Downgrade](#downgrade) (1)
- [DynamicTypeAnalysis](#dynamictypeanalysis) (3)
- [FileSystemRector](#filesystemrector) (1)
- [Generic](#generic) (39)
- [Generic](#generic) (38)
- [JMS](#jms) (2)
- [Laravel](#laravel) (5)
- [Laravel](#laravel) (4)
- [Legacy](#legacy) (4)
- [MagicDisclosure](#magicdisclosure) (8)
- [MockeryToProphecy](#mockerytoprophecy) (2)
@ -67,7 +67,7 @@
- [SymfonyCodeQuality](#symfonycodequality) (1)
- [SymfonyPHPUnit](#symfonyphpunit) (1)
- [SymfonyPhpConfig](#symfonyphpconfig) (2)
- [Transform](#transform) (10)
- [Transform](#transform) (11)
- [Twig](#twig) (1)
- [TypeDeclaration](#typedeclaration) (9)
@ -5443,40 +5443,6 @@ return function (ContainerConfigurator $containerConfigurator) : void {
<br><br>
### `PropertyAssignToMethodCallRector`
- class: [`Rector\Generic\Rector\Assign\PropertyAssignToMethodCallRector`](/../master/rules/generic/src/Rector/Assign/PropertyAssignToMethodCallRector.php)
- [test fixtures](/../master/rules/generic/tests/Rector/Assign/PropertyAssignToMethodCallRector/Fixture)
Turns property assign of specific type and property name to method call
```php
<?php
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Rector\Generic\Rector\Assign\PropertyAssignToMethodCallRector;
return function (ContainerConfigurator $containerConfigurator) : void {
$services = $containerConfigurator->services();
$services->set(PropertyAssignToMethodCallRector::class)
->call('configure', [[
PropertyAssignToMethodCallRector::OLD_PROPERTIES_TO_NEW_METHOD_CALLS_BY_TYPE => [
'SomeClass' => [
'oldPropertyName' => 'oldProperty', 'newMethodName' => 'newMethodCall']]
]]);
};
```
```diff
$someObject = new SomeClass;
-$someObject->oldProperty = false;
+$someObject->newMethodCall(false);
```
<br><br>
### `PseudoNamespaceToNamespaceRector`
- class: [`Rector\Generic\Rector\Name\PseudoNamespaceToNamespaceRector`](/../master/rules/generic/src/Rector/Name/PseudoNamespaceToNamespaceRector.php)
@ -6032,38 +5998,6 @@ Removes JMS\DiExtraBundle\Annotation\Services annotation
## Laravel
### `FacadeStaticCallToConstructorInjectionRector`
- class: [`Rector\Laravel\Rector\StaticCall\FacadeStaticCallToConstructorInjectionRector`](/../master/rules/laravel/src/Rector/StaticCall/FacadeStaticCallToConstructorInjectionRector.php)
- [test fixtures](/../master/rules/laravel/tests/Rector/StaticCall/FacadeStaticCallToConstructorInjectionRector/Fixture)
Move Illuminate\Support\Facades\* static calls to constructor injection
```diff
use Illuminate\Support\Facades\Response;
class ExampleController extends Controller
{
+ /**
+ * @var \Illuminate\Contracts\Routing\ResponseFactory
+ */
+ private $responseFactory;
+
+ public function __construct(\Illuminate\Contracts\Routing\ResponseFactory $responseFactory)
+ {
+ $this->responseFactory = $responseFactory;
+ }
+
public function store()
{
- return Response::view('example', ['new_example' => 123]);
+ return $this->responseFactory->view('example', ['new_example' => 123]);
}
}
```
<br><br>
### `InlineValidationRulesToArrayDefinitionRector`
- class: [`Rector\Laravel\Rector\ArrayItem\InlineValidationRulesToArrayDefinitionRector`](/../master/rules/laravel/src/Rector/ArrayItem/InlineValidationRulesToArrayDefinitionRector.php)
@ -8529,9 +8463,8 @@ return function (ContainerConfigurator $containerConfigurator) : void {
$services = $containerConfigurator->services();
$services->set(ArrayArgumentInTestToDataProviderRector::class)
->call('configure', [[
ArrayArgumentInTestToDataProviderRector::CONFIGURATION => [
[
'class' => 'PHPUnit\Framework\TestCase', 'old_method' => 'doTestMultiple', 'new_method' => 'doTestSingle', 'variable_name' => 'number']]
ArrayArgumentInTestToDataProviderRector::ARRAY_ARGUMENTS_TO_DATA_PROVIDERS => [
\Rector\SymfonyPhpConfig\inline_value_object(new Rector\PHPUnit\ValueObject\ArrayArgumentToDataProvider('PHPUnit\Framework\TestCase', 'doTestMultiple', 'doTestSingle', 'number'))]
]]);
};
```
@ -14122,6 +14055,39 @@ return function (ContainerConfigurator $containerConfigurator) : void {
<br><br>
### `PropertyAssignToMethodCallRector`
- class: [`Rector\Transform\Rector\Assign\PropertyAssignToMethodCallRector`](/../master/rules/transform/src/Rector/Assign/PropertyAssignToMethodCallRector.php)
- [test fixtures](/../master/rules/transform/tests/Rector/Assign/PropertyAssignToMethodCallRector/Fixture)
Turns property assign of specific type and property name to method call
```php
<?php
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Rector\Transform\Rector\Assign\PropertyAssignToMethodCallRector;
return function (ContainerConfigurator $containerConfigurator) : void {
$services = $containerConfigurator->services();
$services->set(PropertyAssignToMethodCallRector::class)
->call('configure', [[
PropertyAssignToMethodCallRector::PROPERTY_ASSIGNS_TO_METHODS_CALLS => [
\Rector\SymfonyPhpConfig\inline_value_object(new Rector\Transform\ValueObject\PropertyAssignToMethodCall('SomeClass', 'oldPropertyName', 'oldProperty')), \Rector\SymfonyPhpConfig\inline_value_object(new Rector\Transform\ValueObject\PropertyAssignToMethodCall('SomeClass', 'newMethodName', 'newMethodCall'))]
]]);
};
```
```diff
$someObject = new SomeClass;
-$someObject->oldProperty = false;
+$someObject->newMethodCall(false);
```
<br><br>
### `PropertyToMethodRector`
- class: [`Rector\Transform\Rector\Assign\PropertyToMethodRector`](/../master/rules/transform/src/Rector/Assign/PropertyToMethodRector.php)

View File

@ -1,33 +0,0 @@
<?php
namespace Rector\Generic\Tests\Rector\Assign\PropertyAssignToMethodCallRector\Fixture;
use Rector\Generic\Tests\Rector\Assign\PropertyAssignToMethodCallRector\Source\ChoiceControl;
class SomePresenter
{
public function createForm()
{
$control = new ChoiceControl();
$control->checkAllowedValues = false;
}
}
?>
-----
<?php
namespace Rector\Generic\Tests\Rector\Assign\PropertyAssignToMethodCallRector\Fixture;
use Rector\Generic\Tests\Rector\Assign\PropertyAssignToMethodCallRector\Source\ChoiceControl;
class SomePresenter
{
public function createForm()
{
$control = new ChoiceControl();
$control->checkDefaultValue(false);
}
}
?>

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Generic\Tests\Rector\Assign\PropertyAssignToMethodCallRector\Source;
final class ChoiceControl
{
}

View File

@ -1,152 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Laravel\Rector\StaticCall;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Type\ObjectType;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\Naming\Naming\PropertyNaming;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PHPStan\Type\FullyQualifiedObjectType;
/**
* @see https://medium.freecodecamp.org/moving-away-from-magic-or-why-i-dont-want-to-use-laravel-anymore-2ce098c979bd
* @see https://laravel.com/docs/5.7/facades#facades-vs-dependency-injection
*
* @see \Rector\Laravel\Tests\Rector\StaticCall\FacadeStaticCallToConstructorInjectionRector\FacadeStaticCallToConstructorInjectionRectorTest
*/
final class FacadeStaticCallToConstructorInjectionRector extends AbstractRector
{
/**
* @see https://laravel.com/docs/5.7/facades#facades-vs-dependency-injection
* @var array<string, string>
*/
private const FACADE_TO_SERVICE_MAP = [
'Illuminate\Support\Facades\App' => 'Illuminate\Foundation\Application',
'Illuminate\Support\Facades\Artisan' => 'Illuminate\Contracts\Console\Kernel',
'Illuminate\Support\Facades\Auth' => 'Illuminate\Auth\AuthManager',
'Illuminate\Support\Facades\Blade' => 'Illuminate\View\Compilers\BladeCompiler',
'Illuminate\Support\Facades\Broadcast' => 'Illuminate\Contracts\Broadcasting\Factory',
'Illuminate\Support\Facades\Bus' => 'Illuminate\Contracts\Bus\Dispatcher',
'Illuminate\Support\Facades\Cache' => 'Illuminate\Cache\CacheManager',
'Illuminate\Support\Facades\Config' => 'Illuminate\Config\Repository',
'Illuminate\Support\Facades\Cookie' => 'Illuminate\Cookie\CookieJar',
'Illuminate\Support\Facades\Crypt' => 'Illuminate\Encryption\Encrypter',
'Illuminate\Support\Facades\DB' => 'Illuminate\Database\DatabaseManager',
'Illuminate\Support\Facades\Event' => 'Illuminate\Events\Dispatcher',
'Illuminate\Support\Facades\File' => 'Illuminate\Filesystem\Filesystem',
'Illuminate\Support\Facades\Gate' => 'Illuminate\Contracts\Auth\Access\Gate',
'Illuminate\Support\Facades\Hash' => 'Illuminate\Contracts\Hashing\Hasher',
'Illuminate\Support\Facades\Lang' => 'Illuminate\Translation\Translator',
'Illuminate\Support\Facades\Log' => 'Illuminate\Log\LogManager',
'Illuminate\Support\Facades\Mail' => 'Illuminate\Mail\Mailer',
'Illuminate\Support\Facades\Notification' => 'Illuminate\Notifications\ChannelManager',
'Illuminate\Support\Facades\Password' => 'Illuminate\Auth\Passwords\PasswordBrokerManager',
'Illuminate\Support\Facades\Queue' => 'Illuminate\Queue\QueueManager',
'Illuminate\Support\Facades\Redirect' => 'Illuminate\Routing\Redirector',
'Illuminate\Support\Facades\Redis' => 'Illuminate\Redis\RedisManager',
'Illuminate\Support\Facades\Request' => 'Illuminate\Http\Request',
'Illuminate\Support\Facades\Response' => 'Illuminate\Contracts\Routing\ResponseFactory',
'Illuminate\Support\Facades\Route' => 'Illuminate\Routing\Router',
'Illuminate\Support\Facades\Schema' => 'Illuminate\Database\Schema\Builder',
'Illuminate\Support\Facades\Session' => 'Illuminate\Session\SessionManager',
'Illuminate\Support\Facades\Storage' => 'Illuminate\Filesystem\FilesystemManager',
'Illuminate\Support\Facades\URL' => 'Illuminate\Routing\UrlGenerator',
'Illuminate\Support\Facades\Validator' => 'Illuminate\Validation\Factory',
'Illuminate\Support\Facades\View' => 'Illuminate\View\Factory',
];
/**
* @var PropertyNaming
*/
private $propertyNaming;
public function __construct(PropertyNaming $propertyNaming)
{
$this->propertyNaming = $propertyNaming;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Move Illuminate\Support\Facades\* static calls to constructor injection', [
new CodeSample(
<<<'PHP'
use Illuminate\Support\Facades\Response;
class ExampleController extends Controller
{
public function store()
{
return Response::view('example', ['new_example' => 123]);
}
}
PHP
,
<<<'PHP'
use Illuminate\Support\Facades\Response;
class ExampleController extends Controller
{
/**
* @var \Illuminate\Contracts\Routing\ResponseFactory
*/
private $responseFactory;
public function __construct(\Illuminate\Contracts\Routing\ResponseFactory $responseFactory)
{
$this->responseFactory = $responseFactory;
}
public function store()
{
return $this->responseFactory->view('example', ['new_example' => 123]);
}
}
PHP
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [StaticCall::class];
}
/**
* @param StaticCall $node
*/
public function refactor(Node $node): ?Node
{
$classLike = $node->getAttribute(AttributeKey::CLASS_NODE);
if (! $classLike instanceof Class_) {
return null;
}
foreach (self::FACADE_TO_SERVICE_MAP as $facadeClass => $serviceClass) {
$facadeObjectType = new ObjectType($facadeClass);
if (! $this->isObjectType($node->class, $facadeObjectType)) {
continue;
}
$serviceObjectType = new FullyQualifiedObjectType($serviceClass);
$propertyName = $this->propertyNaming->fqnToVariableName($serviceObjectType);
$this->addConstructorDependencyToClass($classLike, $serviceObjectType, $propertyName);
$propertyFetchNode = $this->createPropertyFetch('this', $propertyName);
return new MethodCall($propertyFetchNode, $node->name, $node->args);
}
return $node;
}
}

View File

@ -1,31 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Laravel\Tests\Rector\StaticCall\FacadeStaticCallToConstructorInjectionRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\Laravel\Rector\StaticCall\FacadeStaticCallToConstructorInjectionRector;
use Symplify\SmartFileSystem\SmartFileInfo;
final class FacadeStaticCallToConstructorInjectionRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
protected function getRectorClass(): string
{
return FacadeStaticCallToConstructorInjectionRector::class;
}
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Laravel\Tests\Rector\StaticCall\FacadeStaticCallToConstructorInjectionRector\Source;
abstract class LaravelController
{
}

View File

@ -29,8 +29,10 @@ use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
use Rector\PHPUnit\NodeFactory\DataProviderClassMethodFactory;
use Rector\PHPUnit\ValueObject\ArrayArgumentToDataProvider;
use Rector\PHPUnit\ValueObject\DataProviderClassMethodRecipe;
use Rector\PHPUnit\ValueObject\ParamAndArgValueObject;
use Webmozart\Assert\Assert;
/**
* @see \Rector\PHPUnit\Tests\Rector\Class_\ArrayArgumentInTestToDataProviderRector\ArrayArgumentInTestToDataProviderRectorTest
@ -43,12 +45,12 @@ final class ArrayArgumentInTestToDataProviderRector extends AbstractPHPUnitRecto
* @api
* @var string
*/
public const CONFIGURATION = '$configuration';
public const ARRAY_ARGUMENTS_TO_DATA_PROVIDERS = 'array_arguments_to_data_providers';
/**
* @var mixed[]
* @var ArrayArgumentToDataProvider[]
*/
private $configuration = [];
private $arrayArgumentsToDataProviders = [];
/**
* @var DataProviderClassMethodRecipe[]
@ -113,13 +115,13 @@ PHP
,
[
'$configuration' => [
[
'class' => 'PHPUnit\Framework\TestCase',
'old_method' => 'doTestMultiple',
'new_method' => 'doTestSingle',
'variable_name' => 'number',
],
self::ARRAY_ARGUMENTS_TO_DATA_PROVIDERS => [
new ArrayArgumentToDataProvider(
'PHPUnit\Framework\TestCase',
'doTestMultiple',
'doTestSingle',
'number'
),
],
]
),
@ -143,8 +145,6 @@ PHP
return null;
}
$this->ensureConfigurationIsSet($this->configuration);
$this->dataProviderClassMethodRecipes = [];
$this->traverseNodesWithCallable($node->stmts, function (Node $node) {
@ -152,8 +152,8 @@ PHP
return null;
}
foreach ($this->configuration as $singleConfiguration) {
$this->refactorMethodCallWithConfiguration($node, $singleConfiguration);
foreach ($this->arrayArgumentsToDataProviders as $arrayArgumentsToDataProvider) {
$this->refactorMethodCallWithConfiguration($node, $arrayArgumentsToDataProvider);
}
return null;
@ -170,30 +170,18 @@ PHP
return $node;
}
public function configure(array $configuration): void
public function configure(array $arrayArgumentsToDataProviders): void
{
$this->configuration = $configuration[self::CONFIGURATION] ?? [];
$arrayArgumentsToDataProviders = $arrayArgumentsToDataProviders[self::ARRAY_ARGUMENTS_TO_DATA_PROVIDERS] ?? [];
Assert::allIsInstanceOf($arrayArgumentsToDataProviders, ArrayArgumentToDataProvider::class);
$this->arrayArgumentsToDataProviders = $arrayArgumentsToDataProviders;
}
/**
* @param mixed[] $configuration
*/
private function ensureConfigurationIsSet(array $configuration): void
{
if ($configuration !== []) {
return;
}
throw new ShouldNotHappenException(sprintf(
'Add configuration via "%s" argument for "%s"',
'$configuration',
self::class
));
}
private function refactorMethodCallWithConfiguration(MethodCall $methodCall, array $singleConfiguration): void
{
if (! $this->isMethodCallMatch($methodCall, $singleConfiguration)) {
private function refactorMethodCallWithConfiguration(
MethodCall $methodCall,
ArrayArgumentToDataProvider $arrayArgumentToDataProvider
): void {
if (! $this->isMethodCallMatch($methodCall, $arrayArgumentToDataProvider)) {
return;
}
@ -209,7 +197,7 @@ PHP
}
// rename method to new one handling non-array input
$methodCall->name = new Identifier($singleConfiguration['new_method']);
$methodCall->name = new Identifier($arrayArgumentToDataProvider->getNewMethod());
$dataProviderMethodName = $this->createDataProviderMethodName($methodCall);
@ -222,7 +210,7 @@ PHP
$paramAndArgs = $this->collectParamAndArgsFromArray(
$firstArgumentValue,
$singleConfiguration['variable_name']
$arrayArgumentToDataProvider->getVariableName()
);
foreach ($paramAndArgs as $paramAndArg) {
@ -258,22 +246,21 @@ PHP
return $dataProviderClassMethods;
}
/**
* @param string[] $singleConfiguration
*/
private function isMethodCallMatch(MethodCall $methodCall, array $singleConfiguration): bool
{
if (! $this->isObjectType($methodCall->var, $singleConfiguration['class'])) {
private function isMethodCallMatch(
MethodCall $methodCall,
ArrayArgumentToDataProvider $arrayArgumentToDataProvider
): bool {
if (! $this->isObjectType($methodCall->var, $arrayArgumentToDataProvider->getClass())) {
return false;
}
return $this->isName($methodCall->name, $singleConfiguration['old_method']);
return $this->isName($methodCall->name, $arrayArgumentToDataProvider->getOldMethod());
}
private function createDataProviderMethodName(Node $node): string
private function createDataProviderMethodName(MethodCall $methodCall): string
{
/** @var string $methodName */
$methodName = $node->getAttribute(AttributeKey::METHOD_NAME);
$methodName = $methodCall->getAttribute(AttributeKey::METHOD_NAME);
return 'provideDataFor' . ucfirst($methodName);
}

View File

@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace Rector\PHPUnit\ValueObject;
final class ArrayArgumentToDataProvider
{
/**
* @var string
*/
private $class;
/**
* @var string
*/
private $oldMethod;
/**
* @var string
*/
private $newMethod;
/**
* @var string
*/
private $variableName;
public function __construct(string $class, string $oldMethod, string $newMethod, string $variableName)
{
$this->class = $class;
$this->oldMethod = $oldMethod;
$this->newMethod = $newMethod;
$this->variableName = $variableName;
}
public function getClass(): string
{
return $this->class;
}
public function getOldMethod(): string
{
return $this->oldMethod;
}
public function getNewMethod(): string
{
return $this->newMethod;
}
public function getVariableName(): string
{
return $this->variableName;
}
}

View File

@ -7,6 +7,7 @@ namespace Rector\PHPUnit\Tests\Rector\Class_\ArrayArgumentInTestToDataProviderRe
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\PHPUnit\Rector\Class_\ArrayArgumentInTestToDataProviderRector;
use Rector\PHPUnit\ValueObject\ArrayArgumentToDataProvider;
use Symplify\SmartFileSystem\SmartFileInfo;
final class ArrayArgumentInTestToDataProviderRectorTest extends AbstractRectorTestCase
@ -31,13 +32,13 @@ final class ArrayArgumentInTestToDataProviderRectorTest extends AbstractRectorTe
{
return [
ArrayArgumentInTestToDataProviderRector::class => [
ArrayArgumentInTestToDataProviderRector::CONFIGURATION => [
[
'class' => 'PHPUnit\Framework\TestCase',
'old_method' => 'doTestMultiple',
'new_method' => 'doTestSingle',
'variable_name' => 'variable',
],
ArrayArgumentInTestToDataProviderRector::ARRAY_ARGUMENTS_TO_DATA_PROVIDERS => [
new ArrayArgumentToDataProvider(
'PHPUnit\Framework\TestCase',
'doTestMultiple',
'doTestSingle',
'variable'
),
],
],
];

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\Generic\Rector\Assign;
namespace Rector\Transform\Rector\Assign;
use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
@ -12,21 +12,23 @@ use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\ConfiguredCodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\Transform\ValueObject\PropertyAssignToMethodCall;
use Webmozart\Assert\Assert;
/**
* @see \Rector\Generic\Tests\Rector\Assign\PropertyAssignToMethodCallRector\PropertyAssignToMethodCallRectorTest
* @see \Rector\Transform\Tests\Rector\Assign\PropertyAssignToMethodCallRector\PropertyAssignToMethodCallRectorTest
*/
final class PropertyAssignToMethodCallRector extends AbstractRector implements ConfigurableRectorInterface
{
/**
* @var string
*/
public const OLD_PROPERTIES_TO_NEW_METHOD_CALLS_BY_TYPE = '$oldPropertiesToNewMethodCallsByType';
public const PROPERTY_ASSIGNS_TO_METHODS_CALLS = 'property_assigns_to_methods_calls';
/**
* @var string[][]
* @var PropertyAssignToMethodCall[]
*/
private $oldPropertiesToNewMethodCallsByType = [];
private $propertyAssignsToMethodCalls = [];
public function getDefinition(): RectorDefinition
{
@ -43,11 +45,8 @@ $someObject->newMethodCall(false);
PHP
,
[
self::OLD_PROPERTIES_TO_NEW_METHOD_CALLS_BY_TYPE => [
'SomeClass' => [
'oldPropertyName' => 'oldProperty',
'newMethodName' => 'newMethodCall',
],
self::PROPERTY_ASSIGNS_TO_METHODS_CALLS => [
new PropertyAssignToMethodCall('SomeClass', 'oldProperty', 'newMethodCall'),
],
]
),
@ -76,18 +75,20 @@ PHP
/** @var Variable $propertyNode */
$propertyNode = $propertyFetchNode->var;
foreach ($this->oldPropertiesToNewMethodCallsByType as $type => $oldPropertiesToNewMethodCalls) {
if (! $this->isObjectType($propertyFetchNode->var, $type)) {
foreach ($this->propertyAssignsToMethodCalls as $propertyAssignToMethodCall) {
if (! $this->isObjectType($propertyFetchNode->var, $propertyAssignToMethodCall->getClass())) {
continue;
}
foreach ($oldPropertiesToNewMethodCalls as $oldProperty => $newMethodCall) {
if (! $this->isName($propertyFetchNode, $oldProperty)) {
continue;
}
return $this->createMethodCall($propertyNode, $newMethodCall, [$node->expr]);
if (! $this->isName($propertyFetchNode, $propertyAssignToMethodCall->getOldPropertyName())) {
continue;
}
return $this->createMethodCall(
$propertyNode,
$propertyAssignToMethodCall->getNewMethodName(),
[$node->expr]
);
}
return $node;
@ -95,6 +96,8 @@ PHP
public function configure(array $configuration): void
{
$this->oldPropertiesToNewMethodCallsByType = $configuration[self::OLD_PROPERTIES_TO_NEW_METHOD_CALLS_BY_TYPE] ?? [];
$propertyAssignsToMethodCalls = $configuration[self::PROPERTY_ASSIGNS_TO_METHODS_CALLS] ?? [];
Assert::allIsInstanceOf($propertyAssignsToMethodCalls, PropertyAssignToMethodCall::class);
$this->propertyAssignsToMethodCalls = $propertyAssignsToMethodCalls;
}
}

View File

@ -117,7 +117,14 @@ PHP
}
$expr = $this->matchTypeProvidingExpr($classLike, $classMethod, $staticCallToMethodCall->getClassType());
return new MethodCall($expr, $staticCallToMethodCall->getMethodName(), $node->args);
if ($staticCallToMethodCall->getMethodName() === '*') {
$methodName = $this->getName($node->name);
} else {
$methodName = $staticCallToMethodCall->getMethodName();
}
return new MethodCall($expr, $methodName, $node->args);
}
return $node;

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace Rector\Transform\ValueObject;
final class PropertyAssignToMethodCall
{
/**
* @var string
*/
private $class;
/**
* @var string
*/
private $oldPropertyName;
/**
* @var string
*/
private $newMethodName;
public function __construct(string $class, string $oldPropertyName, string $newMethodName)
{
$this->class = $class;
$this->oldPropertyName = $oldPropertyName;
$this->newMethodName = $newMethodName;
}
public function getClass(): string
{
return $this->class;
}
public function getOldPropertyName(): string
{
return $this->oldPropertyName;
}
public function getNewMethodName(): string
{
return $this->newMethodName;
}
}

View File

@ -63,6 +63,11 @@ final class StaticCallToMethodCall
return false;
}
// all methods
if ($this->staticMethod === '*') {
return true;
}
$staticCallMethodName = $staticCall->name->toString();
return $staticCallMethodName === $this->staticMethod;
}

View File

@ -0,0 +1,33 @@
<?php
namespace Rector\Transform\Tests\Rector\Assign\PropertyAssignToMethodCallRector\Fixture;
use Rector\Transform\Tests\Rector\Assign\PropertyAssignToMethodCallRector\Source\ChoiceControl;
class SomePresenter
{
public function createForm()
{
$control = new ChoiceControl();
$control->checkAllowedValues = false;
}
}
?>
-----
<?php
namespace Rector\Transform\Tests\Rector\Assign\PropertyAssignToMethodCallRector\Fixture;
use Rector\Transform\Tests\Rector\Assign\PropertyAssignToMethodCallRector\Source\ChoiceControl;
class SomePresenter
{
public function createForm()
{
$control = new ChoiceControl();
$control->checkDefaultValue(false);
}
}
?>

View File

@ -1,6 +1,6 @@
<?php
namespace Rector\Generic\Tests\Rector\Assign\PropertyAssignToMethodCallRector\Fixture;
namespace Rector\Transform\Tests\Rector\Assign\PropertyAssignToMethodCallRector\Fixture;
use stdClass;

View File

@ -2,12 +2,13 @@
declare(strict_types=1);
namespace Rector\Generic\Tests\Rector\Assign\PropertyAssignToMethodCallRector;
namespace Rector\Transform\Tests\Rector\Assign\PropertyAssignToMethodCallRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\Generic\Rector\Assign\PropertyAssignToMethodCallRector;
use Rector\Generic\Tests\Rector\Assign\PropertyAssignToMethodCallRector\Source\ChoiceControl;
use Rector\Transform\Rector\Assign\PropertyAssignToMethodCallRector;
use Rector\Transform\Tests\Rector\Assign\PropertyAssignToMethodCallRector\Source\ChoiceControl;
use Rector\Transform\ValueObject\PropertyAssignToMethodCall;
use Symplify\SmartFileSystem\SmartFileInfo;
final class PropertyAssignToMethodCallRectorTest extends AbstractRectorTestCase
@ -32,10 +33,8 @@ final class PropertyAssignToMethodCallRectorTest extends AbstractRectorTestCase
{
return [
PropertyAssignToMethodCallRector::class => [
PropertyAssignToMethodCallRector::OLD_PROPERTIES_TO_NEW_METHOD_CALLS_BY_TYPE => [
ChoiceControl::class => [
'checkAllowedValues' => 'checkDefaultValue',
],
PropertyAssignToMethodCallRector::PROPERTY_ASSIGNS_TO_METHODS_CALLS => [
new PropertyAssignToMethodCall(ChoiceControl::class, 'checkAllowedValues', 'checkDefaultValue'),
],
],
];

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Rector\Transform\Tests\Rector\Assign\PropertyAssignToMethodCallRector\Source;
final class ChoiceControl
{
}

View File

@ -1,11 +1,10 @@
<?php
namespace Rector\Laravel\Tests\Rector\StaticCall\FacadeStaticCallToConstructorInjectionRector\Fixture;
namespace Rector\Transform\Tests\Rector\StaticCall\StaticCallToMethodCallRector\Fixture;
use Illuminate\Support\Facades\Response;
use Rector\Laravel\Tests\Rector\StaticCall\FacadeStaticCallToConstructorInjectionRector\Source\LaravelController;
class ExampleController extends LaravelController
class ExampleController
{
public function store()
{
@ -17,12 +16,11 @@ class ExampleController extends LaravelController
-----
<?php
namespace Rector\Laravel\Tests\Rector\StaticCall\FacadeStaticCallToConstructorInjectionRector\Fixture;
namespace Rector\Transform\Tests\Rector\StaticCall\StaticCallToMethodCallRector\Fixture;
use Illuminate\Support\Facades\Response;
use Rector\Laravel\Tests\Rector\StaticCall\FacadeStaticCallToConstructorInjectionRector\Source\LaravelController;
class ExampleController extends LaravelController
class ExampleController
{
private \Illuminate\Contracts\Routing\ResponseFactory $responseFactory;
public function __construct(\Illuminate\Contracts\Routing\ResponseFactory $responseFactory)

View File

@ -39,6 +39,12 @@ final class StaticCallToMethodCallRectorTest extends AbstractRectorTestCase
'Symplify\SmartFileSystem\SmartFileSystem',
'dumpFile'
),
new StaticCallToMethodCall(
'Illuminate\Support\Facades\Response',
'*',
'Illuminate\Contracts\Routing\ResponseFactory',
'*'
),
],
],
];