How to Style a Console Command

One of the most boring tasks when creating console commands is to deal with the styling of the command's input and output. Displaying titles and tables or asking questions to the user involves a lot of repetitive code.

コンソール コマンドを作成するときに最も退屈なタスクの 1 つは、コマンドの入力と出力のスタイルを処理することです。タイトルや表を表示したり、ユーザーに質問したりするには、多くの繰り返しコードが必要です。

Consider for example the code used to display the title of the following command:

たとえば、次のコマンドのタイトルを表示するために使用されるコードを考えてみます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// src/Command/GreetCommand.php
namespace App\Command;

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
    {
        $output->writeln([
            '<info>Lorem Ipsum Dolor Sit Amet</>',
            '<info>==========================</>',
            '',
        ]);

        // ...
    }
}

Displaying a simple title requires three lines of code, to change the font color, underline the contents and leave an additional blank line after the title. Dealing with styles is required for well-designed commands, but it complicates their code unnecessarily.

単純なタイトルを表示するには、フォントの色を変更し、内容に下線を引き、タイトルの後に空白行を追加する 3 行のコードが必要です。適切に設計されたコマンドにはスタイルの処理が必要ですが、コードが不必要に複雑になります。

In order to reduce that boilerplate code, Symfony commands can optionally use the Symfony Style Guide. These styles are implemented as a set of helper methods which allow to create semantic commands and forget about their styling.

そのボイラープレート コードを削減するために、Symfony コマンドはオプションで Symfony スタイル ガイドを使用できます。これらのスタイルはヘルパー メソッドのセットとして実装されており、セマンティック コマンドを作成し、そのスタイリングを忘れることができます。

Basic Usage

In your command, instantiate the SymfonyStyle class and pass the $input and $output variables as its arguments. Then, you can start using any of its helpers, such as title(), which displays the title of the command:

コマンドで、SymfonyStyle クラスをインスタンス化し、その引数として $input 変数と $output 変数を渡します。次に、コマンドのタイトルを表示する title() などの任意のヘルパーの使用を開始できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// src/Command/GreetCommand.php
namespace App\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

class GreetCommand extends Command
{
    // ...

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $io->title('Lorem Ipsum Dolor Sit Amet');

        // ...
    }
}

Helper Methods

The SymfonyStyle class defines some helper methods that cover the most common interactions performed by console commands.

SymfonyStyle クラスは、コンソール コマンドによって実行される最も一般的な対話をカバーするいくつかのヘルパー メソッドを定義します。

Titling Methods

title()

It displays the given string as the command title. This method is meant to be used only once in a given command, but nothing prevents you to use it repeatedly:

指定された文字列をコマンド タイトルとして表示します。このメソッドは、特定のコマンドで 1 回だけ使用することを意図していますが、繰り返し使用することを妨げるものは何もありません。
1
$io->title('Lorem ipsum dolor sit amet');
section()

It displays the given string as the title of some command section. This is only needed in complex commands which want to better separate their contents:

指定された文字列をコマンド セクションのタイトルとして表示します。これは、内容をより適切に分離したい複雑なコマンドでのみ必要です。
1
2
3
4
5
6
7
$io->section('Adding a User');

// ...

$io->section('Generating the Password');

// ...

Content Methods

text()

It displays the given string or array of strings as regular text. This is useful to render help messages and instructions for the user running the command:

指定された文字列または文字列の配列を通常のテキストとして表示します。これは、コマンドを実行しているユーザーにヘルプ メッセージと指示を表示するのに役立ちます。
1
2
3
4
5
6
7
8
9
10
11
// use simple strings for short messages
$io->text('Lorem ipsum dolor sit amet');

// ...

// consider using arrays when displaying long messages
$io->text([
    'Lorem ipsum dolor sit amet',
    'Consectetur adipiscing elit',
    'Aenean sit amet arcu vitae sem faucibus porta',
]);
listing()

It displays an unordered list of elements passed as an array:

