fi1a/console

PHP 控制台命令。参数、选项和格式化

2.2.2 2023-02-21 02:08 UTC

This package is auto-updated.

Last update: 2024-09-21 05:40:31 UTC


README

Latest Version Software License PHP Version Coverage Status Total Downloads Support mail

PHP 实现控制台命令和文本美化格式的库。

功能

  • 命令自动支持 --help 来输出帮助信息;
  • 支持一个或多个命令;
  • 可以在命令中将传递的参数和选项值进行验证(检查);
  • 控制台中的颜色格式化;
  • 实现表格、列表、树等组件;

安装

可以使用 Composer 将此包作为依赖项安装。

composer require fi1a/console

依赖注入

来自包 fi1a/dependency-injection 的依赖注入容器

在依赖注入容器中,接口可用以下定义

  • Fi1a\Console\IO\InputArgumentsInterface;
  • Fi1a\Console\IO\FormatterInterface;
  • Fi1a\Console\IO\ConsoleOutputInterface;
  • Fi1a\Console\IO\InputInterface;
  • Fi1a\Console\IO\InteractiveInputInterface;
  • Fi1a\Console\Component\GroupComponent\GroupStyleInterface;
  • Fi1a\Console\Component\GroupComponent\GroupComponentInterface;
  • Fi1a\Console\Component\ListComponent\ListStyleInterface;
  • Fi1a\Console\Component\ListComponent\ListComponentInterface;
  • Fi1a\Console\Component\PaginationComponent\PaginationStyleInterface;
  • Fi1a\Console\Component\PaginationComponent\PaginationComponentInterface;
  • Fi1a\Console\Component\PanelComponent\PanelStyleInterface;
  • Fi1a\Console\Component\PanelComponent\PanelComponentInterface;
  • Fi1a\Console\Component\ProgressbarComponent\ProgressbarStyleInterface;
  • Fi1a\Console\Component\ProgressbarComponent\ProgressbarComponentInterface;
  • Fi1a\Console\Component\SpinnerComponent\SpinnerStyleInterface;
  • Fi1a\Console\Component\SpinnerComponent\SpinnerComponentInterface;
  • Fi1a\Console\Component\TableComponent\TableStyleInterface;
  • Fi1a\Console\Component\TableComponent\TableComponentInterface;
  • Fi1a\Console\Component\TreeComponent\TreeStyleInterface;
  • Fi1a\Console\Component\TreeComponent\TreeComponentInterface;
di()->get(Fi1a\Console\IO\ConsoleOutputInterface::class)->writeln('Вывод в консоль');

使用

控制台中的命令、参数和选项

Fi1a\Console\App 提供了一个方便的接口来添加命令和启动应用程序。

命令

命令应该实现接口 Fi1a\Console\CommandInterface。以下是一个简单命令的示例。

declare(strict_types=1);

namespace Foo\Bar;

/**
 * Простая команда
 */
class BazCommand extends AbstractCommand
{
    /**
     * @inheritDoc
     */
    public function __construct(DefinitionInterface $definition)
    {
        $definition->addOption('time', 't')
            ->default(false)
            ->description('Вывод времени.')
            ->validation()
            ->allOf()
            ->boolean();

        $definition->addArgument('format')
            ->default('H:i:s')
            ->description('Формат вывода времени.');
    }

    /**
     * @inheritDoc
     */
    public function run(
        InputArgumentsInterface $input,
        ConsoleOutputInterface $output,
        InputInterface $stream,
        DefinitionInterface $definition,
        AppInterface $app
    ): int {
        $output->writeln('<option=bold>Пример команды</>');
        
        if ($definition->getOption('time')->getValue()) {
            $output->writeln(
                '<success>Серверное время: <option=bold>{{time}}</></success>',
                ['time' => date($definition->getArgument('format')->getValue())]
            );
        }
        
        return 0;
    }

    /**
     * @inheritDoc
     */
    public function description(): ?string
    {
        return 'Тестовая команда baz.';
    }
}

在这个例子中,我们在命令的构造函数中添加了选项 time 和参数 format。启动命令后,会检查是否传入了 time 选项,如果传入,则输出指定格式 format 的服务器时间。如果没有传入格式,方法 getValue 将通过方法 default 返回默认值。

Запуск команды

run 方法,在命令启动时作为参数传递

  • InputArgumentsInterface $input - 输入参数和选项;
  • ConsoleOutputInterface $output - 控制台输出;
  • InputInterface $stream - 控制台输入流;
  • DefinitionInterface $definition - 访问声明的参数和选项;
  • AppInterface $app - Fi1a\Console\App 类的实例,该实例触发了该命令。

使用选项和参数

run 方法中传递的 DefinitionInterface $definition 对象,可以用来访问选项和参数的值。

