Skip to content
赞助商赞助商
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待

提示

介绍

Laravel Prompts 是一个 PHP 包,用于为您的命令行应用程序添加美观且用户友好的表单,具有浏览器般的功能,包括占位符文本和验证。

Laravel Prompts 非常适合在您的 Artisan 控制台命令 中接受用户输入,但也可以在任何命令行 PHP 项目中使用。

NOTE

Laravel Prompts 支持 macOS、Linux 和带有 WSL 的 Windows。有关更多信息,请参见我们关于 不支持的环境和回退 的文档。

安装

Laravel Prompts 已包含在最新版本的 Laravel 中。

您还可以通过使用 Composer 包管理器在其他 PHP 项目中安装 Laravel Prompts:

shell
composer require laravel/prompts

可用提示

文本

text 函数将提示用户给定的问题,接受他们的输入,然后返回它:

php
use function Laravel\Prompts\text;

$name = text('你叫什么名字?');

您还可以包含占位符文本、默认值和信息提示:

php
$name = text(
    label: '你叫什么名字?',
    placeholder: '例如:Taylor Otwell',
    default: $user?->name,
    hint: '这将显示在您的个人资料上。'
);

必填值

如果您需要输入值,可以传递 required 参数:

php
$name = text(
    label: '你叫什么名字?',
    required: true
);

如果您想自定义验证消息,也可以传递一个字符串:

php
$name = text(
    label: '你叫什么名字?',
    required: '您的名字是必填的。'
);

额外验证

最后,如果您想执行额外的验证逻辑,可以将闭包传递给 validate 参数:

php
$name = text(
    label: '你叫什么名字?',
    validate: fn (string $value) => match (true) {
        strlen($value) < 3 => '名字必须至少 3 个字符。',
        strlen($value) > 255 => '名字不得超过 255 个字符。',
        default => null
    }
);

闭包将接收输入的值,并可以返回错误消息,或者如果验证通过则返回 null

或者,您可以利用 Laravel 的 验证器。为此,请提供一个包含属性名称和所需验证规则的数组作为 validate 参数:

php
$name = text(
    label: '你叫什么名字?',
    validate: ['name' => 'required|max:255|unique:users']
);

文本区域

textarea 函数将提示用户给定的问题,通过多行文本区域接受他们的输入,然后返回它:

php
use function Laravel\Prompts\textarea;

$story = textarea('给我讲个故事。');

您还可以包含占位符文本、默认值和信息提示:

php
$story = textarea(
    label: '给我讲个故事。',
    placeholder: '这是一个关于...的故事。',
    hint: '这将显示在您的个人资料上。'
);

必填值

如果您需要输入值,可以传递 required 参数:

php
$story = textarea(
    label: '给我讲个故事。',
    required: true
);

如果您想自定义验证消息,也可以传递一个字符串:

php
$story = textarea(
    label: '给我讲个故事。',
    required: '故事是必填的。'
);

额外验证

最后,如果您想执行额外的验证逻辑,可以将闭包传递给 validate 参数:

php
$story = textarea(
    label: '给我讲个故事。',
    validate: fn (string $value) => match (true) {
        strlen($value) < 250 => '故事必须至少 250 个字符。',
        strlen($value) > 10000 => '故事不得超过 10,000 个字符。',
        default => null
    }
);

闭包将接收输入的值,并可以返回错误消息,或者如果验证通过则返回 null

或者,您可以利用 Laravel 的 验证器。为此,请提供一个包含属性名称和所需验证规则的数组作为 validate 参数:

php
$story = textarea(
    label: '给我讲个故事。',
    validate: ['story' => 'required|max:10000']
);

密码

password 函数与 text 函数类似,但用户输入时会被掩码。这在询问敏感信息(如密码)时非常有用:

php
use function Laravel\Prompts\password;

$password = password('你的密码是什么?');

您还可以包含占位符文本和信息提示:

php
$password = password(
    label: '你的密码是什么?',
    placeholder: '密码',
    hint: '至少 8 个字符。'
);

必填值

如果您需要输入值,可以传递 required 参数:

php
$password = password(
    label: '你的密码是什么?',
    required: true
);

如果您想自定义验证消息,也可以传递一个字符串:

php
$password = password(
    label: '你的密码是什么?',
    required: '密码是必填的。'
);

额外验证

最后,如果您想执行额外的验证逻辑,可以将闭包传递给 validate 参数:

php
$password = password(
    label: '你的密码是什么?',
    validate: fn (string $value) => match (true) {
        strlen($value) < 8 => '密码必须至少 8 个字符。',
        default => null
    }
);

闭包将接收输入的值,并可以返回错误消息,或者如果验证通过则返回 null

或者,您可以利用 Laravel 的 验证器。为此,请提供一个包含属性名称和所需验证规则的数组作为 validate 参数:

php
$password = password(
    label: '你的密码是什么?',
    validate: ['password' => 'min:8']
);

确认

如果您需要询问用户“是或否”的确认,可以使用 confirm 函数。用户可以使用箭头键或按 yn 选择他们的响应。此函数将返回 truefalse

php
use function Laravel\Prompts\confirm;

$confirmed = confirm('您接受条款吗?');

您还可以包含默认值、自定义“是”和“否”标签的措辞,以及信息提示:

php
$confirmed = confirm(
    label: '您接受条款吗?',
    default: false,
    yes: '我接受',
    no: '我拒绝',
    hint: '必须接受条款才能继续。'
);

要求“是”

如果需要,您可以通过传递 required 参数来要求用户选择“是”:

php
$confirmed = confirm(
    label: '您接受条款吗?',
    required: true
);

如果您想自定义验证消息,也可以传递一个字符串:

php
$confirmed = confirm(
    label: '您接受条款吗?',
    required: '您必须接受条款才能继续。'
);

选择

如果您需要用户从预定义的选项集中进行选择,可以使用 select 函数:

php
use function Laravel\Prompts\select;

$role = select(
    label: '用户应该拥有什么角色?',
    options: ['成员', '贡献者', '所有者']
);

您还可以指定默认选择和信息提示:

php
$role = select(
    label: '用户应该拥有什么角色?',
    options: ['成员', '贡献者', '所有者'],
    default: '所有者',
    hint: '角色可以随时更改。'
);

您还可以将关联数组传递给 options 参数,以便返回所选键而不是其值:

php
$role = select(
    label: '用户应该拥有什么角色?',
    options: [
        'member' => '成员',
        'contributor' => '贡献者',
        'owner' => '所有者',
    ],
    default: 'owner'
);

最多将显示五个选项,然后列表将开始滚动。您可以通过传递 scroll 参数自定义此设置:

php
$role = select(
    label: '您想分配哪个类别?',
    options: Category::pluck('name', 'id'),
    scroll: 10
);

额外验证

与其他提示函数不同,select 函数不接受 required 参数,因为不可能选择无。 但是,如果您需要呈现一个选项但防止其被选中,可以将闭包传递给 validate 参数:

php
$role = select(
    label: '用户应该拥有什么角色?',
    options: [
        'member' => '成员',
        'contributor' => '贡献者',
        'owner' => '所有者',
    ],
    validate: fn (string $value) =>
        $value === 'owner' && User::where('role', 'owner')->exists()
            ? '已经存在一个所有者。'
            : null
);

如果 options 参数是关联数组,则闭包将接收所选键,否则将接收所选值。闭包可以返回错误消息,或者如果验证通过则返回 null

多选

如果您需要用户能够选择多个选项,可以使用 multiselect 函数:

php
use function Laravel\Prompts\multiselect;

$permissions = multiselect(
    label: '应该分配哪些权限?',
    options: ['读取', '创建', '更新', '删除']
);

您还可以指定默认选择和信息提示:

php
use function Laravel\Prompts\multiselect;

$permissions = multiselect(
    label: '应该分配哪些权限?',
    options: ['读取', '创建', '更新', '删除'],
    default: ['读取', '创建'],
    hint: '权限可以随时更新。'
);

您还可以将关联数组传递给 options 参数,以返回所选选项的键而不是它们的值:

php
$permissions = multiselect(
    label: '应该分配哪些权限?',
    options: [
        'read' => '读取',
        'create' => '创建',
        'update' => '更新',
        'delete' => '删除',
    ],
    default: ['read', 'create']
);

最多将显示五个选项,然后列表将开始滚动。您可以通过传递 scroll 参数自定义此设置:

php
$categories = multiselect(
    label: '应该分配哪些类别?',
    options: Category::pluck('name', 'id'),
    scroll: 10
);

要求值

默认情况下,用户可以选择零个或多个选项。您可以传递 required 参数以强制选择一个或多个选项:

php
$categories = multiselect(
    label: '应该分配哪些类别?',
    options: Category::pluck('name', 'id'),
    required: true
);

如果您想自定义验证消息,可以提供一个字符串作为 required 参数:

php
$categories = multiselect(
    label: '应该分配哪些类别?',
    options: Category::pluck('name', 'id'),
    required: '您必须选择至少一个类别'
);

额外验证

如果您需要呈现一个选项但防止其被选中,可以将闭包传递给 validate 参数:

php
$permissions = multiselect(
    label: '用户应该拥有哪些权限?',
    options: [
        'read' => '读取',
        'create' => '创建',
        'update' => '更新',
        'delete' => '删除',
    ],
    validate: fn (array $values) => ! in_array('read', $values)
        ? '所有用户都需要读取权限。'
        : null
);

如果 options 参数是关联数组,则闭包将接收所选键,否则将接收所选值。闭包可以返回错误消息,或者如果验证通过则返回 null

建议

suggest 函数可用于为可能的选择提供自动补全。用户仍然可以提供任何答案,而不管自动补全提示:

php
use function Laravel\Prompts\suggest;

$name = suggest('你叫什么名字?', ['Taylor', 'Dayle']);

或者,您可以将闭包作为第二个参数传递给 suggest 函数。每当用户输入字符时,闭包将被调用。闭包应接受一个包含用户迄今为止输入的字符串参数,并返回一个用于自动补全的选项数组:

php
$name = suggest(
    label: '你叫什么名字?',
    options: fn ($value) => collect(['Taylor', 'Dayle'])
        ->filter(fn ($name) => Str::contains($name, $value, ignoreCase: true))
)

您还可以包含占位符文本、默认值和信息提示:

php
$name = suggest(
    label: '你叫什么名字?',
    options: ['Taylor', 'Dayle'],
    placeholder: '例如:Taylor',
    default: $user?->name,
    hint: '这将显示在您的个人资料上。'
);

必填值

如果您需要输入值,可以传递 required 参数:

php
$name = suggest(
    label: '你叫什么名字?',
    options: ['Taylor', 'Dayle'],
    required: true
);

如果您想自定义验证消息,也可以传递一个字符串:

php
$name = suggest(
    label: '你叫什么名字?',
    options: ['Taylor', 'Dayle'],
    required: '您的名字是必填的。'
);

额外验证

最后,如果您想执行额外的验证逻辑,可以将闭包传递给 validate 参数:

php
$name = suggest(
    label: '你叫什么名字?',
    options: ['Taylor', 'Dayle'],
    validate: fn (string $value) => match (true) {
        strlen($value) < 3 => '名字必须至少 3 个字符。',
        strlen($value) > 255 => '名字不得超过 255 个字符。',
        default => null
    }
);

闭包将接收输入的值,并可以返回错误消息,或者如果验证通过则返回 null

或者,您可以利用 Laravel 的 验证器。为此,请提供一个包含属性名称和所需验证规则的数组作为 validate 参数:

php
$name = suggest(
    label: '你叫什么名字?',
    options: ['Taylor', 'Dayle'],
    validate: ['name' => 'required|min:3|max:255']
);

搜索

如果您有很多选项供用户选择,search 函数允许用户输入搜索查询以过滤结果,然后使用箭头键选择选项:

php
use function Laravel\Prompts\search;

$id = search(
    label: '搜索应该接收邮件的用户',
    options: fn (string $value) => strlen($value) > 0
        ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
        : []
);

闭包将接收用户迄今为止输入的文本,并必须返回一个选项数组。如果您返回一个关联数组,则将返回所选选项的键;否则,将返回其值。

在过滤数组时,如果您打算返回值,您应该使用 array_values 函数或 values 集合方法,以确保数组不会变成关联数组:

php
$names = collect(['Taylor', 'Abigail']);

$selected = search(
    label: '搜索应该接收邮件的用户',
    options: fn (string $value) => $names
        ->filter(fn ($name) => Str::contains($name, $value, ignoreCase: true))
        ->values()
        ->all(),
);

您还可以包含占位符文本和信息提示:

php
$id = search(
    label: '搜索应该接收邮件的用户',
    placeholder: '例如:Taylor Otwell',
    options: fn (string $value) => strlen($value) > 0
        ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
        : [],
    hint: '该用户将立即收到电子邮件。'
);

最多将显示五个选项,然后列表将开始滚动。您可以通过传递 scroll 参数自定义此设置:

php
$id = search(
    label: '搜索应该接收邮件的用户',
    options: fn (string $value) => strlen($value) > 0
        ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
        : [],
    scroll: 10
);

额外验证

如果您想执行额外的验证逻辑,可以将闭包传递给 validate 参数:

php
$id = search(
    label: '搜索应该接收邮件的用户',
    options: fn (string $value) => strlen($value) > 0
        ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
        : [],
    validate: function (int|string $value) {
        $user = User::findOrFail($value);

        if ($user->opted_out) {
            return '该用户已选择不接收邮件。';
        }
    }
);

如果 options 闭包返回一个关联数组,则闭包将接收所选键;否则,它将接收所选值。闭包可以返回错误消息,或者如果验证通过则返回 null

多重搜索

如果您有很多可搜索的选项,并且需要用户能够选择多个项目,multisearch 函数允许用户输入搜索查询以过滤结果,然后使用箭头键和空格键选择选项:

php
use function Laravel\Prompts\multisearch;

$ids = multisearch(
    '搜索应该接收邮件的用户',
    fn (string $value) => strlen($value) > 0
        ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
        : []
);

闭包将接收用户迄今为止输入的文本,并必须返回一个选项数组。如果您返回一个关联数组,则将返回所选选项的键;否则,将返回其值。

在过滤数组时,如果您打算返回值,您应该使用 array_values 函数或 values 集合方法,以确保数组不会变成关联数组:

php
$names = collect(['Taylor', 'Abigail']);

$selected = multisearch(
    label: '搜索应该接收邮件的用户',
    options: fn (string $value) => $names
        ->filter(fn ($name) => Str::contains($name, $value, ignoreCase: true))
        ->values()
        ->all(),
);

您还可以包含占位符文本和信息提示:

php
$ids = multisearch(
    label: '搜索应该接收邮件的用户',
    placeholder: '例如:Taylor Otwell',
    options: fn (string $value) => strlen($value) > 0
        ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
        : [],
    hint: '该用户将立即收到电子邮件。'
);

最多将显示五个选项,然后列表将开始滚动。您可以通过提供 scroll 参数自定义此设置:

php
$ids = multisearch(
    label: '搜索应该接收邮件的用户',
    options: fn (string $value) => strlen($value) > 0
        ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
        : [],
    scroll: 10
);

要求值

默认情况下,用户可以选择零个或多个选项。您可以传递 required 参数以强制选择一个或多个选项:

php
$ids = multisearch(
    label: '搜索应该接收邮件的用户',
    options: fn (string $value) => strlen($value) > 0
        ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
        : [],
    required: true
);

如果您想自定义验证消息,可以将字符串提供给 required 参数:

php
$ids = multisearch(
    label: '搜索应该接收邮件的用户',
    options: fn (string $value) => strlen($value) > 0
        ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
        : [],
    required: '您必须选择至少一个用户。'
);

额外验证

如果您想执行额外的验证逻辑,可以将闭包传递给 validate 参数:

php
$ids = multisearch(
    label: '搜索应该接收邮件的用户',
    options: fn (string $value) => strlen($value) > 0
        ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
        : [],
    validate: function (array $values) {
        $optedOut = User::whereLike('name', '%a%')->findMany($values);

        if ($optedOut->isNotEmpty()) {
            return $optedOut->pluck('name')->join(', ', ', 和 ').' 已选择不接收邮件。';
        }
    }
);

如果 options 闭包返回一个关联数组,则闭包将接收所选键;否则,它将接收所选值。闭包可以返回错误消息,或者如果验证通过则返回 null

暂停

pause 函数可用于向用户显示信息文本,并等待他们通过按 Enter / Return 键确认他们希望继续:

php
use function Laravel\Prompts\pause;

pause('按 ENTER 继续。');

在验证前转换输入

有时,您可能希望在验证发生之前转换提示输入。例如,您可能希望删除提供字符串中的空格。为此,许多提示函数提供了一个 transform 参数,该参数接受一个闭包:

php
$name = text(
    label: '你叫什么名字?',
    transform: fn (string $value) => trim($value),
    validate: fn (string $value) => match (true) {
        strlen($value) < 3 => '名字必须至少 3 个字符。',
        strlen($value) > 255 => '名字不得超过 255 个字符。',
        default => null
    }
);

表单

通常,您将有多个提示将按顺序显示,以收集信息,然后执行其他操作。您可以使用 form 函数创建一组分组的提示供用户完成:

php
use function Laravel\Prompts\form;

$responses = form()
    ->text('你叫什么名字?', required: true)
    ->password('你的密码是什么?', validate: ['password' => 'min:8'])
    ->confirm('您接受条款吗?')
    ->submit();

submit 方法将返回一个包含表单提示的所有响应的数字索引数组。但是,您可以通过 name 参数为每个提示提供名称。当提供名称时,可以通过该名称访问命名提示的响应:

php
use App\Models\User;
use function Laravel\Prompts\form;

$responses = form()
    ->text('你叫什么名字?', required: true, name: 'name')
    ->password(
        label: '你的密码是什么?',
        validate: ['password' => 'min:8'],
        name: 'password'
    )
    ->confirm('您接受条款吗?')
    ->submit();

User::create([
    'name' => $responses['name'],
    'password' => $responses['password'],
]);

使用 form 函数的主要好处是用户可以使用 CTRL + U 返回表单中的先前提示。这允许用户修正错误或更改选择,而无需取消并重新启动整个表单。

如果您需要对表单中的提示进行更细粒度的控制,可以调用 add 方法,而不是直接调用其中一个提示函数。add 方法将传递用户提供的所有先前响应:

php
use function Laravel\Prompts\form;
use function Laravel\Prompts\outro;

$responses = form()
    ->text('你叫什么名字?', required: true, name: 'name')
    ->add(function ($responses) {
        return text("你多大了,{$responses['name']}?");
    }, name: 'age')
    ->submit();

outro("你的名字是 {$responses['name']},你 {$responses['age']} 岁。");

信息消息

noteinfowarningerroralert 函数可用于显示信息消息:

php
use function Laravel\Prompts\info;

info('包安装成功。');

表格

table 函数使得显示多行和多列数据变得简单。您只需提供列名和表格数据:

php
use function Laravel\Prompts\table;

table(
    headers: ['姓名', '电子邮件'],
    rows: User::all(['name', 'email'])->toArray()
);

旋转

spin 函数在执行指定的回调时显示一个旋转器和可选消息。它用于指示正在进行的过程,并在完成后返回回调的结果:

php
use function Laravel\Prompts\spin;

$response = spin(
    message: '正在获取响应...',
    callback: fn () => Http::get('http://example.com')
);

WARNING

spin 函数需要 pcntl PHP 扩展才能动画旋转器。当此扩展不可用时,将显示旋转器的静态版本。

进度条

对于长时间运行的任务,显示进度条可以帮助用户了解任务的完成情况。使用 progress 函数,Laravel 将显示进度条,并在对给定可迭代值的每次迭代中推进其进度:

php
use function Laravel\Prompts\progress;

$users = progress(
    label: '正在更新用户',
    steps: User::all(),
    callback: fn ($user) => $this->performTask($user)
);

progress 函数类似于映射函数,并将返回一个包含每次迭代的回调返回值的数组。

回调还可以接受 Laravel\Prompts\Progress 实例,允许您在每次迭代中修改标签和提示:

php
$users = progress(
    label: '正在更新用户',
    steps: User::all(),
    callback: function ($user, $progress) {
        $progress
            ->label("正在更新 {$user->name}")
            ->hint("创建于 {$user->created_at}");

        return $this->performTask($user);
    },
    hint: '这可能需要一些时间。'
);

有时,您可能需要更手动地控制进度条的推进。首先,定义过程将迭代的总步骤数。然后,在处理每个项目后,通过 advance 方法推进进度条:

php
$progress = progress(label: '正在更新用户', steps: 10);

$users = User::all();

$progress->start();

foreach ($users as $user) {
    $this->performTask($user);

    $progress->advance();
}

$progress->finish();

清除终端

clear 函数可用于清除用户的终端:

use function Laravel\Prompts\clear;

clear();

终端注意事项

终端宽度

如果任何标签、选项或验证消息的长度超过用户终端中的“列”数,它将自动截断以适应。考虑在用户可能使用较窄的终端时最小化这些字符串的长度。通常安全的最大长度是 74 个字符,以支持 80 字符的终端。

终端高度

对于接受 scroll 参数的任何提示,配置的值将自动减少以适应用户终端的高度,包括验证消息的空间。

不支持的环境和回退

Laravel Prompts 支持 macOS、Linux 和带有 WSL 的 Windows。由于 Windows 版本的 PHP 的限制,目前无法在不带 WSL 的 Windows 上使用 Laravel Prompts。

因此,Laravel Prompts 支持回退到替代实现,例如 Symfony Console Question Helper

NOTE

当在 Laravel 框架中使用 Laravel Prompts 时,已为您配置每个提示的回退,并将在不支持的环境中自动启用。

回退条件

如果您不使用 Laravel 或需要自定义何时使用回退行为,可以将布尔值传递给 Prompt 类上的 fallbackWhen 静态方法:

php
use Laravel\Prompts\Prompt;

Prompt::fallbackWhen(
    ! $input->isInteractive() || windows_os() || app()->runningUnitTests()
);

回退行为

如果您不使用 Laravel 或需要自定义回退行为,可以将闭包传递给每个提示类上的 fallbackUsing 静态方法:

php
use Laravel\Prompts\TextPrompt;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Style\SymfonyStyle;

TextPrompt::fallbackUsing(function (TextPrompt $prompt) use ($input, $output) {
    $question = (new Question($prompt->label, $prompt->default ?: null))
        ->setValidator(function ($answer) use ($prompt) {
            if ($prompt->required && $answer === null) {
                throw new \RuntimeException(
                    is_string($prompt->required) ? $prompt->required : '必填。'
                );
            }

            if ($prompt->validate) {
                $error = ($prompt->validate)($answer ?? '');

                if ($error) {
                    throw new \RuntimeException($error);
                }
            }

            return $answer;
        });

    return (new SymfonyStyle($input, $output))
        ->askQuestion($question);
});

必须单独为每个提示类配置回退。闭包将接收提示类的实例,并必须返回提示的适当类型。