Skip to content

Commit e9d070a

Browse files
committed
add type support to option add array support
1 parent ba2209e commit e9d070a

File tree

4 files changed

+82
-12
lines changed

4 files changed

+82
-12
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
namespace Rector\Symfony\Tests\Symfony73\Rector\Class_\InvokableCommandInputAttributeRector\Fixture\DefaultValue;
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\Input\InputOption;
10+
use Symfony\Component\Console\Output\OutputInterface;
11+
12+
#[AsCommand(
13+
name: 'app:hello',
14+
)]
15+
class OptionWithOptionalValue extends Command
16+
{
17+
protected function configure(): void
18+
{
19+
$this->addOption('some-array', null, InputOption::VALUE_IS_ARRAY, '', ['third value']);
20+
$this->addOption('no-default-array', null, InputOption::VALUE_IS_ARRAY);
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\DefaultValue;
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\Input\InputOption;
38+
use Symfony\Component\Console\Output\OutputInterface;
39+
40+
#[AsCommand(
41+
name: 'app:hello',
42+
)]
43+
class OptionWithOptionalValue
44+
{
45+
public function __invoke(#[\Symfony\Component\Console\Attribute\Option(name: 'some-array', mode: InputOption::VALUE_IS_ARRAY)]
46+
array $someArray = ['third value'], #[\Symfony\Component\Console\Attribute\Option(name: 'no-default-array', mode: InputOption::VALUE_IS_ARRAY)]
47+
array $noDefaultArray): int
48+
{
49+
}
50+
}
51+
52+
?>

rules/Symfony73/NodeAnalyzer/CommandOptionsResolver.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Rector\Symfony\Symfony73\NodeAnalyzer;
66

77
use PhpParser\Node\Arg;
8+
use PhpParser\Node\Expr;
89
use PhpParser\Node\Stmt\ClassMethod;
910
use PHPStan\Type\Type;
1011
use Rector\NodeTypeResolver\NodeTypeResolver;
@@ -42,6 +43,7 @@ public function resolve(ClassMethod $configureClassMethod): array
4243
$addOptionArgs[2]->value ?? null,
4344
$addOptionArgs[3]->value ?? null,
4445
$addOptionArgs[4]->value ?? null,
46+
$this->isArrayMode($addOptionArgs),
4547
$this->resolveDefaultType($addOptionArgs)
4648
);
4749
}
@@ -61,4 +63,19 @@ private function resolveDefaultType(array $args): ?Type
6163

6264
return $this->nodeTypeResolver->getType($defaultArg->value);
6365
}
66+
67+
/**
68+
* @param Arg[] $args
69+
*/
70+
private function isArrayMode(array $args): bool
71+
{
72+
$modeExpr = $args[2]->value ?? null;
73+
if (! $modeExpr instanceof Expr) {
74+
return false;
75+
}
76+
77+
$modeValue = $this->valueResolver->getValue($modeExpr);
78+
// binary check for InputOptions::VALUE_IS_ARRAY
79+
return (bool) ($modeValue & 8);
80+
}
6481
}

rules/Symfony73/NodeFactory/CommandInvokeParamsFactory.php

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ private function createArgumentParams(array $commandArguments): array
5454
$variableName = $this->createCamelCase($commandArgument->getNameValue());
5555
$argumentParam = new Param(new Variable($variableName));
5656

57-
$this->decorateArgumentParamType($argumentParam, $commandArgument);
57+
$this->decorateParamType($argumentParam, $commandArgument);
5858

5959
if ($commandArgument->getDefault() instanceof Expr) {
6060
$argumentParam->default = $commandArgument->getDefault();
@@ -100,7 +100,7 @@ private function createOptionParams(array $commandOptions): array
100100
$optionParam->default = $commandOption->getDefault();
101101
}
102102

103-
$this->decorateParamTypeByDefault($optionParam, $commandOption);
103+
$this->decorateParamType($optionParam, $commandOption);
104104

105105
$optionArgs = [new Arg(value: $commandOption->getName(), name: new Identifier('name'))];
106106

@@ -160,20 +160,15 @@ private function isNonEmptyExpr(?Expr $expr): bool
160160
return ! $this->valueResolver->isValue($expr, '');
161161
}
162162

163-
private function decorateArgumentParamType(Param $argumentParam, CommandArgument $commandArgument): void
164-
{
165-
if ($commandArgument->isArray()) {
163+
private function decorateParamType(
164+
Param $argumentParam,
165+
CommandArgument|CommandOption $commandArgumentOrOption
166+
): void {
167+
if ($commandArgumentOrOption->isArray()) {
166168
$argumentParam->type = new Identifier('array');
167169
return;
168170
}
169171

170-
$this->decorateParamTypeByDefault($argumentParam, $commandArgument);
171-
}
172-
173-
private function decorateParamTypeByDefault(
174-
Param $argumentParam,
175-
CommandArgument|CommandOption $commandArgumentOrOption
176-
): void {
177172
$defaultType = $commandArgumentOrOption->getDefaultType();
178173
if ($defaultType instanceof Type) {
179174
$paramType = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($defaultType, TypeKind::PARAM);

rules/Symfony73/ValueObject/CommandOption.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public function __construct(
1616
private ?Expr $mode,
1717
private ?Expr $description,
1818
private ?Expr $default,
19+
private bool $isArray,
1920
private ?Type $defaultType
2021
) {
2122
}
@@ -54,4 +55,9 @@ public function getDefaultType(): ?Type
5455
{
5556
return $this->defaultType;
5657
}
58+
59+
public function isArray(): bool
60+
{
61+
return $this->isArray;
62+
}
5763
}

0 commit comments

Comments
 (0)