Таблица

Дата обновления перевода 2023-01-20

Таблица

При построении приложения консоли может быть полезным отображать данные в табличном виде:

1
2
3
4
5
6
7
8
+---------------+--------------------------+------------------+
| ISBN          | Название                 | Автор            |
+---------------+--------------------------+------------------+
| 99921-58-10-7 | Божественная комедия     | Данте Алигьери   |
| 9971-5-0210-0 | Рассказ о двух городах   | Чарльз Дикенс    |
| 960-425-059-0 | Властелин колец          | Дж. Р. Р. Толкиен|
| 80-902734-1-6 | И никого не стало        | Агата Кристи     |
+---------------+--------------------------+------------------+

Чтобы отобразить таблицу, используйте Table, чтобы установить заголовки, установить ряды, а потом отобразить таблицу:

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
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
// ...

class SomeCommand extends Command
{
    public function execute(InputInterface $input, OutputInterface $output): int
    {
        $table = new Table($output);
        $table
            ->setHeaders(['ISBN', 'Title', 'Author'])
            ->setRows([
                ['99921-58-10-7', 'Божественная комедия', 'Данте Алигьери'],
                ['9971-5-0210-0', 'Рассказ о двух городах', 'Чарльз Дикенс'],
                ['960-425-059-0', 'Властелин колец', 'Дж. Р. Р. Толкиен'],
                ['80-902734-1-6', 'И никого не стало', 'Агата Кристи'],
            ])
        ;
        $table->render();
        
        return Command::SUCCESS;
    }
}

Вы можете добавлять разделитель таблицы где-угодно в выводе, передав экземпляр TableSeparator в качестве строки:

1
2
3
4
5
6
7
8
9
use Symfony\Component\Console\Helper\TableSeparator;

$table->setRows([
    ['99921-58-10-7', 'Божественная комедия', 'Данте Алигьери'],
    ['9971-5-0210-0', 'Рассказ о двух городах', 'Чарльз Дикенс'],
    new TableSeparator(),
    ['960-425-059-0', 'Властелин колец', 'Дж. Р. Р. Толкиен'],
    ['80-902734-1-6', 'И никого не стало', 'Агата Кристи'],
]);
1
2
3
4
5
6
7
8
9
+---------------+--------------------------+------------------+
| ISBN          | Название                 | Автор            |
+---------------+--------------------------+------------------+
| 99921-58-10-7 | Божественная комедия     | Данте Алигьери   |
| 9971-5-0210-0 | Рассказ о двух городах   | Чарльз Дикенс    |
+---------------+--------------------------+------------------+
| 960-425-059-0 | Властелин колец          | Дж. Р. Р. Толкиен|
| 80-902734-1-6 | И никого не стало        | Агата Кристи     |
+---------------+--------------------------+------------------+

По желани, вы можете отобразитьь названия сверху и снизу таблицы:

1
2
3
4
// ...
$table->setHeaderTitle('Books');
$table->setFooterTitle('Page 1/2');
$table->render();
1
2
3
4
5
6
7
8
9
+---------------+----------- Книги --------+-------------------+
| ISBN          | Название                 | Автор             |
+---------------+--------------------------+-------------------+
| 99921-58-10-7 | Божественная комедия     | Данте Алигьери    |
| 9971-5-0210-0 | Рассказ о двух городах   | Чарльз Дикенс     |
+---------------+--------------------------+-------------------+
| 960-425-059-0 | Властелин колец          | Дж. Р. Р. Толкиен |
| 80-902734-1-6 | И никого не стало        | Агата Кристи      |
+---------------+--------- Страница 1/2 -------+-------------------+

По умолчанию, ширина столбцов вычисляется автоматически, основываясь на их содержании. Используйте метод setColumnWidths(), чтобы ясно установить ширину столбцов:

1
2
3
// ...
$table->setColumnWidths([10, 0, 30]);
$table->render();

В этом примере, ширина первого столбца будет 10, последнего - 30, а ширина второго будет вычисляться автоматически, в связи со значением 0.

Вы также можете устанавливать ширину индивидуально для каждого столбца с помощью метода setColumnWidth(). Его первый аргумент - индекс столбца (начинающийся с 0), а второй аргумент - ширина столбца:

1
2
3
4
// ...
$table->setColumnWidth(0, 10);
$table->setColumnWidth(2, 30);
$table->render();

Вывод этой команды будет:

1
2
3
4
5
6
7
8
9
+---------------+--------------------------+--------------------------------+
| ISBN          | Название                 | Автор                          |
+---------------+--------------------------+--------------------------------+
| 99921-58-10-7 | Божественная комедия     | Данте Алигьери                 |
| 9971-5-0210-0 | Рассказ о двух городах   | Чарльз Дикенс                  |
+---------------+--------------------------+--------------------------------+
| 960-425-059-0 | Властелин колец          | Дж. Р. Р. Толкиен              |
| 80-902734-1-6 | И никого не стало        | Агата Кристи                   |
+---------------+--------------------------+--------------------------------+