配列として渡された要素の順序付けられていないリストを表示します。
1
2
3
4
5
$io->listing([
    'Element #1 Lorem ipsum dolor sit amet',
    'Element #2 Lorem ipsum dolor sit amet',
    'Element #3 Lorem ipsum dolor sit amet',
]);
table()

It displays the given array of headers and rows as a compact table:

指定されたヘッダーと行の配列をコンパクトなテーブルとして表示します。
1
2
3
4
5
6
7
8
$io->table(
    ['Header 1', 'Header 2'],
    [
        ['Cell 1-1', 'Cell 1-2'],
        ['Cell 2-1', 'Cell 2-2'],
        ['Cell 3-1', 'Cell 3-2'],
    ]
);
horizontalTable()

It displays the given array of headers and rows as a compact horizontal table:

指定されたヘッダーと行の配列をコンパクトな水平テーブルとして表示します。
1
2
3
4
5
6
7
8
$io->horizontalTable(
    ['Header 1', 'Header 2'],
    [
        ['Cell 1-1', 'Cell 1-2'],
        ['Cell 2-1', 'Cell 2-2'],
        ['Cell 3-1', 'Cell 3-2'],
    ]
);
definitionList()

It displays the given key => value pairs as a compact list of elements:

指定されたキー => 値のペアを要素のコンパクトなリストとして表示します。
1
2
3
4
5
6
7
8
9
$io->definitionList(
    'This is a title',
    ['foo1' => 'bar1'],
    ['foo2' => 'bar2'],
    ['foo3' => 'bar3'],
    new TableSeparator(),
    'This is another title',
    ['foo4' => 'bar4']
);
createTable()
Creates an instance of Table styled according to the Symfony Style Guide, which allows you to use features such as dynamically appending rows.
Symfony Style Guide に従って Tablestyled のインスタンスを作成します。これにより、動的に行を追加するなどの機能を使用できます。
newLine()

It displays a blank line in the command output. Although it may seem useful, most of the times you won't need it at all. The reason is that every helper already adds their own blank lines, so you don't have to care about the vertical spacing:

コマンド出力に空白行が表示されます。便利に見えるかもしれませんが、ほとんどの場合、まったく必要ありません。その理由は、すべてのヘルペラが独自の空白行を追加するため、垂直方向のスペースを気にする必要がないからです:
1
2
3
4
5
// outputs a single blank line
$io->newLine();

// outputs three consecutive blank lines
$io->newLine(3);

Admonition Methods

note()

It displays the given string or array of strings as a highlighted admonition. Use this helper sparingly to avoid cluttering command's output:

指定された文字列または文字列の配列を強調表示された警告として表示します。コマンドの出力が乱雑にならないように、このヘルパーは慎重に使用してください。
1
2
3
4
5
6
7
8
9
10
11
// use simple strings for short notes
$io->note('Lorem ipsum dolor sit amet');

// ...

// consider using arrays when displaying long notes
$io->note([
    'Lorem ipsum dolor sit amet',
    'Consectetur adipiscing elit',
    'Aenean sit amet arcu vitae sem faucibus porta',
]);
caution()

Similar to the note() helper, but the contents are more prominently highlighted. The resulting contents resemble an error message, so you should avoid using this helper unless strictly necessary:

note() ヘルパーに似ていますが、コンテンツがより目立つように強調表示されます。結果の内容はエラー メッセージに似ているため、厳密に必要な場合を除き、このヘルパーの使用は避ける必要があります。
1
2
3
4
5
6
7
8
9
10
11
// use simple strings for short caution message
$io->caution('Lorem ipsum dolor sit amet');

// ...

// consider using arrays when displaying long caution messages
$io->caution([
    'Lorem ipsum dolor sit amet',
    'Consectetur adipiscing elit',
    'Aenean sit amet arcu vitae sem faucibus porta',
]);

Progress Bar Methods

progressStart()

