php-school/cli-menu

PHP 的命令行菜单助手

4.3.0 2021-12-16 09:40 UTC

README

内容

最低要求

  • PHP 7.1
  • Composer
  • ext-posix

安装

composer require php-school/cli-menu

升级

请参阅升级文档,了解升级已安装的 cli-menu 版本所需的内容。

使用方法

快速设置

以下是一个非常基础的示例菜单,它将输出所选项目的文本,以帮助您开始。

<?php

use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\Builder\CliMenuBuilder;

require_once(__DIR__ . '/../vendor/autoload.php');

$itemCallable = function (CliMenu $menu) {
    echo $menu->getSelectedItem()->getText();
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('First Item', $itemCallable)
    ->addItem('Second Item', $itemCallable)
    ->addItem('Third Item', $itemCallable)
    ->addLineBreak('-')
    ->setBorder(1, 2, 'yellow')
    ->setPadding(2, 4)
    ->setMarginAuto()
    ->build();


$menu->open();

示例

查看 示例目录 并运行它们,以查看可能的内容!运行示例的最佳方式是使用 git clone 仓库

git clone https://github.com/php-school/cli-menu.git
cd cli-menu
composer install --no-dev
cd examples
php basic.php

基本菜单

basic

基本菜单自动居中

submenu

带有分隔的基本菜单

basic-seperation

带有疯狂分隔的菜单

crazy-seperation

自定义样式

custom-styles

边框和 256 色彩

submenu

有用的分隔

useful-seperation

显示项目额外

item-extra

移除默认值

remove-defaults

子菜单

submenu

submenu-options

分割项

split-item

禁用项目和子菜单

submenu

复选框项

checkbox

checkbox-split

单选按钮项

radio

radio-split

闪烁对话框

submenu

确认对话框

submenu

数字输入

submenu

submenu

文本输入

submenu

密码输入

submenu

使用 cli-menu 创建艺术

想看一些真正酷的东西吗?您可以使用 cli-menu 在您的终端上创建一个绘图画布。看看吧!

submenu

API

CliMenu 对象是通过 Builder 类构建的

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    /**
     *  Customise
    **/
    ->build();

一旦您有了菜单对象,您就可以像这样打开和关闭它

$menu->open();
$menu->close();

外观

菜单标题

您可以给您的菜单一个标题,并且可以自定义分隔符,即在标题下方显示的行。传递给 setTitleSeparator 的任何字符串都将重复,直到菜单的宽度。

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    ->setTitle('One Menu to rule them all!')
    ->setTitleSeparator('*-')
    ->build();

颜色

您可以将菜单的前景色和背景色更改为以下颜色中的任何一种

  • 黑色
  • 红色
  • 绿色
  • 黄色
  • 蓝色
  • 品红色
  • 青色
  • 白色
<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    ->setForegroundColour('green')
    ->setBackgroundColour('black')
    ->build();

如果您的终端支持 256 种颜色,则也可以使用其中任何一种,通过指定代码,如 230。您可以在此处找到颜色和代码列表。如果您指定了代码,而终端不支持 256 种颜色,则将自动回退到合理的默认值,使用在 src/Util/ColourUtil.php 中可见的生成映射。您还可以手动指定回退颜色作为 setForegroundColour 和 `setBackgroundColour` 的第二个参数。

在此示例中,如果没有找到 256 色支持,它将自动回退到 绿色蓝色

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    ->setForegroundColour('40')
    ->setBackgroundColour('92')
    ->build();

在这个例子中,如果没有找到256色支持,它将回退到黄色品红色

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    ->setForegroundColour('40', 'yellow')
    ->setBackgroundColour('92', 'magenta')
    ->build();

宽度

自定义菜单的宽度。设置一个大于终端大小的值将导致宽度与终端大小相同。宽度将包括填充和边框。因此,宽度为100,四周边框为5,四周填充为5,则内容宽度为80(5 + 5 + 80 + 5 + 5)。

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    ->setWidth(1000) //if terminal is only 400, width will also be 400
    ->build();

如果您想使用终端的全宽度,可以获取终端对象并从那里获取/设置,如下所示

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = ($builder = new CliMenuBuilder)
    ->setWidth($builder->getTerminal()->getWidth())
    ->build();

如果您想使用终端的全宽度并应用边距,请使用终端宽度,我们将自动进行计算(根据边距缩小宽度)。

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = ($builder = new CliMenuBuilder)
    ->setWidth($builder->getTerminal()->getWidth())
    ->setMargin(2)
    ->build();

填充

填充可以设置为一个值,用于所有边,或者可以单独为顶部/底部和左侧/右侧设置。

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    ->setPadding(10) //10 padding top/bottom/left/right
    ->build();

顶部/底部和左侧/右侧填充也可以设置不同的值

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    ->setPaddingTopBottom(10)
    ->setPaddingLeftRight(5)
    ->build();

使用简写方法配置顶部/底部和左侧/右侧填充

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    ->setPadding(10, 5) //top/bottom = 10, left/right = 5
    ->build();

边距

边距可以自定义为一个值。它也可以自动设置,这样菜单就可以在终端中很好地居中。

自动居中菜单

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    ->setWidth(200)
    ->setMarginAuto() 
    ->build();

任意边距

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    ->setWidth(200)
    ->setMargin(5)
    ->build();

边框

边框可以像CSS边框一样自定义。我们可以向任意一边添加任意数量的边框,包括左、右、上或下,并且我们可以为它应用颜色。

设置通用的2像素红色边框

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    ->setWidth(200)
    ->setBorder(2, 'red')
    ->build();

分别配置每个边框

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    ->setWidth(200)
    ->setBorderTopWidth(2)
    ->setBorderRightWidth(4)
    ->setBorderBottomWidth(2)
    ->setBorderLeftWidth(4)
    ->setBorderColour('42', 'red') //SpringGreen2 fallback to red
    ->build();

使用简写方法,像CSS一样分别配置每个边框

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    ->setWidth(200)
    ->setBorder(3, 4, 'red') //top/bottom = 3, left/right = 4
    ->setBorder(3, 4, 5, 'red') //top = 3, left/right = 4, bottom = 5
    ->setBorder(3, 4, 5, 6, 'red') //top = 3, left = 4, bottom = 5, right = 6
    ->build();

退出按钮文本

修改退出按钮的文本

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    ->setExitButtonText("Don't you want me baby?")
    ->build();

移除退出按钮

您可以将退出按钮完全删除

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    ->disableDefaultItems()
    ->build();

注意:这将同时禁用子菜单的返回按钮。

您可以使用以下方式手动添加退出和返回按钮

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\Action\ExitAction;
use PhpSchool\CliMenu\Action\GoBackAction;

$menu = (new CliMenuBuilder)
    ->disableDefaultItems()
    ->addSubMenu('Super Sub Menu', function (CliMenuBuilder $b) {
        $b->disableDefaultItems()
            ->setTitle('Behold the awesomeness')
            ->addItem('Return to parent menu', new GoBackAction); //add a go back button
    })
    ->addItem('Leave this place now !', new ExitAction) //add an exit button
    ->build();

项目

您可以在菜单中添加几种不同类型的项目

  • 可选项 - 这是您需要用于使某些内容可选择的类型(您可以按回车键并调用您的可调用函数)
  • 复选框项 - 这是一个复选框类型的项,它跟踪其切换状态以显示不同的标记。
  • 单选项 - 这是一个单选类型的项,它跟踪其切换状态以显示不同的标记。它将禁用其CliMenu级别内的所有其他单选按钮。
  • 换行项 - 这用于分隔区域,它可以跨越多行,宽度与菜单相同。传递的任何字符串都将重复。
  • 静态项 - 这将打印传递的任何文本,对于标题很有用。
  • ASCII艺术项 - 允许使用ASCII艺术的特殊项。它负责填充和对齐。
  • 子菜单项 - 允许一个项打开另一个菜单的特殊项。对于选项菜单很有用。
  • 分隔项 - 适合同一行的多个项目的特殊项。

可选项

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$menu = (new CliMenuBuilder)
    ->addItem('The Item Text', function (CliMenu $menu) { 
        echo 'I am alive!'; 
    })
    ->build();

您可以一次添加多个项,如下所示

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$callable = function (CliMenu $menu) {
    echo 'I am alive!';
};

$menu = (new CliMenuBuilder)
    ->addItems([
        ['Item 1', $callable],
        ['Item 2', $callable],
        ['Item 3', $callable],
    ])
    ->build();

注意:您可以添加任意数量的项,并且它们都可以有不同的操作。操作是第二个参数,必须是一个有效的PHP callable。尝试使用Invokable类来使您的操作易于测试。

复选框项

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$callable = function (CliMenu $menu) {
    echo $menu->getSelectedItem()->getText();
};

$menu = (new CliMenuBuilder)
    ->addCheckboxItem('Item 1', $callable)
    ->addCheckboxItem('Item 2', $callable)
    ->addCheckboxItem('Item 3', $callable)
    ->build();

您可以一次添加多个复选框项,如下所示

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$callable = function (CliMenu $menu) {
    echo 'I am alive!';
};

$menu = (new CliMenuBuilder)
    ->addCheckboxItems([
        ['Item 1', $callable],
        ['Item 2', $callable],
        ['Item 3', $callable],
    ])
    ->build();

在选择一个项时,它将被切换。注意,最初每个项都是未选中的。选择一个后,它将变为选中状态。

单选按钮项

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$callable = function (CliMenu $menu) {
    echo $menu->getSelectedItem()->getText();
};

$menu = (new CliMenuBuilder)
    ->addRadioItem('Item 1', $callable)
    ->addRadioItem('Item 2', $callable)
    ->addRadioItem('Item 3', $callable)
    ->build();

您可以一次添加多个单选项,如下所示

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$callable = function (CliMenu $menu) {
    echo 'I am alive!';
};

$menu = (new CliMenuBuilder)
    ->addRadioItems([
        ['Item 1', $callable],
        ['Item 2', $callable],
        ['Item 3', $callable],
    ])
    ->build();

在选择一个项时,它将被切换。注意,最初每个项都是未选中的。选择一个后,它将变为选中状态,并且同一级别的所有其他RadioItem都将被取消选中。

换行项

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    ->addLineBreak('<3', 2)
    ->build();

上面的代码将在菜单中重复字符序列<3跨越2行

静态项

静态项与换行符类似,但不会重复填充。它将按原样输出。如果文本长度超过菜单宽度,则将在下一行继续。

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
    ->addStaticItem('AREA 1')
    //add some items here
    ->addStaticItem('AREA 2')
    //add some boring items here
    ->addStaticItem('AREA 51')
    //add some top secret items here 
    ->build();

ASCII 码艺术项

以下操作将ASCII艺术放置在菜单的中心。使用这些常量来更改对齐方式

  • AsciiArtItem::POSITION_CENTER
  • AsciiArtItem::POSITION_LEFT
  • AsciiArtItem::POSITION_RIGHT
<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\MenuItem\AsciiArtItem;

$art = <<<ART
        _ __ _
       / |..| \
       \/ || \/
        |_''_|
      PHP SCHOOL
LEARNING FOR ELEPHANTS
ART;

$menu = (new CliMenuBuilder)
    ->addAsciiArt($art, AsciiArtItem::POSITION_CENTER)
    ->build();

addAsciiArt的第三个可选参数是备用文本。如果ASCII艺术对于终端来说太宽,则根本不会显示。然而,如果您传递一个字符串给第三个参数,如果ASCII艺术对于终端来说太宽,备用文本将代替显示。

子菜单项

子菜单功能强大!您可以在菜单中添加菜单,哇塞?您可以有主菜单和选项菜单。选项项将看起来像一个普通项,除非您点击它,您将进入另一个菜单,该菜单可以有不同的样式和颜色!

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$callable = function (CliMenu $menu) {
    echo "I'm just a boring selectable item";
};

$menu = (new CliMenuBuilder)
    ->addItem('Normal Item', $callable)
    ->addSubMenu('Super Sub Menu', function (CliMenuBuilder $b) {
        $b->setTitle('Behold the awesomeness')
            ->addItem(/** **/);
    })
    ->build();

在此示例中,将创建一个单独的子菜单。进入子菜单后,您将能够返回主菜单或完全退出。将自动添加一个“返回”按钮。您可以使用CliMenuBuilder实例的->setGoBackButtonText()方法自定义此文本,该实例用于子菜单。

关于语法和构建过程有以下几点需要注意

  1. addSubMenu的第一个参数是要显示在菜单上的文本,用于选择进入子菜单。
  2. 第二个参数是一个闭包,它将使用一个新实例的CliMenuBuilder调用,您可以使用它以完全相同的方式自定义子菜单,就像父菜单一样。
  3. 如果您没有修改子菜单的样式(例如,颜色),它将继承父菜单的样式!

如果您已经有一个配置好的菜单构建器,您只需将其传递给addSubMenuFromBuilder即可完成。

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$subMenuBuilder = (new CliMenuBuilder)
    ->setTitle('Behold the awesomeness')
    ->addItem(/** **/);

$menu = (new CliMenuBuilder)
    ->addSubMenuFromBuilder('Super Sub Menu', $subMenuBuilder)
    ->build();

注意:子菜单菜单项将是\PhpSchool\CliMenu\MenuItem\MenuMenuItem的实例。如果您需要访问子菜单,可以通过$menuMenuItem->getSubMenu()获取。

分割项

分隔项允许您在同一行上添加多个项目。菜单的全宽将均匀分配给所有项目。您可以使用左右箭头在这些项目之间移动。

您可以使用->setGutter()(默认为2)设置项目之间分隔的空格数。

目前,在分隔项内部仅允许使用可选择的、复选框、单选按钮、静态和子菜单项。

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\Builder\SplitItemBuilder;
use PhpSchool\CliMenu\CliMenu;

$itemCallable = function (CliMenu $menu) {
    echo $menu->getSelectedItem()->getText();
};

$menu = (new CliMenuBuilder)
    ->setWidth(150)
    ->addStaticItem('Below is a SplitItem')
    ->addSplitItem(function (SplitItemBuilder $b) use ($itemCallable) {
        $b->setGutter(5)
            ->addSubMenu('Sub Menu on a split item', function (CliMenuBuilder $b) {
                $b->setTitle('Behold the awesomeness')
                    ->addItem('This is awesome', function() { print 'Yes!'; });
            })
            ->addItem('Item 2', $itemCallable)
            ->addStaticItem('Item 3 - Static');
    })
    ->build();

$menu->open();

关于语法和构建过程有以下几点需要注意

  1. addSplitItem的第一个参数是一个闭包,它将使用一个新实例的SplitItemBuilder调用,您可以使用它向分隔项添加项目。
  2. 您可以在SplitItemBuilder上调用addItemaddCheckboxItemaddRadioItemaddSubMenuaddStaticItem
  3. SplitItemBuilder具有流畅的接口,因此您可以链式调用方法。

禁用项目和子菜单

在此示例中,我们将禁用某些项目和子菜单,但仍然在菜单中显示它们。

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$itemCallable = function (CliMenu $menu) {
    echo $menu->getSelectedItem()->getText();
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu Disabled Items')
    ->addItem('First Item', $itemCallable)
    ->addItem('Second Item', $itemCallable, false, true)
    ->addItem('Third Item', $itemCallable, false, true)
    ->addSubMenu('Submenu', function (CliMenuBuilder $b) use ($itemCallable) {
        $b->setTitle('Basic CLI Menu Disabled Items > Submenu')
            ->addItem('You can go in here!', $itemCallable);
    })
    ->addSubMenu('Disabled Submenu', function (CliMenuBuilder $b) use ($itemCallable) {
        $b->setTitle('Basic CLI Menu Disabled Items > Disabled Submenu')
            ->addItem('Nope can\'t see this!', $itemCallable)
            ->disableMenu();
    })
    ->addLineBreak('-')
    ->build();

->addItem调用的第三个参数是禁用项目的因素,而->disableMenu调用禁用相关菜单。

结果是具有褪色行的完整菜单,以表示它们已被禁用。当用户导航菜单时,这些项将被跳过,转到下一个可用的可选项。

项目标记

目前,当前活动项旁边的标记可以修改,支持UTF-8字符。未选择项的标记也可以修改。如果您想禁用它,只需将其设置为空字符串即可。项目标记仅在可选择项上显示,这些项是:\PhpSchool\CliMenu\MenuItem\SelectableItem\PhpSchool\CliMenu\MenuItem\MenuMenuItem

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\Style\SelectableStyle;

$menu = (new CliMenuBuilder)
    ->modifySelectableStyle(function (SelectableStyle $style) {
        $style->setUnselectedMarker('')
            ->setSelectedMarker('')

            // disable unselected marker
            ->setUnselectedMarker('')
        ;
    })
    ->build();

您还可以更改\PhpSchool\CliMenu\MenuItem\CheckboxItem的标记

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\Style\CheckboxStyle;

$menu = (new CliMenuBuilder)
    ->modifyCheckboxStyle(function (CheckboxStyle $style) {
        $style->setUncheckedMarker('[○] ')
            ->setCheckedMarker('[●] ');
    })
    ->addCheckboxItem('Orange juice', function () {})
    ->addCheckboxItem('Bread', function () {})
    ->build();

和为\PhpSchool\CliMenu\MenuItem\RadioItem

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\Style\RadioStyle;

$menu = (new CliMenuBuilder)
    ->modifyRadioStyle(function (RadioStyle $style) {
        $style->setUncheckedMarker('[ ] ')
            ->setCheckedMarker('[✔] ');
    })
    ->addRadioItem('Go shopping', function () {})
    ->addRadioItem('Go camping', function () {})
    ->build();

项目额外

您可以选择在项目右侧显示任意文本。您可以自定义此文本,并指定要在哪些项目上显示。我们使用它来显示 [完成] 在完成的练习上,菜单列出了研讨会应用的练习。

项目额外功能目前仅限于可选择的项(包括菜单、复选框和单选按钮)

addItem 的第三个参数是一个布尔值,表示是否显示项目额外内容。默认为 false。

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\Style\SelectableStyle;

$menu = (new CliMenuBuilder)
    ->modifySelectableStyle(function (SelectableStyle $style) {
        $style->setItemExtra('');
    })
    ->addItem('Exercise 1', function (CliMenu $menu) { echo 'I am complete!'; }, true)
    ->build();

如果没有项目设置显示额外内容为 true,则项目额外内容将不会显示。如果您在回调或运行时切换项目以显示其项目额外内容,则渲染将不正确。

为了修复此问题,您需要显式告诉菜单显示项目额外内容。您可以在构建菜单时这样做

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$menu = (new CliMenuBuilder)
    ->setItemExtra('')
    ->addItem('Exercise 1', function (CliMenu $menu) { 
        $selectedItem = $menu->getSelectedItem();
        if ($selectedItem->showsItemExtra()) {
            $selectedItem->hideItemExtra();
        } else {
            $selectedItem->showItemExtra();
        }       
    })
    ->displayExtra()
    ->build();

菜单方法

以下文档适用于直接在 \PhpSchool\CliMenu\CliMenu 实例上的方法。通常,您将在菜单打开时在您的操作回调中调用这些方法。

重绘菜单

您可以在执行操作时修改菜单及其样式,然后您可以重新绘制它!在这个例子中,我们将切换背景颜色。

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$itemCallable = function (CliMenu $menu) {
    $menu->getStyle()->setBg($menu->getStyle()->getBg() === 'red' ? 'blue' : 'red');
    $menu->redraw();
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('First Item', $itemCallable)
    ->addItem('Second Item', $itemCallable)
    ->addItem('Third Item', $itemCallable)
    ->addLineBreak('-')
    ->build();

$menu->open();

如果您剧烈更改菜单,例如使宽度更小,当它重新绘制时,您可能会看到上一个绘制的碎片,因为 redraw 只在终端顶部绘制。如果发生这种情况,您可以将 true 传递给 redraw,它将首先清除终端然后再重新绘制。

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$itemCallable = function (CliMenu $menu) {
    $menu->getStyle()->setWidth($menu->getStyle()->getWidth() === 100 ? 80 : 100);
    $menu->redraw(true);
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('First Item', $itemCallable)
    ->addItem('Second Item', $itemCallable)
    ->addItem('Third Item', $itemCallable)
    ->addLineBreak('-')
    ->build();

$menu->open();

获取、移除和添加项目

您还可以在操作中与菜单项交互。您可以添加、删除和替换项。如果您这样做,您可能还想重新绘制菜单,以便渲染新列表。

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\MenuItem\LineBreakItem;

$itemCallable = function (CliMenu $menu) {
    foreach ($menu->getItems() as $item) {
        $menu->removeItem($item);
    }
    
    //add single item
    $menu->addItem(new LineBreakItem('-'));
    
    //add multiple items
    $menu->addItems([new LineBreakItem('-'), new LineBreakItem('*')]);
    
    //replace all items
    $menu->setItems([new LineBreakItem('+'), new LineBreakItem('-')]);

    $menu->redraw();
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('First Item', $itemCallable)
    ->addItem('Second Item', $itemCallable)
    ->addItem('Third Item', $itemCallable)
    ->addLineBreak('-')
    ->build();

$menu->open();

自定义控制映射

此功能允许将自定义按键映射到可调用的函数。例如,我们可以将按键“x”设置为关闭菜单

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$exit = function(CliMenu $menu) {
    $menu->close();
};

$menu = (new CliMenuBuilder)
    ->addItem('Item 1', function(CliMenu $menu) {})
    ->build();

$menu->addCustomControlMapping("x", $exit);

$menu->open();

另一个示例是将快捷键映射到项目列表

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$myCallback = function(CliMenu $menu) {
    echo "Client 1\nClient 2\nClient 3\n";
};

$menu = (new CliMenuBuilder)
    ->addItem('List of [C]lients', $myCallback)
    ->build();

// Now, pressing Uppercase C (it's case sensitive) will call $myCallback
$menu->addCustomControlMapping('C', $myCallback);

$menu->open();

项目键盘快捷键

如果您启用自动快捷键,则 CliMenuBuilder 将解析项目文本并检查快捷键。方括号内的任何单个字符都将被视为快捷键。当菜单打开时按下该字符将触发该项目的可调用函数。

此功能也适用于分割项目和子菜单。可以在子菜单中使用相同的字符,并且调用的可调用函数将取决于当前打开的菜单。

注意:所有快捷键都是小写。

要启用此自动键盘快捷键映射,只需调用 ->enableAutoShortcuts()

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$myCallback = function(CliMenu $menu) {
    echo "Client 1\nClient 2\nClient 3\n";
};

$menu = (new CliMenuBuilder)
    ->enableAutoShortcuts()
    ->addItem('List of [C]lients', $myCallback)
    ->build();

$menu->open();

//Pressing c will execute $myCallback.

您可以通过传递自己的正则表达式到 enableAutoShortcuts 来自定义快捷键匹配。请小心只匹配第一个捕获组中的一个字符,否则会抛出异常。

对话框

闪烁

在菜单上方显示一条单行消息。它有一个单独的样式对象,默认情况下颜色与菜单不同。您可以修改它以适合您自己的样式。对话框可以通过任何按键来取消。以下示例中,我们将闪屏的背景颜色改为绿色。

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

require_once(__DIR__ . '/../vendor/autoload.php');
    
$itemCallable = function (CliMenu $menu) {
    $flash = $menu->flash("PHP School FTW!!");
    $flash->getStyle()->setBg('green');
    $flash->display();
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('First Item', $itemCallable)
    ->addItem('Second Item', $itemCallable)
    ->addItem('Third Item', $itemCallable)
    ->addLineBreak('-')
    ->build();

$menu->open();

确认

提示与闪屏非常相似,除了显示一个必须选择的按钮来取消它们。按钮文本可以自定义。

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$itemCallable = function (CliMenu $menu) {
    $menu->confirm('PHP School FTW!')
        ->display('OK!');
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('First Item', $itemCallable)
    ->addItem('Second Item', $itemCallable)
    ->addItem('Third Item', $itemCallable)
    ->addLineBreak('-')
    ->build();

$menu->open();

输入

输入 - 在 cli-menu 的 3.0 版本中添加 - 允许提示用户输入并验证它。支持以下类型:文本、数字和密码。可以在任何项目回调中执行输入。它们有独立的样式对象,默认情况下颜色与菜单不同。您可以修改它们以适合您自己的样式。

每个输入是通过调用一个 ask* 方法创建的,它将返回您请求的输入的实例。要执行提示并等待输入,您必须在输入上调用 ask()。当接收到并验证输入后,ask() 将返回一个 InputResult 的实例。 InputResult 提供了 fetch 方法来获取原始输入。

文本输入

文本输入将提示输入一个字符串,当按下回车键时,将验证该字符串是否为空。除了样式外,您还可以修改提示文本(默认为'输入文本:')、占位文本(默认为空)以及验证失败文本(默认为'无效,请重试')。

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$itemCallable = function (CliMenu $menu) {
    $result = $menu->askText()
        ->setPromptText('Enter your name')
        ->setPlaceholderText('Jane Doe')
        ->setValidationFailedText('Please enter your name')
        ->ask();

    var_dump($result->fetch());
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('Enter text', $itemCallable)
    ->addLineBreak('-')
    ->build();

$menu->open();

数字输入

数字输入将提示输入一个整数(有符号或无符号)值,当按下回车键时,将验证输入是否实际上是一个数字(/^-?\d+$/)。除了样式外,您还可以修改提示文本(默认为'输入一个数字:')、占位文本(默认为空)以及验证失败文本(默认为'不是有效的数字,请重试')。

当输入数字时,您可以使用上下键来增加和减少数字。

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$itemCallable = function (CliMenu $menu) {
    $result = $menu->askNumber()
        ->setPromptText('Enter your age')
        ->setPlaceholderText(10)
        ->setValidationFailedText('Invalid age, try again')
        ->ask();

    var_dump($result->fetch());
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('Enter number', $itemCallable)
    ->addLineBreak('-')
    ->build();

$menu->open();

密码输入

密码输入将提示输入文本值,当按下回车键时,将验证输入是否为16个字符或更长。除了样式外,您还可以修改提示文本(默认为'输入密码:')、占位文本(默认为空)以及验证失败文本(默认为'无效密码,请重试')。您还可以设置一个自定义的密码验证器作为PHP可调用。当输入密码时,它们将回显为星号。

使用默认验证请求密码

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$itemCallable = function (CliMenu $menu) {
    $result = $menu->askPassword()
        ->setPromptText('Please enter your password')
        ->setValidationFailedText('Invalid password, try again')
        ->setPlaceholderText('')
        ->ask();

    var_dump($result->fetch());
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('Enter password', $itemCallable)
    ->addLineBreak('-')
    ->build();

$menu->open();

验证器可以是任何PHP可调用。可调用将被传递输入值,必须返回一个布尔值,false表示验证失败,true表示验证成功。如果验证失败,则将显示验证失败文本。

还有可能动态自定义验证失败消息,但仅当使用Closure作为验证器时。闭包将被绑定到Password输入类,这将允许您在闭包内部调用setValidationFailedText

使用自定义验证请求密码。这里我们验证密码不等于password且密码长度超过20个字符。

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$itemCallable = function (CliMenu $menu) {
    $result = $menu->askPassword()
        ->setPromptText('Please enter your password')
        ->setValidationFailedText('Invalid password, try again')
        ->setPlaceholderText('')
        ->setValidator(function ($password) {
            return $password !== 'password' && strlen($password) > 20;            
        })
        ->ask();

    var_dump($result->fetch());
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('Enter password', $itemCallable)
    ->addLineBreak('-')
    ->build();

$menu->open();

使用自定义验证请求密码并动态设置验证失败消息

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$itemCallable = function (CliMenu $menu) {
    $result = $menu->askPassword()
        ->setPromptText('Please enter your password')
        ->setValidationFailedText('Invalid password, try again')
        ->setPlaceholderText('')
        ->setValidator(function ($password) {
            if ($password === 'password') {
                $this->setValidationFailedText('Password is too weak');
                return false;
            } else if (strlen($password) <= 20) {
                $this->setValidationFailedText('Password is not long enough');
                return false;
            } 
            
            return true;
        })
        ->ask();

    var_dump($result->fetch());
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('Enter password', $itemCallable)
    ->addLineBreak('-')
    ->build();

$menu->open();

自定义输入

如果您需要一个未在捆绑选择中涵盖的新类型输入,您可以通过实现\PhpSchool\CliMenu\Input\Input来创建自己的输入 - 查看现有实现以了解它们是如何构建的。如果您只需要一些自定义验证,则扩展\PhpSchool\CliMenu\Input\Text类并重写validate方法。然后您可以在菜单项操作中使用它,如下所示

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\MenuStyle;
use PhpSchool\CliMenu\Input\Text;
use PhpSchool\CliMenu\Input\InputIO;

$itemCallable = function (CliMenu $menu) {
    
    $style = (new MenuStyle())
        ->setBg('yellow')
        ->setFg('black');
        
    $input = new class (new InputIO($menu, $menu->getTerminal()), $style) extends Text {
        public function validate(string $value) : bool
        {
            //some validation
            return true;
        }
    };
    
    $result = $input->ask();

    var_dump($result->fetch());
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('Enter password', $itemCallable)
    ->addLineBreak('-')
    ->build();

$menu->open();

对话框和输入样式

所有对话框和输入都公开了一个getStyle()方法,您可以使用它来自定义它们的外观。但是,如果您想为所有对话框和输入创建一个一致的风格,而无需为每个配置它,则可以构建一个MenuStyle对象并将其传递给对话框和输入方法,如下所示

<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\MenuStyle;

$popupStyle = (new MenuStyle)
    ->setBg('green')
    ->setFg('magenta');
    
$itemCallable = function (CliMenu $menu) use ($popupStyle) {
    $menu->flash("PHP School FTW!!", $popupStyle)->display();
    $menu->confirm('PHP School FTW!', $popupStyle)->display('OK!');
    $menu->askNumber($popupStyle)->ask();
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('First Item', $itemCallable)
    ->addItem('Second Item', $itemCallable)
    ->addItem('Third Item', $itemCallable)
    ->addLineBreak('-')
    ->build();

$menu->open();

一旦开始,您可能会得到一些看起来像这样的事物...

Learn You PHP CLI Menu

您可以在以下代码中查看构建代码,以更清楚地了解如何执行高级配置: PHP School

集成