$definition->getOption('time')->getValue();
$definition->getArgument('format')->getValue();
  • 选项通过 --name=value 完整名称或 -s value 短代码传递;
  • 参数作为字符串传递,由空格分隔。

启动控制台应用程序

要使用应用程序,需要调用方法 run。方法 run 执行以下操作

  • 分析 $argv 参数以确定命令;
  • 验证选项和参数;
  • 配置命令;
  • 执行命令。

启动一个特定命令。以下代码将启动命令 \Foo\Bar\BazCommand

declare(strict_types=1);

use Fi1a\Console\App;

$code = (new App())
    ->run(\Foo\Bar\BazCommand::class);

exit($code);

启动多个命令,在第一个参数中指定。如果第一个参数是命令的名称 php foo.php qux,则将启动命令 \Foo\Bar\QuxCommand

declare(strict_types=1);

use Fi1a\Console\App;

$code = (new App())
    ->addCommand('baz', \Foo\Bar\BazCommand::class)
    ->addCommand('qux', \Foo\Bar\QuxCommand::class)
    ->run();

exit($code);

命令列表

调用没有参数或仅带参数 info 的脚本,将显示可用命令列表。示例

php foo.phpphp foo.php info

Список команд

命令描述来自 description 方法的返回值。

显示帮助信息

如果调用带参数 --help 的命令(php foo.php baz --help),可以查看以下命令帮助信息

Отображение справки

命令描述来自 description 方法的返回值。

显示错误信息

假设你调用示例 php foo.php baz -t j

$definition->addOption('time', 't')
    ->default(false)
    ->description('Вывод времени.')
    ->validation()
    ->allOf()
    ->boolean();
    
$definition->addArgument('format')
    ->default('H:i:s')
    ->description('Формат вывода времени.');

将看到以下错误信息

Сообщения об ошибках

验证通过包 fi1a/validation 实现。所有验证规则均可用。

$definition->addOption('option1')
    ->validation()
    ->allOf()
    ->required()
    ->min(10)
    ->max(20);

$argument = $definition->addArgument('argument1')
    ->multiple();

$argument->multipleValidation()
    ->allOf()
    ->array()
    ->required()
    ->minCount(2);

$argument->validation()
    ->allOf()
    ->required()
    ->min(10)
    ->max(20);
  • validation 方法 - 验证单个值的规则;
  • multipleValidation 方法 - 验证多个值的规则。

格式化

颜色方案(控制台颜色板)

提供三种颜色方案

  • ANSI(4位颜色);
  • 扩展(8位颜色);
  • 真彩色(1670万)。

启动示例以显示颜色板

php examples/examples.php colors

Пример с отображением палитры цветов

控制台输出

使用控制台输出中的颜色,您可以格式化不同的输出类型(错误、标题、注释等)。

使用颜色样式

在输出时可以使用标签来着色显示的文本。

...

/**
 * @inheritDoc
 */
public function run(
    InputArgumentsInterface $input,
    ConsoleOutputInterface $output,
    InputInterface $stream,
    DefinitionInterface $definition,
    AppInterface $app
): int {
    $output->writeln('<info>foo</info>');
    $output->writeln('<error>bar</error>');
    $output->writeln('<success>baz<info>qux</info></success>');
}

...

使用容器的示例

use Fi1a\Console\IO\ConsoleOutputInterface;

$output = di()->get(ConsoleOutputInterface::class);

$output->writeln('<info>foo</info>');
$output->writeln('<error>bar</error>');
$output->writeln('<success>baz<info>qux</info></success>');

以下为预定义样式

  • error;
  • success;
  • info;
  • comment;
  • question;
  • notice.

可以使用 Fi1a\Console\IO\Formatter 类的 addStyle 方法定义自己的样式。

use Fi1a\Console\IO\Formatter;
use Fi1a\Console\IO\Style\TrueColor;
use Fi1a\Console\IO\Style\TrueColorStyle;

Formatter::addStyle('error', new TrueColorStyle(TrueColor::WHITE, TrueColor::RED));

TrueColor 方案支持任何十六进制颜色。此外,还支持通过 Fi1a\Console\IO\Style\ColorInterface 接口常量定义的命名颜色(ColorInterface::BLACKColorInterface::REDColorInterface::GREEN 等)。

如果终端不支持 TrueColor 或扩展,则使用最近的 ANSI 颜色。

提供格式化参数:blink、bold、conceal、reverse、underscore。您可以直接在标签内设置颜色、背景和参数。支持样式嵌套。

...

/**
 * @inheritDoc
 */
public function run(
    InputArgumentsInterface $input,
    ConsoleOutputInterface $output,
    InputInterface $stream,
    DefinitionInterface $definition,
    AppInterface $app
): int {
    $output->writeln('<color=black>foo</>');
    $output->writeln('<bg=white;color=black>bar</>');
    $output->writeln('<color=red>baz<option=bold,underscore>qux</></>');
}

