1. Paquetes
  2. Prompts

Introducción

Laravel Prompts es un paquete PHP para agregar formularios hermosos y amigables para el usuario a sus aplicaciones de línea de comandos, con funciones similares a las de un navegador, como texto de marcador de posición y validación.

<img src="https://laravel-docs.com/images/docs/10.x/prompts-example.png">

Laravel Prompts es perfecto para aceptar la entrada del usuario en sus comandos de consola Artisan, pero también se puede utilizar en cualquier proyecto PHP de línea de comandos.

Nota Laravel Prompts es compatible con macOS, Linux y Windows con WSL. Para obtener más información, consulte nuestra documentación sobre entornos no compatibles y fallbacks.

Instalación

Laravel Prompts ya está incluido en la última versión de Laravel.

Laravel Prompts también se puede instalar en otros proyectos PHP utilizando el administrador de paquetes Composer:

composer require laravel/prompts

Prompts Disponibles

Texto

La función text solicitará al usuario con la pregunta dada, aceptará su entrada y luego la devolverá:

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

También puede incluir texto de marcador de posición, un valor predeterminado y una pista informativa:

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

Valores Requeridos

Si se requiere que se ingrese un valor, puede pasar el argumento required:

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

Si desea personalizar el mensaje de validación, también puede pasar una cadena:

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

Validación Adicional

Finalmente, si desea realizar lógica de validación adicional, puede pasar una clausura al argumento 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
}
);

La clausura recibirá el valor que se ha ingresado y puede devolver un mensaje de error o null si la validación es exitosa.

Contraseña

La función password es similar a la función text, pero la entrada del usuario se enmascarará a medida que la escriben en la consola. Esto es útil al solicitar información sensible como contraseñas:

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

También puede incluir texto de marcador de posición y una pista informativa:

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

Valores Requeridos

Si se requiere que se ingrese un valor, puede pasar el argumento required:

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

Si desea personalizar el mensaje de validación, también puede pasar una cadena:

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

Validación Adicional

Finalmente, si desea realizar lógica de validación adicional, puede pasar una clausura al argumento 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
}
);

La clausura recibirá el valor que se ha ingresado y puede devolver un mensaje de error o null si la validación es exitosa.

Confirmar

Si necesita preguntar al usuario por una confirmación de "sí o no", puede usar la función confirm. Los usuarios pueden utilizar las teclas de flecha o presionar y o n para seleccionar su respuesta. Esta función devolverá true o false.

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

También puede incluir un valor predeterminado, palabras personalizadas para las etiquetas "Sí" y "No" y una pista informativa:

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

Requerir "Sí"

Si es necesario, puede requerir que sus usuarios seleccionen "Sí" pasando el argumento required:

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

Si desea personalizar el mensaje de validación, también puede pasar una cadena:

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

Seleccionar

Si necesita que el usuario elija entre un conjunto predefinido de opciones, puede usar la función select:

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

También puede especificar la opción predeterminada y una pista informativa:

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

También puede pasar un array asociativo al argumento options para que se devuelva la clave seleccionada en lugar de su valor:

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

Se mostrarán hasta cinco opciones antes de que la lista comience a desplazarse. Puede personalizar esto pasando el argumento scroll:

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

Validación

A diferencia de otras funciones de prompt, la función select no acepta el argumento required porque no es posible seleccionar nada. Sin embargo, puede pasar una clausura al argumento validate si necesita presentar una opción pero evitar que se seleccione:

$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
);

Si el argumento options es un array asociativo, entonces la clausura recibirá la clave seleccionada, de lo contrario recibirá el valor seleccionado. La clausura puede devolver un mensaje de error o null si la validación es exitosa.

Selección Múltiple

Si necesita que el usuario pueda seleccionar múltiples opciones, puede usar la función multiselect:

use function Laravel\Prompts\multiselect;
 
$permissions = multiselect(
'¿Qué permisos deben asignarse?',
['Leer', 'Crear', 'Actualizar', 'Eliminar']
);

También puede especificar opciones predeterminadas y una pista informativa:

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

