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

提示

介绍

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

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

NOTE

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

安装

Laravel 提示已经包含在最新版本的 Laravel 中。

您也可以通过 Composer 包管理器将 Laravel 提示安装到其他 PHP 项目中:

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 的 validator。为此,请提供一个包含属性名称和所需验证规则的数组给 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 的 validator。为此,请提供一个包含属性名称和所需验证规则的数组给 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 的 validator。为此,请提供一个包含属性名称和所需验证规则的数组给 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 的 validator。为此,请提供一个包含属性名称和所需验证规则的数组给 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;
use function Laravel\Prompts\text;

$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 函数的行为类似于 map 函数,并将返回一个包含回调每次迭代返回值的数组。

回调还可以接受 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 函数可用于清除用户的终端:

php
use function Laravel\Prompts\clear;

clear();

终端注意事项

终端宽度

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

终端高度

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

不支持的环境和回退

Laravel 提示支持 macOS、Linux 和 Windows 的 WSL。由于 Windows 版本的 PHP 存在限制,目前无法在 WSL 之外的 Windows 上使用 Laravel 提示。

因此,Laravel 提示支持回退到其他实现,例如 Symfony Console Question Helper

NOTE

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

回退条件

如果您不使用 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);
});

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