8000 [Symfony 2.5] Add AddViolationToBuildViolationRector (#211) · rectorphp/rector-symfony@8e81496 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8e81496

Browse files
[Symfony 2.5] Add Add 8000 ViolationToBuildViolationRector (#211)
Co-authored-by: GitHub Action <action@github.com>
1 parent 6867598 commit 8e81496

17 files changed

+425
-2
lines changed
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\Set\SymfonySetList;
7+
8+
return static function (RectorConfig $rectorConfig): void {
9+
$rectorConfig->sets([SymfonySetList::SYMFONY_25]);
10+
};

config/sets/symfony/level/up-to-symfony-26.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
declare(strict_types=1);
44

55
use Rector\Config\RectorConfig;
6+
use Rector\Symfony\Set\SymfonyLevelSetList;
67
use Rector\Symfony\Set\SymfonySetList;
78

89
return static function (RectorConfig $rectorConfig): void {
9-
$rectorConfig->sets([SymfonySetList::SYMFONY_26]);
10+
$rectorConfig->sets([SymfonySetList::SYMFONY_26, SymfonyLevelSetList::UP_TO_SYMFONY_25]);
1011
};

config/sets/symfony/symfony25.php

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\Rector\MethodCall\AddViolationToBuildViolationRector;
7+
8+
return static function (RectorConfig $rectorConfig): void {
9+
$rectorConfig->rule(AddViolationToBuildViolationRector::class);
10+
};

docs/rector_rules_overview.md

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

33
## ActionSuffixRemoverRector
44

@@ -66,6 +66,24 @@ Collect routes from Symfony project router and add Route annotation to controlle
6666

6767
<br>
6868

69+
## AddViolationToBuildViolationRector
70+
71+
Change `$context->addViolationAt` to `$context->buildViolation` on Validator ExecutionContext
72+
73+
- class: [`Rector\Symfony\Rector\MethodCall\AddViolationToBuildViolationRector`](../src/Rector/MethodCall/AddViolationToBuildViolationRector.php)
74+
75+
```diff
76+
-$context->addViolationAt('property', 'The value {{ value }} is invalid.', array(
77+
- '{{ value }}' => $invalidValue,
78+
-));
79+
+$context->buildViolation('The value {{ value }} is invalid.')
80+
+ ->atPath('property')
81+
+ ->setParameter('{{ value }}', $invalidValue)
82+
+ ->addViolation();
83+
```
84+
85+
<br>
86+
6987
## AuthorizationCheckerIsGrantedExtractorRector
7088

7189
Change `$this->authorizationChecker->isGranted([$a, $b])` to `$this->authorizationChecker->isGranted($a) || $this->authorizationChecker->isGranted($b)`
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Symfony\Rector\MethodCall;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Arg;
9+
use PhpParser\Node\Expr;
10+
use PhpParser\Node\Expr\Array_;
11+
use PhpParser\Node\Expr\ArrayItem;
12+
use PhpParser\Node\Expr\MethodCall;
13+
use PhpParser\Node\Identifier;
14+
use PHPStan\Type\ObjectType;
15+
use Rector\Core\Rector\AbstractRector;
16+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
17+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
18+
19+
/**
20+
* @see https://stackoverflow.com/questions/25264922/symfony-2-5-addviolationat-deprecated-use-buildviolation
21+
* @see \Rector\Symfony\Tests\Rector\MethodCall\AddViolationToBuildViolationRector\AddViolationToBuildViolationRectorTest
22+
*/
23+
final class AddViolationToBuildViolationRector extends AbstractRector
24+
{
25+
public function getRuleDefinition(): RuleDefinition
26+
{
27+
return new RuleDefinition(
28+
'Change `$context->addViolationAt` to `$context->buildViolation` on Validator ExecutionContext',
29+
[
30+
new CodeSample(
31+
<<<'CODE_SAMPLE'
32+
$context->addViolationAt('property', 'The value {{ value }} is invalid.', array(
33+
'{{ value }}' => $invalidValue,
34+
));
35+
CODE_SAMPLE
36+
,
37+
<<<'CODE_SAMPLE'
38+
$context->buildViolation('The value {{ value }} is invalid.')
39+
->atPath('property')
40+
->setParameter('{{ value }}', $invalidValue)
41+
->addViolation();
42+
CODE_SAMPLE
43+
),
44+
]
45+
);
46+
}
47+
48+
/**
49+
* @return array<class-string<Node>>
50+
*/
51+
public function getNodeTypes(): array
52+
{
53+
return [MethodCall::class];
54+
}
55+
56+
/**
57+
* @param MethodCall $node
58+
*/
59+
public function refactor(Node $node): ?MethodCall
60+
{
61+
$objectType = $this->nodeTypeResolver->getType($node->var);
62+
if (! $objectType instanceof ObjectType) {
63+
return null;
64+
}
65+
66+
$executionContext = new ObjectType('Symfony\Component\Validator\Context\ExecutionContextInterface');
67+
if (! $executionContext->isSuperTypeOf($objectType)->yes()) {
68+
return null;
69+
}
70+
71+
if (! $this->nodeNameResolver->isName($node->name, 'addViolationAt')) {
72+
return null;
73+
}
74+
75+
$args = $node->getArgs();
76+
$path = $args[0];
77+
$message = $args[1];
78+
79+
$node->name = new Identifier('buildViolation');
80+
$node->args = [$message];
81+
$node = new MethodCall($node, 'atPath', [$path]);
82+
$node = $this->buildFluentWithParameters($node, $args);
83+
$node = $this->buildFluentWithInvalidValue($node, $args);
84+
$node = $this->buildFluentWithPlural($node, $args);
85+
$node = $this->buildFluentWithCode($node, $args);
86+
87+
$node = new MethodCall($node, 'addViolation');
88+
return $node;
89+
}
90+
91+
/**
92+
* @param Arg[] $args
93+
*/
94+
private function buildFluentWithParameters(MethodCall $methodCall, array $args): MethodCall
95+
{
96+
if (isset($args[2]) && $args[2]->value instanceof Array_) {
97+
foreach ($args[2]->value->items as $item) {
98+
if ($item instanceof ArrayItem && $item->key instanceof Expr) {
99+
$methodCall = new MethodCall($methodCall, 'setParameter', [
100+
new Arg($item->key),
101+
new Arg($item->value),
102+
]);
103+
}
104+
}
105+
}
106+
107+
return $methodCall;
108+
}
109+
110+
/**
111+
* @param Arg[] $args
112+
*/
113+
private function buildFluentWithInvalidValue(MethodCall $methodCall, array $args): MethodCall
114+
{
115+
if (isset($args[3])) {
116+
$methodCall = new MethodCall($methodCall, 'setInvalidValue', [new Arg($args[3]->value)]);
117+
}
118+
119+
return $methodCall;
120+
}
121+
122+
/**
123+
* @param Arg[] $args
124+
*/
125+
private function buildFluentWithPlural(MethodCall $methodCall, array $args): MethodCall
126+
{
127+
if (isset($args[4])) {
128+
$methodCall = new MethodCall($methodCall, 'setPlural', [new Arg($args[4]->value)]);
129+
}
130+
131+
return $methodCall;
132+
}
133+
134+
/**
135+
* @param Arg[] $args
136+
*/
137+
private function buildFluentWithCode(MethodCall $methodCall, array $args): MethodCall
138+
{
139+
if (isset($args[5])) {
140+
$methodCall = new MethodCall($methodCall, 'setCode', [new Arg($args[5]->value)]);
141+
}
142+
143+
return $methodCall;
144+
}
145+
}

src/Set/SymfonyLevelSetList.php

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

99
final class SymfonyLevelSetList implements SetListInterface
1010
{
11+
/**
12+
* @var string
13+
*/
14+
final public const UP_TO_SYMFONY_25 = __DIR__ . '/../../config/sets/symfony/level/up-to-symfony-25.php';
15+
1116
/**
1217
* @var string
1318
*/

src/Set/SymfonySetList.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ final class SymfonySetList implements SetListInterface
1313
*/
1414
final public const SYMFONY_STRICT = __DIR__ . '/../../config/sets/symfony/symfony-strict.php';
1515

16+
/**
17+
* @var string
18+
*/
19+
final public const SYMFONY_25 = __DIR__ . '/../../config/sets/symfony/symfony25.php';
20+
1621
/**
1722
* @var string
1823
*/
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Symfony\Component\Validator;
6+
7+
if (class_exists('Symfony\Component\Validator\ConstraintValidator')) {
8+
return;
9+
}
10+
11+
abstract class ConstraintValidator
12+
{
13+
/**
14+
* @var Context\ExecutionContextInterface
15+
*/
16+
protected $context;
17+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Symfony\Component\Validator\Context;
6+
7+
if (interface_exists('Symfony\Component\Validator\Context\ExecutionContextInterface')) {
8+
return;
9+
}
10+
11+
interface ExecutionContextInterface
12+
{
13+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Symfony\Tests\Rector\MethodCall\AddViolationToBuildViolationRector;
6+
7+
use Iterator;
8+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
9+
use Symplify\SmartFileSystem\SmartFileInfo;
10+
11+
final class AddViolationToBuildViolationRectorTest extends AbstractRectorTestCase
12+
{
13+
/**
14+
* @dataProvider provideData()
15+
*/
16+
public function test(SmartFileInfo $fileInfo): void
17+
{
18+
$this->doTestFileInfo($fileInfo);
19+
}
20+
21+
/**
22+
* @return Iterator<SmartFileInfo>
23+
*/
24+
public function provideData(): Iterator
25+
{
26+
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
27+
}
28+
29+
public function provideConfigFilePath(): string
30+
{
31+
return __DIR__ . '/config/configured_rule.php';
32+
}
33+
}

0 commit comments

Comments
 (0)
0