Skip to content

Commit 037f997

Browse files
authored
Adds the ReverseCondiationableMethodCallRector (#245)
* Adds the ReverseCondiationableMethodCallRector * fix docs
1 parent d237f6e commit 037f997

File tree

9 files changed

+217
-1
lines changed

9 files changed

+217
-1
lines changed

config/sets/laravel-code-quality.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
use Rector\Config\RectorConfig;
66
use RectorLaravel\Rector\Assign\CallOnAppArrayAccessToStandaloneAssignRector;
7+
use RectorLaravel\Rector\MethodCall\ReverseConditionableMethodCallRector;
78

89
return static function (RectorConfig $rectorConfig): void {
910
$rectorConfig->import(__DIR__ . '/../config.php');
1011
$rectorConfig->rule(CallOnAppArrayAccessToStandaloneAssignRector::class);
12+
$rectorConfig->rule(ReverseConditionableMethodCallRector::class);
1113
};

docs/rector_rules_overview.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# 65 Rules Overview
1+
# 66 Rules Overview
22

33
## AbortIfRector
44

@@ -1231,6 +1231,26 @@ Change static `validate()` method to `$request->validate()`
12311231

12321232
<br>
12331233

1234+
## ReverseConditionableMethodCallRector
1235+
1236+
Reverse conditionable method calls
1237+
1238+
- class: [`RectorLaravel\Rector\MethodCall\ReverseConditionableMethodCallRector`](../src/Rector/MethodCall/ReverseConditionableMethodCallRector.php)
1239+
1240+
```diff
1241+
-$conditionable->when(!$condition, function () {});
1242+
+$conditionable->unless($condition, function () {});
1243+
```
1244+
1245+
<br>
1246+
1247+
```diff
1248+
-$conditionable->unless(!$condition, function () {});
1249+
+$conditionable->when($condition, function () {});
1250+
```
1251+
1252+
<br>
1253+
12341254
## RouteActionCallableRector
12351255

12361256
Use PHP callable syntax instead of string syntax for controller route declarations.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
namespace RectorLaravel\Rector\MethodCall;
4+
5+
use PhpParser\Node;
6+
use PhpParser\Node\Arg;
7+
use PhpParser\Node\Expr\BooleanNot;
8+
use PhpParser\Node\Expr\MethodCall;
9+
use PhpParser\Node\Identifier;
10+
use PHPStan\Type\ObjectType;
11+
use Rector\Rector\AbstractRector;
12+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
13+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
14+
15+
/**
16+
* @see \RectorLaravel\Tests\Rector\MethodCall\ReverseConditionableMethodCallRector\ReverseConditionableMethodCallRectorTest
17+
*/
18+
class ReverseConditionableMethodCallRector extends AbstractRector
19+
{
20+
private const CONDITIONABLE_TRAIT = 'Illuminate\Support\Traits\Conditionable';
21+
22+
public function getRuleDefinition(): RuleDefinition
23+
{
24+
return new RuleDefinition(
25+
'Reverse conditionable method calls',
26+
[
27+
new CodeSample(<<<'CODE_SAMPLE'
28+
$conditionable->when(!$condition, function () {});
29+
CODE_SAMPLE,
30+
<<<'CODE_SAMPLE'
31+
$conditionable->unless($condition, function () {});
32+
CODE_SAMPLE
33+
),
34+
new CodeSample(<<<'CODE_SAMPLE'
35+
$conditionable->unless(!$condition, function () {});
36+
CODE_SAMPLE,
37+
<<<'CODE_SAMPLE'
38+
$conditionable->when($condition, function () {});
39+
CODE_SAMPLE
40+
),
41+
]
42+
);
43+
}
44+
45+
public function getNodeTypes(): array
46+
{
47+
return [MethodCall::class];
48+
}
49+
50+
/**
51+
* @param MethodCall $node
52+
*/
53+
public function refactor(Node $node): ?MethodCall
54+
{
55+
if (! $this->isObjectType($node->var, new ObjectType(self::CONDITIONABLE_TRAIT))) {
56+
return null;
57+
}
58+
59+
if (! $this->isNames($node->name, ['when', 'unless'])) {
60+
return null;
61+
}
62+
63+
if ($node->isFirstClassCallable()) {
64+
return null;
65+
}
66+
67+
if ($node->getArgs() === []) {
68+
return null;
69+
}
70+
71+
$arg = $node->getArgs()[0];
72+
73+
if (! $node->name instanceof Identifier) {
74+
return null;
75+
}
76+
77+
if ($arg->value instanceof BooleanNot) {
78+
$node->args[0] = new Arg($arg->value->expr);
79+
$name = $node->name->toString() === 'when' ? 'unless' : 'when';
80+
81+
$node->name = new Identifier($name);
82+
83+
return $node;
84+
}
85+
86+
return null;
87+
}
88+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Illuminate\Support\Traits;
4+
5+
if (trait_exists('Illuminate\Support\Traits\Conditionable')) {
6+
return;
7+
}
8+
9+
trait Conditionable
10+
{
11+
public function when($value = null, ?callable $callback = null, ?callable $default = null)
12+
{
13+
}
14+
15+
public function unless($value = null, ?callable $callback = null, ?callable $default = null)
16+
{
17+
}
18+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace RectorLaravel\Tests\Rector\MethodCall\ReverseConditionableMethodCallRector\Fixture;
4+
5+
use RectorLaravel\Tests\Rector\MethodCall\ReverseConditionableMethodCallRector\Source\ConditionableExample;
6+
7+
$conditionable = new ConditionableExample();
8+
9+
$conditionable->when(!true, function () {});
10+
$conditionable->unless(!false, function () {});
11+
12+
?>
13+
-----
14+
<?php
15+
16+
namespace RectorLaravel\Tests\Rector\MethodCall\ReverseConditionableMethodCallRector\Fixture;
17+
18+
use RectorLaravel\Tests\Rector\MethodCall\ReverseConditionableMethodCallRector\Source\ConditionableExample;
19+
20+
$conditionable = new ConditionableExample();
21+
22+
$conditionable->unless(true, function () {});
23+
$conditionable->when(false, function () {});
24+
25+
?>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace RectorLaravel\Tests\Rector\MethodCall\ReverseConditionableMethodCallRector\Fixture;
4+
5+
$conditionable = new \stdClass();
6+
7+
$conditionable->when(!true, function () {});
8+
$conditionable->unless(!false, function () {});
9+
10+
?>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace RectorLaravel\Tests\Rector\MethodCall\ReverseConditionableMethodCallRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class ReverseConditionableMethodCallRectorTest extends AbstractRectorTestCase
12+
{
13+
public static function provideData(): Iterator
14+
{
15+
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
16+
}
17+
18+
/**
19+
* @test
20+
*/
21+
#[DataProvider('provideData')]
22+
public function test(string $filePath): void
23+
{
24+
$this->doTestFile($filePath);
25+
}
26+
27+
public function provideConfigFilePath(): string
28+
{
29+
return __DIR__ . '/config/configured_rule.php';
30+
}
31+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace RectorLaravel\Tests\Rector\MethodCall\ReverseConditionableMethodCallRector\Source;
4+
5+
use Illuminate\Support\Traits\Conditionable;
6+
7+
class ConditionableExample
8+
{
9+
use Conditionable;
10+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use RectorLaravel\Rector\MethodCall\ReverseConditionableMethodCallRector;
7+
8+
return static function (RectorConfig $rectorConfig): void {
9+
$rectorConfig->import(__DIR__ . '/../../../../../config/config.php');
10+
11+
$rectorConfig->rule(ReverseConditionableMethodCallRector::class);
12+
};

0 commit comments

Comments
 (0)