Skip to content

Prompts

简介

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

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

NOTE

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

安装

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

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

shell
composer require laravel/prompts

可用提示

文本

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

php
use function Laravel\Prompts\text;

$name = text('What is your name?');

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

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

必填值

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

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

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

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

附加验证

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

php
$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 参数提供包含属性名称和所需验证规则的数组:

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

文本区域

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

php
use function Laravel\Prompts\textarea;

$story = textarea('Tell me a story.');

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

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

必填值

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

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

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

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

附加验证

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

php
$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 参数提供包含属性名称和所需验证规则的数组:

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

数字

number 函数将使用给定问题提示用户,接受其数字输入,然后返回它。number 函数允许用户使用上下箭头键操作数字:

php
use function Laravel\Prompts\number;

$number = number('How many copies would you like?');

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

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

必填值

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

php
$copies = number(
    label: 'How many copies would you like?',
    required: true
);

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

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

附加验证

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

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

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

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

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

密码

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

php
use function Laravel\Prompts\password;

$password = password('What is your password?');

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

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

必填值

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

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

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

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

附加验证

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

php
$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 参数提供包含属性名称和所需验证规则的数组:

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

确认

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

php
use function Laravel\Prompts\confirm;

$confirmed = confirm('Do you accept the terms?');

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

php
$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 参数来要求用户选择「是」:

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

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

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

选择

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

php
use function Laravel\Prompts\select;

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

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

php
$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 参数传递关联数组,以返回所选键而不是其值:

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

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

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

次要信息

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

php
$role = select(
    label: 'What role should the user have?',
    options: [
        'member' => 'Member',
        'contributor' => 'Contributor',
        'owner' => 'Owner',
    ],
    info: fn (string $value) => match ($value) {
        'member' => 'Can view and comment.',
        'contributor' => 'Can view, comment, and edit.',
        'owner' => 'Full access to all resources.',
        default => null,
    }
);

如果信息不依赖于突出显示的选项,您还可以向 info 参数传递静态字符串:

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

附加验证

与其他提示函数不同,select 函数不接受 required 参数,因为不可能选择空值。但是,如果您需要呈现选项但阻止其被选择,可以向 validate 参数传递闭包:

php
$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 函数:

php
use function Laravel\Prompts\multiselect;

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

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

php
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 参数传递关联数组,以返回所选选项的键而不是其值:

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

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

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

次要信息

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

php
$permissions = multiselect(
    label: 'What permissions should be assigned?',
    options: [
        'read' => 'Read',
        'create' => 'Create',
        'update' => 'Update',
        'delete' => 'Delete',
    ],
    info: fn (string $value) => match ($value) {
        'read' => 'View resources and their properties.',
        'create' => 'Create new resources.',
        'update' => 'Modify existing resources.',
        'delete' => 'Permanently remove resources.',
        default => null,
    }
);

要求值

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

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

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

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

附加验证

如果您需要呈现选项但阻止其被选择,可以向 validate 参数传递闭包:

php
$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 函数可用于为可能的选择提供自动完成。用户仍然可以提供任何答案,无论自动完成提示如何:

php
use function Laravel\Prompts\suggest;

$name = suggest('What is your name?', ['Taylor', 'Dayle']);

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

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

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

php
$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.'
);

次要信息

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

php
$name = suggest(
    label: 'What is your name?',
    options: ['Taylor', 'Dayle'],
    info: fn (string $value) => match ($value) {
        'Taylor' => 'Administrator',
        'Dayle' => 'Contributor',
        default => null,
    }
);

必填值

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

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

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

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

附加验证

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

php
$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 参数提供包含属性名称和所需验证规则的数组:

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

搜索

search 函数将提示用户输入搜索查询,然后根据该查询过滤选项,允许用户选择一个选项:

php
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::where('name', 'like', "%{$value}%")->pluck('name', 'id')->all()
        : []
);

闭包将接收用户目前输入的文本,并应返回选项数组。如果您返回关联数组,则将返回所选选项的键,否则将返回其值。

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

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

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

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

附加验证

与其他提示函数不同,search 函数不接受 required 参数,因为不可能选择空值。但是,如果您需要呈现选项但阻止其被选择,可以向 validate 参数传递闭包:

php
$id = search(
    label: 'Search for the user that should receive the mail',
    options: fn (string $value) => strlen($value) > 0
        ? User::where('name', 'like', "%{$value}%")->pluck('name', 'id')->all()
        : [],
    validate: function (int|string $value) {
        $user = User::find($value);

        if ($user->opted_out) {
            return 'This user has opted-out of receiving mail.';
        }
    }
);

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

多搜索

multisearch 函数将提示用户输入搜索查询,然后根据该查询过滤选项,允许用户选择多个选项:

php
use function Laravel\Prompts\multisearch;

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

闭包将接收用户目前输入的文本,并应返回选项数组。如果您返回关联数组,则将返回所选选项的键,否则将返回其值。

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

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

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

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

要求值

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

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

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

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

附加验证

如果您需要呈现选项但阻止其被选择,可以向 validate 参数传递闭包:

php
$ids = multisearch(
    label: 'Search for the users that should receive the mail',
    options: fn (string $value) => strlen($value) > 0
        ? User::where('name', 'like', "%{$value}%")->pluck('name', 'id')->all()
        : [],
    validate: function (array $values) {
        $optedOut = User::where('name', 'like', '%a%')->findMany($values);

        if ($optedOut->isNotEmpty()) {
            return $optedOut->pluck('name')->join(', ', ', and ').' have opted out.';
        }
    }
);

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

暂停

pause 函数向用户显示给定消息,并等待他们按 Enter/Return 键继续:

php
use function Laravel\Prompts\pause;

pause('Press ENTER to continue...');

自动完成

autocomplete 函数类似于 suggest 函数,但允许用户使用箭头键从自动完成选项中选择:

php
use function Laravel\Prompts\autocomplete;

$name = autocomplete(
    label: 'What is your name?',
    options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim']
);

或者,您可以将闭包作为第二个参数传递给 autocomplete 函数。每次用户输入字符时都会调用闭包。闭包应接受包含用户目前输入的字符串参数,并返回自动完成选项数组:

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

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

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

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

php
$name = autocomplete(
    label: 'What is your name?',
    options: User::pluck('name')->sort()->all(),
    scroll: 10
);

必填值

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

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

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

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

附加验证

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

php
$name = autocomplete(
    label: 'What is your name?',
    options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim'],
    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

验证前转换输入

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

php
$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 函数创建一组分组的提示供用户完成:

php
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 参数为每个提示提供名称。当提供名称时,可以通过该名称访问命名提示的响应:

php
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 方法传递用户提供的所有先前响应:

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

$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 函数可用于显示信息消息:

php
use function Laravel\Prompts\info;

info('Package installed successfully.');

表格

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

php
use function Laravel\Prompts\table;

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

旋转

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

php
use function Laravel\Prompts\spin;

$response = spin(
    callback: fn () => Http::get('http://example.com'),
    message: 'Fetching response...'
);

WARNING

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

进度条

对于长时间运行的任务,显示进度条通知用户任务完成程度可能会有所帮助。使用 progress 函数,Laravel 将显示进度条,并在对给定可迭代值的每次迭代中推进其进度:

php
use function Laravel\Prompts\progress;

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

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

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

php
$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 方法推进进度条:

php
$progress = progress(label: 'Updating users', steps: 10);

$users = User::all();

$progress->start();

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

    $progress->advance();
}

$progress->finish();

任务

task 函数在执行给定回调时显示带有旋转器和滚动实时输出区域的标记任务。它非常适合包装长时间运行的进程,如依赖安装或部署脚本,提供对正在发生事情的实时可见性:

php
use function Laravel\Prompts\task;

task(
    label: 'Installing dependencies',
    callback: function ($logger) {
        // 长时间运行的进程...
    }
);

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

WARNING

task 函数需要 PCNTL PHP 扩展来动画化旋转器。当此扩展不可用时,将显示静态版本的任务。

记录行

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

php
task(
    label: 'Installing dependencies',
    callback: function ($logger) {
        $logger->line('Resolving packages...');
        // ...
        $logger->line('Downloading laravel/framework');
        // ...
    }
);

状态消息

您可以使用 successwarningerror 方法显示状态消息。这些消息显示为滚动日志区域上方的稳定、突出显示的消息:

php
task(
    label: 'Deploying application',
    callback: function ($logger) {
        $logger->line('Pulling latest changes...');
        // ...
        $logger->success('Changes pulled!');

        $logger->line('Running migrations...');
        // ...
        $logger->warning('No new migrations to run.');

        $logger->line('Clearing cache...');
        // ...
        $logger->success('Cache cleared!');
    }
);

更新标签

label 方法允许您在任务运行时更新任务的标签:

php
task(
    label: 'Starting deployment...',
    callback: function ($logger) {
        $logger->label('Pulling latest changes...');
        // ...
        $logger->label('Running migrations...');
        // ...
        $logger->label('Clearing cache...');
        // ...
    }
);

流式文本

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

php
task(
    label: 'Generating response...',
    callback: function ($logger) {
        foreach ($words as $word) {
            $logger->partial($word . ' ');
        }

        $logger->commitPartial();
    }
);

自定义输出限制

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

php
task(
    label: 'Installing dependencies',
    callback: function ($logger) {
        // ...
    },
    limit: 20
);

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

php
use function Laravel\Prompts\stream;

$stream = stream();

foreach ($words as $word) {
    $stream->append($word . ' ');
    usleep(25_000); // 模拟块之间的延迟...
}

$stream->close();

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

终端标题

title 函数更新用户终端窗口或选项卡的标题:

php
use function Laravel\Prompts\title;

title('Installing Dependencies');

要将终端标题重置为默认值,传递空字符串:

php
title('');

清除终端

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

php
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 : 'Required.'
                );
            }

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

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

            return $answer;
        });

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

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

测试

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

php
test('report generation', function () {
    $this->artisan('report:generate')
        ->expectsPromptsInfo('Welcome to the application!')
        ->expectsPromptsWarning('This action cannot be undone')
        ->expectsPromptsError('Something went wrong')
        ->expectsPromptsAlert('Important notice!')
        ->expectsPromptsIntro('Starting process...')
        ->expectsPromptsOutro('Process completed!')
        ->expectsPromptsTable(
            headers: ['Name', 'Email'],
            rows: [
                ['Taylor Otwell', 'taylor@example.com'],
                ['Jason Beggs', 'jason@example.com'],
            ]
        )
        ->assertExitCode(0);
});
php
public function test_report_generation(): void
{
    $this->artisan('report:generate')
        ->expectsPromptsInfo('Welcome to the application!')
        ->expectsPromptsWarning('This action cannot be undone')
        ->expectsPromptsError('Something went wrong')
        ->expectsPromptsAlert('Important notice!')
        ->expectsPromptsIntro('Starting process...')
        ->expectsPromptsOutro('Process completed!')
        ->expectsPromptsTable(
            headers: ['Name', 'Email'],
            rows: [
                ['Taylor Otwell', 'taylor@example.com'],
                ['Jason Beggs', 'jason@example.com'],
            ]
        )
        ->assertExitCode(0);
}