También puede pasar un array asociativo al argumento options para devolver las claves de las opciones seleccionadas en lugar de sus valores:

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

Se mostrarán hasta cinco opciones antes de que la lista comience a desplazarse. Puede personalizar esto pasando el argumento scroll:

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

Requerir un Valor

Por defecto, el usuario puede seleccionar cero o más opciones. Puede pasar el argumento required para obligar a seleccionar una o más opciones en su lugar:

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

Si desea personalizar el mensaje de validación, puede proporcionar una cadena al argumento required:

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

Validación

Puede pasar una clausura al argumento validate si necesita presentar una opción pero evitar que se seleccione:

$permissions = select(
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
);

Si el argumento options es un array asociativo, entonces la clausura recibirá las claves seleccionadas, de lo contrario recibirá los valores seleccionados. La clausura puede devolver un mensaje de error o null si la validación es exitosa.

Sugerir

La función suggest se puede utilizar para proporcionar autocompletado para opciones posibles. El usuario todavía puede proporcionar cualquier respuesta, independientemente de las sugerencias de autocompletado:

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

Alternativamente, puede pasar una clausura como segundo argumento a la función suggest. La clausura se llamará cada vez que el usuario escriba un carácter de entrada. La clausura debe aceptar un parámetro de cadena que contenga la entrada del usuario hasta ahora y devolver un array de opciones para el autocompletado:

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

También puede incluir texto de marcador de posición, un valor predeterminado y una pista informativa:

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

Valores Requeridos

Si se requiere que se ingrese un valor, puede pasar el argumento required:

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

Si desea personalizar el mensaje de validación, también puede pasar una cadena:

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

Validación Adicional

Finalmente, si desea realizar lógica de validación adicional, puede pasar una clausura al argumento 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
}
);

La clausura recibirá el valor que se ha ingresado y puede devolver un mensaje de error o null si la validación es exitosa.

Buscar

Si tiene muchas opciones para que el usuario seleccione, la función search permite al usuario escribir una consulta de búsqueda para filtrar los resultados antes de usar las teclas de flecha para seleccionar una opción:

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

La clausura recibirá el texto que ha sido escrito por el usuario hasta ahora y debe devolver un array de opciones. Si devuelve un array asociativo, se devolverá la clave de la opción seleccionada; de lo contrario, se devolverá su valor.

También puede incluir texto de marcador de posición y una pista informativa:

$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::where('name', 'like', "%{$value}%")->pluck('name', 'id')->all()
: [],
hint: 'The user will receive an email immediately.'
);

Se mostrarán hasta cinco opciones antes de que la lista comience a desplazarse. Puede personalizar esto pasando el argumento scroll:

$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
);

Validación

Si desea realizar lógica de validación adicional, puede pasar una clausura al argumento validate:

$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::findOrFail($value);
 
if ($user->opted_out) {
return 'This user has opted-out of receiving mail.';
}
}
);

Si la clausura options devuelve un array asociativo, entonces la clausura recibirá la clave seleccionada, de lo contrario, recibirá el valor seleccionado. La clausura puede devolver un mensaje de error o null si la validación es exitosa.

Búsqueda Múltiple

Si tiene muchas opciones buscables y necesita que el usuario pueda seleccionar varios elementos, la función multisearch permite al usuario escribir una consulta de búsqueda para filtrar los resultados antes de usar las teclas de flecha y la barra espaciadora para seleccionar opciones:

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

La clausura recibirá el texto que ha sido escrito por el usuario hasta ahora y debe devolver un array de opciones. Si devuelve un array asociativo, se devolverán las claves de las opciones seleccionadas; de lo contrario, se devolverán sus valores.

También puede incluir texto de marcador de posición y una pista informativa:

$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::where('name', 'like', "%{$value}%")->pluck('name', 'id')->all()
: [],
hint: 'The user will receive an email immediately.'
);

Se mostrarán hasta cinco opciones antes de que la lista comience a desplazarse. Puede personalizar esto proporcionando el argumento scroll:

$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
);