It displays a progress bar with a number of steps equal to the argument passed to the method (don't pass any value if the length of the progress bar is unknown):

メソッドに渡された引数に等しいステップ数の進行状況バーを表示します (進行状況バーの長さが不明な場合は値を渡さないでください)。
1
2
3
4
5
// displays a progress bar of unknown length
$io->progressStart();

// displays a 100-step length progress bar
$io->progressStart(100);
progressAdvance()

It makes the progress bar advance the given number of steps (or 1 step if no argument is passed):

プログレスバーを指定されたステップ数 (または引数が渡​​されない場合は 1 ステップ) 進めます。
1
2
3
4
5
// advances the progress bar 1 step
$io->progressAdvance();

// advances the progress bar 10 steps
$io->progressAdvance(10);
progressFinish()

It finishes the progress bar (filling up all the remaining steps when its length is known):

プログレス バーを終了します (長さがわかっている場合は、残りのすべてのステップを埋めます)。
1
$io->progressFinish();
progressIterate()

If your progress bar loops over an iterable collection, use the progressIterate() helper:

プログレス バーが反復可能なコレクションをループする場合は、progressIterate() ヘルパーを使用します。
1
2
3
4
5
$iterable = [1, 2];

foreach ($io->progressIterate($iterable) as $value) {
    // ... do some work
}
createProgressBar()
Creates an instance of ProgressBar styled according to the Symfony Style Guide.
Symfony スタイル ガイドに従って、ProgressBarstyled のインスタンスを作成します。

User Input Methods

ask()

It asks the user to provide some value:

ユーザーに何らかの値を提供するように求めます。
1
$io->ask('What is your name?');

You can pass the default value as the second argument so the user can hit the <Enter> key to select that value:

ユーザーがキーを押してその値を選択できるように、デフォルト値を 2 番目の引数として渡すことができます。
1
$io->ask('Where are you from?', 'United States');

In case you need to validate the given value, pass a callback validator as the third argument:

指定された値を検証する必要がある場合は、3 番目の引数としてコールバック バリデーターを渡します。
1
2
3
4
5
6
7
$io->ask('Number of workers to start', 1, function ($number) {
    if (!is_numeric($number)) {
        throw new \RuntimeException('You must type a number.');
    }

    return (int) $number;
});
askHidden()

It's very similar to the ask() method but the user's input will be hidden and it cannot define a default value. Use it when asking for sensitive information:

ask() メソッドと非常に似ていますが、ユーザーの入力は非表示になり、デフォルト値を定義できません。機密情報を尋ねるときに使用します。
1
$io->askHidden('What is your password?');

In case you need to validate the given value, pass a callback validator as the second argument:

指定された値を検証する必要がある場合は、2 番目の引数としてコールバック バリデーターを渡します。
1
2
3
4
5
6
7
$io->askHidden('What is your password?', function ($password) {
    if (empty($password)) {
        throw new \RuntimeException('Password cannot be empty.');
    }

    return $password;
});
confirm()

It asks a Yes/No question to the user and it only returns true or false:

ユーザーに Yes/No の質問をし、true または false のみを返します。
1
$io->confirm('Restart the web server?');

You can pass the default value as the second argument so the user can hit the <Enter> key to select that value:

ユーザーがキーを押してその値を選択できるように、デフォルト値を 2 番目の引数として渡すことができます。
1
$io->confirm('Restart the web server?', true);
choice()

It asks a question whose answer is constrained to the given list of valid answers:

指定された有効な回答のリストに制限された回答を持つ質問をします。
1
$io->choice('Select the queue to analyze', ['queue1', 'queue2', 'queue3']);

You can pass the default value as the third argument so the user can hit the <Enter> key to select that value:

ユーザーがキーを押してその値を選択できるように、デフォルト値を 3 番目の引数として渡すことができます。
1
$io->choice('Select the queue to analyze', ['queue1', 'queue2', 'queue3'], 'queue1');

Finally, you can allow users to select multiple choices. To do so, users must separate each choice with a comma (e.g. typing 1, 2 will select choice 1 and 2):

最後に、ユーザーが複数の選択肢を選択できるようにすることができます。これを行うには、ユーザーは各選択肢をコンマで区切る必要があります (たとえば、1, 2 と入力すると、選択肢 1 と 2 が選択されます)。
1
$io->choice('Select the queue to analyze', ['queue1', 'queue2', 'queue3'], multiSelect: true);

6.2

6.2

The multiSelect option of choice() was introduced in Symfony 6.2.

choice() の multiSelect オプションは Symfony 6.2 で導入されました。

Result Methods

Note

ノート

If you print any URL it won't be broken/cut, it will be clickable - if the terminal provides it. If the "well formatted output" is more important, you can switch it off:

任意の URL を印刷すると、壊れたり切れたりすることはなく、端末が提供する場合はクリック可能になります。 「適切にフォーマットされた出力」がより重要な場合は、オフにすることができます。
1
$io->getOutputWrapper()->setAllowCutUrls(true);
success()

It displays the given string or array of strings highlighted as a successful message (with a green background and the [OK] label). It's meant to be used once to display the final result of executing the given command, but you can use it repeatedly during the execution of the command:

指定された文字列または文字列の配列を成功メッセージとして強調表示します (緑色の背景と [OK] ラベル)。特定のコマンドを実行した最終結果を表示するために 1 回使用することを意図していますが、コマンドの実行中に繰り返し使用できます。
1
2
3
4
5
6
7
8
9
10
// use simple strings for short success messages
$io->success('Lorem ipsum dolor sit amet');

// ...

// consider using arrays when displaying long success messages
$io->success([
    'Lorem ipsum dolor sit amet',
    'Consectetur adipiscing elit',
]);
info()

It's similar to the success() method (the given string or array of strings are displayed with a green background) but the [OK] label is not prefixed. It's meant to be used once to display the final result of executing the given command, without showing the result as a successful or failed one:

これは success() メソッド (指定された文字列または文字列の配列が緑色の背景で表示される) に似ていますが、[OK] ラベルは前に付いていません。成功または失敗した結果としての結果:
1
2
3
4
5
6
7
8
9
10
// use simple strings for short info messages
$io->info('Lorem ipsum dolor sit amet');

// ...

// consider using arrays when displaying long info messages
$io->info([
    'Lorem ipsum dolor sit amet',
    'Consectetur adipiscing elit',
]);
warning()

It displays the given string or array of strings highlighted as a warning message (with a red background and the [WARNING] label). It's meant to be used once to display the final result of executing the given command, but you can use it repeatedly during the execution of the command:

指定された文字列または文字列の配列を警告メッセージとして強調表示します (赤い背景と [WARNING] ラベルを使用)。特定のコマンドを実行した最終結果を表示するために 1 回使用することを意図していますが、コマンドの実行中に繰り返し使用できます。
1
2
3
4
5
6
7
8
9
10
// use simple strings for short warning messages
$io->warning('Lorem ipsum dolor sit amet');

// ...

// consider using arrays when displaying long warning messages
$io->warning([
    'Lorem ipsum dolor sit amet',
    'Consectetur adipiscing elit',
]);
error()

It displays the given string or array of strings highlighted as an error message (with a red background and the [ERROR] label). It's meant to be used once to display the final result of executing the given command, but you can use it repeatedly during the execution of the command:

指定された文字列または文字列の配列がエラー メッセージとして強調表示されます (赤い背景と [ERROR] ラベル)。特定のコマンドを実行した最終結果を表示するために 1 回使用することを意図していますが、コマンドの実行中に繰り返し使用できます。
1
2
3
4
5
6
7
8
9
10
// use simple strings for short error messages
$io->error('Lorem ipsum dolor sit amet');

// ...

// consider using arrays when displaying long error messages
$io->error([
    'Lorem ipsum dolor sit amet',
    'Consectetur adipiscing elit',
]);

Configuring the Default Styles

By default, Symfony Styles wrap all contents to avoid having lines of text that are too long. The only exception is URLs, which are not wrapped, no matter how long they are. This is done to enable clickable URLs in terminals that support them.

デフォルトでは、Symfony スタイルはテキスト行が長すぎるのを避けるためにすべてのコンテンツをラップします。唯一の例外は、長さに関係なくラップされない URL です。これは、それらをサポートする端末でクリック可能な URL を有効にするために行われます。

If you prefer to wrap all contents, including URLs, use this method:

URL を含むすべてのコンテンツをラップする場合は、次の方法を使用します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// src/Command/GreetCommand.php
namespace App\Command;

// ...
use Symfony\Component\Console\Style\SymfonyStyle;

class GreetCommand extends Command
{
    // ...

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $io->getOutputWrapper()->setAllowCutUrls(true);

        // ...
    }
}

