Skip to content

Commit 39316cc

Browse files
authored
AddVoteArgumentToVoteOnAttributeRector (#804)
* AddVoteArgumentToVoteOnAttributeRector * Add rector to sets
1 parent 158a72e commit 39316cc

File tree

8 files changed

+249
-0
lines changed

8 files changed

+249
-0
lines changed

config/sets/symfony/symfony7/symfony73.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@
88

99
return static function (RectorConfig $rectorConfig): void {
1010
$rectorConfig->import(__DIR__ . '/symfony73/symfony73-console.php');
11+
$rectorConfig->import(__DIR__ . '/symfony73/symfony73-security-core.php');
1112
$rectorConfig->import(__DIR__ . '/symfony73/symfony73-twig-bundle.php');
1213
};
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use Rector\Symfony\Symfony73\Rector\Class_\AddVoteArgumentToVoteOnAttributeRector;
7+
8+
return static function (RectorConfig $rectorConfig): void {
9+
$rectorConfig->rules([AddVoteArgumentToVoteOnAttributeRector::class]);
10+
};
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 Rector\Symfony\Tests\Symfony73\Rector\Class_\AddVoteArgumentToVoteOnAttributeRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class AddVoteArgumentToVoteOnAttributeRectorTest 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/configured_rule.php';
27+
}
28+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace Rector\Symfony\Tests\Symfony73\Rector\Class_\AddVoteArgumentToVoteOnAttributeRector\Fixture;
4+
5+
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
6+
7+
final class MyVoter implements VoterInterface
8+
{
9+
public function vote(TokenInterface $token, mixed $subject, array $attributes): int
10+
{
11+
return 1;
12+
}
13+
}
14+
15+
?>
16+
-----
17+
<?php
18+
19+
namespace Rector\Symfony\Tests\Symfony73\Rector\Class_\AddVoteArgumentToVoteOnAttributeRector\Fixture;
20+
21+
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
22+
23+
final class MyVoter implements VoterInterface
24+
{
25+
public function vote(TokenInterface $token, mixed $subject, array $attributes, ?\Symfony\Component\Security\Core\Authorization\Voter\Vote $vote = null): int
26+
{
27+
return 1;
28+
}
29+
}
30+
31+
?>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
namespace Rector\Symfony\Tests\Symfony73\Rector\Class_\AddVoteArgumentToVoteOnAttributeRector\Fixture;
4+
5+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
6+
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
7+
8+
final class MyVoter extends Voter
9+
{
10+
protected function supports(string $attribute, mixed $subject): bool
11+
{
12+
return true;
13+
}
14+
15+
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
16+
{
17+
return true;
18+
}
19+
}
20+
21+
?>
22+
-----
23+
<?php
24+
25+
namespace Rector\Symfony\Tests\Symfony73\Rector\Class_\AddVoteArgumentToVoteOnAttributeRector\Fixture;
26+
27+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
28+
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
29+
30+
final class MyVoter extends Voter
31+
{
32+
protected function supports(string $attribute, mixed $subject): bool
33+
{
34+
return true;
35+
}
36+
37+
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token, ?\Symfony\Component\Security\Core\Authorization\Voter\Vote $vote = null): bool
38+
{
39+
return true;
40+
}
41+
}
42+
43+
?>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use Rector\Symfony\Symfony73\Rector\Class_\AddVoteArgumentToVoteOnAttributeRector;
7+
8+
return static function (RectorConfig $rectorConfig): void {
9+
$rectorConfig->rule(AddVoteArgumentToVoteOnAttributeRector::class);
10+
};
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Symfony\Symfony73\Rector\Class_;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr\ConstFetch;
9+
use PhpParser\Node\Expr\Variable;
10+
use PhpParser\Node\Name;
11+
use PhpParser\Node\Name\FullyQualified;
12+
use PhpParser\Node\Param;
13+
use PhpParser\Node\Stmt\Class_;
14+
use Rector\Rector\AbstractRector;
15+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
16+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
17+
18+
/**
19+
* @see \Rector\Symfony\Tests\Symfony73\Rector\Class_\AddVoteArgumentToVoteOnAttributeRector\AddVoteArgumentToVoteOnAttributeRectorTest
20+
*/
21+
final class AddVoteArgumentToVoteOnAttributeRector extends AbstractRector
22+
{
23+
private const VOTE_INTERFACE = 'Symfony\Component\Security\Core\Authorization\Voter\VoterInterface';
24+
25+
private const VOTER_CLASS = 'Symfony\Component\Security\Core\Authorization\Voter\Voter';
26+
27+
private const VOTE_CLASS = 'Symfony\Component\Security\Core\Authorization\Voter\Vote';
28+
29+
public function getRuleDefinition(): RuleDefinition
30+
{
31+
return new RuleDefinition(
32+
'Adds a new `$voter` argument in protected function `voteOnAttribute(string $attribute, $subject, TokenInterface $token, ?Vote $vote = null): bool`',
33+
[
34+
new CodeSample(
35+
<<<'CODE_SAMPLE'
36+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
37+
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
38+
39+
final class MyVoter extends Voter
40+
{
41+
protected function supports(string $attribute, mixed $subject): bool
42+
{
43+
return true;
44+
}
45+
46+
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
47+
{
48+
return true;
49+
}
50+
}
51+
CODE_SAMPLE
52+
,
53+
<<<'CODE_SAMPLE'
54+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
55+
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
56+
57+
final class MyVoter extends Voter
58+
{
59+
protected function supports(string $attribute, mixed $subject): bool
60+
{
61+
return true;
62+
}
63+
64+
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token, ?\Symfony\Component\Security\Core\Authorization\Voter\Vote $vote = null): bool
65+
{
66+
return true;
67+
}
68+
}
69+
CODE_SAMPLE
70+
,
71+
),
72+
],
73+
);
74+
}
75+
76+
/**
77+
* @return array<class-string<Node>>
78+
*/
79+
public function getNodeTypes(): array
80+
{
81+
return [Class_::class];
82+
}
83+
84+
/**
85+
* @param Class_ $node
86+
*/
87+
public function refactor(Node $node): ?Node
88+
{
89+
$classMethod = null;
90+
91+
if ($node->extends !== null && $this->isName($node->extends, self::VOTER_CLASS)) {
92+
$classMethod = $node->getMethod('voteOnAttribute');
93+
}
94+
95+
if ($classMethod === null) {
96+
foreach ($node->implements as $implement) {
97+
if ($this->isName($implement, self::VOTE_INTERFACE)) {
98+
$classMethod = $node->getMethod('vote');
99+
break;
100+
}
101+
}
102+
}
103+
104+
if ($classMethod === null) {
105+
return null;
106+
}
107+
108+
if (count($classMethod->params) !== 3) {
109+
return null;
110+
}
111+
112+
$classMethod->params[] = new Param(
113+
new Variable('vote'),
114+
new ConstFetch(new Name('null')),
115+
new Node\NullableType(new FullyQualified(self::VOTE_CLASS))
116+
);
117+
118+
return $node;
119+
}
120+
}

src/Set/SetProvider/Symfony7SetProvider.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ public function provide(): array
9292
'7.3',
9393
__DIR__ . '/../../../config/sets/symfony/symfony7/symfony73/symfony73-console.php'
9494
),
95+
new ComposerTriggeredSet(
96+
SetGroup::SYMFONY,
97+
'symfony/security-core',
98+
'7.3',
99+
__DIR__ . '/../../../config/sets/symfony/symfony7/symfony73/symfony73-security-core.php'
100+
),
95101
new ComposerTriggeredSet(
96102
SetGroup::SYMFONY,
97103
'symfony/twig-bundle',

0 commit comments

Comments
 (0)