跳至内容

提示

简介

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

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

lightbulb

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

安装

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

Laravel Prompts 也可以使用 Composer 包管理器安装到您的其他 PHP 项目中。

composer require laravel/prompts

可用的提示

文本

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

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

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

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

必需值

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

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

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

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

其他验证

最后,如果您想执行其他验证逻辑,可以将闭包传递给 validate 参数。

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

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

或者,您可以利用 Laravel 的 验证器 的强大功能。为此,请将包含属性名称和所需验证规则的数组提供给 validate 参数。

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

文本区域

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

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

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

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

必需值

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

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

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

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

其他验证

最后,如果您想执行其他验证逻辑,可以将闭包传递给 validate 参数。

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

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

或者,您可以利用 Laravel 的 验证器 的强大功能。为此,请将包含属性名称和所需验证规则的数组提供给 validate 参数。

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

密码

password 函数类似于 text 函数,但用户的输入在他们在控制台中键入时会被屏蔽。这在询问敏感信息(如密码)时非常有用。

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

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

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

必需值

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

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

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

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

其他验证

最后,如果您想执行其他验证逻辑,可以将闭包传递给 validate 参数。

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

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

或者,您可以利用 Laravel 的 验证器 的强大功能。为此,请将包含属性名称和所需验证规则的数组提供给 validate 参数。

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

确认

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

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

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

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

要求“是”

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

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

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

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

选择

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

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

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

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

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

$role = select(
label: 'What role should the user have?',
options: [
'member' => 'Member',
'contributor' => 'Contributor',
'owner' => 'Owner',
],
default: 'owner'
);

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

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

其他验证

与其他提示函数不同,select 函数不接受 required 参数,因为无法选择任何内容。但是,如果您需要显示选项但阻止其被选中,则可以将闭包传递给 validate 参数。

$role = select(
label: 'What role should the user have?',
options: [
'member' => 'Member',
'contributor' => 'Contributor',
'owner' => 'Owner',
],
validate: fn (string $value) =>
$value === 'owner' && User::where('role', 'owner')->exists()
? 'An owner already exists.'
: null
);

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

多选

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

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

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

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

您还可以将关联数组传递给 options 参数,以返回选定选项的键而不是其值。

$permissions = multiselect(
label: 'What permissions should be assigned?',
options: [
'read' => 'Read',
'create' => 'Create',
'update' => 'Update',
'delete' => 'Delete',
],
default: ['read', 'create']
);

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

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

要求值

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

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

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

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

其他验证

您可以将闭包传递给 validate 参数,如果您需要显示选项但阻止其被选中。

$permissions = multiselect(
label: 'What permissions should the user have?',
options: [
'read' => 'Read',
'create' => 'Create',
'update' => 'Update',
'delete' => 'Delete',
],
validate: fn (array $values) => ! in_array('read', $values)
? 'All users require the read permission.'
: null
);

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

建议

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

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

或者,您可以将闭包作为第二个参数传递给 suggest 函数。每次用户键入输入字符时,都会调用闭包。闭包应接受一个字符串参数,其中包含用户迄今为止的输入,并返回一个用于自动完成的选项数组。

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

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

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

必需值

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

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

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

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

其他验证

最后,如果您想执行其他验证逻辑,可以将闭包传递给 validate 参数。

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

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

或者,您可以利用 Laravel 的 验证器 的强大功能。为此,请将包含属性名称和所需验证规则的数组提供给 validate 参数。

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

如果用户有很多选项可供选择,search 函数允许用户键入搜索查询以筛选结果,然后使用箭头键选择选项。

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

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

在筛选您打算返回值的数组时,您应该使用 array_values 函数或 values 集合方法来确保数组不会成为关联数组。

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

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

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

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

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

其他验证

如果您想执行其他验证逻辑,可以将闭包传递给 validate 参数。

$id = search(
label: 'Search for the user that should receive the mail',
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 'This user has opted-out of receiving mail.';
}
}
);

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

多搜索

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

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

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

在筛选您打算返回值的数组时,您应该使用 array_values 函数或 values 集合方法来确保数组不会成为关联数组。

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

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

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

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

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

要求值

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

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

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

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

其他验证

如果您想执行其他验证逻辑,可以将闭包传递给 validate 参数。

$ids = multisearch(
label: 'Search for the users that should receive the mail',
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(', ', ', and ').' have opted out.';
}
}
);

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

暂停

pause 函数可用于向用户显示信息文本,并等待他们按下 Enter/Return 键确认是否继续。

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

验证前转换输入

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

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

表单

通常,您将有多个提示依次显示以收集信息,然后再执行其他操作。您可以使用 form 函数创建一组用于用户完成的提示。

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

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

use App\Models\User;
use function Laravel\Prompts\form;
 
$responses = form()
->text('What is your name?', required: true, name: 'name')
->password(
label: 'What is your password?',
validate: ['password' => 'min:8'],
name: 'password'
)
->confirm('Do you accept the terms?')
->submit();
 
User::create([
'name' => $responses['name'],
'password' => $responses['password'],
]);

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

如果您需要更精细地控制表单中的提示,则可以使用 add 方法,而不是直接调用提示函数。add 方法将传递用户提供的所有先前响应。

use function Laravel\Prompts\form;
use function Laravel\Prompts\outro;
 
$responses = form()
->text('What is your name?', required: true, name: 'name')
->add(function ($responses) {
return text("How old are you, {$responses['name']}?");
}, name: 'age')
->submit();
 
outro("Your name is {$responses['name']} and you are {$responses['age']} years old.");

信息消息

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

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

表格

table 函数使显示多行多列数据变得容易。您只需提供列名和表格数据即可。

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

旋转

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

use function Laravel\Prompts\spin;
 
$response = spin(
message: 'Fetching response...',
callback: fn () => Http::get('http://example.com')
);
exclamation

spin 函数需要 pcntl PHP 扩展来动画化微调器。当此扩展不可用时,将显示微调器的静态版本。

进度条

对于长时间运行的任务,显示进度条以告知用户任务完成的程度会很有帮助。使用 progress 函数,Laravel 将显示一个进度条,并在遍历给定可迭代值时推进其进度。

use function Laravel\Prompts\progress;
 
$users = progress(
label: 'Updating users',
steps: User::all(),
callback: fn ($user) => $this->performTask($user)
);

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

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

$users = progress(
label: 'Updating users',
steps: User::all(),
callback: function ($user, $progress) {
$progress
->label("Updating {$user->name}")
->hint("Created on {$user->created_at}");
 
return $this->performTask($user);
},
hint: 'This may take some time.'
);

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

$progress = progress(label: 'Updating users', 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

lightbulb

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

回退条件

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

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

回退行为

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

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 : 'Required.'
);
}
 
if ($prompt->validate) {
$error = ($prompt->validate)($answer ?? '');
 
if ($error) {
throw new \RuntimeException($error);
}
}
 
return $answer;
});
 
return (new SymfonyStyle($input, $output))
->askQuestion($question);
});

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