Console Input (Arguments & Options)

The most interesting part of the commands are the arguments and options that you can make available. These arguments and options allow you to pass dynamic information from the terminal to the command.

コマンドの最も興味深い部分は、使用できる引数とオプションです。これらの引数とオプションを使用すると、端末からコマンドに動的情報を渡すことができます。

Using Command Arguments

Arguments are the strings - separated by spaces - that come after the command name itself. They are ordered, and can be optional or required. For example, to add an optional last_name argument to the command and make the name argument required:

引数は、コマンド名自体の後に続く、スペースで区切られた文字列です。それらは順序付けられており、オプションまたは必須にすることができます。たとえば、オプションの last_name 引数をコマンドに追加し、name 引数を必須にするには、次のようにします。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// ...
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;

class GreetCommand extends Command
{
    // ...

    protected function configure(): void
    {
        $this
            // ...
            ->addArgument('name', InputArgument::REQUIRED, 'Who do you want to greet?')
            ->addArgument('last_name', InputArgument::OPTIONAL, 'Your last name?')
        ;
    }
}

You now have access to a last_name argument in your command:

コマンドで last_name 引数にアクセスできるようになりました。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// ...
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class GreetCommand extends Command
{
    // ...

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $text = 'Hi '.$input->getArgument('name');

        $lastName = $input->getArgument('last_name');
        if ($lastName) {
            $text .= ' '.$lastName;
        }

        $output->writeln($text.'!');

        return Command::SUCCESS;
    }
}

The command can now be used in either of the following ways:

このコマンドは、次のいずれかの方法で使用できるようになりました。
1
2
3
4
5
$ php bin/console app:greet Fabien
Hi Fabien!

$ php bin/console app:greet Fabien Potencier
Hi Fabien Potencier!

It is also possible to let an argument take a list of values (imagine you want to greet all your friends). Only the last argument can be a list:

引数に値のリストを持たせることもできます (すべての友達に挨拶したいと想像してください)。リストにできるのは最後の引数のみです。
1
2
3
4
5
6
7
8
$this
    // ...
    ->addArgument(
        'names',
        InputArgument::IS_ARRAY,
        'Who do you want to greet (separate multiple names with a space)?'
    )
;

To use this, specify as many names as you want:

これを使用するには、必要な数の名前を指定します。
1
$ php bin/console app:greet Fabien Ryan Bernhard

You can access the names argument as an array:

names 引数に配列としてアクセスできます。
1
2
3
4
$names = $input->getArgument('names');
if (count($names) > 0) {
    $text .= ' '.implode(', ', $names);
}

There are three argument variants you can use:

使用できる引数のバリエーションは 3 つあります。
InputArgument::REQUIRED
The argument is mandatory. The command doesn't run if the argument isn't provided;
引数は必須です。引数が指定されていない場合、コマンドは実行されません。
InputArgument::OPTIONAL
The argument is optional and therefore can be omitted. This is the default behavior of arguments;
引数はオプションであるため、省略できます。これが引数のデフォルトの動作です。
InputArgument::IS_ARRAY
The argument can contain any number of values. For that reason, it must be used at the end of the argument list.
引数には、任意の数の値を含めることができます。そのため、引数リストの最後で使用する必要があります。

You can combine IS_ARRAY with REQUIRED or OPTIONAL like this:

次のように IS_ARRAY を REQUIRED または OPTIONAL と組み合わせることができます。
1
2
3
4
5
6
7
8
$this
    // ...
    ->addArgument(
        'names',
        InputArgument::IS_ARRAY | InputArgument::REQUIRED,
        'Who do you want to greet (separate multiple names with a space)?'
    )
;

Using Command Options

Unlike arguments, options are not ordered (meaning you can specify them in any order) and are specified with two dashes (e.g. --yell). Options are always optional, and can be setup to accept a value (e.g. --dir=src) or as a boolean flag without a value (e.g. --yell).

引数とは異なり、オプションは順序付けされておらず (つまり、任意の順序で指定できます)、ダッシュ 2 つ (例: --yell) で指定されます。オプションは常にオプションであり、値 (例: --dir=src) または値のないブール値フラグ (例: --yell) を受け入れるように設定できます。

For example, add a new option to the command that can be used to specify how many times in a row the message should be printed:

たとえば、メッセージを連続して何回出力するかを指定するために使用できる新しいオプションをコマンドに追加します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// ...
use Symfony\Component\Console\Input\InputOption;

$this
    // ...
    ->addOption(
        // this is the name that users must type to pass this option (e.g. --iterations=5)
        'iterations',
        // this is the optional shortcut of the option name, which usually is just a letter
        // (e.g. `i`, so users pass it as `-i`); use it for commonly used options
        // or options with long names
        null,
        // this is the type of option (e.g. requires a value, can be passed more than once, etc.)
        InputOption::VALUE_REQUIRED,
        // the option description displayed when showing the command help
        'How many times should the message be printed?',
        // the default value of the option (for those which allow to pass values)
        1
    )
;

Next, use this in the command to print the message multiple times:

次に、コマンドでこれを使用して、メッセージを複数回出力します。
1
2
3
for ($i = 0; $i < $input->getOption('iterations'); $i++) {
    $output->writeln($text);
}

Now, when you run the command, you can optionally specify a --iterations flag:

これで、コマンドを実行するときに、オプションで --iterations フラグを指定できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# no --iterations provided, the default (1) is used
$ php bin/console app:greet Fabien
Hi Fabien!

$ php bin/console app:greet Fabien --iterations=5
Hi Fabien!
Hi Fabien!
Hi Fabien!
Hi Fabien!
Hi Fabien!

# the order of options isn't important
$ php bin/console app:greet Fabien --iterations=5 --yell
$ php bin/console app:greet Fabien --yell --iterations=5
$ php bin/console app:greet --yell --iterations=5 Fabien

Tip

ヒント

You can also declare a one-letter shortcut that you can call with a single dash, like -i:

-i のように、一重ダッシュで呼び出すことができる 1 文字のショートカットを宣言することもできます。
1
2
3
4
5
6
7
8
9
10
$this
    // ...
    ->addOption(
        'iterations',
        'i',
        InputOption::VALUE_REQUIRED,
        'How many times should the message be printed?',
        1
    )
;

Note that to comply with the docopt standard, long options can specify their values after a whitespace or an = sign (e.g. --iterations 5 or --iterations=5), but short options can only use whitespaces or no separation at all (e.g. -i 5 or -i5).

docopt 標準に準拠するために、長いオプションでは空白または = 記号の後に値を指定できますが (例: --iterations 5 または --iterations=5)、短いオプションでは空白またはノーズ区切りのみを使用できます (例: -i 5 または -i5)。

Caution

注意

While it is possible to separate an option from its value with a whitespace, using this form leads to an ambiguity should the option appear before the command name. For example, php bin/console --iterations 5 app:greet Fabien is ambiguous; Symfony would interpret 5 as the command name. To avoid this situation, always place options after the command name, or avoid using a space to separate the option name from its value.

オプションとその値を空白で区切ることは可能ですが、この形式を使用すると、オプションがコマンド名の前に表示される場合にあいまいさが生じます。たとえば、php bin/console --iterations 5 app:greet Fabienis ambiguous; symfony は 5 をコマンド名として解釈します。この状況を回避するには、常にコマンド名の後にオプションを配置するか、オプション名とその値を区切るためにスペースを使用しないようにします。

There are five option variants you can use:

使用できるオプションのバリエーションは 5 つあります。
InputOption::VALUE_IS_ARRAY
This option accepts multiple values (e.g. --dir=/foo --dir=/bar);
このオプションは複数の値を受け入れます (例: --dir=/foo --dir=/bar)。
InputOption::VALUE_NONE
Do not accept input for this option (e.g. --yell). The value returned from is a boolean (false if the option is not provided). This is the default behavior of options;
このオプションへの入力は受け付けません (例: --yell)。返される値はブール値です (オプションが指定されていない場合は false)。これがオプションのデフォルトの動作です。
InputOption::VALUE_REQUIRED
This value is required (e.g. --iterations=5 or -i5), the option itself is still optional;
この値は必須です (例: --iterations=5 または -i5)。オプション自体はオプションです。
InputOption::VALUE_OPTIONAL
This option may or may not have a value (e.g. --yell or --yell=loud).
このオプションには、値がある場合とない場合があります (例: --yell または --yell=loud)。
InputOption::VALUE_NEGATABLE
Accept either the flag (e.g. --yell) or its negation (e.g. --no-yell).
フラグ (例: --yell) またはその否定 (例: --no-yell) のいずれかを受け入れます。

You need to combine VALUE_IS_ARRAY with VALUE_REQUIRED or VALUE_OPTIONAL like this:

次のように VALUE_IS_ARRAY を VALUE_REQUIRED または VALUE_OPTIONAL と組み合わせる必要があります。
1
2
3
4
5
6
7
8
9
10
$this
    // ...
    ->addOption(
        'colors',
        null,
        InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
        'Which colors do you like?',
        ['blue', 'red']
    )
;

Options with optional arguments

There is nothing forbidding you to create a command with an option that optionally accepts a value, but it's a bit tricky. Consider this example:

オプションで値を受け入れるオプションを指定してコマンドを作成することを禁止するものは何もありませんが、少し注意が必要です。次の例を検討してください。
1
2
3
4
5
6
7
8
9
10
11
12
// ...
use Symfony\Component\Console\Input\InputOption;

$this
    // ...
    ->addOption(
        'yell',
        null,
        InputOption::VALUE_OPTIONAL,
        'Should I yell while greeting?'
    )
;

This option can be used in 3 ways: greet --yell, greet --yell=louder, and greet. However, it's hard to distinguish between passing the option without a value (greet --yell) and not passing the option (greet).

このオプションは、greet --yell、greet --yell=louder、greet の 3 つの方法で使用できます。ただし、値なしでオプションを渡す (greet --yell) か、オプションを渡さない (greet) かを区別するのは困難です。

