Skip to content

Commit eaa09ba

Browse files
authored
[console] [7.3] Add support for default values in InvokableCommandInputAttributeRector (#841)
* add default value fixture * add full fixture, avoid passign null or string as default values * add support for default values in InvokableCommandInputAttributeRector
1 parent 635b415 commit eaa09ba

File tree

6 files changed

+112
-12
lines changed

6 files changed

+112
-12
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
namespace Rector\Symfony\Tests\Symfony73\Rector\Class_\InvokableCommandInputAttributeRector\Fixture;
4+
5+
use Symfony\Component\Console\Attribute\AsCommand;
6+
use Symfony\Component\Console\Command\Command;
7+
use Symfony\Component\Console\Input\InputArgument;
8+
use Symfony\Component\Console\Input\InputInterface;
9+
use Symfony\Component\Console\Output\OutputInterface;
10+
11+
#[AsCommand(
12+
name: 'app:hello',
13+
)]
14+
class ArgumentWithDefaultValue extends Command
15+
{
16+
protected function configure(): void
17+
{
18+
$this->addArgument('first', InputArgument::OPTIONAL, null, 'optional value');
19+
$this->addArgument('second', InputArgument::REQUIRED, null, 'required value');
20+
$this->addOption('third', null, null, '', 'third value');
21+
}
22+
protected function execute(InputInterface $input, OutputInterface $output): int
23+
{
24+
}
25+
}
26+
27+
?>
28+
-----
29+
<?php
30+
31+
namespace Rector\Symfony\Tests\Symfony73\Rector\Class_\InvokableCommandInputAttributeRector\Fixture;
32+
33+
use Symfony\Component\Console\Attribute\AsCommand;
34+
use Symfony\Component\Console\Command\Command;
35+
use Symfony\Component\Console\Input\InputArgument;
36+
use Symfony\Component\Console\Input\InputInterface;
37+
use Symfony\Component\Console\Output\OutputInterface;
38+
39+
#[AsCommand(
40+
name: 'app:hello',
41+
)]
42+
class ArgumentWithDefaultValue
43+
{
44+
public function __invoke(
45+
#[\Symfony\Component\Console\Attribute\Argument(name: 'first')]
46+
?string $first = 'optional value',
47+
#[\Symfony\Component\Console\Attribute\Argument(name: 'second')]
48+
string $second = 'required value',
49+
#[\Symfony\Component\Console\Attribute\Option(name: 'third')]
50+
$third = 'third value'
51+
): int
52+
{
53+
}
54+
}
55+
56+
?>

rules/Symfony73/NodeAnalyzer/CommandArgumentsResolver.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public function resolve(ClassMethod $configureClassMethod): array
3535
$addArgumentArgs[0]->value,
3636
$addArgumentArgs[1]->value ?? null,
3737
$addArgumentArgs[2]->value ?? null,
38+
$addArgumentArgs[3]->value ?? null,
3839
);
3940
}
4041

rules/Symfony73/NodeAnalyzer/CommandOptionsResolver.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ public function resolve(ClassMethod $configureClassMethod): array
3636
$addOptionArgs[0]->value,
3737
$addOptionArgs[1]->value ?? null,
3838
$addOptionArgs[2]->value ?? null,
39-
$addOptionArgs[3]->value ?? null
39+
$addOptionArgs[3]->value ?? null,
40+
$addOptionArgs[4]->value ?? null
4041
);
4142
}
4243