6.2

6.2

The setAllowCutUrls() method was introduced in Symfony 6.2.

setAllowCutUrls() メソッドは Symfony 6.2 で導入されました。

Defining your Own Styles

If you don't like the design of the commands that use the Symfony Style, you can define your own set of console styles. Create a class that implements the StyleInterface:

Symfony スタイルを使用するコマンドのデザインが気に入らない場合は、独自のコンソール スタイル セットを定義できます。 theStyleInterface を実装するクラスを作成します。
1
2
3
4
5
6
7
8
namespace App\Console;

use Symfony\Component\Console\Style\StyleInterface;

class CustomStyle implements StyleInterface
{
    // ...implement the methods of the interface
}

Then, instantiate this custom class instead of the default SymfonyStyle in your commands. Thanks to the StyleInterface you won't need to change the code of your commands to change their appearance:

次に、コマンドでデフォルトの SymfonyStyle の代わりにこのカスタム クラスをインスタンス化します。 StyleInterface のおかげで、コマンドのコードを変更して外観を変更する必要はありません。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// src/Command/GreetCommand.php
namespace App\Console;

use App\Console\CustomStyle;
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
    {
        // Before
        $io = new SymfonyStyle($input, $output);

        // After
        $io = new CustomStyle($input, $output);

        // ...
    }
}