...

启动示例以显示格式化输出

php examples/examples.php output

Пример форматированного вывода в консоль

控制台流输入

通过类 InputInterface $streamread 方法读取(输入)控制台。

...

/**
 * @inheritDoc
 */
public function run(
    InputArgumentsInterface $input,
    ConsoleOutputInterface $output,
    InputInterface $stream,
    DefinitionInterface $definition,
    AppInterface $app
): int {
    $value = $stream->read('y');
}

...

使用容器的示例

use Fi1a\Console\IO\InputInterface;

$stream = di()->get(InputInterface::class);

$value = $stream->read('y');

控制台交互输入

使用类 Fi1a\Console\IO\InteractiveInput,可以添加要读取的控制台值,并访问输入的值。使用 addValue 方法添加要读取的控制台值。与参数和选项一样,可以访问来自包 fi1a/validation 的值验证器。

use Fi1a\Console\IO\InteractiveInput;

...

/**
 * @inheritDoc
 * @psalm-suppress PossiblyFalseReference
 * @psalm-suppress MixedMethodCall
 */
public function run(
    InputArgumentsInterface $input,
    ConsoleOutputInterface $output,
    InputInterface $stream,
    DefinitionInterface $definition,
    AppInterface $app
): int {
    $output->writeln(['', '<option=bold>Интерактивный ввод</>', '']);

    $interactive = new InteractiveInput($output, $stream);

    $interactive->addValue('foo')
        ->description('Введите количество от 1 до 10')
        ->validation()
        ->allOf()
        ->min(1)
        ->max(10);

    $bar = $interactive->addValue('bar')
        ->description('Введите строки длиной от 2-х символов')
        ->multiple();

    $bar->multipleValidation()
        ->allOf()
        ->minCount(1)
        ->required();

    $bar->validation()
        ->allOf()
        ->minLength(2);

    $interactive->addValue('baz')
        ->description('Согласны (y/n)')
        ->validation()
        ->allOf()
        ->boolean();

    $interactive->read();

    // Доступ к введенным значениям
    $output->writeln((string) $interactive->getValue('foo')->getValue());
    $output->writeln((string) count((array) $interactive->getValue('bar')->getValue()));
    $output->writeln((string) $interactive->getValue('baz')->getValue());

    return 0;
}

...

使用容器的示例

use Fi1a\Console\IO\ConsoleOutputInterface;
use Fi1a\Console\IO\InteractiveInputInterface;

$output  = di()->get(ConsoleOutputInterface::class);
$interactive = di()->get(InteractiveInputInterface::class);

$output->writeln(['', '<option=bold>Интерактивный ввод</>', '']);

$interactive->addValue('foo')
    ->description('Введите количество от 1 до 10')
    ->validation()
    ->allOf()
    ->min(1)
    ->max(10);

$bar = $interactive->addValue('bar')
    ->description('Введите строки длиной от 2-х символов')
    ->multiple();

$bar->multipleValidation()
    ->allOf()
    ->minCount(1)
    ->required();

$bar->validation()
    ->allOf()
    ->minLength(2);

$interactive->addValue('baz')
    ->description('Согласны (y/n)')
    ->validation()
    ->allOf()
    ->boolean();

$interactive->read();

// Доступ к введенным значениям
$output->writeln((string) $interactive->getValue('foo')->getValue());
$output->writeln((string) count((array) $interactive->getValue('bar')->getValue()));
$output->writeln((string) $interactive->getValue('baz')->getValue());

启动示例以进行交互式输入

php examples/examples.php interactive

Интерактивный ввод

组件

面板组件

要绘制文本周围的边框或设置对齐方式,请使用 Fi1a\Console\Component\PanelComponent\PanelComponent。面板组件可以嵌套。

use Fi1a\Console\Component\PanelComponent\PanelComponent;
use Fi1a\Console\Component\PanelComponent\PanelStyle;
use Fi1a\Console\Component\PanelComponent\PanelStyleInterface;
use Fi1a\Console\IO\Style\ColorInterface;

...

/**
 * @inheritDoc
 */
public function run(
    InputArgumentsInterface $input,
    ConsoleOutputInterface $output,
    InputInterface $stream,
    DefinitionInterface $definition,
    AppInterface $app
): int {
    $panelStyle = new PanelStyle();

    $panelStyle->setWidth(40)
        ->setPadding(1)
        ->setBorder('heavy')
        ->setBackgroundColor(ColorInterface::YELLOW)
        ->setBorderColor(ColorInterface::RED)
        ->setColor(ColorInterface::BLACK)
        ->setAlign(PanelStyleInterface::ALIGN_CENTER);

    $panel = new PanelComponent(
        $output,
        'Lorem ipsum dolor sit amet, <error>consectetur adipiscing elit</error>, '
        . 'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
        $panelStyle
    );

    $panel->display();

    return 0;
}

