10BC0 [CommandConstantReturnCodeRector] Add CommandConstantReturnCodeRector… · rectorphp/rector-symfony@5f0c972 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5f0c972

Browse files
authored
[CommandConstantReturnCodeRector] Add CommandConstantReturnCodeRector (#255) (#256)
Co-authored-by: johan <johan@adivare.nl>
1 parent d7a2d62 commit 5f0c972

File tree

11 files changed

+325
-0
lines changed

11 files changed

+325
-0
lines changed

config/sets/symfony/symfony51.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Rector\Renaming\ValueObject\RenameClassAndConstFetch;
1616
use Rector\Symfony\Rector\Class_\LogoutHandlerToLogoutEventSubscriberRector;
1717
use Rector\Symfony\Rector\Class_\LogoutSuccessHandlerToLogoutEventSubscriberRector;
18+
use Rector\Symfony\Rector\ClassMethod\CommandConstantReturnCodeRector;
1819
use Rector\Symfony\Rector\ClassMethod\RouteCollectionBuilderToRoutingConfiguratorRector;
1920
use Rector\Transform\Rector\New_\NewArgToMethodCallRector;
2021
use Rector\Transform\Rector\StaticCall\StaticCallToNewRector;
@@ -55,6 +56,9 @@
5556
'Symfony\Component\DependencyInjection\Loader\Configuraton\ref' => 'Symfony\Component\DependencyInjection\Loader\Configuraton\service',
5657
]);
5758