Заметьте, что определённая ширина столбцов всегда воспринимается, как минимальная ширина столбца. Если содержание не помещается, заданная ширина будет увеличена до максимальной длины содержания. Поэтому в предыдущем примере первый столбец имеет ширину в 13 знаков, хотя пользователь определил 10.

Если вы предпочитаете оборачивать длинное содержание в несколько рядов, используйте метод setColumnMaxWidth():

1
2
3
4
// ...
$table->setColumnMaxWidth(0, 5);
$table->setColumnMaxWidth(1, 10);
$table->render();

Вывод этой коменды будет:

1
2
3
4
5
6
7
8
+-------+------------+--------------------------------+
| ISBN  | Название   | Автор                          |
+-------+------------+--------------------------------+
| 99921 | Божественн | Данте Алигьери                 |
| -58-1 | ая комедия |                                |
| 0-7   |            |                                |
|                (остальные ряды...)                  |
+-------+------------+--------------------------------+

По умолчанию, содержание таблицы отображается горизонтально. Вы можете изменить это поведение через метод setVertical():

1
2
3
// ...
$table->setVertical();
$table->render();

Вывод этой команды будет:

1
2
3
4
5
6
7
8
9
+-----------------------------------+
|      ISBN: 99921-58-10-7          |
|  Название: Божественная комедия   |
|     Автор: Данте Алигьери         |
+-----------------------------------+
|      ISBN: 9971-5-0210-0          |
|  Название: Рассказ о двух городах |
|     Автор: Чарльз Дикенс          |
+-----------------------------------+

6.1

Поддержка вертикального отображения была представлена в Symfony 6.1.

Стиль таблицы может быть изменён на любой встроенный стиль через setStyle():

1
2
3
4
5
6
// то же самое, что ничего не вызывать
$table->setStyle('default');

// изменяет стиль по умолчанию на компактный
$table->setStyle('compact');
$table->render();

Этот код приводит к:

1
2
3
4
5
ISBN          Название                 Автор
99921-58-10-7 Божественная комедия     Данте Алигьери
9971-5-0210-0 Рассказ о двух городах   Чарльз Дикенс
960-425-059-0 Властелин колец          Дж. Р. Р. Толкиен
80-902734-1-6 И никого не стало        Агата Кристи

Вы также можете установить стиль borderless:

1
2
$table->setStyle('borderless');
$table->render();

Что выведет:

1
2
3
4
5
6
7
8
=============== ========================== ==================
 ISBN            Название                   Автор
=============== ========================== ==================
 99921-58-10-7   Божественная комедия       Данте Алигьери
 9971-5-0210-0   Рассказ о двух городах     Чарльз Дикенс
 960-425-059-0   Властелин колец            Дж. Р. Р. Толкиен
 80-902734-1-6   И никого не стало          Агата Кристи
=============== ========================== ==================

Вы также можете установить стиль box:

1
2
$table->setStyle('box');
$table->render();

Что выведет:

1
2
3
4
5
6
7
8
┌───────────────┬──────────────────────────┬──────────────────┐
│ ISBN          │ Название                 │ Автор            │
├───────────────┼──────────────────────────┼──────────────────┤
│ 99921-58-10-7 │ Божественная комедия     │ Данте Алигьери   │
│ 9971-5-0210-0 │ Рассказ о двух городах   │ Чарльз Дикенс    │
│ 960-425-059-0 │ Властелин колец          │ Дж. Р. Р. Толкиен│
│ 80-902734-1-6 │ И никого не стало        │ Агата Кристи     │
└───────────────┴──────────────────────────┴──────────────────┘

Вы также можете установить стиль box-double:

1
2
$table->setStyle('box-double');
$table->render();

Что выведет:

1
2
3
4
5
6
7
8
╔═══════════════╤══════════════════════════╤══════════════════╗
║ ISBN          │ Название                 │ Автор            ║
╠═══════════════╪══════════════════════════╪══════════════════╣
║ 99921-58-10-7 │ Божественная комедия     │ Данте Алигьери   ║
║ 9971-5-0210-0 │ Рассказ о двух городах   │ Чарльз Дикенс    ║
║ 960-425-059-0 │ Властелин колец          │ Дж. Р. Р. Толкиен║
║ 80-902734-1-6 │  И никого не стало       │ Агата Кристи     ║
╚═══════════════╧══════════════════════════╧══════════════════╝