...

使用容器的示例

use Fi1a\Console\Component\PanelComponent\PanelComponentInterface;
use Fi1a\Console\Component\PanelComponent\PanelStyleInterface;
use Fi1a\Console\IO\Style\ColorInterface;

$panel = di()->get(PanelComponentInterface::class);
$panelStyle = $panel->getStyle();

$panelStyle->setWidth(40)
    ->setPadding(1)
    ->setBorder('heavy')
    ->setBackgroundColor(ColorInterface::YELLOW)
    ->setBorderColor(ColorInterface::RED)
    ->setColor(ColorInterface::BLACK)
    ->setAlign(PanelStyleInterface::ALIGN_CENTER);

$panel->setText('Lorem ipsum dolor sit amet, <error>consectetur adipiscing elit</error>, '
    . 'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.');

$panel->display();

启动示例以显示面板

php examples/examples.php panel

Панели

可以通过设置以下值之一来更改面板边框样式

  • ascii;
  • double;
  • heavy;
  • horizontals;
  • rounded.

启动示例以显示面板边框样式

php examples/examples.php panel-borders

Стили границ панели

可以使用 Fi1a\Console\Component\PanelComponent\BorderRegistry 类的 add 方法定义自己的边框样式。边框样式类必须实现 Fi1a\Console\Component\PanelComponent\BorderInterface 接口。

use Fi1a\Console\Component\PanelComponent\AsciiBorder;
use Fi1a\Console\Component\PanelComponent\BorderRegistry;

BorderRegistry::add(
    'ascii',
    new AsciiBorder()
);

组组件

要使面板具有相同的宽度和在同一行上排列,可以使用组组件。

use Fi1a\Console\Component\GroupComponent\GroupComponent;
use Fi1a\Console\Component\GroupComponent\GroupStyle;
use Fi1a\Console\Component\PanelComponent\PanelComponent;
use Fi1a\Console\Component\PanelComponent\PanelStyle;

...

/**
 * @inheritDoc
 */
public function run(
    InputArgumentsInterface $input,
    ConsoleOutputInterface $output,
    InputInterface $stream,
    DefinitionInterface $definition,
    AppInterface $app
): int {
    $groupStyle = new GroupStyle(40);
    $groupStyle->setPanelSpacing(2);
    $group = new GroupComponent($output, $groupStyle);

    $panelStyle = new PanelStyle();
    $panelStyle->setBorder('heavy')
        ->setPadding(1);

    $panel1 = new PanelComponent(
        $output,
        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, '
        . 'sed do eiusmod tempor incididunt ut '
        . 'labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris '
        . 'nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit '
        . 'in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat '
        . 'non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
        $panelStyle
    );
    $panel2 = new PanelComponent(
        $output,
        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, '
        . 'sed do eiusmod tempor incididunt ut '
        . 'labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris '
        . 'nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit '
        . 'in voluptate velit esse cillum dolore eu fugiat nulla pariatur.',
        $panelStyle
    );
    $panel3 = new PanelComponent(
        $output,
        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, '
        . 'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
        $panelStyle
    );

    $group->addPanel($panel1);
    $group->addPanel($panel2);
    $group->addPanel($panel3);

    $group->display();
        
    return 0;
}

...

使用容器的示例

use Fi1a\Console\Component\GroupComponent\GroupComponentInterface;
use Fi1a\Console\Component\PanelComponent\PanelComponentInterface;
use Fi1a\Console\Component\PanelComponent\PanelStyleInterface;

$group = di()->get(GroupComponentInterface::class);

$group->getStyle()->setPanelSpacing(2);

$panelStyle = di()->get(PanelStyleInterface::class);
$panelStyle->setBorder('heavy')
    ->setPadding(1);

$panel1 = di()->get(PanelComponentInterface::class);

$panel1->setStyle($panelStyle);
$panel1->setText('Lorem ipsum dolor sit amet, consectetur adipiscing elit, '
    . 'sed do eiusmod tempor incididunt ut '
    . 'labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris '
    . 'nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit '
    . 'in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat '
    . 'non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.');

$panel2 = di()->get(PanelComponentInterface::class);

$panel2->setStyle($panelStyle);
$panel2->setText('Lorem ipsum dolor sit amet, consectetur adipiscing elit, '
    . 'sed do eiusmod tempor incididunt ut '
    . 'labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris '
    . 'nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit '
    . 'in voluptate velit esse cillum dolore eu fugiat nulla pariatur.');

$panel3 = di()->get(PanelComponentInterface::class);