59+
// see https://symfony.com/blog/new-in-symfony-5-1-misc-improvements-part-1#added-constants-for-command-exit-codes
60+
$rectorConfig->rule(CommandConstantReturnCodeRector::class);
61+
5862
// https://github.com/symfony/symfony/pull/35308
5963
$rectorConfig->ruleWithConfiguration(
6064
NewArgToMethodCallRector::class,

docs/rector_rules_overview.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,28 @@ Change type in CollectionType from alias string to class reference
251251

252252
<br>
253253

254+
## CommandConstantReturnCodeRector
255+
256+
Changes int return from execute to use Symfony Command constants.
257+
258+
-
259+
class: [`Rector\Symfony\Rector\ClassMethod\CommandConstantReturnCodeRector`](../src/Rector/ClassMethod/CommandConstantReturnCodeRector.php)
260+
261+
```diff
262+
use Symfony\Component\Console\Command\Command;
263+
264+
class SomeCommand extends Command
265+
{
266+
protected function execute(InputInterface $input, OutputInterface $output): int
267+
{
268+
- return 0;
269+
+ return Command::SUCCESS;
270+
}
271+
}
272+
```
273+
274+
<br>
275+
254276
## CommandDescriptionToPropertyRector
255277

256278
Moves Command description setter to defaultDescription property
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Symfony\Rector\ClassMethod;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr\ClassConstFetch;
9+
use PhpParser\Node\Scalar\LNumber;
10+
use PhpParser\Node\Stmt\ClassMethod;
11+
use PhpParser\Node\Stmt\Return_;
12+
use PHPStan\Reflection\ClassReflection;
13+
use Rector\Core\Rector\AbstractRector;
14+
use Rector\Core\Reflection\ReflectionResolver;
15+
use Rector\Symfony\ValueObject\ConstantMap\SymfonyCommandConstantMap;
16+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
17+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
18+
19+
/**
20+
* https://symfony.com/blog/new-in-symfony-5-1-misc-improvements-part-1#added-constants-for-command-exit-codes
21+
*
22+
* @see \Rector\Symfony\Tests\Rector\ClassMethod\CommandConstantReturnCodeRector\CommandConstantReturnCodeRectorTest
23+
*/
24+
final class CommandConstantReturnCodeRector extends AbstractRector
25+
{
26+
public function __construct(
27+
private readonly ReflectionResolver $reflectionResolver,
28+
) {
29+
}
30+
31+
public function getRuleDefinition(): RuleDefinition
32+
{
33+
return new RuleDefinition(
34+
'Changes int return from execute to use Symfony Command constants.',
35+
[
36+
new CodeSample(
37+
<<<'CODE_SAMPLE'
38+
class SomeCommand extends Command
39+
{
40+
protected function execute(InputInterface $input, OutputInterface $output): int
41+
{
42+
return 0;
43+
}
44+
45+
}
46+
CODE_SAMPLE
47+
,
48+
<<<'CODE_SAMPLE'
49+
class SomeCommand extends Command
50+
{
51+
protected function execute(InputInterface $input, OutputInterface $output): int
52+
{
53+
return Command::SUCCESS;
54+
}
55+
56+
}
57+
CODE_SAMPLE
58+
),
59+
]
60+
);
61+
}
62+
63+
/**
64+
* @return array<class-string<Node>>
65+
*/
66+
public function getNodeTypes(): array
67+
{
68+
return [ClassMethod::class];
69+
}
70+
71+
/**
72+
* @param ClassMethod $node
73+
*/
74+
public function refactor(Node $node): ?Node
75+
{
76+
$classReflection = $this->reflectionResolver->resolveClassReflection($node);
77+
if (! $classReflection instanceof ClassReflection) {
78+
return null;
79+
}
80+
81+
if (! $classReflection->isSubclassOf('Symfony\Component\Console\Command\Command')) {
82+
return null;
83+
}
84+
85+
if (! $this->nodeNameResolver->isName($node, 'execute')) {
86+
return null;
87+
}
88+
89+
foreach ($this->betterNodeFinder->findInstancesOfInFunctionLikeScoped($node, [Return_::class]) as $returnNode) {
90+
if (! $returnNode->expr instanceof LNumber) {
91+
continue;
92+
}
93+
$returnNode->expr = $this->convertNumberToConstant($returnNode->expr);
94+
}
95+
96+
return $node;
97+
}
98+
99+
private function convertNumberToConstant(LNumber $lNumber): ClassConstFetch|LNumber
100+
{
101+
if (! isset(SymfonyCommandConstantMap::RETURN_TO_CONST[$lNumber->value])) {
102+
return $lNumber;
103+
}
104+
105+
return $this->nodeFactory->createShortClassConstFetch(
106+
'Command',
107+
SymfonyCommandConstantMap::RETURN_TO_CONST[$lNumber->value]
108+
);
109+
}
110+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Symfony\ValueObject\ConstantMap;
6+
7+
final class SymfonyCommandConstantMap
8+
{
9+
/**
10+
* @see https://github.com/symfony/symfony/blob/8e8207bb72d7f2cb8be355994ad2fcfa97c00f74/src/Symfony/Component/Console/Command/Command.php#L36-L38
11+
*
12+
* @var array<int, string>
13+
*/
14+
public const RETURN_TO_CONST = [
15+
0 => 'SUCCESS',
16+
1 => 'FAILURE',
17+
2 => 'INVALID',
18+
];
19+
}

src/ValueObject/ConstantMap/SymfonyResponseConstantMap.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
final class SymfonyResponseConstantMap
88
{
99
/**
10+
* @see https://github.com/symfony/symfony/blob/8e8207bb72d7f2cb8be355994ad2fcfa97c00f74/src/Symfony/Component/HttpFoundation/Response.php#L24-L86
11+
*
1012
* @var array<int, string>
1113
*/
1214
public const CODE_TO_CONST = [
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Symfony\Tests\Rector\ClassMethod\CommandConstantReturnCodeRector;
6+
7+
use Iterator;
8+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
9+
10+
final class CommandConstantReturnCodeRectorTest extends AbstractRectorTestCase
11+
{
12+
/**
13+
* @dataProvider provideData()
14+
*/
15+
public function test(string $filePath): void
16+
{
17+
$this->doTestFile($filePath);
18+
}
19+
20+
public function provideData(): Iterator
21+
{
22+
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
23+
}
24+
25+
public function provideConfigFilePath(): string
26+
{
27+
return __DIR__ . '/config/configured_rule.php';
28+
}
29+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Rector\Symfony\Tests\Rector\ClassMethod\CommandConstantReturnCodeRector\Fixture;
4+
5+
use Symfony\Component\Console\Command\Command;
6+
use Symfony\Component\Console\Input\InputInterface;
7+
use Symfony\Component\Console\Output\OutputInterface;
8+
9+
class ReplaceFail extends Command
10+
{
11+
protected function execute(InputInterface $input, OutputInterface $output): int
12+
{
13+
return 1;
14+
}
15+
16+
}
17+
18+
?>
19+
-----
20+
<?php
21+
22+
namespace Rector\Symfony\Tests\Rector\ClassMethod\CommandConstantReturnCodeRector\Fixture;
23+
24+
use Symfony\Component\Console\Command\Command;
25+
use Symfony\Component\Console\Input\InputInterface;
26+
use Symfony\Component\Console\Output\OutputInterface;
27+
28+
class ReplaceFail extends Command
29+
{
30+
protected function execute(InputInterface $input, OutputInterface $output): int
31+
{
32+
return Command::FAILURE;
33+
}
34+
35+
}
36+
37+
?>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Rector\Symfony\Tests\Rector\ClassMethod\CommandConstantReturnCodeRector\Fixture;
4+
5+
use Symfony\Component\Console\Command\Command;
6+
use Symfony\Component\Console\Input\InputInterface;
7+
use Symfony\Component\Console\Output\OutputInterface;
8+
9+
class ReplaceInvalid extends Command
10+
{
11+
protected function execute(InputInterface $input, OutputInterface $output): int
12+
{
13+
return 2;
14+
}
15+
16+
}
17+
18+
?>
19+
-----
20+
<?php
21+
22+
namespace Rector\Symfony\Tests\Rector\ClassMethod\CommandConstantReturnCodeRector\Fixture;
23+
24+
use Symfony\Component\Console\Command\Command;
25+
use Symfony\Component\Console\Input\InputInterface;
26+
use Symfony\Component\Console\Output\OutputInterface;
27+
28+
class ReplaceInvalid extends Command
29+
{
30+
protected function execute(InputInterface $input, OutputInterface $output): int
31+
{
32+
return Command::INVALID;
33+
}
34+
35+
}
36+
37+
?>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Rector\Symfony\Tests\Rector\ClassMethod\CommandConstantReturnCodeRector\Fixture;
4+
5+
use Symfony\Component\Console\Command\Command;
6+
use Symfony\Component\Console\Input\InputInterface;
7+
use Symfony\Component\Console\Output\OutputInterface;
8+
9+
class ReplaceWithConstant extends Command
10+
{
11+
protected function execute(InputInterface $input, OutputInterface $output): int
12+
{
13+
return 0;
14+
}
15+
16+
}
17+
18+
?>
19+
-----
20+
<?php
21+
22+
namespace Rector\Symfony\Tests\Rector\ClassMethod\CommandConstantReturnCodeRector\Fixture;
23+
24+
use Symfony\Component\Console\Command\Command;
25+
use Symfony\Component\Console\Input\InputInterface;
26+
use Symfony\Component\Console\Output\OutputInterface;
27+
28+
class ReplaceWithConstant extends Command
29+
{
30+
protected function execute(InputInterface $input, OutputInterface $output): int
31+
{
32+
return Command::SUCCESS;
33+
}
34+
35+
}
36+
37+
?>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace Rector\Symfony\Tests\Rector\ClassMethod\CommandConstantReturnCodeRector\Fixture;
4+
5+
use Symfony\Component\Console\Command\Command;
6+
use Symfony\Component\Console\Input\InputInterface;
7+
use Symfony\Component\Console\Output\OutputInterface;
8+
9+
class SkipAlreadyUsingConstant extends Command
10+
{
11+
protected function execute(InputInterface $input, OutputInterface $output): int
12+
{
13+
return Command::SUCCESS;
14+
}
15+
}
16+
17+
?>

0 commit comments

Comments
 (0)
0