Skip to content

Commit 6acbd59

Browse files
committed
Replace deprecated PropertyFetchToMethodCallRector with custom rule
PropertyFetchToMethodCallRector was deprecated in Rector 2.2.6 as it was considered too generic. This commit introduces a custom FakerPropertyToMethodCallRector that specifically handles the transformation of Faker\Generator property access to method calls. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
1 parent 93dd3ae commit 6acbd59

File tree

12 files changed

+1900
-26
lines changed

12 files changed

+1900
-26
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@
55
/vendor-bin/psalm/vendor/
66
/vendor-bin/rector/vendor/
77
/.php-cs-fixer.cache
8+
/.phpunit.cache/
89
/composer.lock
10+
/vendor-bin/rector/.phpunit.cache/

rector-migrate.php

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
declare(strict_types=1);
44

5-
use Faker\Generator;
6-
use Rector\Config;
7-
use Rector\Transform;
5+
require_once __DIR__ . '/rector/FakerPropertyToMethodCallRector.php';
6+
7+
use Faker\Rector\FakerPropertyToMethodCallRector;
8+
use Rector\Config\RectorConfig;
89

910
// This file configures rector/rector to replace all deprecated property usages with their equivalent functions.
10-
return static function (Config\RectorConfig $rectorConfig): void {
11+
return static function (RectorConfig $rectorConfig): void {
1112
$properties = [
1213
'address',
1314
'amPm',
@@ -149,13 +150,7 @@
149150
];
150151

151152
$rectorConfig->ruleWithConfiguration(
152-
Transform\Rector\Assign\PropertyFetchToMethodCallRector::class,
153-
array_map(static function (string $property): Transform\ValueObject\PropertyFetchToMethodCall {
154-
return new Transform\ValueObject\PropertyFetchToMethodCall(
155-
Generator::class,
156-
$property,
157-
$property,
158-
);
159-
}, $properties),
153+
FakerPropertyToMethodCallRector::class,
154+
$properties,
160155
);
161156
};
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 Faker\Rector;
6+
7+
use Faker\Generator;
8+
use PhpParser\Node;
9+
use PhpParser\Node\Expr\PropertyFetch;
10+
use PhpParser\Node\Identifier;
11+
use PHPStan\Type\ObjectType;
12+
use Rector\Contract\Rector\ConfigurableRectorInterface;
13+
use Rector\Rector\AbstractRector;
14+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
15+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
16+
17+
final class FakerPropertyToMethodCallRector extends AbstractRector implements ConfigurableRectorInterface
18+
{
19+
/**
20+
* @var list<string>
21+
*/
22+
private array $propertyNames = [];
23+
24+
/**
25+
* @param array<mixed> $configuration
26+
*/
27+
public function configure(array $configuration): void
28+
{
29+
$this->propertyNames = array_values(array_filter($configuration, 'is_string'));
30+
}
31+
32+
public function getRuleDefinition(): RuleDefinition
33+
{
34+
return new RuleDefinition(
35+
'Replaces deprecated Faker property access with method calls',
36+
[
37+
new ConfiguredCodeSample(
38+
<<<'CODE_SAMPLE'
39+
$faker->name;
40+
CODE_SAMPLE
41+
,
42+
<<<'CODE_SAMPLE'
43+
$faker->name();
44+
CODE_SAMPLE
45+
,
46+
['name', 'email', 'address'],
47+
),
48+
],
49+
);
50+
}
51+
52+
/**
53+
* @return array<class-string<Node>>
54+
*/
55+
public function getNodeTypes(): array
56+
{
57+
return [PropertyFetch::class];
58+
}
59+
60+
/**
61+
* @param PropertyFetch $node
62+
*/
63+
public function refactor(Node $node): ?Node
64+
{
65+
if (!$node->name instanceof Identifier) {
66+
return null;
67+
}
68+
69+
$propertyName = $node->name->toString();
70+
71+
if (!\in_array($propertyName, $this->propertyNames, true)) {
72+
return null;
73+
}
74+
75+
if (!$this->isObjectType($node->var, new ObjectType(Generator::class))) {
76+
return null;
77+
}
78+
79+
return $this->nodeFactory->createMethodCall($node->var, $propertyName);
80+
}
81+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Faker\Rector\Tests\FakerPropertyToMethodCallRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class FakerPropertyToMethodCallRectorTest extends AbstractRectorTestCase
12+
{
13+
#[DataProvider('provideData')]
14+
public function test(string $filePath): void
15+
{
16+
$this->doTestFile($filePath);
17+
}
18+
19+
public static function provideData(): Iterator
20+
{
21+
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
22+
}
23+
24+
public function provideConfigFilePath(): string
25+
{
26+
return __DIR__ . '/config/config.php';
27+
}
28+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
use Faker\Generator;
4+
5+
/** @var Generator $faker */
6+
$faker = new Generator();
7+
8+
$name = $faker->name;
9+
$email = $faker->email;
10+
$address = $faker->address;
11+
12+
?>
13+
-----
14+
<?php
15+
16+
use Faker\Generator;
17+
18+
/** @var Generator $faker */
19+
$faker = new Generator();
20+
21+
$name = $faker->name();
22+
$email = $faker->email();
23+
$address = $faker->address();
24+
25+
?>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
use Faker\Generator;
4+
5+
/** @var Generator $faker */
6+
$faker = new Generator();
7+
8+
// Already method calls - should not change
9+
$name = $faker->name();
10+
$email = $faker->email();
11+
$address = $faker->address();
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
class SomeOtherClass
4+
{
5+
public string $name;
6+
public string $email;
7+
}
8+
9+
$other = new SomeOtherClass();
10+
11+
// Should not change - not a Faker\Generator instance
12+
$name = $other->name;
13+
$email = $other->email;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
use Faker\Generator;
4+
5+
/** @var Generator $faker */
6+
$faker = new Generator();
7+
8+
// Should not change - 'firstName' is not in the configured list
9+
$firstName = $faker->firstName;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Faker\Rector\FakerPropertyToMethodCallRector;
6+
use Rector\Config\RectorConfig;
7+
8+
return RectorConfig::configure()
9+
->withRules([FakerPropertyToMethodCallRector::class])
10+
->withConfiguredRule(FakerPropertyToMethodCallRector::class, [
11+
'name',
12+
'email',
13+
'address',
14+
]);

vendor-bin/rector/composer.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,19 @@
33
"php": "^8.1",
44
"rector/rector": "^2.2.6"
55
},
6+
"require-dev": {
7+
"phpunit/phpunit": "^10.5 || ^11.0"
8+
},
9+
"autoload": {
10+
"psr-4": {
11+
"Faker\\Rector\\": "../../rector/"
12+
}
13+
},
14+
"autoload-dev": {
15+
"psr-4": {
16+
"Faker\\Rector\\Tests\\": "../../rector/tests/"
17+
}
18+
},
619
"config": {
720
"platform": {
821
"php": "8.1.12"

0 commit comments

Comments
 (0)