Writing to the error output

If you reuse the output of a command as the input of other commands or dump it into a file for later reuse, you probably want to exclude progress bars, notes and other output that provides no real value.

コマンドの出力を他のコマンドの入力として再利用したり、後で再利用するためにファイルにダンプしたりする場合、実際の価値を提供しないプログレス バー、メモ、およびその他の出力を除外することをお勧めします。

Commands can output information in two different streams: stdout (standard output) is the stream where the real contents should be output and stderr (standard error) is the stream where the errors and the debugging messages should be output.

コマンドは、2 つの異なるストリームで情報を出力できます。stdout (標準出力) は、実際の内容が出力されるストリームであり、stderr (標準エラー) は、エラーおよびデバッグ メッセージが出力されるストリームです。

The SymfonyStyle class provides a convenient method called getErrorStyle() to switch between both streams. This method returns a new SymfonyStyle instance which makes use of the error output:

SymfonyStyle クラスは、両方のストリームを切り替える getErrorStyle() と呼ばれる便利なメソッドを提供します。このメソッドは、エラー出力を利用する新しい SymfonyStyle インスタンスを返します。
1
2
3
4
5
6
7
$io = new SymfonyStyle($input, $output);

// Write to the standard output
$io->write('Reusable information');

// Write to the error output
$io->getErrorStyle()->warning('Debugging information or errors');

Note

ノート

If you create a SymfonyStyle instance with an OutputInterface object that is not an instance of ConsoleOutputInterface, the getErrorStyle() method will have no effect and the returned object will still write to the standard output instead of the error output.

ConsoleOutputInterface のインスタンスではない OutputInterface オブジェクトで SymfonyStyle インスタンスを作成した場合、getErrorStyle() メソッドは効果がなく、返されたオブジェクトはエラー出力ではなく標準出力に書き込まれます。