$panel3->setStyle($panelStyle);
$panel3->setText('Lorem ipsum dolor sit amet, consectetur adipiscing elit, '
    . 'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.');

$group->addPanel($panel1);
$group->addPanel($panel2);
$group->addPanel($panel3);

$group->display();

启动示例以显示面板组

php examples/examples.php group

Группа панелей

列表组件

用于显示列表的组件为 Fi1a\Console\Component\ListComponent\ListComponent。支持嵌套列表。

use Fi1a\Console\Component\ListComponent\ListComponent;
use Fi1a\Console\Component\ListComponent\ListStyle;
use Fi1a\Console\Component\ListComponent\ListStyleInterface;
use Fi1a\Console\IO\Style\ColorInterface;

...

/**
 * @inheritDoc
 */
public function run(
    InputArgumentsInterface $input,
    ConsoleOutputInterface $output,
    InputInterface $stream,
    DefinitionInterface $definition,
    AppInterface $app
): int {
    $listStyle = new ListStyle();
    $listStyle->setType('upper-alpha')
        ->setMarkerColor(ColorInterface::GREEN);

    $subListStyle = new ListStyle();
    $subListStyle->setType('lower-alpha')
        ->setMarkerColor(ColorInterface::RED)
        ->setPosition(ListStyleInterface::POSITION_OUTSIDE);

    $subList = new ListComponent($output, $subListStyle);

    $subList->addItem('Lorem ipsum dolor sit amet');
    $subList->addItem('Consectetur adipiscing elit');

    $list = new ListComponent($output, $listStyle);

    $list->addItem('Lorem ipsum dolor sit amet');
    $list->addItem('Consectetur adipiscing elit');
    $list->addItem($subList);
    $list->addItem('Sed do eiusmod tempor incididunt');
    $list->addItem('Duis aute irure dolor in reprehenderit');
    $list->addItem('Reprehenderit in voluptate velit');

    $list->display();
    
    return 0;
}

...

使用容器的示例

use Fi1a\Console\Component\ListComponent\ListComponentInterface;
use Fi1a\Console\Component\ListComponent\ListStyleInterface;
use Fi1a\Console\IO\Style\ColorInterface;

$subList = di()->get(ListComponentInterface::class);

$subList->getStyle()
    ->setType('lower-alpha')
    ->setMarkerColor(ColorInterface::RED)
    ->setPosition(ListStyleInterface::POSITION_OUTSIDE);

$subList->addItem('Lorem ipsum dolor sit amet');
$subList->addItem('Consectetur adipiscing elit');

$list = di()->get(ListComponentInterface::class);

$list->getStyle()
    ->setType('upper-alpha')
    ->setMarkerColor(ColorInterface::GREEN);

$list->addItem('Lorem ipsum dolor sit amet');
$list->addItem('Consectetur adipiscing elit');
$list->addItem($subList);
$list->addItem('Sed do eiusmod tempor incididunt');
$list->addItem('Duis aute irure dolor in reprehenderit');
$list->addItem('Reprehenderit in voluptate velit');

$list->display();

可以使用列表样式类的 setType 方法设置标记类型。

以下为支持的标记类型

  • upper-alpha - 大写字母列表 (A, B, C, D, E, …);
  • square - 用作标记的是正方形;
  • lower-alpha - 小写字母列表 (a, b, c, d, e, …);
  • decimal-leading-zero - 带前导零的序号 (01, 02, 03, 04, 05, …);
  • decimal - 序号 (1, 2, 3, 4, 5, …);
  • circle - 用作标记的是空心圆圈;
  • disc - 用作列表元素的标记的是实心圆圈。

启动列表示例

php examples/examples.php list

Списки в консоли php

可以使用 Fi1a\Console\Component\ListComponent\ListTypeRegistry 类的 add 方法定义自己的列表标记类型。列表标记类型类必须实现 Fi1a\Console\Component\ListComponent\ListTypeInterface 接口。

use Fi1a\Console\Component\ListComponent\ListTypeRegistry;
use Fi1a\Console\Component\ListComponent\UpperAlphaListType;

ListTypeRegistry::add('upper-alpha', new UpperAlphaListType());

分页导航组件

如果需要分页显示输出,可以使用分页导航组件。

示例

use Fi1a\Console\Component\PaginationComponent\PaginationComponent;
use Fi1a\Console\Component\PaginationComponent\PaginationStyle;
use Fi1a\Console\Component\TableComponent\TableComponent;
use Fi1a\Console\Component\TableComponent\TableStyle;

...

/**
 * @inheritDoc
 */