Если встроенные стили не соответствуют вашим нуждам, определите свой собственный:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use Symfony\Component\Console\Helper\TableStyle;

// по умолчанию, базируется на стиле по умолчанию
$tableStyle = new TableStyle();

// настраивает стиль
$tableStyle
    ->setDefaultCrossingChars('<fg=magenta>|</>')
    ->setVerticalBorderChars('<fg=magenta>-</>')
    ->setDefaultCrossingChar(' ')
;

// использует стиль по умолчанию для этой таблицы
$table->setStyle($tableStyle);

Вот полный список того, что вы можете настроить:

Tip

Вы также можете зарегистрировать стиль глобально:

1
2
3
4
5
// регистрирует стиль под цветным названием
Table::setStyleDefinition('colorful', $tableStyle);

// применяет пользовательский стиль для заданной таблицы
$table->setStyle('colorful');

Этот метод также может быть использован для переопределения встроенного стиля.

В дополнение к встроенным стилям таблицы, вы можете также применять разные стили к каждой ячейке таблицы через TableCellStyle:

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
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableCellStyle;

$table = new Table($output);

$table->setRows([
    [
        '978-0804169127',
        new TableCell(
            'Divine Comedy',
            [
                'style' => new TableCellStyle([
                    'align' => 'center',
                    'fg' => 'red',
                    'bg' => 'green',

                    // or
                    'cellFormat' => '<info>%s</info>',
                ])
            ]
        )
    ],
]);

$table->render();

Объединение нескольких столбцов и строк

Чтобы сделать ячейку таблицы, объединяющую несколько столбцов, вы можете использовать TableCell:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableCell;
use Symfony\Component\Console\Helper\TableSeparator;

$table = new Table($output);
$table
    ->setHeaders(['ISBN', 'Title', 'Author'])
    ->setRows([
        ['99921-58-10-7', 'Божественная комедия', 'Данте Алигьери'],
        new TableSeparator(),
        [new TableCell('This value spans 3 columns.', ['colspan' => 3])],
    ])
;
$table->render();

Это приводит к:

1
2
3
4
5
6
7
+---------------+----------------------+-----------------+
| ISBN          | Название             | Автор           |
+---------------+----------------------+-----------------+
| 99921-58-10-7 | Божественная комедия | Данте Алигьери  |
+---------------+----------------------+-----------------+
| Это значение объединяет 3 столбца.                     |
+---------------+----------------------+-----------------+

Tip

Вы можете создать название страницы в несколько строк, используя ячейку, объединяющую всю ширину таблицы:

1
2
3
4
5
$table->setHeaders([
    [new TableCell('Название главной таблицы', ['colspan' => 3])],
    ['ISBN', 'Title', 'Author'],
]);
// ...

Это генерирует:

1
2
3
4
5
6
7
+-------+----------+--------+
| Название главной таблицы  |
+-------+----------+--------+
| ISBN  | Название | Автор  |
+-------+----------+--------+
| ...                       |
+-------+----------+--------+

Схожим образом вы можете объединять несколько рядов:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableCell;

$table = new Table($output);
$table
    ->setHeaders(['ISBN', 'Title', 'Author'])
    ->setRows([
        [
            '978-0521567817',
            'Монархия',
            new TableCell("Данте Алигьери\nspans multiple rows", array('rowspan' => 2)),
        ],
        ['978-0804169127', 'Божественная комедия'],
    ])
;
$table->render();

Это выводит:

1
2
3
4
5
6
+----------------+----------------------+----------------------------+
| ISBN           | Название             | Автор                      |
+----------------+----------------------+----------------------------+
| 978-0521567817 | Монархия             | Данте Алигьери             |
| 978-0804169127 | Божественная комедия | объединяет несколько строк |
+----------------+----------------------+----------------------------+

Вы можете использовать опции colspan и rowspan одновременно, что позволяет вам создавать любой желаемый макет таблицы.

Изменение отображённых таблиц

Метод render() требует передачи всего содержания таблицы. Однако, иногда эта информация недоступна заранее, так как она генерируется динамически. В таких случаях, используйте метод appendRow(), который берёт те же аргументы, что и метод addRow(), чтобы добавить ряды внизу уже отображённой таблицы.

Единственным требованием для добавления рядов является отображение таблицы внутри Раздела вывода Console :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use Symfony\Component\Console\Helper\Table;
// ...

class SomeCommand extends Command
{
    public function execute(InputInterface $input, OutputInterface $output): int
    {
        $section = $output->section();
        $table = new Table($section);

        $table->addRow(['Love']);
        $table->render();

        $table->appendRow(['Symfony']);
        
        return Command::SUCCESS;
    }
}

Это отобразит следующую таблицу в терминале:

1
2
3
4
+---------+
| Love    |
| Symfony |
+---------+