diff --git a/config/sets/laravel-code-quality.php b/config/sets/laravel-code-quality.php index b8644ff8..e8ba5935 100644 --- a/config/sets/laravel-code-quality.php +++ b/config/sets/laravel-code-quality.php @@ -4,8 +4,10 @@ use Rector\Config\RectorConfig; use RectorLaravel\Rector\Assign\CallOnAppArrayAccessToStandaloneAssignRector; +use RectorLaravel\Rector\MethodCall\ReverseConditionableMethodCallRector; return static function (RectorConfig $rectorConfig): void { $rectorConfig->import(__DIR__ . '/../config.php'); $rectorConfig->rule(CallOnAppArrayAccessToStandaloneAssignRector::class); + $rectorConfig->rule(ReverseConditionableMethodCallRector::class); }; diff --git a/docs/rector_rules_overview.md b/docs/rector_rules_overview.md index 16b4f746..530b51c4 100644 --- a/docs/rector_rules_overview.md +++ b/docs/rector_rules_overview.md @@ -1,4 +1,4 @@ -# 65 Rules Overview +# 66 Rules Overview ## AbortIfRector @@ -1231,6 +1231,26 @@ Change static `validate()` method to `$request->validate()`
+## ReverseConditionableMethodCallRector + +Reverse conditionable method calls + +- class: [`RectorLaravel\Rector\MethodCall\ReverseConditionableMethodCallRector`](../src/Rector/MethodCall/ReverseConditionableMethodCallRector.php) + +```diff +-$conditionable->when(!$condition, function () {}); ++$conditionable->unless($condition, function () {}); +``` + +
+ +```diff +-$conditionable->unless(!$condition, function () {}); ++$conditionable->when($condition, function () {}); +``` + +
+ ## RouteActionCallableRector Use PHP callable syntax instead of string syntax for controller route declarations. diff --git a/src/Rector/MethodCall/ReverseConditionableMethodCallRector.php b/src/Rector/MethodCall/ReverseConditionableMethodCallRector.php new file mode 100644 index 00000000..871cd125 --- /dev/null +++ b/src/Rector/MethodCall/ReverseConditionableMethodCallRector.php @@ -0,0 +1,88 @@ +when(!$condition, function () {}); +CODE_SAMPLE, + <<<'CODE_SAMPLE' +$conditionable->unless($condition, function () {}); +CODE_SAMPLE + ), + new CodeSample(<<<'CODE_SAMPLE' +$conditionable->unless(!$condition, function () {}); +CODE_SAMPLE, + <<<'CODE_SAMPLE' +$conditionable->when($condition, function () {}); +CODE_SAMPLE + ), + ] + ); + } + + public function getNodeTypes(): array + { + return [MethodCall::class]; + } + + /** + * @param MethodCall $node + */ + public function refactor(Node $node): ?MethodCall + { + if (! $this->isObjectType($node->var, new ObjectType(self::CONDITIONABLE_TRAIT))) { + return null; + } + + if (! $this->isNames($node->name, ['when', 'unless'])) { + return null; + } + + if ($node->isFirstClassCallable()) { + return null; + } + + if ($node->getArgs() === []) { + return null; + } + + $arg = $node->getArgs()[0]; + + if (! $node->name instanceof Identifier) { + return null; + } + + if ($arg->value instanceof BooleanNot) { + $node->args[0] = new Arg($arg->value->expr); + $name = $node->name->toString() === 'when' ? 'unless' : 'when'; + + $node->name = new Identifier($name); + + return $node; + } + + return null; + } +} diff --git a/stubs/Illuminate/Support/Traits/Conditionable.php b/stubs/Illuminate/Support/Traits/Conditionable.php new file mode 100644 index 00000000..58abe2cd --- /dev/null +++ b/stubs/Illuminate/Support/Traits/Conditionable.php @@ -0,0 +1,18 @@ +when(!true, function () {}); +$conditionable->unless(!false, function () {}); + +?> +----- +unless(true, function () {}); +$conditionable->when(false, function () {}); + +?> diff --git a/tests/Rector/MethodCall/ReverseConditionableMethodCallRector/Fixture/skip_non_conditionable_object.php.inc b/tests/Rector/MethodCall/ReverseConditionableMethodCallRector/Fixture/skip_non_conditionable_object.php.inc new file mode 100644 index 00000000..3db99d0b --- /dev/null +++ b/tests/Rector/MethodCall/ReverseConditionableMethodCallRector/Fixture/skip_non_conditionable_object.php.inc @@ -0,0 +1,10 @@ +when(!true, function () {}); +$conditionable->unless(!false, function () {}); + +?> diff --git a/tests/Rector/MethodCall/ReverseConditionableMethodCallRector/ReverseConditionableMethodCallRectorTest.php b/tests/Rector/MethodCall/ReverseConditionableMethodCallRector/ReverseConditionableMethodCallRectorTest.php new file mode 100644 index 00000000..95715778 --- /dev/null +++ b/tests/Rector/MethodCall/ReverseConditionableMethodCallRector/ReverseConditionableMethodCallRectorTest.php @@ -0,0 +1,31 @@ +doTestFile($filePath); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/tests/Rector/MethodCall/ReverseConditionableMethodCallRector/Source/ConditionableExample.php b/tests/Rector/MethodCall/ReverseConditionableMethodCallRector/Source/ConditionableExample.php new file mode 100644 index 00000000..25290570 --- /dev/null +++ b/tests/Rector/MethodCall/ReverseConditionableMethodCallRector/Source/ConditionableExample.php @@ -0,0 +1,10 @@ +import(__DIR__ . '/../../../../../config/config.php'); + + $rectorConfig->rule(ReverseConditionableMethodCallRector::class); +};