public function run(
    InputArgumentsInterface $input,
    ConsoleOutputInterface $output,
    InputInterface $stream,
    DefinitionInterface $definition,
    AppInterface $app
): int {
    $data = [
        ['Смартфон', '1000', '2', '2000'],
        ['Шкаф', '500', '1', '500'],
        ['Электробритва', '300', '5', '1500'],
        ['Станок', '200', '1', '200'],
        ['Диван', '1200', '1', '1200'],
        ['Кровать', '100', '2', '200'],
        ['Кресло', '300', '3', '900'],
        ['Шифанер', '150', '1', '150'],
        ['Стул', '50', '4', '200'],
        ['Стол', '100', '1', '100'],
    ];

    $tableStyle = new TableStyle();
    $table = new TableComponent($output, $tableStyle);
    $table->setHeaders(['Товар', 'Стоимость', 'Количество', 'Итоговая сумма']);
    $paginationStyle = new PaginationStyle();

    $pagination = new PaginationComponent($output, $stream, $paginationStyle);
    $pagination->setCount((int) ceil(count($data) / 3));
    $page = 1;
    do {
        $rows = array_slice($data, ($page - 1) * 3, 3);
        $table->setRows($rows);
        $table->display();
        $pagination->display();
        $page = $pagination->getCurrent();
    } while ($pagination->isValid());

    $output->writeln('');

    return 0;
}

...

使用容器的示例

use Fi1a\Console\Component\PaginationComponent\PaginationComponentInterface;
use Fi1a\Console\Component\TableComponent\TableComponentInterface;
use Fi1a\Console\IO\ConsoleOutputInterface;

$data = [
    ['Смартфон', '1000', '2', '2000'],
    ['Шкаф', '500', '1', '500'],
    ['Электробритва', '300', '5', '1500'],
    ['Станок', '200', '1', '200'],
    ['Диван', '1200', '1', '1200'],
    ['Кровать', '100', '2', '200'],
    ['Кресло', '300', '3', '900'],
    ['Шифанер', '150', '1', '150'],
    ['Стул', '50', '4', '200'],
    ['Стол', '100', '1', '100'],
];

$output = di()->get(ConsoleOutputInterface::class);

$table = di()->get(TableComponentInterface::class);
$table->setHeaders(['Товар', 'Стоимость', 'Количество', 'Итоговая сумма']);

$pagination = di()->get(PaginationComponentInterface::class);
$pagination->setCount((int) ceil(count($data) / 3));
$page = 1;
do {
    $rows = array_slice($data, ($page - 1) * 3, 3);
    $table->setRows($rows);
    $table->display();
    $pagination->display();
    $page = $pagination->getCurrent();
} while ($pagination->isValid());

$output->writeln('');

启动带有分页导航的示例

php examples/examples.php pagination

Постраничная навигация

Progressbar 组件

在执行长时间命令时,显示进度信息非常有用。

要显示进度信息,请使用 Fi1a\Console\Component\ProgressbarComponent\ProgressbarComponent

use Fi1a\Console\Component\ProgressbarComponent\ProgressbarComponent;
use Fi1a\Console\Component\ProgressbarComponent\ProgressbarStyle;

...

/**
 * @inheritDoc
 */
public function run(
    InputArgumentsInterface $input,
    ConsoleOutputInterface $output,
    InputInterface $stream,
    DefinitionInterface $definition,
    AppInterface $app
): int {
    $progressbarStyle = new ProgressbarStyle();
    $progressbarStyle->setTemplateByName('full');
    $progressbar = new ProgressbarComponent($output, $progressbarStyle);

    $progressbar->start(10);
    do {
        $progressbar->increment();
        $progressbar->display();
        sleep(1);
    } while($progressbar->getProgress() < $progressbar->getMaxSteps());
    $progressbar->finish();
    $output->writeln(['', '']);

    return 0;
}

...

使用容器的示例

use Fi1a\Console\Component\ProgressbarComponent\ProgressbarComponentInterface;
use Fi1a\Console\IO\ConsoleOutputInterface;

$output = di()->get(ConsoleOutputInterface::class);

$progressbar = di()->get(ProgressbarComponentInterface::class);

$progressbar->getStyle()
    ->setTemplateByName('full');

$progressbar->start(10);
do {
    $progressbar->increment();
    $progressbar->display();
    sleep(1);
} while($progressbar->getProgress() < $progressbar->getMaxSteps());
$progressbar->finish();
$output->writeln(['', '']);

使用 setTemplateByName 方法可以设置预定义模板之一。

  • 短模板 ([{{bar}}]);
  • 正常模板 ({{current}}/{{max}} [{{bar}}] {{percent|sprintf("3s")}}%{{if(title)}} {{title}}{{endif}});
  • 时间模板 ([{{bar}}] {{elapsed|sprintf("10s")}} / {{remaining|sprintf("-10s")}}{{if(title)}} {{title}}{{endif}});
  • 内存模板 ([{{bar}}] {{memory|memory}}{{if(title)}} {{title}}{{endif}});
  • 完整模板 ({{current}}/{{max}} [{{bar}}] {{percent|sprintf("3s")}}% {{elapsed|sprintf("10s")}} / {{remaining|sprintf("-10s")}} {{memory|memory}}{{if(title)}} {{title}}{{endif}}).

