Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d740cfa

Browse filesBrowse files
committed
Invokable command adjustments
1 parent f6312d3 commit d740cfa
Copy full SHA for d740cfa

File tree

5 files changed

+91
-17
lines changed
Filter options

5 files changed

+91
-17
lines changed

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ public function load(array $configs, ContainerBuilder $container): void
610610
$container->registerForAutoconfiguration(AssetCompilerInterface::class)
611611
->addTag('asset_mapper.compiler');
612612
$container->registerAttributeForAutoconfiguration(AsCommand::class, static function (ChildDefinition $definition, AsCommand $attribute, \ReflectionClass $reflector): void {
613-
$definition->addTag('console.command', ['command' => $attribute->name, 'description' => $attribute->description ?? $reflector->getName()]);
613+
$definition->addTag('console.command', ['command' => $attribute->name, 'description' => $attribute->description]);
614614
});
615615
$container->registerForAutoconfiguration(Command::class)
616616
->addTag('console.command');

‎src/Symfony/Component/Console/Attribute/Argument.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Attribute/Argument.php
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ class Argument
2929
*
3030
* If unset, the `name` and `default` values will be inferred from the parameter definition.
3131
*
32-
* @param string|bool|int|float|array|null $default The default value (for InputArgument::OPTIONAL mode only)
33-
* @param array|callable-string(CompletionInput):list<string|Suggestion> $suggestedValues The values used for input completion
32+
* @param string|bool|int|float|array|null $default The default value (for InputArgument::OPTIONAL mode only)
33+
* @param array<string|Suggestion>|callable-string(CompletionInput):list<string|Suggestion> $suggestedValues The values used for input completion
3434
*/
3535
public function __construct(
3636
public string $name = '',

‎src/Symfony/Component/Console/Attribute/Option.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Attribute/Option.php
+7-10Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ class Option
3030
*
3131
* If unset, the `name` and `default` values will be inferred from the parameter definition.
3232
*
33-
* @param array|string|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
34-
* @param scalar|array|null $default The default value (must be null for self::VALUE_NONE)
35-
* @param array|callable-string(CompletionInput):list<string|Suggestion> $suggestedValues The values used for input completion
33+
* @param array|string|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
34+
* @param scalar|array|null $default The default value (must be null for self::VALUE_NONE)
35+
* @param array<string|Suggestion>|callable-string(CompletionInput):list<string|Suggestion> $suggestedValues The values used for input completion
3636
*/
3737
public function __construct(
3838
public string $name = '',
@@ -76,17 +76,13 @@ public static function tryFrom(\ReflectionParameter $parameter): ?self
7676
if ('bool' === $self->typeName) {
7777
$self->mode = InputOption::VALUE_NONE | InputOption::VALUE_NEGATABLE;
7878
} else {
79-
$self->mode = null !== $self->default || $parameter->isDefaultValueAvailable() ? InputOption::VALUE_OPTIONAL : InputOption::VALUE_REQUIRED;
79+
$self->mode = $parameter->allowsNull() ? InputOption::VALUE_OPTIONAL : InputOption::VALUE_REQUIRED;
8080
if ('array' === $self->typeName) {
8181
$self->mode |= InputOption::VALUE_IS_ARRAY;
8282
}
8383
}
8484

85-
if (InputOption::VALUE_NONE === (InputOption::VALUE_NONE & $self->mode)) {
86-
$self->default = null;
87-
} else {
88-
$self->default ??= $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null;
89-
}
85+
$self->default ??= $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null;
9086

9187
if (\is_array($self->suggestedValues) && !\is_callable($self->suggestedValues) && 2 === \count($self->suggestedValues) && ($instance = $parameter->getDeclaringFunction()->getClosureThis()) && $instance::class === $self->suggestedValues[0] && \is_callable([$instance, $self->suggestedValues[1]])) {
9288
$self->suggestedValues = [$instance, $self->suggestedValues[1]];
@@ -100,9 +96,10 @@ public static function tryFrom(\ReflectionParameter $parameter): ?self
10096
*/
10197
public function toInputOption(): InputOption
10298
{
99+
$default = InputOption::VALUE_NONE === (InputOption::VALUE_NONE & $this->mode) ? null : $this->default;
103100
$suggestedValues = \is_callable($this->suggestedValues) ? ($this->suggestedValues)(...) : $this->suggestedValues;
104101

105-
return new InputOption($this->name, $this->shortcut, $this->mode, $this->description, $this->default, $suggestedValues);
102+
return new InputOption($this->name, $this->shortcut, $this->mode, $this->description, $default, $suggestedValues);
106103
}
107104

108105
/**

‎src/Symfony/Component/Console/Command/InvokableCommand.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Command/InvokableCommand.php
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public function __invoke(InputInterface $input, OutputInterface $output): int
4949

5050
if (null !== $statusCode && !\is_int($statusCode)) {
5151
if ($this->triggerDeprecations) {
52-
trigger_deprecation('symfony/console', '7.3', \sprintf('Returning a non-integer value from the command "%s" is deprecated and will throw an exception in PHP 8.0.', $this->command->getName()));
52+
trigger_deprecation('symfony/console', '7.3', \sprintf('Returning a non-integer value from the command "%s" is deprecated and will throw an exception in Symfony 8.0.', $this->command->getName()));
5353

5454
return 0;
5555
}
@@ -97,7 +97,7 @@ private function getParameters(InputInterface $input, OutputInterface $output):
9797

9898
if (!$type instanceof \ReflectionNamedType) {
9999
if ($this->triggerDeprecations) {
100-
trigger_deprecation('symfony/console', '7.3', \sprintf('Omitting the type declaration for the parameter "$%s" is deprecated and will throw an exception in PHP 8.0.', $parameter->getName()));
100+
trigger_deprecation('symfony/console', '7.3', \sprintf('Omitting the type declaration for the parameter "$%s" is deprecated and will throw an exception in Symfony 8.0.', $parameter->getName()));
101101

102102
continue;
103103
}

‎src/Symfony/Component/Console/Tests/Command/InvokableCommandTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Tests/Command/InvokableCommandTest.php
+79-2Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
use Symfony\Component\Console\Completion\CompletionInput;
1919
use Symfony\Component\Console\Completion\CompletionSuggestions;
2020
use Symfony\Component\Console\Completion\Suggestion;
21+
use Symfony\Component\Console\Exception\InvalidOptionException;
2122
use Symfony\Component\Console\Exception\LogicException;
23+
use Symfony\Component\Console\Input\ArrayInput;
24+
use Symfony\Component\Console\Output\NullOutput;
2225

2326
class InvokableCommandTest extends TestCase
2427
{
@@ -76,7 +79,7 @@ public function testCommandInputOptionDefinition()
7679

7780
$typeInputOption = $command->getDefinition()->getOption('type');
7881
self::assertSame('type', $typeInputOption->getName());
79-
self::assertFalse($typeInputOption->isValueRequired());
82+
self::assertTrue($typeInputOption->isValueRequired());
8083
self::assertSame('USER_TYPE', $typeInputOption->getDefault());
8184

8285
$verboseInputOption = $command->getDefinition()->getOption('verbose');
@@ -94,7 +97,7 @@ public function testCommandInputOptionDefinition()
9497

9598
$rolesInputOption = $command->getDefinition()->getOption('roles');
9699
self::assertSame('roles', $rolesInputOption->getName());
97-
self::assertFalse($rolesInputOption->isValueRequired());
100+
self::assertTrue($rolesInputOption->isValueRequired());
98101
self::assertTrue($rolesInputOption->isArray());
99102
self::assertSame(['ROLE_USER'], $rolesInputOption->getDefault());
100103
self::assertTrue($rolesInputOption->hasCompletion());
@@ -124,6 +127,80 @@ public function testInvalidOptionType()
124127
$command->getDefinition();
125128
}
126129

130+
/**
131+
* @dataProvider provideBinaryInputOptions
132+
*/
133+
public function testBinaryInputOptions(array $parameters, array $expected)
134+
{
135+
$command = new Command('foo');
136+
$command->setCode(function (
137+
#[Option] bool $a,
138+
#[Option] bool $b = true,
139+
#[Option] bool $c = false,
140+
) use ($expected) {
141+
$this->assertSame($expected[0], $a);
142+
$this->assertSame($expected[1], $b);
143+
$this->assertSame($expected[2], $c);
144+
});
145+
146+
$command->run(new ArrayInput($parameters), new NullOutput());
147+
}
148+
149+
public static function provideBinaryInputOptions(): \Generator
150+
{
151+
yield 'defaults' => [[], [false, true, false]];
152+
yield 'positive' => [['--a' => null, '--b' => null, '--c' => null], [true, true, true]];
153+
yield 'negative' => [['--no-a' => null, '--no-b' => null, '--no-c' => null], [false, false, false]];
154+
}
155+
156+
/**
157+
* @dataProvider provideNonBinaryInputOptions
158+
*/
159+
public function testNonBinaryInputOptions(array $parameters, array $expected)
160+
{
161+
$command = new Command('foo');
162+
$command->setCode(function (
163+
#[Option] ?string $a,
164+
#[Option] ?string $b = 'b',
165+
#[Option] ?array $c = [],
166+
) use ($expected) {
167+
$this->assertSame($expected[0], $a);
168+
$this->assertSame($expected[1], $b);
169+
$this->assertSame($expected[2], $c);
170+
});
171+
172+
$command->run(new ArrayInput($parameters), new NullOutput());
173+
}
174+
175+
public static function provideNonBinaryInputOptions(): \Generator
176+
{
177+
yield 'defaults' => [[], [null, 'b', []]];
178+
yield 'value-required' => [['--a' => 'x', '--b' => 'y', '--c' => ['z']], ['x', 'y', ['z']]];
179+
yield 'value-optional' => [['--a' => null, '--b' => null, '--c' => null], [null, null, null]];
180+
}
181+
182+
public function testInvalidRequiredValueOption()
183+
{
184+
$command = new Command('foo');
185+
$command->setCode(function (#[Option] string $a) {});
186+
187+
$this->expectException(InvalidOptionException::class);
188+
$this->expectExceptionMessage('The "--a" option requires a value.');
189+
190+
$command->run(new ArrayInput(['--a' => null]), new NullOutput());
191+
}
192+
193+
public function testInvalidRequiredValueOptionEvenWithDefault()
194+
{
195+
$command = new Command('foo');
196+
$command->setCode(function (#[Option] string $a = 'a') {});
197+
198+
$this->expectException(InvalidOptionException::class);
199+
$this->expectExceptionMessage('The "--a" option requires a value.');
200+
201+
$command->run(new ArrayInput(['--a' => null]), new NullOutput());
202+
}
203+
127204
public function getSuggestedRoles(CompletionInput $input): array
128205
{
129206
return ['ROLE_ADMIN', 'ROLE_USER'];

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.