rules/Symfony73/NodeFactory/CommandInvokeParamsFactory.php

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,22 +49,21 @@ private function createArgumentParams(array $commandArguments): array
4949
foreach ($commandArguments as $commandArgument) {
5050
$variableName = $this->createCamelCase($commandArgument->getNameValue());
5151
$argumentParam = new Param(new Variable($variableName));
52-
5352
$argumentParam->type = new Identifier('string');
5453

55-
// is argument optional?
56-
if ($commandArgument->getMode() === null) {
57-
$argumentParam->type = new NullableType($argumentParam->type);
58-
} elseif ($this->valueResolver->isValue($commandArgument->getMode(), 2)) {
54+
if ($commandArgument->getDefault() instanceof Expr) {
55+
$argumentParam->default = $commandArgument->getDefault();
56+
}
57+
58+
if ($this->isOptionalArgument($commandArgument)) {
5959
$argumentParam->type = new NullableType($argumentParam->type);
6060
}
6161

62-
// @todo fill type or default value
6362
// @todo default string, multiple values array
6463

6564
$argumentArgs = [new Arg(value: $commandArgument->getName(), name: new Identifier('name'))];
6665

67-
if ($commandArgument->getDescription() instanceof Expr) {
66+
if ($this->hasUsefulDescription($commandArgument)) {
6867
$argumentArgs[] = new Arg(value: $commandArgument->getDescription(), name: new Identifier(
6968
'description'
7069
));
@@ -92,17 +91,25 @@ private function createOptionParams(array $commandOptions): array
9291
$variableName = $this->createCamelCase($commandOption->getNameValue());
9392
$optionParam = new Param(new Variable($variableName));
9493

94+
if ($commandOption->getDefault() instanceof Expr) {
95+
$optionParam->default = $commandOption->getDefault();
96+
}
97+
9598
$optionArgs = [new Arg(value: $commandOption->getName(), name: new Identifier('name'))];
9699

97-
if ($commandOption->getShortcut() instanceof Expr) {
100+
if ($commandOption->getShortcut() instanceof Expr && ! $this->valueResolver->isNull(
101+
$commandOption->getShortcut()
102+
)) {
98103
$optionArgs[] = new Arg(value: $commandOption->getShortcut(), name: new Identifier('shortcut'));
99104
}
100105

101-
if ($commandOption->getMode() instanceof Expr) {
106+
if ($commandOption->getMode() instanceof Expr && ! $this->valueResolver->isNull(
107+
$commandOption->getMode()
108+
)) {
102109
$optionArgs[] = new Arg(value: $commandOption->getMode(), name: new Identifier('mode'));
103110
}
104111

105-
if ($commandOption->getDescription() instanceof Expr) {
112+
if ($this->hasUsefulDescription($commandOption)) {
106113
$optionArgs[] = new Arg(value: $commandOption->getDescription(), name: new Identifier('description'));
107114
}
108115

@@ -127,4 +134,27 @@ private function createCamelCase(string $value): string
127134
// Lowercase first character to make it camelCase
128135
return lcfirst($value);
129136
}
137+
138+
private function hasUsefulDescription(CommandArgument|CommandOption $commandArgumentOrOption): bool
139+
{
140+
if (! $commandArgumentOrOption->getDescription() instanceof Expr) {
141+
return false;
142+
}
143+
144+
$expr = $commandArgumentOrOption->getDescription();
145+
if ($this->valueResolver->isNull($expr)) {
146+
return false;
147+
}
148+
149+
return ! $this->valueResolver->isValue($expr, '');
150+
}
151+
152+
private function isOptionalArgument(CommandArgument $commandArgument): bool
153+
{
154+
if (! $commandArgument->getMode() instanceof Expr) {
155+
return true;
156+
}
157+
158+
return $this->valueResolver->isValue($commandArgument->getMode(), 2);
159+
}
130160
}

rules/Symfony73/ValueObject/CommandArgument.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ public function __construct(
1212
private string $nameValue,
1313
private Expr $name,
1414
private ?Expr $mode,
15-
private ?Expr $description
15+
private ?Expr $description,
16+
private ?Expr $default,
1617
) {
1718
}
1819

@@ -35,4 +36,9 @@ public function getDescription(): ?Expr
3536
{
3637
return $this->description;
3738
}
39+
40+
public function getDefault(): ?Expr
41+
{
42+
return $this->default;
43+
}
3844
}

rules/Symfony73/ValueObject/CommandOption.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public function __construct(
1414
private ?Expr $shortcut,
1515
private ?Expr $mode,
1616
private ?Expr $description,
17+
private ?Expr $default,
1718
) {
1819
}
1920

@@ -41,4 +42,9 @@ public function getNameValue(): string
4142
{
4243
return $this->nameValue;
4344
}
45+
46+
public function getDefault(): ?Expr
47+
{
48+
return $this->default;
49+
}
4450
}

0 commit comments

Comments
 (0)