To solve this issue, you have to set the option's default value to false:

この問題を解決するには、オプションのデフォルト値を false に設定する必要があります。
1
2
3
4
5
6
7
8
9
10
11
12
13
// ...
use Symfony\Component\Console\Input\InputOption;

$this
    // ...
    ->addOption(
        'yell',
        null,
        InputOption::VALUE_OPTIONAL,
        'Should I yell while greeting?',
        false // this is the new default value, instead of null
    )
;

Now it's possible to differentiate between not passing the option and not passing any value for it:

オプションを渡さない場合と値を渡さない場合を区別できるようになりました。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$optionValue = $input->getOption('yell');
if (false === $optionValue) {
    // in this case, the option was not passed when running the command
    $yell = false;
    $yellLouder = false;
} elseif (null === $optionValue) {
    // in this case, the option was passed when running the command
    // but no value was given to it
    $yell = true;
    $yellLouder = false;
} else {
    // in this case, the option was passed when running the command and
    // some specific value was given to it
    $yell = true;
    if ('louder' === $optionValue) {
        $yellLouder = true;
    } else {
        $yellLouder = false;
    }
}

The above code can be simplified as follows because false !== null:

false !== null であるため、上記のコードは次のように簡略化できます。
1
2
3
$optionValue = $input->getOption('yell');
$yell = ($optionValue !== false);
$yellLouder = ($optionValue === 'louder');

Adding Argument/Option Value Completion

If Console completion is installed, command and option names will be auto completed by the shell. However, you can also implement value completion for the input in your commands. For instance, you may want to complete all usernames from the database in the name argument of your greet command.

コンソール補完がインストールされている場合、コマンドとオプション名はシェルによって自動補完されます。ただし、コマンドの入力に値の補完を実装することもできます。たとえば、greet コマンドの name 引数でデータベースからすべてのユーザー名を完成させたい場合があります。

To achieve this, use the 5th argument of addArgument()/addOption:

これを実現するには、addArgument()/addOption の 5 番目の引数を使用します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// ...
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;

class GreetCommand extends Command
{
    // ...
    protected function configure(): void
    {
        $this
            ->addArgument(
                'names',
                InputArgument::IS_ARRAY,
                'Who do you want to greet (separate multiple names with a space)?',
                null,
                function (CompletionInput $input) {
                    // the value the user already typed, e.g. when typing "app:greet Fa" before
                    // pressing Tab, this will contain "Fa"
                    $currentValue = $input->getCompletionValue();

                    // get the list of username names from somewhere (e.g. the database)
                    // you may use $currentValue to filter down the names
                    $availableUsernames = ...;

                    // then suggested the usernames as values
                    return $availableUsernames;
                }
            )
        ;
    }
}

6.1

6.1

The argument to addOption()/addArgument() was introduced in Symfony 6.1. Prior to this version, you had to override the complete() method of the command.

addOption()/addArgument() への引数は、Symfony 6.1 で導入されました。このバージョンより前は、コマンドの complete() メソッドをオーバーライドする必要がありました。

That's all you need! Assuming users "Fabien" and "Fabrice" exist, pressing tab after typing app:greet Fa will give you these names as a suggestion.

それだけです!ユーザー "Fabien" と "Fabrice" が存在すると仮定すると、 app:greet Fa と入力した後に Tab キーを押すと、これらの名前が候補として表示されます。

Tip

ヒント

The shell script is able to handle huge amounts of suggestions and will automatically filter the suggested values based on the existing input from the user. You do not have to implement any filter logic in the command.

シェル スクリプトは大量の提案を処理でき、ユーザーからの既存の入力に基づいて提案された値を自動的にフィルター処理します。コマンドにフィルタ ロジックを実装する必要はありません。

You may use CompletionInput::getCompletionValue() to get the current input if that helps improving performance (e.g. by reducing the number of rows fetched from the database).

CompletionInput::getCompletionValue() を使用して現在の入力を取得できますが、それがパフォーマンスの向上に役立つ場合 (たとえば、データベースからフェッチされる行数を減らすことによって) があります。

Testing the Completion script

The Console component comes with a special CommandCompletionTester` class to help you unit test the completion logic:

Console コンポーネントには、完了ロジックの単体テストに役立つ特別な CommandCompletionTester` クラスが付属しています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// ...
use Symfony\Component\Console\Application;

class GreetCommandTest extends TestCase
{
    public function testComplete()
    {
        $application = new Application();
        $application->add(new GreetCommand());

        // create a new tester with the greet command
        $tester = new CommandCompletionTester($application->get('app:greet'));

        // complete the input without any existing input (the empty string represents
        // the position of the cursor)
        $suggestions = $tester->complete(['']);
        $this->assertSame(['Fabien', 'Fabrice', 'Wouter'], $suggestions);

        // complete the input with "Fa" as input
        $suggestions = $tester->complete(['Fa']);
        $this->assertSame(['Fabien', 'Fabrice'], $suggestions);
    }
}