Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

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

Sign up
Appearance settings

Commit5a046cb

Browse files
committed
[Console] Expose the original input arguments and options
PoC
1 parent68a5704 commit5a046cb

File tree

6 files changed

+620
-0
lines changed

6 files changed

+620
-0
lines changed

‎src/Symfony/Component/Console/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
CHANGELOG
22
=========
33

4+
7.2
5+
---
6+
7+
* Add`InputInterface::getRawArguments()`
8+
* Add`InputInterface::getRawOptions()`
9+
* Add`Input::unparse()`
10+
11+
412
7.1
513
---
614

‎src/Symfony/Component/Console/Input/Input.php

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
useSymfony\Component\Console\Exception\InvalidArgumentException;
1515
useSymfony\Component\Console\Exception\RuntimeException;
16+
usefunctionarray_keys;
1617

1718
/**
1819
* Input is the base class for all concrete Input classes.
@@ -85,6 +86,35 @@ public function getArguments(): array
8586
returnarray_merge($this->definition->getArgumentDefaults(),$this->arguments);
8687
}
8788

89+
/**
90+
* Returns all the given arguments NOT merged with the default values.
91+
*
92+
* @param bool $strip Whether to return the raw parameters (false) or the values after the command name (true)
93+
*
94+
* @return array<string|bool|int|float|null|array<string|bool|int|float|null>>
95+
*/
96+
publicfunctiongetRawArguments(bool$strip =false):array
97+
{
98+
if (!$strip) {
99+
return$this->arguments;
100+
}
101+
102+
$arguments = [];
103+
$keep =false;
104+
foreach ($this->argumentsas$argument) {
105+
if (!$keep &&$argument ===$this->getFirstArgument()) {
106+
$keep =true;
107+
108+
continue;
109+
}
110+
if ($keep) {
111+
$arguments[] =$argument;
112+
}
113+
}
114+
115+
return$arguments;
116+
}
117+
88118
publicfunctiongetArgument(string$name):mixed
89119
{
90120
if (!$this->definition->hasArgument($name)) {
@@ -113,6 +143,16 @@ public function getOptions(): array
113143
returnarray_merge($this->definition->getOptionDefaults(),$this->options);
114144
}
115145

146+
/**
147+
* Returns all the given options NOT merged with the default values.
148+
*
149+
* @return array<string|bool|int|float|null|array<string|bool|int|float|null>>
150+
*/
151+
publicfunctiongetRawOptions():array
152+
{
153+
return$this->options;
154+
}
155+
116156
publicfunctiongetOption(string$name):mixed
117157
{
118158
if ($this->definition->hasNegation($name)) {
@@ -171,4 +211,51 @@ public function getStream()
171211
{
172212
return$this->stream;
173213
}
214+
215+
/**
216+
* @param string[] $optionNames
217+
*
218+
* @return list<string>
219+
*/
220+
publicfunctionunparse(array$optionNames = []):array
221+
{
222+
$rawOptions =$this->getRawOptions();
223+
224+
$filteredRawOptions =count($optionNames) ===0
225+
?$rawOptions
226+
:array_intersect_key($rawOptions,array_fill_keys($optionNames,''),
227+
);
228+
229+
returnarray_map(
230+
fn (string$optionName) =>$this->unparseOption(
231+
$this->definition->getOption($optionName),
232+
$optionName,
233+
$filteredRawOptions[$optionName],
234+
),
235+
array_keys($filteredRawOptions),
236+
);
237+
}
238+
239+
/**
240+
* @param string|bool|int|float|null|array<string|bool|int|float|null> $value
241+
*/
242+
privatefunctionunparseOption(
243+
InputOption$option,
244+
string$name,
245+
array|bool|float|int|string|null$value,
246+
):string {
247+
returnmatch(true) {
248+
$option->isNegatable() =>sprintf('--%s%s',$value ?'' :'no-',$name),
249+
!$option->acceptValue() =>sprintf('--%s',$name),
250+
$option->isArray() =>implode('',array_map(fn($item) =>$this->unparseOptionWithValue($name,$item),$value,)),
251+
default =>$this->unparseOptionWithValue($name,$value),
252+
};
253+
}
254+
255+
privatefunctionunparseOptionWithValue(
256+
string$name,
257+
bool|float|int|string|null$value,
258+
):string {
259+
returnsprintf('--%s=%s',$name,$this->escapeToken($value));
260+
}
174261
}

‎src/Symfony/Component/Console/Input/InputInterface.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
* InputInterface is the interface implemented by all input classes.
1919
*
2020
* @author Fabien Potencier <fabien@symfony.com>
21+
*
22+
* @method getRawArguments(bool $strip = false): array<string|bool|int|float|null|array<string|bool|int|float|null>> Returns all the given arguments NOT merged with the default values.
23+
* @method getRawOptions(): array<string|bool|int|float|null|array<string|bool|int|float|null>> Returns all the given options NOT merged with the default values.
2124
*/
2225
interface InputInterface
2326
{

‎src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,4 +594,254 @@ public static function provideGetRawTokensTrueTests(): iterable
594594
yield [['app/console','--no-ansi','foo:bar','foo:bar'], ['foo:bar']];
595595
yield [['app/console','--no-ansi','foo:bar','--','argument'], ['--','argument']];
596596
}
597+
598+
/**
599+
* @dataProvider unparseProvider
600+
*/
601+
publicfunctiontestUnparse(
602+
?InputDefinition$inputDefinition,
603+
ArgvInput$input,
604+
?array$parsedOptions,
605+
array$expected,
606+
)
607+
{
608+
if (null !==$inputDefinition) {
609+
$input->bind($inputDefinition);
610+
}
611+
612+
$actual =null ===$parsedOptions ?$input->unparse() :$input->unparse($parsedOptions);
613+
614+
self::assertEquals($expected,$actual);
615+
}
616+
617+
publicstaticfunctionunparseProvider():iterable
618+
{
619+
yield'empty input and empty definition' => [
620+
newInputDefinition(),
621+
newArgvInput([]),
622+
[],
623+
[],
624+
];
625+
626+
yield'empty input and definition with default values: ignore default values' => [
627+
newInputDefinition([
628+
newInputArgument(
629+
'argWithDefaultValue',
630+
InputArgument::OPTIONAL,
631+
'Argument with a default value',
632+
'arg1DefaultValue',
633+
),
634+
newInputOption(
635+
'optWithDefaultValue',
636+
null,
637+
InputOption::VALUE_REQUIRED,
638+
'Option with a default value',
639+
'opt1DefaultValue',
640+
),
641+
]),
642+
newArgvInput([]),
643+
[],
644+
[],
645+
];
646+
647+
$completeInputDefinition =newInputDefinition([
648+
newInputArgument(
649+
'requiredArgWithoutDefaultValue',
650+
InputArgument::REQUIRED,
651+
'Argument without a default value',
652+
),
653+
newInputArgument(
654+
'optionalArgWithDefaultValue',
655+
InputArgument::OPTIONAL,
656+
'Argument with a default value',
657+
'argDefaultValue',
658+
),
659+
newInputOption(
660+
'optWithoutDefaultValue',
661+
null,
662+
InputOption::VALUE_REQUIRED,
663+
'Option without a default value',
664+
),
665+
newInputOption(
666+
'optWithDefaultValue',
667+
null,
668+
InputOption::VALUE_REQUIRED,
669+
'Option with a default value',
670+
'optDefaultValue',
671+
),
672+
]);
673+
674+
yield'arguments & options: returns all passed options but ignore default values' => [
675+
$completeInputDefinition,
676+
newArgvInput(['argValue','--optWithoutDefaultValue=optValue']),
677+
[],
678+
['--optWithoutDefaultValue=optValue'],
679+
];
680+
681+
yield'arguments & options; explicitly pass the default values: the default values are returned' => [
682+
$completeInputDefinition,
683+
newArgvInput(['argValue','argDefaultValue','--optWithoutDefaultValue=optValue','--optWithDefaultValue=optDefaultValue']),
684+
[],
685+
[
686+
'--optWithoutDefaultValue=optValue',
687+
'--optWithDefaultValue=optDefaultValue',
688+
],
689+
];
690+
691+
yield'arguments & options; parsing an argument name instead of an option name: that option is ignored' => [
692+
$completeInputDefinition,
693+
newArgvInput(['argValue']),
694+
['requiredArgWithoutDefaultValue'],
695+
[],
696+
];
697+
698+
yield'arguments & options; non passed option: it is ignored' => [
699+
$completeInputDefinition,
700+
newArgvInput(['argValue']),
701+
['optWithDefaultValue'],
702+
[],
703+
];
704+
705+
$createSingleOptionScenario =staticfn (
706+
InputOption$option,
707+
array$input,
708+
array$expected
709+
) => [
710+
newInputDefinition([$option]),
711+
newArgvInput(['appName', ...$input]),
712+
[],
713+
$expected,
714+
];
715+
716+
yield'option without value' =>$createSingleOptionScenario(
717+
newInputOption(
718+
'opt',
719+
null,
720+
InputOption::VALUE_NONE,
721+
),
722+
['--opt'],
723+
['--opt'],
724+
);
725+
726+
yield'option without value by shortcut' =>$createSingleOptionScenario(
727+
newInputOption(
728+
'opt',
729+
'o',
730+
InputOption::VALUE_NONE,
731+
),
732+
['-o'],
733+
['--opt'],
734+
);
735+
736+
yield'option with value required' =>$createSingleOptionScenario(
737+
newInputOption(
738+
'opt',
739+
null,
740+
InputOption::VALUE_REQUIRED,
741+
),
742+
['--opt=foo'],
743+
['--opt=foo'],
744+
);
745+
746+
yield'option with non string value (bool)' =>$createSingleOptionScenario(
747+
newInputOption(
748+
'opt',
749+
null,
750+
InputOption::VALUE_REQUIRED,
751+
),
752+
['--opt=1'],
753+
['--opt=1'],
754+
);
755+
756+
yield'option with non string value (int)' =>$createSingleOptionScenario(
757+
newInputOption(
758+
'opt',
759+
null,
760+
InputOption::VALUE_REQUIRED,
761+
),
762+
['--opt=20'],
763+
['--opt=20'],
764+
);
765+
766+
yield'option with non string value (float)' =>$createSingleOptionScenario(
767+
newInputOption(
768+
'opt',
769+
null,
770+
InputOption::VALUE_REQUIRED,
771+
),
772+
['--opt=5.3'],
773+
['--opt=\'5.3\''],
774+
);
775+
776+
yield'option with non string value (array of strings)' =>$createSingleOptionScenario(
777+
newInputOption(
778+
'opt',
779+
null,
780+
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
781+
),
782+
['--opt=v1','--opt=v2','--opt=v3'],
783+
['--opt=v1--opt=v2--opt=v3'],
784+
);
785+
786+
yield'negatable option (positive)' =>$createSingleOptionScenario(
787+
newInputOption(
788+
'opt',
789+
null,
790+
InputOption::VALUE_NEGATABLE,
791+
),
792+
['--opt'],
793+
['--opt'],
794+
);
795+
796+
yield'negatable option (negative)' =>$createSingleOptionScenario(
797+
newInputOption(
798+
'opt',
799+
null,
800+
InputOption::VALUE_NEGATABLE,
801+
),
802+
['--no-opt'],
803+
['--no-opt'],
804+
);
805+
806+
$createEscapeOptionTokenScenario =staticfn (
807+
string$optionValue,
808+
?string$expected
809+
) => [
810+
newInputDefinition([
811+
newInputOption(
812+
'opt',
813+
null,
814+
InputOption::VALUE_REQUIRED,
815+
),
816+
]),
817+
newArgvInput(['appName','--opt='.$optionValue]),
818+
[],
819+
['--opt='.$expected],
820+
];
821+
822+
yield'escape token; string token' =>$createEscapeOptionTokenScenario(
823+
'foo',
824+
'foo',
825+
);
826+
827+
yield'escape token; escaped string token' =>$createEscapeOptionTokenScenario(
828+
'"foo"',
829+
escapeshellarg('"foo"'),
830+
);
831+
832+
yield'escape token; escaped string token with both types of quotes' =>$createEscapeOptionTokenScenario(
833+
'"o_id in(\'20\')"',
834+
escapeshellarg('"o_id in(\'20\')"'),
835+
);
836+
837+
yield'escape token; string token with spaces' =>$createEscapeOptionTokenScenario(
838+
'a b c d',
839+
escapeshellarg('a b c d'),
840+
);
841+
842+
yield'escape token; string token with line return' =>$createEscapeOptionTokenScenario(
843+
"A\nB'C",
844+
escapeshellarg("A\nB'C"),
845+
);
846+
}
597847
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp