跳转至内容

Prompts

简介

Laravel Prompts 是一个 PHP 软件包,旨在为你的命令行应用程序添加美观且用户友好的表单,并提供类似浏览器的功能,包括占位符文本和验证。

Laravel Prompts 非常适合在 Artisan 控制台命令中获取用户输入,但它也可以用于任何命令行 PHP 项目。

Laravel Prompts 支持 macOS、Linux 和带有 WSL 的 Windows。有关详细信息,请参阅我们关于不支持的环境与回退机制的文档。

安装

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

Laravel Prompts 也可以通过 Composer 软件包管理器安装到你的其他 PHP 项目中。

1composer require laravel/prompts

可用提示 (Prompts)

文本输入 (Text)

text 函数将向用户提出给定的问题,接收他们的输入,并将其返回。

1use function Laravel\Prompts\text;
2 
3$name = text('What is your name?');

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

1$name = text(
2 label: 'What is your name?',
3 placeholder: 'E.g. Taylor Otwell',
4 default: $user?->name,
5 hint: 'This will be displayed on your profile.'
6);

必需值

如果你要求必须输入一个值,可以传递 required 参数。

1$name = text(
2 label: 'What is your name?',
3 required: true
4);

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

1$name = text(
2 label: 'What is your name?',
3 required: 'Your name is required.'
4);

额外验证

最后,如果你想执行额外的验证逻辑,可以向 validate 参数传递一个闭包。

1$name = text(
2 label: 'What is your name?',
3 validate: fn (string $value) => match (true) {
4 strlen($value) < 3 => 'The name must be at least 3 characters.',
5 strlen($value) > 255 => 'The name must not exceed 255 characters.',
6 default => null
7 }
8);

闭包将接收已输入的值,并返回一个错误消息;如果验证通过,则返回 null

此外,你也可以利用 Laravel 验证器 的强大功能。为此,请向 validate 参数提供一个包含属性名称和所需验证规则的数组。

1$name = text(
2 label: 'What is your name?',
3 validate: ['name' => 'required|max:255|unique:users']
4);

多行文本输入 (Textarea)

textarea 函数将向用户提出给定的问题,通过多行文本区域接收输入,然后将其返回。

1use function Laravel\Prompts\textarea;
2 
3$story = textarea('Tell me a story.');

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

1$story = textarea(
2 label: 'Tell me a story.',
3 placeholder: 'This is a story about...',
4 hint: 'This will be displayed on your profile.'
5);

必需值

如果你要求必须输入一个值,可以传递 required 参数。

1$story = textarea(
2 label: 'Tell me a story.',
3 required: true
4);

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

1$story = textarea(
2 label: 'Tell me a story.',
3 required: 'A story is required.'
4);

额外验证

最后,如果你想执行额外的验证逻辑,可以向 validate 参数传递一个闭包。

1$story = textarea(
2 label: 'Tell me a story.',
3 validate: fn (string $value) => match (true) {
4 strlen($value) < 250 => 'The story must be at least 250 characters.',
5 strlen($value) > 10000 => 'The story must not exceed 10,000 characters.',
6 default => null
7 }
8);

闭包将接收已输入的值,并返回一个错误消息;如果验证通过,则返回 null

此外,你也可以利用 Laravel 验证器 的强大功能。为此,请向 validate 参数提供一个包含属性名称和所需验证规则的数组。

1$story = textarea(
2 label: 'Tell me a story.',
3 validate: ['story' => 'required|max:10000']
4);

数字输入 (Number)

number 函数将向用户提出给定的问题,接收他们的数字输入,然后将其返回。number 函数允许用户使用上下箭头键来调整数字。

1use function Laravel\Prompts\number;
2 
3$number = number('How many copies would you like?');

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

1$name = number(
2 label: 'How many copies would you like?',
3 placeholder: '5',
4 default: 1,
5 hint: 'This will be determine how many copies to create.'
6);

必需值

如果你要求必须输入一个值,可以传递 required 参数。

1$copies = number(
2 label: 'How many copies would you like?',
3 required: true
4);

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

1$copies = number(
2 label: 'How many copies would you like?',
3 required: 'A number of copies is required.'
4);

额外验证

最后,如果你想执行额外的验证逻辑,可以向 validate 参数传递一个闭包。

1$copies = number(
2 label: 'How many copies would you like?',
3 validate: fn (?int $value) => match (true) {
4 $value < 1 => 'At least one copy is required.',
5 $value > 100 => 'You may not create more than 100 copies.',
6 default => null
7 }
8);

闭包将接收已输入的值,并返回一个错误消息;如果验证通过,则返回 null

此外,你也可以利用 Laravel 验证器 的强大功能。为此,请向 validate 参数提供一个包含属性名称和所需验证规则的数组。

1$copies = number(
2 label: 'How many copies would you like?',
3 validate: ['copies' => 'required|integer|min:1|max:100']
4);

密码输入 (Password)

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

1use function Laravel\Prompts\password;
2 
3$password = password('What is your password?');

你还可以包含占位符文本和提示信息。

1$password = password(
2 label: 'What is your password?',
3 placeholder: 'password',
4 hint: 'Minimum 8 characters.'
5);

必需值

如果你要求必须输入一个值,可以传递 required 参数。

1$password = password(
2 label: 'What is your password?',
3 required: true
4);

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

1$password = password(
2 label: 'What is your password?',
3 required: 'The password is required.'
4);

额外验证

最后,如果你想执行额外的验证逻辑,可以向 validate 参数传递一个闭包。

1$password = password(
2 label: 'What is your password?',
3 validate: fn (string $value) => match (true) {
4 strlen($value) < 8 => 'The password must be at least 8 characters.',
5 default => null
6 }
7);

闭包将接收已输入的值,并返回一个错误消息;如果验证通过,则返回 null

此外,你也可以利用 Laravel 验证器 的强大功能。为此,请向 validate 参数提供一个包含属性名称和所需验证规则的数组。

1$password = password(
2 label: 'What is your password?',
3 validate: ['password' => 'min:8']
4);

确认 (Confirm)

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

1use function Laravel\Prompts\confirm;
2 
3$confirmed = confirm('Do you accept the terms?');

你还可以包含默认值、自定义“是”和“否”标签的文字,以及提示信息。

1$confirmed = confirm(
2 label: 'Do you accept the terms?',
3 default: false,
4 yes: 'I accept',
5 no: 'I decline',
6 hint: 'The terms must be accepted to continue.'
7);

要求选择“是”

如有必要,你可以通过传递 required 参数要求用户必须选择“是”。

1$confirmed = confirm(
2 label: 'Do you accept the terms?',
3 required: true
4);

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

1$confirmed = confirm(
2 label: 'Do you accept the terms?',
3 required: 'You must accept the terms to continue.'
4);

单选 (Select)

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

1use function Laravel\Prompts\select;
2 
3$role = select(
4 label: 'What role should the user have?',
5 options: ['Member', 'Contributor', 'Owner']
6);

你还可以指定默认选项和提示信息。

1$role = select(
2 label: 'What role should the user have?',
3 options: ['Member', 'Contributor', 'Owner'],
4 default: 'Owner',
5 hint: 'The role may be changed at any time.'
6);

你也可以向 options 参数传递关联数组,以返回所选的键而不是值。

1$role = select(
2 label: 'What role should the user have?',
3 options: [
4 'member' => 'Member',
5 'contributor' => 'Contributor',
6 'owner' => 'Owner',
7 ],
8 default: 'owner'
9);

在列表滚动之前最多显示五个选项。你可以通过传递 scroll 参数来自定义此数量。

1$role = select(
2 label: 'Which category would you like to assign?',
3 options: Category::pluck('name', 'id'),
4 scroll: 10
5);

次要信息

info 参数可用于显示关于当前高亮选项的附加信息。当提供闭包时,它将接收当前高亮选项的值,并应返回字符串或 null

1$role = select(
2 label: 'What role should the user have?',
3 options: [
4 'member' => 'Member',
5 'contributor' => 'Contributor',
6 'owner' => 'Owner',
7 ],
8 info: fn (string $value) => match ($value) {
9 'member' => 'Can view and comment.',
10 'contributor' => 'Can view, comment, and edit.',
11 'owner' => 'Full access to all resources.',
12 default => null,
13 }
14);

如果信息不依赖于高亮选项,你也可以向 info 参数传递一个静态字符串。

1$role = select(
2 label: 'What role should the user have?',
3 options: ['Member', 'Contributor', 'Owner'],
4 info: 'The role may be changed at any time.'
5);

额外验证

与其他提示函数不同,select 函数不接受 required 参数,因为不可能什么都不选。但是,如果你需要展示一个选项但阻止它被选中,可以将闭包传递给 validate 参数。

1$role = select(
2 label: 'What role should the user have?',
3 options: [
4 'member' => 'Member',
5 'contributor' => 'Contributor',
6 'owner' => 'Owner',
7 ],
8 validate: fn (string $value) =>
9 $value === 'owner' && User::where('role', 'owner')->exists()
10 ? 'An owner already exists.'
11 : null
12);

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

多选 (Multi-select)

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

1use function Laravel\Prompts\multiselect;
2 
3$permissions = multiselect(
4 label: 'What permissions should be assigned?',
5 options: ['Read', 'Create', 'Update', 'Delete']
6);

你还可以指定默认选择和提示信息。

1use function Laravel\Prompts\multiselect;
2 
3$permissions = multiselect(
4 label: 'What permissions should be assigned?',
5 options: ['Read', 'Create', 'Update', 'Delete'],
6 default: ['Read', 'Create'],
7 hint: 'Permissions may be updated at any time.'
8);

你也可以向 options 参数传递关联数组,以返回所选选项的键而不是值。

1$permissions = multiselect(
2 label: 'What permissions should be assigned?',
3 options: [
4 'read' => 'Read',
5 'create' => 'Create',
6 'update' => 'Update',
7 'delete' => 'Delete',
8 ],
9 default: ['read', 'create']
10);

在列表滚动之前最多显示五个选项。你可以通过传递 scroll 参数来自定义此数量。

1$categories = multiselect(
2 label: 'What categories should be assigned?',
3 options: Category::pluck('name', 'id'),
4 scroll: 10
5);

次要信息

info 参数可用于显示关于当前高亮选项的附加信息。当提供闭包时,它将接收当前高亮选项的值,并应返回字符串或 null

1$permissions = multiselect(
2 label: 'What permissions should be assigned?',
3 options: [
4 'read' => 'Read',
5 'create' => 'Create',
6 'update' => 'Update',
7 'delete' => 'Delete',
8 ],
9 info: fn (string $value) => match ($value) {
10 'read' => 'View resources and their properties.',
11 'create' => 'Create new resources.',
12 'update' => 'Modify existing resources.',
13 'delete' => 'Permanently remove resources.',
14 default => null,
15 }
16);

要求必须选择

默认情况下,用户可以选择零个或多个选项。你可以通过传递 required 参数来强制要求选择一个或多个选项。

1$categories = multiselect(
2 label: 'What categories should be assigned?',
3 options: Category::pluck('name', 'id'),
4 required: true
5);

如果你想自定义验证消息,可以向 required 参数提供一个字符串。

1$categories = multiselect(
2 label: 'What categories should be assigned?',
3 options: Category::pluck('name', 'id'),
4 required: 'You must select at least one category'
5);

额外验证

如果你需要展示一个选项但阻止它被选中,可以将闭包传递给 validate 参数。

1$permissions = multiselect(
2 label: 'What permissions should the user have?',
3 options: [
4 'read' => 'Read',
5 'create' => 'Create',
6 'update' => 'Update',
7 'delete' => 'Delete',
8 ],
9 validate: fn (array $values) => ! in_array('read', $values)
10 ? 'All users require the read permission.'
11 : null
12);

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

建议 (Suggest)

suggest 函数可用于为可能的选择提供自动补全。无论自动补全的提示如何,用户仍然可以输入任何答案。

1use function Laravel\Prompts\suggest;
2 
3$name = suggest('What is your name?', ['Taylor', 'Dayle']);

此外,你可以将闭包作为 suggest 函数的第二个参数传递。每次用户输入字符时都会调用该闭包。闭包应接受一个包含用户目前输入内容的字符串参数,并返回一个用于自动补全的选项数组。

1$name = suggest(
2 label: 'What is your name?',
3 options: fn ($value) => collect(['Taylor', 'Dayle'])
4 ->filter(fn ($name) => Str::contains($name, $value, ignoreCase: true))
5)

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

1$name = suggest(
2 label: 'What is your name?',
3 options: ['Taylor', 'Dayle'],
4 placeholder: 'E.g. Taylor',
5 default: $user?->name,
6 hint: 'This will be displayed on your profile.'
7);

次要信息

info 参数可用于显示关于当前高亮选项的附加信息。当提供闭包时,它将接收当前高亮选项的值,并应返回字符串或 null

1$name = suggest(
2 label: 'What is your name?',
3 options: ['Taylor', 'Dayle'],
4 info: fn (string $value) => match ($value) {
5 'Taylor' => 'Administrator',
6 'Dayle' => 'Contributor',
7 default => null,
8 }
9);

必需值

如果你要求必须输入一个值,可以传递 required 参数。

1$name = suggest(
2 label: 'What is your name?',
3 options: ['Taylor', 'Dayle'],
4 required: true
5);

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

1$name = suggest(
2 label: 'What is your name?',
3 options: ['Taylor', 'Dayle'],
4 required: 'Your name is required.'
5);

额外验证

最后,如果你想执行额外的验证逻辑,可以向 validate 参数传递一个闭包。

1$name = suggest(
2 label: 'What is your name?',
3 options: ['Taylor', 'Dayle'],
4 validate: fn (string $value) => match (true) {
5 strlen($value) < 3 => 'The name must be at least 3 characters.',
6 strlen($value) > 255 => 'The name must not exceed 255 characters.',
7 default => null
8 }
9);

闭包将接收已输入的值,并返回一个错误消息;如果验证通过,则返回 null

此外,你也可以利用 Laravel 验证器 的强大功能。为此,请向 validate 参数提供一个包含属性名称和所需验证规则的数组。

1$name = suggest(
2 label: 'What is your name?',
3 options: ['Taylor', 'Dayle'],
4 validate: ['name' => 'required|min:3|max:255']
5);

如果你有大量选项供用户选择,search 函数允许用户键入搜索查询来过滤结果,然后再使用箭头键选择选项。

1use function Laravel\Prompts\search;
2 
3$id = search(
4 label: 'Search for the user that should receive the mail',
5 options: fn (string $value) => strlen($value) > 0
6 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
7 : []
8);

闭包将接收用户目前键入的文本,并必须返回一个选项数组。如果你返回关联数组,则将返回所选选项的键;否则将返回其值。

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

1$names = collect(['Taylor', 'Abigail']);
2 
3$selected = search(
4 label: 'Search for the user that should receive the mail',
5 options: fn (string $value) => $names
6 ->filter(fn ($name) => Str::contains($name, $value, ignoreCase: true))
7 ->values()
8 ->all(),
9);

你还可以包含占位符文本和提示信息。

1$id = search(
2 label: 'Search for the user that should receive the mail',
3 placeholder: 'E.g. Taylor Otwell',
4 options: fn (string $value) => strlen($value) > 0
5 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
6 : [],
7 hint: 'The user will receive an email immediately.'
8);

在列表滚动之前最多显示五个选项。你可以通过传递 scroll 参数来自定义此数量。

1$id = search(
2 label: 'Search for the user that should receive the mail',
3 options: fn (string $value) => strlen($value) > 0
4 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
5 : [],
6 scroll: 10
7);

次要信息

info 参数可用于显示关于当前高亮选项的附加信息。当提供闭包时,它将接收当前高亮选项的值,并应返回字符串或 null

1$id = search(
2 label: 'Search for the user that should receive the mail',
3 options: fn (string $value) => strlen($value) > 0
4 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
5 : [],
6 info: fn (int $userId) => User::find($userId)?->email
7);

额外验证

如果你想执行额外的验证逻辑,可以向 validate 参数传递一个闭包。

1$id = search(
2 label: 'Search for the user that should receive the mail',
3 options: fn (string $value) => strlen($value) > 0
4 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
5 : [],
6 validate: function (int|string $value) {
7 $user = User::findOrFail($value);
8 
9 if ($user->opted_out) {
10 return 'This user has opted-out of receiving mail.';
11 }
12 }
13);

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

多选搜索 (Multi-search)

如果你有大量可搜索的选项,并且需要用户能够选择多个项目,multisearch 函数允许用户键入搜索查询来过滤结果,然后再使用箭头键和空格键选择选项。

1use function Laravel\Prompts\multisearch;
2 
3$ids = multisearch(
4 'Search for the users that should receive the mail',
5 fn (string $value) => strlen($value) > 0
6 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
7 : []
8);

闭包将接收用户目前键入的文本,并必须返回一个选项数组。如果你返回关联数组,则将返回所选选项的键;否则将返回它们的值。

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

1$names = collect(['Taylor', 'Abigail']);
2 
3$selected = multisearch(
4 label: 'Search for the users that should receive the mail',
5 options: fn (string $value) => $names
6 ->filter(fn ($name) => Str::contains($name, $value, ignoreCase: true))
7 ->values()
8 ->all(),
9);

你还可以包含占位符文本和提示信息。

1$ids = multisearch(
2 label: 'Search for the users that should receive the mail',
3 placeholder: 'E.g. Taylor Otwell',
4 options: fn (string $value) => strlen($value) > 0
5 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
6 : [],
7 hint: 'The user will receive an email immediately.'
8);

在列表滚动之前最多显示五个选项。你可以通过提供 scroll 参数来自定义此数量。

1$ids = multisearch(
2 label: 'Search for the users that should receive the mail',
3 options: fn (string $value) => strlen($value) > 0
4 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
5 : [],
6 scroll: 10
7);

次要信息

info 参数可用于显示关于当前高亮选项的附加信息。当提供闭包时,它将接收当前高亮选项的值,并应返回字符串或 null

1$ids = multisearch(
2 label: 'Search for the users that should receive the mail',
3 options: fn (string $value) => strlen($value) > 0
4 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
5 : [],
6 info: fn (int $userId) => User::find($userId)?->email
7);

要求必须选择

默认情况下,用户可以选择零个或多个选项。你可以通过传递 required 参数来强制要求选择一个或多个选项。

1$ids = multisearch(
2 label: 'Search for the users that should receive the mail',
3 options: fn (string $value) => strlen($value) > 0
4 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
5 : [],
6 required: true
7);

如果你想自定义验证消息,也可以向 required 参数提供一个字符串。

1$ids = multisearch(
2 label: 'Search for the users that should receive the mail',
3 options: fn (string $value) => strlen($value) > 0
4 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
5 : [],
6 required: 'You must select at least one user.'
7);

额外验证

如果你想执行额外的验证逻辑,可以向 validate 参数传递一个闭包。

1$ids = multisearch(
2 label: 'Search for the users that should receive the mail',
3 options: fn (string $value) => strlen($value) > 0
4 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all()
5 : [],
6 validate: function (array $values) {
7 $optedOut = User::whereLike('name', '%a%')->findMany($values);
8 
9 if ($optedOut->isNotEmpty()) {
10 return $optedOut->pluck('name')->join(', ', ', and ').' have opted out.';
11 }
12 }
13);

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

暂停 (Pause)

pause 函数可用于向用户显示提示文本,并等待他们按下回车键(Enter / Return)来确认他们希望继续。

1use function Laravel\Prompts\pause;
2 
3pause('Press ENTER to continue.');

自动补全 (Autocomplete)

autocomplete 函数可用于为可能的选择提供内联自动补全。当用户输入时,匹配输入的建议将以虚影文本形式出现,用户可以通过按下 Tab 键或右箭头键来接受该建议。

1use function Laravel\Prompts\autocomplete;
2 
3$name = autocomplete(
4 label: 'What is your name?',
5 options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim']
6);

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

1$name = autocomplete(
2 label: 'What is your name?',
3 options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim'],
4 placeholder: 'E.g. Taylor',
5 default: $user?->name,
6 hint: 'Use tab to accept, up/down to cycle.'
7);

动态选项

你还可以传递一个闭包,根据用户的输入动态生成选项。每次用户输入字符时都会调用该闭包,它应返回一个用于自动补全的选项数组。

1$file = autocomplete(
2 label: 'Which file?',
3 options: fn (string $value) => collect($files)
4 ->filter(fn ($file) => str_starts_with(strtolower($file), strtolower($value)))
5 ->values()
6 ->all(),
7);

必需值

如果你要求必须输入一个值,可以传递 required 参数。

1$name = autocomplete(
2 label: 'What is your name?',
3 options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim'],
4 required: true
5);

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

1$name = autocomplete(
2 label: 'What is your name?',
3 options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim'],
4 required: 'Your name is required.'
5);

额外验证

最后,如果你想执行额外的验证逻辑,可以向 validate 参数传递一个闭包。

1$name = autocomplete(
2 label: 'What is your name?',
3 options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim'],
4 validate: fn (string $value) => match (true) {
5 strlen($value) < 3 => 'The name must be at least 3 characters.',
6 strlen($value) > 255 => 'The name must not exceed 255 characters.',
7 default => null
8 }
9);

闭包将接收已输入的值,并返回一个错误消息;如果验证通过,则返回 null

在验证前转换输入

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

1$name = text(
2 label: 'What is your name?',
3 transform: fn (string $value) => trim($value),
4 validate: fn (string $value) => match (true) {
5 strlen($value) < 3 => 'The name must be at least 3 characters.',
6 strlen($value) > 255 => 'The name must not exceed 255 characters.',
7 default => null
8 }
9);

表单 (Forms)

通常,你需要按顺序显示多个提示,以便在执行额外操作之前收集信息。你可以使用 form 函数创建一组提示,供用户完成。

1use function Laravel\Prompts\form;
2 
3$responses = form()
4 ->text('What is your name?', required: true)
5 ->password('What is your password?', validate: ['password' => 'min:8'])
6 ->confirm('Do you accept the terms?')
7 ->submit();

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

1use App\Models\User;
2use function Laravel\Prompts\form;
3 
4$responses = form()
5 ->text('What is your name?', required: true, name: 'name')
6 ->password(
7 label: 'What is your password?',
8 validate: ['password' => 'min:8'],
9 name: 'password'
10 )
11 ->confirm('Do you accept the terms?')
12 ->submit();
13 
14User::create([
15 'name' => $responses['name'],
16 'password' => $responses['password'],
17]);

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

如果你需要对表单中的提示进行更细粒度的控制,可以调用 add 方法,而不是直接调用提示函数。add 方法会接收用户提供的所有先前响应。

1use function Laravel\Prompts\form;
2use function Laravel\Prompts\outro;
3use function Laravel\Prompts\text;
4 
5$responses = form()
6 ->text('What is your name?', required: true, name: 'name')
7 ->add(function ($responses) {
8 return text("How old are you, {$responses['name']}?");
9 }, name: 'age')
10 ->submit();
11 
12outro("Your name is {$responses['name']} and you are {$responses['age']} years old.");

提示消息

noteinfowarningerroralert 函数可用于显示提示信息。

1use function Laravel\Prompts\info;
2 
3info('Package installed successfully.');

数据表 (Tables)

table 函数可以轻松显示多行和多列数据。你只需提供列名和表格数据即可。

1use function Laravel\Prompts\table;
2 
3table(
4 headers: ['Name', 'Email'],
5 rows: User::all(['name', 'email'])->toArray()
6);

加载动画 (Spin)

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

1use function Laravel\Prompts\spin;
2 
3$response = spin(
4 callback: fn () => Http::get('http://example.com'),
5 message: 'Fetching response...'
6);

spin 函数需要 PCNTL PHP 扩展来播放加载动画。当此扩展不可用时,将显示静态版本的加载动画。

进度条

对于长时间运行的任务,显示一个进度条来通知用户任务的完成进度非常有用。使用 progress 函数,Laravel 将显示一个进度条,并针对给定可迭代值的每次迭代推进进度。

1use function Laravel\Prompts\progress;
2 
3$users = progress(
4 label: 'Updating users',
5 steps: User::all(),
6 callback: fn ($user) => $this->performTask($user)
7);

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

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

1$users = progress(
2 label: 'Updating users',
3 steps: User::all(),
4 callback: function ($user, $progress) {
5 $progress
6 ->label("Updating {$user->name}")
7 ->hint("Created on {$user->created_at}");
8 
9 return $this->performTask($user);
10 },
11 hint: 'This may take some time.'
12);

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

1$progress = progress(label: 'Updating users', steps: 10);
2 
3$users = User::all();
4 
5$progress->start();
6 
7foreach ($users as $user) {
8 $this->performTask($user);
9 
10 $progress->advance();
11}
12 
13$progress->finish();

任务 (Task)

task 函数在给定回调执行时显示一个带有加载动画和滚动实时输出区域的带标签任务。它非常适合封装长时间运行的进程,如依赖项安装或部署脚本,从而提供对正在发生的事情的实时可见性。

1use function Laravel\Prompts\task;
2 
3task(
4 label: 'Installing dependencies',
5 callback: function ($logger) {
6 // Long-running process...
7 }
8);

回调接收一个 Logger 实例,你可以使用它在任务的输出区域显示日志行、状态消息和流式文本。

task 函数需要 PCNTL PHP 扩展来播放加载动画。当此扩展不可用时,将显示静态版本的任务。

日志记录

line 方法将单行日志写入任务的滚动输出区域。

1task(
2 label: 'Installing dependencies',
3 callback: function ($logger) {
4 $logger->line('Resolving packages...');
5 // ...
6 $logger->line('Downloading laravel/framework');
7 // ...
8 }
9);

状态消息

你可以使用 successwarningerror 方法显示状态消息。它们作为稳定的高亮消息显示在滚动日志区域上方。

1task(
2 label: 'Deploying application',
3 callback: function ($logger) {
4 $logger->line('Pulling latest changes...');
5 // ...
6 $logger->success('Changes pulled!');
7 
8 $logger->line('Running migrations...');
9 // ...
10 $logger->warning('No new migrations to run.');
11 
12 $logger->line('Clearing cache...');
13 // ...
14 $logger->success('Cache cleared!');
15 }
16);

更新标签

label 方法允许你在任务运行时更新其标签。

1task(
2 label: 'Starting deployment...',
3 callback: function ($logger) {
4 $logger->label('Pulling latest changes...');
5 // ...
6 $logger->label('Running migrations...');
7 // ...
8 $logger->label('Clearing cache...');
9 // ...
10 }
11);

流式文本

对于增量产生输出的进程(如 AI 生成的响应),partial 方法允许你逐字或逐块流式传输文本。流完成后,调用 commitPartial 来完成输出。

1task(
2 label: 'Generating response...',
3 callback: function ($logger) {
4 foreach ($words as $word) {
5 $logger->partial($word . ' ');
6 }
7 
8 $logger->commitPartial();
9 }
10);

自定义输出限制

默认情况下,任务最多显示 10 行滚动输出。你可以通过 limit 参数自定义此设置。

1task(
2 label: 'Installing dependencies',
3 callback: function ($logger) {
4 // ...
5 },
6 limit: 20
7);