您可以使用 Fi1a\Console\Component\ProgressbarComponent\ProgressbarTemplateRegistry 类的 add 方法添加自己的模板。

use Fi1a\Console\Component\ProgressbarComponent\ProgressbarTemplateRegistry;

ProgressbarTemplateRegistry::add(
    'normal',
    '{{current}}/{{max}} [{{bar}}] {{percent|sprintf("3s")}}%{{if(title)}} {{title}}{{endif}}'
);

启动带有 progressbar 的示例

php examples/examples.php progressbar

Progressbar

Spinner 组件

功能

  • 旋转时的标题;
  • 支持模板 ({{if(title)}}{{title}} {{endif}}<color=green>{{spinner}}</> );
  • 具有 clear 方法;
  • 不同的外观和添加自定义 spinner 的能力。

Spinner 的外观

  • 点状;
  • 线条;
  • 垂直增长;
  • 水平增长;
  • 条状。

您可以使用 Fi1a\Console\Component\SpinnerComponent\SpinnerRegistry 类的 add 方法添加自己的 spinner。添加的 spinner 必须实现 Fi1a\Console\Component\SpinnerComponent\SpinnerInterface 接口。

use Fi1a\Console\Component\SpinnerComponent\DotsSpinner;
use Fi1a\Console\Component\SpinnerComponent\SpinnerRegistry;

SpinnerRegistry::add('dots', new DotsSpinner());

示例

use Fi1a\Console\Component\SpinnerComponent\SpinnerComponent;
use Fi1a\Console\Component\SpinnerComponent\SpinnerStyle;

...

/**
 * @inheritDoc
 */
public function run(
    InputArgumentsInterface $input,
    ConsoleOutputInterface $output,
    InputInterface $stream,
    DefinitionInterface $definition,
    AppInterface $app
): int {
    $spinnerStyle = new SpinnerStyle();
    $spinnerStyle->setTemplate('{{if(title)}}{{title}} {{endif}}<color=green>{{spinner}}</> ');

    $spinner = new SpinnerComponent($output, $spinnerStyle);

    $index = 0;
    do {
        if ($index % 1000000 === 0) {
            $title = $spinner->getTitle();
            if ($title) {
                $spinner->clear();
                $output->writeln($title);
            }
            $spinner->setTitle('In progress (' . $index . ')');
        }

        $spinner->display();
        $index++;
    } while ($index < 10000000);
    $output->writeln('');

    return 0;
}

...

使用容器的示例

use Fi1a\Console\Component\SpinnerComponent\SpinnerComponentInterface;
use Fi1a\Console\IO\ConsoleOutputInterface;

$output = di()->get(ConsoleOutputInterface::class);

$spinner = di()->get(SpinnerComponentInterface::class);

$spinner->getStyle()
    ->setTemplate('{{if(title)}}{{title}} {{endif}}<color=green>{{spinner}}</> ');

$index = 0;
do {
    if ($index % 1000000 === 0) {
        $title = $spinner->getTitle();
        if ($title) {
            $spinner->clear();
            $output->writeln($title);
        }
        $spinner->setTitle('In progress (' . $index . ')');
    }

    $spinner->display();
    $index++;
} while ($index < 10000000);
$output->writeln('');

启动示例

php examples/examples.php spinner

Spinner

表格组件

Fi1a\Console\Component\TableComponent\TableComponent 类用于在终端上显示表格数据。

要显示表格,创建一个 Fi1a\Console\Component\TableComponent\TableComponent 对象,使用 setHeaders 添加标题,使用 setRows 添加行,然后使用 display 方法输出到控制台。

use Fi1a\Console\Component\TableComponent\TableComponent;
use Fi1a\Console\Component\TableComponent\TableStyle;

...

/**
 * @inheritDoc
 */
public function run(
    InputArgumentsInterface $input,
    ConsoleOutputInterface $output,
    InputInterface $stream,
    DefinitionInterface $definition,
    AppInterface $app
): int {
    $headers = ['Товар', 'Стоимость', 'Количество', 'Итоговая сумма'];
    $rows = [
        ['Смартфон', '1000', '2', '2000'],
        ['Шкаф', '500', '1', '500'],
    ];

    $tableStyle = new TableStyle();
    $tableStyle->setBorder('ascii')
        ->setWidth(50);

    $table = new TableComponent($output, $tableStyle);
    $table->setHeaders($headers);
    $table->setRows($rows);

    $table->display();
    
    return 0;
}

...

使用容器的示例

use Fi1a\Console\Component\TableComponent\TableComponentInterface;

