Skip to content

Commit 03c1396

Browse files
authored
Add UnaliasCollectionMethodsRector (#291)
1 parent 915565b commit 03c1396

File tree

9 files changed

+194
-2
lines changed

9 files changed

+194
-2
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
},
3434
"scripts": {
3535
"phpstan": "vendor/bin/phpstan analyse --ansi",
36+
"test": "vendor/bin/phpunit tests",
3637
"lint": "vendor/bin/duster lint",
3738
"fix": "vendor/bin/duster fix",
3839
"rector-dry-run": "vendor/bin/rector process --dry-run --ansi",

config/sets/laravel-collection.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
use Rector\Config\RectorConfig;
66
use RectorLaravel\Rector\BooleanNot\AvoidNegatedCollectionContainsOrDoesntContainRector;
77
use RectorLaravel\Rector\MethodCall\AvoidNegatedCollectionFilterOrRejectRector;
8+
use RectorLaravel\Rector\MethodCall\UnaliasCollectionMethodsRector;
89

910
return static function (RectorConfig $rectorConfig): void {
1011
$rectorConfig->import(__DIR__ . '/../config.php');
1112
$rectorConfig->rule(AvoidNegatedCollectionContainsOrDoesntContainRector::class);
1213
$rectorConfig->rule(AvoidNegatedCollectionFilterOrRejectRector::class);
14+
$rectorConfig->rule(UnaliasCollectionMethodsRector::class);
1315
};

docs/rector_rules_overview.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# 76 Rules Overview
1+
# 77 Rules Overview
22

33
## AbortIfRector
44

@@ -1445,6 +1445,24 @@ Automatically type hints your tappable closures
14451445

14461446
<br>
14471447

1448+
## UnaliasCollectionMethodsRector
1449+
1450+
Use the base collection methods instead of their aliases.
1451+
1452+
- class: [`RectorLaravel\Rector\MethodCall\UnaliasCollectionMethodsRector`](../src/Rector/MethodCall/UnaliasCollectionMethodsRector.php)
1453+
1454+
```diff
1455+
use Illuminate\Support\Collection;
1456+
1457+
$collection = new Collection([0, 1, null, -1]);
1458+
-$collection->average();
1459+
-$collection->some(fn (?int $number): bool => is_null($number));
1460+
+$collection->avg();
1461+
+$collection->contains(fn (?int $number): bool => is_null($number));
1462+
```
1463+
1464+
<br>
1465+
14481466
## UnifyModelDatesWithCastsRector
14491467

14501468
Unify Model `$dates` property with `$casts`
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace RectorLaravel\Rector\MethodCall;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr\MethodCall;
9+
use PhpParser\Node\Identifier;
10+
use PHPStan\Type\ObjectType;
11+
use RectorLaravel\AbstractRector;
12+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
13+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
14+
15+
/**
16+
* @see \RectorLaravel\Tests\Rector\MethodCall\UnaliasCollectionMethodsRector\UnaliasCollectionMethodsRectorTest
17+
*/
18+
final class UnaliasCollectionMethodsRector extends AbstractRector
19+
{
20+
public function getRuleDefinition(): RuleDefinition
21+
{
22+
return new RuleDefinition(
23+
'Use the base collection methods instead of their aliases.',
24+
[
25+
new CodeSample(
26+
<<<'CODE_SAMPLE'
27+
use Illuminate\Support\Collection;
28+
29+
$collection = new Collection([0, 1, null, -1]);
30+
$collection->average();
31+
$collection->some(fn (?int $number): bool => is_null($number));
32+
CODE_SAMPLE
33+
,
34+
<<<'CODE_SAMPLE'
35+
use Illuminate\Support\Collection;
36+
37+
$collection = new Collection([0, 1, null, -1]);
38+
$collection->avg();
39+
$collection->contains(fn (?int $number): bool => is_null($number));
40+
CODE_SAMPLE
41+
),
42+
]
43+
);
44+
}
45+
46+
/**
47+
* @return array<class-string<Node>>
48+
*/
49+
public function getNodeTypes(): array
50+
{
51+
return [MethodCall::class];
52+
}
53+
54+
/**
55+
* @param MethodCall $node
56+
*/
57+
public function refactor(Node $node): ?Node
58+
{
59+
return $this->updateMethodCall($node);
60+
}
61+
62+
private function updateMethodCall(MethodCall $methodCall): ?MethodCall
63+
{
64+
if (! $this->isObjectType($methodCall->var, new ObjectType('Illuminate\Support\Enumerable'))) {
65+
return null;
66+
}
67+
68+
$name = $methodCall->name;
69+
if ($this->isName($name, 'some')) {
70+
$replacement = 'contains';
71+
} elseif ($this->isName($name, 'average')) {
72+
$replacement = 'avg';
73+
} else {
74+
return null;
75+
}
76+
77+
$methodCall->name = new Identifier($replacement);
78+
79+
return $methodCall;
80+
}
81+
}

stubs/Illuminate/Support/Enumerable.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,32 @@
1818
*/
1919
interface Enumerable
2020
{
21+
/**
22+
* Alias for the "avg" method.
23+
*
24+
* @param (callable(TValue): float|int)|string|null $callback
25+
* @return float|int|null
26+
*/
27+
public function average($callback = null);
28+
29+
/**
30+
* Get the average value of a given key.
31+
*
32+
* @param (callable(TValue): float|int)|string|null $callback
33+
* @return float|int|null
34+
*/
35+
public function avg($callback = null);
36+
37+
/**
38+
* Alias for the "contains" method.
39+
*
40+
* @param (callable(TValue, TKey): bool)|TValue|string $key
41+
* @param mixed $operator
42+
* @param mixed $value
43+
* @return bool
44+
*/
45+
public function some($key, $operator = null, $value = null);
46+
2147
/**
2248
* Determine if an item exists in the enumerable.
2349
*

tests/Rector/MethodCall/AvoidNegatedCollectionFilterOrRejectRector/config/configured_rule.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,5 @@
77

88
return static function (RectorConfig $rectorConfig): void {
99
$rectorConfig->import(__DIR__ . '/../../../../../config/config.php');
10-
1110
$rectorConfig->rule(AvoidNegatedCollectionFilterOrRejectRector::class);
1211
};
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace RectorLaravel\Tests\Rector\MethodCall\UnaliasCollectionMethodsRector\Fixture;
4+
5+
use Illuminate\Support\Collection;
6+
7+
$collection = new Collection([0, 1, null, -1]);
8+
$collection->average();
9+
$collection->some(fn (?int $number): bool => is_null($number));
10+
11+
?>
12+
-----
13+
<?php
14+
15+
namespace RectorLaravel\Tests\Rector\MethodCall\UnaliasCollectionMethodsRector\Fixture;
16+
17+
use Illuminate\Support\Collection;
18+
19+
$collection = new Collection([0, 1, null, -1]);
20+
$collection->avg();
21+
$collection->contains(fn (?int $number): bool => is_null($number));
22+
23+
?>
Lines changed: 31 additions & 0 deletions
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\UnaliasCollectionMethodsRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class UnaliasCollectionMethodsRectorTest 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: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use RectorLaravel\Rector\MethodCall\UnaliasCollectionMethodsRector;
7+
8+
return static function (RectorConfig $rectorConfig): void {
9+
$rectorConfig->import(__DIR__ . '/../../../../../config/config.php');
10+
$rectorConfig->rule(UnaliasCollectionMethodsRector::class);
11+
};

0 commit comments

Comments
 (0)