流式输出 (Stream)

stream 函数显示流向终端的文本,非常适合显示 AI 生成的内容或任何增量到达的文本。

1use function Laravel\Prompts\stream;
2 
3$stream = stream();
4 
5foreach ($words as $word) {
6 $stream->append($word . ' ');
7 usleep(25_000); // Simulate delay between chunks...
8}
9 
10$stream->close();

append 方法将文本添加到流中,并以逐渐淡入的效果渲染它。当所有内容都流式传输完毕后,调用 close 方法来完成输出并恢复光标。

终端标题 (Terminal Title)

title 函数更新用户终端窗口或标签页的标题。

1use function Laravel\Prompts\title;
2 
3title('Installing Dependencies');

要将终端标题重置回默认状态,请传递一个空字符串。

1title('');

清空终端

clear 函数可用于清空用户的终端。

1use function Laravel\Prompts\clear;
2 
3clear();

终端注意事项

终端宽度

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

终端高度

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

不支持的环境与回退机制

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

因此,Laravel Prompts 支持回退到替代实现,例如 Symfony 控制台问答助手 (Symfony Console Question Helper)

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

回退条件

如果你没有使用 Laravel 或需要自定义何时使用回退行为,可以向 Prompt 类上的 fallbackWhen 静态方法传递一个布尔值。

1use Laravel\Prompts\Prompt;
2 
3Prompt::fallbackWhen(
4 ! $input->isInteractive() || windows_os() || app()->runningUnitTests()
5);

回退行为

如果你没有使用 Laravel 或需要自定义回退行为,可以向每个提示类上的 fallbackUsing 静态方法传递一个闭包。

1use Laravel\Prompts\TextPrompt;
2use Symfony\Component\Console\Question\Question;
3use Symfony\Component\Console\Style\SymfonyStyle;
4 
5TextPrompt::fallbackUsing(function (TextPrompt $prompt) use ($input, $output) {
6 $question = (new Question($prompt->label, $prompt->default ?: null))
7 ->setValidator(function ($answer) use ($prompt) {
8 if ($prompt->required && $answer === null) {
9 throw new \RuntimeException(
10 is_string($prompt->required) ? $prompt->required : 'Required.'
11 );
12 }
13 
14 if ($prompt->validate) {
15 $error = ($prompt->validate)($answer ?? '');
16 
17 if ($error) {
18 throw new \RuntimeException($error);
19 }
20 }
21 
22 return $answer;
23 });
24 
25 return (new SymfonyStyle($input, $output))
26 ->askQuestion($question);
27});

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

测试

Laravel 提供了多种方法来测试你的命令是否显示了预期的提示消息。

1test('report generation', function () {
2 $this->artisan('report:generate')
3 ->expectsPromptsInfo('Welcome to the application!')
4 ->expectsPromptsWarning('This action cannot be undone')
5 ->expectsPromptsError('Something went wrong')
6 ->expectsPromptsAlert('Important notice!')
7 ->expectsPromptsIntro('Starting process...')
8 ->expectsPromptsOutro('Process completed!')
9 ->expectsPromptsTable(
10 headers: ['Name', 'Email'],
11 rows: [
12 ['Taylor Otwell', '[email protected]'],
13 ['Jason Beggs', '[email protected]'],
14 ]
15 )
16 ->assertExitCode(0);
17});
1public function test_report_generation(): void
2{
3 $this->artisan('report:generate')
4 ->expectsPromptsInfo('Welcome to the application!')
5 ->expectsPromptsWarning('This action cannot be undone')
6 ->expectsPromptsError('Something went wrong')
7 ->expectsPromptsAlert('Important notice!')
8 ->expectsPromptsIntro('Starting process...')
9 ->expectsPromptsOutro('Process completed!')
10 ->expectsPromptsTable(
11 headers: ['Name', 'Email'],
12 rows: [
13 ['Taylor Otwell', '[email protected]'],
14 ['Jason Beggs', '[email protected]'],
15 ]
16 )
17 ->assertExitCode(0);
18}