Requerir un Valor

Por defecto, el usuario puede seleccionar cero o más opciones. Puede pasar el argumento required para obligar a seleccionar una o más opciones en su lugar:

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

Si desea personalizar el mensaje de validación, puede proporcionar una cadena al argumento required:

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

Validación

Si desea realizar lógica de validación adicional, puede pasar una clausura al argumento validate:

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

Si la clausura options devuelve un array asociativo, entonces la clausura recibirá las claves seleccionadas; de lo contrario, recibirá los valores seleccionados. La clausura puede devolver un mensaje de error o null si la validación es exitosa.

Mensajes Informativos

Las funciones note, info, warning, error y alert se pueden utilizar para mostrar mensajes informativos:

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

Tablas

La función table facilita la visualización de múltiples filas y columnas de datos. Todo lo que necesita hacer es proporcionar los nombres de las columnas y los datos para la tabla:

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

Girar

La función spin muestra un spinner junto con un mensaje opcional mientras ejecuta un callback especificado. Sirve para indicar procesos en curso y devuelve los resultados del callback al completarse:

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

Advertencia La función spin requiere que la extensión PHP pcntl esté habilitada para animar el spinner. Cuando esta extensión no está disponible, en su lugar aparecerá una versión estática del spinner.

Barras de Progreso

Para tareas de larga duración, puede ser útil mostrar una barra de progreso que informe a los usuarios sobre la completitud de la tarea. Usando la función progress, Laravel mostrará una barra de progreso y avanzará su progreso en cada iteración sobre un valor iterable dado:

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

La función progress actúa como una función de map y devolverá un array que contiene el valor de retorno de cada iteración de su callback.

El callback también puede aceptar la instancia \Laravel\Prompts\Progress, lo que le permite modificar la etiqueta y la pista en cada iteración:

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

A veces, puede necesitar un control más manual sobre cómo se avanza una barra de progreso. Primero, defina el número total de pasos que el proceso iterará. Luego, avance la barra de progreso mediante el método advance después de procesar cada elemento:

$progress = progress(label: 'Updating users', steps: 10);
 
$users = User::all();
 
$progress->start();
 
foreach ($users as $user) {
$this->performTask($user);
 
$progress->advance();
}
 
$progress->finish();

Consideraciones para la Terminal

Ancho de la Terminal

Si la longitud de cualquier etiqueta, opción o mensaje de validación supera el número de "columnas" en la terminal del usuario, se truncará automáticamente para ajustarse. Considere minimizar la longitud de estas cadenas si sus usuarios pueden estar utilizando terminales más estrechas. Una longitud máxima típicamente segura es de 74 caracteres para admitir una terminal de 80 caracteres.

Altura de la Terminal

Para cualquier prompt que acepte el argumento scroll, el valor configurado se reducirá automáticamente para ajustarse a la altura de la terminal del usuario, incluido el espacio para un mensaje de validación.

Entornos No Compatibles y Alternativas

Laravel Prompts es compatible con macOS, Linux y Windows con WSL. Debido a limitaciones en la versión de PHP para Windows, actualmente no es posible usar Laravel Prompts en Windows fuera de WSL.

Por esta razón, Laravel Prompts admite la posibilidad de caer de nuevo a una implementación alternativa, como el Symfony Console Question Helper.

Nota Al utilizar Laravel Prompts con el framework Laravel, los fallbacks para cada prompt ya han sido configurados para usted y se habilitarán automáticamente en entornos no compatibles.

Condiciones de Reserva

Si no está utilizando Laravel o necesita personalizar cuándo se utiliza el comportamiento de fallback, puede pasar un booleano al método estático fallbackWhen en la clase Prompt:

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

Comportamiento de Reserva

Si no está utilizando Laravel o necesita personalizar el comportamiento de fallback, puede pasar una clausura al método estático fallbackUsing en cada clase de prompt:

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);
});

Los fallbacks deben configurarse individualmente para cada clase de prompt. La clausura recibirá una instancia de la clase de prompt y debe devolver un tipo apropiado para el prompt.