$headers = ['Товар', 'Стоимость', 'Количество', 'Итоговая сумма'];
$rows = [
    ['Смартфон', '1000', '2', '2000'],
    ['Шкаф', '500', '1', '500'],
];

$table = di()->get(TableComponentInterface::class);

$table->getStyle()
    ->setBorder('ascii')
    ->setWidth(50);

$table->setHeaders($headers);
$table->setRows($rows);

$table->display();

如果未设置表格宽度,则列宽将根据单元格内容计算。

单元格属性

  • value - 值;
  • colspan - 单元格跨越的列数;
  • style - Fi1a\Console\Component\TableComponent\TableCellStyleInterface 风格。
use Fi1a\Console\Component\TableComponent\TableCell;
use Fi1a\Console\Component\TableComponent\TableCellStyle;
use Fi1a\Console\Component\TableComponent\TableCellStyleInterface;

$style = new TableCellStyle();
$style->setAlign(TableCellStyleInterface::ALIGN_CENTER)

$cell = new TableCell([
    'value' => 'foo',
    'colspan' => 2,
    'style' => $style,
]);

您可以使用 setBorder 方法设置表格边框样式,指定以下值之一:Fi1a\Console\Component\TableComponent\TableStyle 对象的方法

  • none;
  • ascii;
  • ascii_compact;
  • double;
  • double_compact;
  • heavy;
  • heavy_compact;
  • horizontals;
  • rounded;
  • rounded_compact.

启动示例

php examples/examples.php table

Таблицы в консоли

可以使用 Fi1a\Console\Component\TableComponent\BorderRegistry 类的 add 方法定义自己的边框样式。边框样式类必须实现 Fi1a\Console\Component\TableComponent\BorderInterface 接口。

use Fi1a\Console\Component\TableComponent\BorderRegistry;

BorderRegistry::add('none', new NoneBorder());

显示树组件

Fi1a\Console\Component\TreeComponent\TreeComponent 类可以在终端中生成树形表示。树形结构是表示文件系统或其他任何层次结构数据的好方法。

use Fi1a\Console\Component\TreeComponent\TreeComponent;
use Fi1a\Console\Component\TreeComponent\TreeStyle;

...

/**
 * @inheritDoc
 */
public function run(
    InputArgumentsInterface $input,
    ConsoleOutputInterface $output,
    InputInterface $stream,
    DefinitionInterface $definition,
    AppInterface $app
): int {
    $style = new TreeStyle();
    $style->setWidth(20)
        ->setLine('heavy');

    $tree = new TreeComponent($output);

    $node1 = $tree->addNode('Lorem ipsum dolor', $style);
    $node1->addNode('Ex ea commodo consequat', $style);
    $node2 = $tree->addNode('Consectetur adipiscing elit', $style);
    $node3 = $node2->addNode('Ex ea commodo consequat', $style);
    $node2->addNode('Sunt in culpa qui officia', $style);
    $node3->addNode('Ut aliquip ex ea commodo');
    $node3->addNode('Sunt in culpa qui officia');
    $tree->addNode('Ut enim ad minim veniam', $style);

    $tree->display();
    
    return 0;
}

...

使用容器的示例

use Fi1a\Console\Component\TreeComponent\TreeComponentInterface;
use Fi1a\Console\Component\TreeComponent\TreeStyleInterface;

$style = di()->get(TreeStyleInterface::class);

$style->setWidth(20)
    ->setLine('heavy');

$tree = di()->get(TreeComponentInterface::class);
$tree->setStyle($style);

$node1 = $tree->addNode('Lorem ipsum dolor', $style);
$node1->addNode('Ex ea commodo consequat', $style);
$node2 = $tree->addNode('Consectetur adipiscing elit', $style);
$node3 = $node2->addNode('Ex ea commodo consequat', $style);
$node2->addNode('Sunt in culpa qui officia', $style);
$node3->addNode('Ut aliquip ex ea commodo');
$node3->addNode('Sunt in culpa qui officia');
$tree->addNode('Ut enim ad minim veniam', $style);

$tree->display();

您可以使用 setLine 方法设置线条样式,指定以下值之一:Fi1a\Console\Component\TreeComponent\TreeStyle 对象的方法

  • normal;
  • double;
  • heavy;
  • ascii.

启动示例

php examples/examples.php tree

Дерево в консоли

可以使用 add 方法来定义自己的线条样式,该方法属于 Fi1a\Console\Component\TreeComponent\LineRegistry 类。线条样式类需要实现 Fi1a\Console\Component\TreeComponent\LineInterface 接口。

use Fi1a\Console\Component\TreeComponent\LineRegistry;
use Fi1a\Console\Component\TreeComponent\NormalLine;

LineRegistry::add('normal', new NormalLine());