본문 바로가기

Prompts

업데이트됨

번역일: 2026년 9월 17일

이 페이지는 원문이 업데이트되어 번역이 갱신되었습니다.

원문 수정
2026년 9월 17일
번역 갱신
2026년 9월 17일

Prompts

소개

Laravel Prompts는 명령줄 애플리케이션에 아름답고 사용자 친화적인 폼을 추가하기 위한 PHP 패키지입니다. 플레이스홀더 텍스트나 유효성 검증 같은 기능은 물론, 브라우저 기반 폼처럼 자연스러운 입력 경험을 제공합니다.

Laravel Prompts는 Artisan 콘솔 명령어에서 사용자 입력을 받을 때 최적의 선택입니다. 하지만 어떤 커맨드라인 PHP 프로젝트에서도 사용할 수 있는 독립적인 패키지입니다.

NOTE

Laravel Prompts는 macOS, Linux, 그리고 WSL이 설치된 Windows 환경을 지원합니다. 지원되지 않는 환경과 폴백 동작에 대한 자세한 내용은 지원되지 않는 환경 문서를 참고하세요.

설치

Laravel Prompts는 최신 버전의 Laravel에 이미 포함되어 있습니다.

다른 PHP 프로젝트에서 사용하려면 Composer 패키지 관리자로 별도 설치할 수 있습니다.

composer require laravel/prompts

사용 가능한 프롬프트 종류

Laravel Prompts는 여러 상황에 맞는 다양한 프롬프트를 제공합니다. 예를 들어 text 함수를 사용하면 사용자에게 질문을 던지고 답변을 입력받을 수 있습니다.

use function Laravel\Prompts\text; $name = text('이름이 무엇인가요?');

플레이스홀더 텍스트, 기본값, 안내 힌트 등도 추가로 지정할 수 있습니다.

$name = text( label: '이름이 무엇인가요?', placeholder: '예: 홍길동', default: $user?->name, hint: '이 정보는 프로필에 표시됩니다.' );

필수 값

값이 반드시 입력되도록 하려면 required 인자를 전달하면 됩니다.

$name = text( label: '이름이 무엇인가요?', required: true );

유효성 검증 메시지를 직접 지정하고 싶다면 문자열을 전달할 수도 있습니다.

$name = text( label: '이름이 무엇인가요?', required: '이름은 필수 입력 항목입니다.' );

추가 유효성 검증

추가적인 검증 로직을 적용하려면 validate 인자에 클로저를 전달할 수 있습니다.

$name = text( label: '이름이 무엇인가요?', validate: fn (string $value) => match (true) { strlen($value) < 3 => '이름은 최소 3자 이상이어야 합니다.', strlen($value) > 255 => '이름은 255자를 초과할 수 없습니다.', default => null } );

클로저는 입력받은 값을 받아 오류 메시지를 반환하거나, 검증에 통과하면 null을 반환할 수 있습니다.

또는 Laravel의 validator의 기능을 활용할 수도 있습니다. rules 인자에 속성명과 검증 규칙 배열을 전달하면 됩니다.

$name = text( label: '이름이 무엇인가요?', rules: ['required', 'max:255'] );

Text

text 함수는 지정한 질문과 함께 사용자에게 입력을 요청하고, 입력값을 받아서 반환합니다.

use function Laravel\Prompts\text; $name = text('이름이 무엇인가요?');

플레이스홀더 텍스트, 기본값, 안내 힌트도 함께 지정할 수 있습니다.

$name = text( label: '이름이 무엇인가요?', placeholder: '예: 홍길동', default: $user?->name, hint: '이 정보는 프로필에 표시됩니다.' );

필수 값

값을 반드시 입력하도록 요구하려면 required 인자를 전달하세요.

$name = text( label: '이름이 무엇인가요?', required: true );

검증 메시지를 커스터마이징하려면 문자열을 전달할 수 있습니다.

$name = text( label: '이름이 무엇인가요?', required: '이름은 필수 입력 항목입니다.' );

추가 유효성 검증

마지막으로, 추가적인 검증 로직을 수행하고 싶다면 validate 인자에 클로저를 전달하면 됩니다.

$name = text( label: '이름이 무엇인가요?', validate: fn (string $value) => match (true) { strlen($value) < 3 => '이름은 최소 3자 이상이어야 합니다.', strlen($value) > 255 => '이름은 255자를 초과할 수 없습니다.', default => null } );

이 클로저는 입력된 값을 받아, 오류가 있다면 오류 메시지를 반환하고 검증을 통과했다면 null을 반환하면 됩니다.

또는 Laravel validator의 강력한 기능을 활용할 수도 있습니다. 이를 위해 rules 인자에 속성명과 원하는 검증 규칙을 담은 배열을 전달하세요.

$name = text( label: '이름이 무엇인가요?', rules: ['required', 'max:255'] );

Textarea

textarea 함수는 지정한 질문과 함께 여러 줄 텍스트 입력창을 통해 사용자로부터 입력을 받고, 그 값을 반환합니다.

use function Laravel\Prompts\textarea; $story = textarea('당신의 이야기를 들려주세요.');

플레이스홀더 텍스트, 기본값, 안내 힌트도 지정할 수 있습니다.

$story = textarea( label: '당신의 이야기를 들려주세요.', placeholder: '이야기를 짧게 적어주세요.', hint: '이 내용은 프로필에 표시됩니다.' );

필수 값

값을 반드시 입력하도록 요구하려면 required 인자를 전달하세요.

$story = textarea( label: '당신의 이야기를 들려주세요.', required: true );

검증 메시지를 커스터마이징하려면 문자열을 전달할 수 있습니다.

$story = textarea( label: '당신의 이야기를 들려주세요.', required: '이야기는 필수 입력 항목입니다.' );

추가 유효성 검증

마지막으로, 추가적인 검증 로직을 수행하려면 validate 인자에 클로저를 전달하세요.

$story = textarea( label: '당신의 이야기를 들려주세요.', validate: fn (string $value) => match (true) { strlen($value) < 250 => '이야기는 최소 250자 이상이어야 합니다.', strlen($value) > 10000 => '이야기는 10,000자를 초과할 수 없습니다.', default => null } );

이 클로저는 입력된 값을 받아, 오류가 있다면 오류 메시지를 반환하고 검증을 통과했다면 null을 반환하면 됩니다.

또는 Laravel validator의 기능을 활용할 수도 있습니다. rules 인자에 속성명과 검증 규칙 배열을 전달하세요.

$story = textarea( label: '당신의 이야기를 들려주세요.', rules: ['required', 'max:10000'] );

Number

number 함수는 지정한 질문과 함께 숫자 입력을 요청하고, 입력값을 반환합니다.

use function Laravel\Prompts\number; $age = number('나이가 어떻게 되시나요?');

플레이스홀더 텍스트, 기본값, 안내 힌트도 지정할 수 있습니다.

$age = number( label: '나이가 어떻게 되시나요?', placeholder: '예: 25', hint: '이 정보는 프로필에 표시됩니다.' );

입력값은 숫자 형식으로 검증되며, 값이 없거나 숫자가 아닌 경우 최소/최대값 검증도 지원됩니다.

$age = number( label: '나이가 어떻게 되시나요?', min: 1, max: 120, );

필수 값

값을 반드시 입력하도록 요구하려면 required 인자를 전달하세요.

$age = number( label: '나이가 어떻게 되시나요?', required: true );

검증 메시지를 커스터마이징하려면 문자열을 전달할 수 있습니다.

$age = number( label: '나이가 어떻게 되시나요?', required: '나이는 필수 입력 항목입니다.' );

추가 유효성 검증

마지막으로, 추가적인 검증 로직을 수행하려면 validate 인자에 클로저를 전달하세요.

$age = number( label: '나이가 어떻게 되시나요?', validate: fn (int $value) => match (true) { $value < 18 => '18세 이상이어야 합니다.', $value > 100 => '유효한 나이를 입력해 주세요.', default => null } );

이 클로저는 입력된 값을 받아, 오류가 있다면 오류 메시지를 반환하고 검증을 통과했다면 null을 반환하면 됩니다.

또는 Laravel validator의 기능을 활용할 수도 있습니다. rules 인자에 속성명과 검증 규칙 배열을 전달하세요.

$age = number( label: '나이가 어떻게 되시나요?', rules: ['required', 'numeric', 'min:18', 'max:100'] );

Password

password 함수는 text 함수와 비슷하지만, 사용자가 입력하는 내용이 콘솔에 마스킹 처리되어 보인다는 점이 다릅니다. 비밀번호처럼 민감한 정보를 입력받을 때 유용합니다.

use function Laravel\Prompts\password; $password = password('비밀번호가 무엇인가요?');

플레이스홀더 텍스트와 안내 힌트를 함께 지정할 수도 있습니다.

$password = password( label: '비밀번호가 무엇인가요?', placeholder: '비밀번호를 입력하세요.', hint: '비밀번호는 최소 8자 이상이어야 합니다.' );

필수 값

값을 반드시 입력하도록 요구하려면 required 인자를 전달하세요.

$password = password( label: '비밀번호가 무엇인가요?', required: true );

검증 메시지를 커스터마이징하려면 문자열을 전달할 수 있습니다.

$password = password( label: '비밀번호가 무엇인가요?', required: '비밀번호는 필수 입력 항목입니다.' );

추가 유효성 검증

마지막으로, 추가적인 검증 로직을 수행하려면 validate 인자에 클로저를 전달하세요.

$password = password( label: '비밀번호가 무엇인가요?', validate: fn (string $value) => match (true) { strlen($value) < 8 => '비밀번호는 최소 8자 이상이어야 합니다.', default => null } );

이 클로저는 입력된 값을 받아, 오류가 있다면 오류 메시지를 반환하고 검증을 통과했다면 null을 반환하면 됩니다.

또는 Laravel validator의 기능을 활용할 수도 있습니다. rules 인자에 속성명과 검증 규칙 배열을 전달하세요.

$password = password( label: '비밀번호가 무엇인가요?', rules: ['required', 'min:8'] );

Confirm

사용자에게 "예/아니오" 형태의 확인을 받고 싶다면 confirm 함수를 사용할 수 있습니다. 사용자는 방향키나 y/n 키를 눌러 옵션을 선택하며, 이 함수는 true 또는 false를 반환합니다.

use function Laravel\Prompts\confirm; $confirmed = confirm('이용약관에 동의하시나요?');

기본값, "예"/"아니오" 라벨 문구, 안내 힌트도 커스터마이징할 수 있습니다.

$confirmed = confirm( label: '이용약관에 동의하시나요?', default: false, yes: '동의합니다', no: '동의하지 않습니다', hint: '계속 진행하려면 이용약관에 동의해야 합니다.' );

"예" 필수로 지정하기

필요하다면 required 인자를 통해 사용자가 반드시 "예"를 선택하도록 강제할 수도 있습니다.

$confirmed = confirm( label: '이용약관에 동의하시나요?', required: true );

검증 메시지를 커스터마이징하려면 문자열을 전달할 수 있습니다.

$confirmed = confirm( label: '이용약관에 동의하시나요?', required: '계속 진행하려면 이용약관에 동의해야 합니다.' );

Select

여러 선택지 중 하나를 사용자에게 고르게 하려면 select 함수를 사용하세요.

use function Laravel\Prompts\select; $role = select( label: '사용자에게 어떤 권한을 부여하시겠습니까?', options: ['관리자', '편집자', '구독자'] );

기본 선택값이나 안내 힌트도 지정할 수 있습니다.

$role = select( label: '사용자에게 어떤 권한을 부여하시겠습니까?', options: ['관리자', '편집자', '구독자'], default: '편집자', hint: '이 권한은 언제든지 변경할 수 있습니다.' );

options 인자에 연관 배열을 전달하면, 선택된 키가 반환되고 값이 화면에 표시됩니다.

$role = select( label: '사용자에게 어떤 권한을 부여하시겠습니까?', options: [ 'member' => '일반 회원', 'contributor' => '기여자', 'owner' => '소유자', ], default: 'owner' );

목록에는 화면에 보이는 개수보다 옵션이 많을 경우 스크롤할 수 있도록 최대 5개까지 표시되며, scroll 인자를 통해 개수를 변경할 수 있습니다.

$role = select( label: '어떤 권한을 부여하시겠습니까?', options: User::all()->pluck('name', 'id'), scroll: 10 );

추가 유효성 검증

다른 프롬프트 함수와 달리 select 함수는 아무것도 선택하지 않는 경우가 없으므로 required 인자를 받지 않습니다. 그러나 특정 옵션을 선택하지 못하게 하고 싶다면, validate 인자에 클로저를 전달할 수 있습니다.

$role = select( label: '사용자에게 어떤 역할을 부여하시겠습니까?', options: [ 'member' => '일반 회원', 'contributor' => '기여자', 'owner' => '소유자', ], validate: fn (string $value) => $value === 'owner' && User::where('role', 'owner')->exists() ? '이미 소유자가 존재합니다.' : null );

options 인자가 연관 배열인 경우 클로저는 선택된 키를 전달받으며, 그렇지 않은 경우에는 선택된 값을 전달받습니다.

Multi-select

사용자에게 여러 옵션을 동시에 선택할 수 있게 하려면 multiselect 함수를 사용하세요.

use function Laravel\Prompts\multiselect; $permissions = multiselect( label: '어떤 권한을 부여하시겠습니까?', options: ['글 읽기', '글 작성', '글 수정', '글 삭제'] );

기본으로 선택되어 있는 옵션이나 안내 힌트도 지정할 수 있습니다.

use function Laravel\Prompts\multiselect; $permissions = multiselect( label: '어떤 권한을 부여하시겠습니까?', options: ['글 읽기', '글 작성', '글 수정', '글 삭제'], default: ['글 읽기', '글 작성'], hint: '권한은 언제든지 변경할 수 있습니다.' );

options 인자에 연관 배열을 전달하면 선택된 옵션들의 키가 반환됩니다. 이때 화면에는 값이 표시됩니다.

$permissions = multiselect( label: '어떤 권한을 부여하시겠습니까?', options: [ 'read' => '글 읽기', 'create' => '글 작성', 'update' => '글 수정', 'delete' => '글 삭제', ], default: ['read', 'create'] );

목록은 최대 5개 항목까지 표시되고, 그 이상은 스크롤할 수 있습니다. scroll 인자로 이 값을 조정할 수 있습니다.

$categories = multiselect( label: '어떤 카테고리에 배정하시겠습니까?', options: Category::all()->pluck('name', 'id'), scroll: 10 );

필수 값

기본적으로 사용자는 0개 이상의 옵션을 선택할 수 있습니다. 최소 1개 이상 선택하도록 강제하려면 required 인자를 전달하세요.

$permissions = multiselect( label: '어떤 권한을 부여하시겠습니까?', options: ['글 읽기', '글 작성', '글 수정', '글 삭제'], required: true );

검증 메시지를 커스터마이징하려면 문자열을 전달할 수 있습니다.

$permissions = multiselect( label: '어떤 권한을 부여하시겠습니까?', options: ['글 읽기', '글 작성', '글 수정', '글 삭제'], required: '최소 1개 이상의 권한을 선택해야 합니다.' );

추가 유효성 검증

특정 옵션 선택을 막고 싶다면 validate 인자에 클로저를 전달할 수 있습니다.

$permissions = multiselect( label: '사용자에게 어떤 권한을 부여하시겠습니까?', options: [ 'read' => '글 읽기', 'create' => '글 작성', 'update' => '글 수정', 'delete' => '글 삭제', ], validate: fn (array $values) => ! in_array('read', $values) ? '모든 사용자는 반드시 "글 읽기" 권한이 있어야 합니다.' : null );

options 인자가 연관 배열인 경우 클로저는 선택된 키들을 전달받으며, 그렇지 않은 경우 선택된 값들을 전달받습니다.

Suggest

suggest 함수는 자동완성 기능이 포함된 입력을 제공할 때 사용합니다. 자동완성 힌트와 관계없이 사용자는 원하는 값을 자유롭게 입력할 수 있습니다.

use function Laravel\Prompts\suggest; $name = suggest('이름이 무엇인가요?', ['홍길동', '김철수', '이영희']);

또는 두 번째 인자로 클로저를 전달할 수도 있습니다. 이 클로저는 사용자가 문자를 입력할 때마다 호출되며, 인자로 지금까지 입력한 텍스트를 받고 자동완성 옵션 배열을 반환해야 합니다.

$name = suggest( label: '이름이 무엇인가요?', options: fn ($value) => collect(['홍길동', '김철수', '이영희']) ->filter(fn ($name) => Str::contains($name, $value, ignoreCase: true)) )

플레이스홀더 텍스트, 기본값, 안내 힌트도 지정할 수 있습니다.

$name = suggest( label: '이름이 무엇인가요?', options: ['홍길동', '김철수', '이영희'], placeholder: '예: 홍길동', default: $user?->name, hint: '이 정보는 프로필에 표시됩니다.' );

필수 값

값을 반드시 입력하도록 요구하려면 required 인자를 전달하세요.

$name = suggest( label: '이름이 무엇인가요?', options: ['홍길동', '김철수', '이영희'], required: true );

검증 메시지를 커스터마이징하려면 문자열을 전달할 수 있습니다.

$name = suggest( label: '이름이 무엇인가요?', options: ['홍길동', '김철수', '이영희'], required: '이름은 필수 입력 항목입니다.' );

추가 유효성 검증

마지막으로, 추가적인 검증 로직을 수행하려면 validate 인자에 클로저를 전달하세요.

$name = suggest( label: '이름이 무엇인가요?', options: ['홍길동', '김철수', '이영희'], validate: fn (string $value) => match (true) { strlen($value) < 3 => '이름은 최소 3자 이상이어야 합니다.', strlen($value) > 255 => '이름은 255자를 초과할 수 없습니다.', default => null } );

이 클로저는 입력된 값을 받아, 오류가 있다면 오류 메시지를 반환하고 검증을 통과했다면 null을 반환하면 됩니다.

또는 Laravel validator의 기능을 활용할 수도 있습니다. rules 인자에 속성명과 검증 규칙 배열을 전달하세요.

$name = suggest( label: '이름이 무엇인가요?', options: ['홍길동', '김철수', '이영희'], rules: ['required', 'min:3', 'max:255'] );

Search

옵션이 많아서 select 프롬프트로 표시하기 어려운 경우, search 함수를 사용하면 사용자가 검색어를 입력해 결과를 필터링한 뒤 방향키로 선택하도록 할 수 있습니다.

use function Laravel\Prompts\search; $id = search( label: '어떤 저자를 검색하시겠습니까?', options: fn (string $value) => strlen($value) > 0 ? Author::where('name', 'like', "%{$value}%")->pluck('name', 'id')->all() : [] );

클로저는 지금까지 사용자가 입력한 텍스트를 인자로 받아 옵션 배열을 반환해야 합니다. 연관 배열을 반환하면 선택한 옵션의 키가 반환되고, 그렇지 않으면 값이 반환됩니다.

플레이스홀더 텍스트나 안내 힌트도 지정할 수 있습니다.

$id = search( label: '어떤 저자를 검색하시겠습니까?', placeholder: '예: 이광수', options: fn (string $value) => strlen($value) > 0 ? Author::where('name', 'like', "%{$value}%")->pluck('name', 'id')->all() : [], hint: '검색 결과를 통해 정확한 저자를 선택할 수 있습니다.' );

목록은 최대 5개 항목까지 표시되며, scroll 인자로 개수를 조정할 수 있습니다.

$id = search( label: '어떤 저자를 검색하시겠습니까?', options: fn (string $value) => strlen($value) > 0 ? Author::where('name', 'like', "%{$value}%")->pluck('name', 'id')->all() : [], scroll: 10 );

추가 유효성 검증

마지막으로, 추가적인 검증 로직을 수행하려면 validate 인자에 클로저를 전달하세요.

$id = search( label: '어떤 저자를 검색하시겠습니까?', options: fn (string $value) => strlen($value) > 0 ? Author::where('name', 'like', "%{$value}%")->pluck('name', 'id')->all() : [], validate: function (int|string $value) { $author = Author::findOrFail($value); if ($author->birth_year <= 1900) { return '1900년 이후에 태어난 저자만 선택할 수 있습니다.'; } } );

options 클로저가 연관 배열을 반환하는 경우 이 클로저는 선택된 키를 전달받고, 그렇지 않은 경우 선택된 값을 전달받습니다.

Multi-search

검색 가능한 옵션이 많고 여러 항목을 선택하게 하려면 multisearch 함수를 사용하세요. 사용자는 검색어를 입력해 결과를 필터링한 뒤 방향키와 스페이스바로 옵션을 선택할 수 있습니다.

use function Laravel\Prompts\multisearch; $ids = multisearch( '어떤 저자를 포함하시겠습니까?', fn (string $value) => strlen($value) > 0 ? Author::where('name', 'like', "%{$value}%")->pluck('name', 'id')->all() : [] );

클로저는 지금까지 사용자가 입력한 텍스트를 인자로 받아 옵션 배열을 반환해야 합니다. 연관 배열을 반환하면 선택된 옵션들의 키가 반환되고, 그렇지 않으면 값들이 반환됩니다.

플레이스홀더 텍스트나 안내 힌트도 지정할 수 있습니다.

$ids = multisearch( label: '어떤 저자를 포함하시겠습니까?', placeholder: '예: 이광수', options: fn (string $value) => strlen($value) > 0 ? Author::where('name', 'like', "%{$value}%")->pluck('name', 'id')->all() : [], hint: '검색 결과를 통해 원하는 저자를 선택할 수 있습니다.' );

목록은 최대 5개 항목까지 표시되며, scroll 인자로 개수를 조정할 수 있습니다.

$ids = multisearch( label: '어떤 저자를 포함하시겠습니까?', options: fn (string $value) => strlen($value) > 0 ? Author::where('name', 'like', "%{$value}%")->pluck('name', 'id')->all() : [], scroll: 10 );

필수 값

기본적으로 사용자는 0개 이상의 옵션을 선택할 수 있습니다. 최소 1개 이상 선택하도록 강제하려면 required 인자를 전달하세요.

$ids = multisearch( label: '어떤 저자를 포함하시겠습니까?', options: fn (string $value) => strlen($value) > 0 ? Author::where('name', 'like', "%{$value}%")->pluck('name', 'id')->all() : [], required: true );

검증 메시지를 커스터마이징하려면 문자열을 전달할 수 있습니다.

$ids = multisearch( label: '어떤 저자를 포함하시겠습니까?', options: fn (string $value) => strlen($value) > 0 ? Author::where('name', 'like', "%{$value}%")->pluck('name', 'id')->all() : [], required: '최소 1명 이상의 저자를 선택해야 합니다.' );

추가 유효성 검증

마지막으로, 추가적인 검증 로직을 수행하려면 validate 인자에 클로저를 전달하세요.

$ids = multisearch( label: '어떤 저자를 포함하시겠습니까?', options: fn (string $value) => strlen($value) > 0 ? Author::where('name', 'like', "%{$value}%")->pluck('name', 'id')->all() : [], validate: function (array $values) { $count = Author::whereIn('id', $values)->where('birth_year', '>', 1900)->count(); if ($count !== count($values)) { return '선택한 저자는 모두 1900년 이후에 태어난 사람이어야 합니다.'; } } );

options 클로저가 연관 배열을 반환하는 경우 이 클로저는 선택된 키들을 전달받고, 그렇지 않은 경우 선택된 값들을 전달받습니다.

Pause

pause 함수는 안내 문구를 표시하고, 사용자가 Enter/Return 키를 눌러 계속 진행하겠다는 의사를 밝힐 때까지 진행을 멈추는 데 사용합니다.

use function Laravel\Prompts\pause; pause('계속하려면 ENTER 키를 누르세요.');

Autocomplete

유효성 검증 전 입력값 변환하기

경우에 따라 유효성 검증 전에 프롬프트 입력값을 변형하고 싶을 수 있습니다. 예를 들어 text 함수를 사용할 때 앞뒤 공백을 잘라내고 싶을 수 있습니다. 이를 위해 transform 인자에 클로저를 전달할 수 있습니다.

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

Forms

여러 개의 프롬프트를 순서대로 표시해서 정보를 수집한 뒤, 그 과정에서 이전 프롬프트로 돌아가 수정할 수 있게 하고 싶다면 form 함수를 사용하세요.

use function Laravel\Prompts\form; $responses = form() ->text('이름이 무엇인가요?', required: true) ->password('비밀번호가 무엇인가요?', validate: ['password' => 'min:8']) ->confirm('이용약관에 동의하시나요?') ->submit();

form()->submit() 메서드는 폼에서 사용한 모든 프롬프트의 응답을 숫자 인덱스 배열로 반환합니다. 각 프롬프트에 name 인자를 지정하면 해당 이름으로 응답을 조회할 수 있습니다.

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 함수를 사용하는 가장 큰 장점은, 사용자가 Shift+Tab을 눌러 이전 프롬프트로 되돌아가 수정할 수 있다는 점입니다. 이를 통해 폼 전체를 취소하고 처음부터 다시 시작하지 않고도 실수를 바로잡을 수 있습니다.

프롬프트에 대해 더 세밀하게 제어해야 하는 경우, 새로운 프롬프트를 추가하는 대신 add 메서드에 클로저를 전달할 수 있습니다. 클로저는 지금까지 수집된 응답들을 인자로 받습니다.

$responses = form() ->text('이름이 무엇인가요?', required: true, name: 'name') ->add(function ($responses) { return select( label: "{$responses['name']}님, 나이가 어떻게 되시나요?", options: ['18-25', '26-35', '36-45', '46-55', '56+'] ); }, name: 'age') ->submit();

정보성 메시지

note, info, warning, error, alert 함수는 각각 정보성 메시지를 표시할 때 사용할 수 있습니다.

use function Laravel\Prompts\info; info('작업이 성공적으로 완료되었습니다!');

콜아웃

콜아웃(callout)은 정보성 메시지를 눈에 띄는 상자 형태로 표시하는 데 사용합니다. 사용할 수 있는 콜아웃 함수로는 intro, outro가 있습니다.

use function Laravel\Prompts\intro; use function Laravel\Prompts\outro; intro('환영합니다! 마법사를 시작하겠습니다.'); // ... outro('마법사가 완료되었습니다. 감사합니다!');

테이블

table 함수는 여러 행과 열로 이루어진 데이터를 손쉽게 표시할 수 있게 해줍니다. 컬럼명과 데이터를 전달하기만 하면 됩니다.

use function Laravel\Prompts\table; table( headers: ['이름', '이메일'], rows: User::all(['name', 'email'])->toArray() );

Spin

spin 함수는 지정한 콜백을 실행하는 동안 스피너와 함께 안내 메시지를 표시합니다. 콜백이 실행 중이라는 것을 알리는 동시에, 콜백이 완료되면 그 결과를 반환합니다.

use function Laravel\Prompts\spin; $response = spin( message: '응답을 가져오는 중입니다...', callback: fn () => Http::get('http://example.com') );

WARNING

spin 함수를 사용하려면 pcntl PHP 확장 모듈이 필요합니다. 이 확장 모듈이 없는 경우, 스피너 애니메이션 없이 정적인 형태로 표시됩니다.

진행 상황 표시줄 (Progress Bar)

시간이 오래 걸리는 작업의 경우, 진행 상황을 사용자에게 알려주는 진행 상황 표시줄을 보여주는 것이 도움이 됩니다. progress 함수를 사용하면 Laravel은 주어진 반복 가능한(iterable) 값에 대해 반복을 수행할 때마다 진행 상황 표시줄을 갱신해 줍니다.

use function Laravel\Prompts\progress; $users = progress( label: '사용자 정보를 업데이트하는 중입니다.', steps: User::all(), callback: fn ($user) => $this->performTask($user) );

progress 함수는 map 함수처럼 동작하며, 콜백의 반환값을 모두 모은 배열을 반환합니다.

콜백은 \Laravel\Prompts\Progress 인스턴스를 두 번째 인자로 받아, 각 반복마다 라벨과 힌트를 수정할 수도 있습니다.

$users = progress( label: '사용자 정보를 업데이트하는 중입니다.', steps: User::all(), callback: function ($user, $progress) { $progress ->label("{$user->name}님의 정보를 업데이트하는 중입니다.") ->hint("생성일: {$user->created_at}"); return $this->performTask($user); }, hint: '이 작업은 시간이 걸릴 수 있습니다.' );

경우에 따라 진행 상황 표시줄을 더 세밀하게 제어해야 할 수도 있습니다. 먼저 처리할 전체 단계 수를 정의한 다음, 각 단계를 처리할 때마다 진행 상황 표시줄을 진행시키면 됩니다.

$progress = progress(label: '사용자 정보를 업데이트하는 중입니다.', steps: 10); $users = User::all(); $progress->start(); foreach ($users as $user) { $this->performTask($user); $progress->advance(); } $progress->finish();

Task

Stream

터미널 제목 설정하기

터미널 화면 지우기

터미널 크기(Width)

문자열의 길이나 너비가 터미널의 너비를 초과하면 Laravel Prompts가 이를 자동으로 잘라내어 보기 좋게 표시해 줍니다. 만약 사용자가 좁은 터미널을 사용하고 있다면, 이 자동 처리 방식을 고려하여 라벨, 옵션, 검증 메시지 등을 되도록 짧게 유지하는 것이 좋습니다. 일반적으로 80자 폭의 터미널을 지원하려면 라벨을 74자 이내로 유지하는 것이 안전합니다.

터미널 높이(Height)

scroll 인자를 받는 프롬프트의 경우, 설정한 값은 터미널의 높이에 맞춰 자동으로 줄어들며, 검증 메시지가 표시될 여유 공간도 함께 고려됩니다.

지원되지 않는 환경과 폴백(Fallback) 처리

Laravel Prompts는 macOS, Linux, WSL이 있는 Windows 환경을 지원합니다. Windows용 PHP는 PHP 확장 모듈에 대한 제약으로 인해 현재 WSL을 제외한 Windows 환경을 지원하지 않습니다.

이런 이유로 Laravel Prompts는 Symfony Console Question Helper와 같은 대체 구현으로 폴백하는 것을 지원합니다.

NOTE

Laravel 프레임워크와 함께 Laravel Prompts를 사용하는 경우, 각 프롬프트별로 폴백 구현이 이미 설정되어 있으며 지원되지 않는 환경에서는 자동으로 활성화됩니다.

폴백 조건

Laravel Prompts를 사용하는 프로젝트가 Laravel을 사용하고 있지 않거나, 폴백 동작을 커스터마이징하고 싶다면 Prompt 클래스의 fallbackWhen 정적 메서드에 boolean 값을 전달할 수 있습니다.

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

폴백 동작 커스터마이징

또한, Laravel Prompts를 사용하는 프로젝트가 Laravel을 사용하지 않거나 폴백 동작을 커스터마이징하고 싶다면, 각 프롬프트 클래스에 fallbackUsing 정적 메서드로 클로저를 전달할 수 있습니다.

use Laravel\Prompts\TextPrompt; use Laravel\Prompts\ConfirmPrompt; use Laravel\Prompts\SelectPrompt; use Laravel\Prompts\MultiSelectPrompt; use Laravel\Prompts\SuggestPrompt; use Laravel\Prompts\SearchPrompt; use Laravel\Prompts\MultiSearchPrompt; use Laravel\Prompts\PasswordPrompt; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Question\Question; use Symfony\Component\Console\Style\SymfonyStyle; TextPrompt::fallbackUsing(function (TextPrompt $prompt) use ($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); });

폴백 처리는 각 프롬프트 클래스별로 개별적으로 설정해야 합니다. 클로저는 해당 프롬프트 클래스의 인스턴스를 전달받으며, Symfony Console 명령어에서 실행되는 타입에 맞는 값을 반환해야 합니다.

테스트

Laravel은 애플리케이션 테스트를 쉽게 작성할 수 있도록 Laravel Prompts를 위한 여러 테스트 헬퍼를 제공합니다. 이 헬퍼들은 Illuminate\Support\Facades\Prompts 파사드와 함께 사용됩니다.

예를 들어 다음과 같은 Artisan 명령어가 있다고 가정해 보겠습니다.

use function Laravel\Prompts\outro; use function Laravel\Prompts\text; $name = text('이름이 무엇인가요?'); $content = multiselect( label: '어떤 권한을 부여하시겠습니까?', options: ['글 읽기', '글 작성', '글 수정', '글 삭제'] ); // ... outro("{$name}님, 감사합니다!");

이 명령어는 다음과 같이 테스트할 수 있습니다.

use function Laravel\Prompts\Testing\fake; test('사용자 정보를 업데이트할 수 있다', function () { Prompts::fake([ text: '홍길동', multiselect: ['글 읽기', '글 작성'], ]); $this->artisan('update:user') ->assertOk(); Prompts::assertOutroWasCalled('홍길동님, 감사합니다!'); });

Pest

use function Laravel\Prompts\Testing\fake; test('사용자 정보를 업데이트할 수 있다', function () { Prompts::fake([ 'text' => '홍길동', 'multiselect' => ['글 읽기', '글 작성'], ]); $this->artisan('update:user') ->assertOk(); Prompts::assertOutroWasCalled('홍길동님, 감사합니다!'); });

PHPUnit

use Illuminate\Support\Facades\Prompts; public function test_it_can_update_user_information(): void { Prompts::fake([ 'text' => '홍길동', 'multiselect' => ['글 읽기', '글 작성'], ]); $this->artisan('update:user') ->assertOk(); Prompts::assertOutroWasCalled('홍길동님, 감사합니다!'); }

NOTE

위 예시는 개념을 설명하기 위한 것으로, 실제 Laravel Prompts 테스트 헬퍼의 정확한 API는 사용 버전에 따라 다를 수 있습니다. 정확한 사용법은 Laravel Prompts 저장소의 최신 문서를 참고하시기 바랍니다.

Prompts

소개

Laravel Prompts는 명령줄 애플리케이션에 아름답고 사용하기 편한 입력 폼을 추가할 수 있게 해주는 PHP 패키지입니다. 플레이스홀더 텍스트나 유효성 검사처럼 브라우저에서나 볼 법한 기능들을 콘솔 환경에서도 그대로 사용할 수 있습니다.

Laravel Prompts는 Artisan 콘솔 명령어에서 사용자 입력을 받을 때 안성맞춤이지만, Artisan에 국한되지 않고 어떤 명령줄 PHP 프로젝트에서든 사용할 수 있습니다.

NOTE

Laravel Prompts는 macOS, Linux, 그리고 WSL을 사용하는 Windows 환경을 지원합니다. 자세한 내용은 지원되지 않는 환경 및 대체 동작 문서를 참고하세요.

설치

먼저 Composer 패키지 관리자를 사용해 Laravel Prompts를 프로젝트에 설치합니다.

composer require laravel/prompts

NOTE

Laravel을 이미 사용 중이라면 Laravel Prompts는 기본적으로 함께 설치되어 있으며, 바로 사용할 수 있습니다.

설치

Laravel Prompts는 최신 버전의 Laravel에 이미 포함되어 있습니다.

다른 PHP 프로젝트에서도 Composer 패키지 매니저를 사용해 Laravel Prompts를 설치할 수 있습니다.

composer require laravel/prompts

사용 가능한 프롬프트

text — 텍스트 입력

text 함수는 사용자에게 질문을 표시하고, 입력값을 받아 반환합니다:

use function Laravel\Prompts\text; $name = text('이름이 어떻게 되시나요?');

플레이스홀더, 기본값, 안내 문구(hint)도 함께 지정할 수 있습니다:

$name = text( label: '이름이 어떻게 되시나요?', placeholder: '예: 홍길동', default: $user?->name, hint: '입력하신 이름은 프로필에 표시됩니다.' );

필수 입력값 지정

값 입력을 필수로 만들고 싶다면 required 인자를 전달하면 됩니다:

$name = text( label: '이름이 어떻게 되시나요?', required: true );

검증 실패 메시지를 직접 지정하고 싶다면, required에 문자열을 전달할 수도 있습니다:

$name = text( label: '이름이 어떻게 되시나요?', required: '이름은 필수 입력 항목입니다.' );

추가 유효성 검증

더 복잡한 검증 로직이 필요하다면, validate 인자에 클로저를 전달하세요:

$name = text( label: '이름이 어떻게 되시나요?', validate: fn (string $value) => match (true) { strlen($value) < 3 => '이름은 3자 이상이어야 합니다.', strlen($value) > 255 => '이름은 255자를 초과할 수 없습니다.', default => null } );

이 클로저는 사용자가 입력한 값을 전달받으며, 에러 메시지를 반환하거나 검증을 통과했다면 null을 반환하면 됩니다.

또는 라라벨의 Validator를 그대로 활용할 수도 있습니다. 이 경우 validate 인자에 속성 이름과 검증 규칙으로 구성된 배열을 전달합니다:

$name = text( label: '이름이 어떻게 되시나요?', validate: ['name' => 'required|max:255|unique:users'] );

textarea — 여러 줄 텍스트 입력

textarea 함수는 사용자에게 질문을 표시하고, 여러 줄로 입력받은 값을 반환합니다:

use function Laravel\Prompts\textarea; $story = textarea('당신의 이야기를 들려주세요.');

플레이스홀더, 기본값, 안내 문구도 지정할 수 있습니다:

$story = textarea( label: '당신의 이야기를 들려주세요.', placeholder: '예: 이 이야기는...', hint: '입력하신 내용은 프로필에 표시됩니다.' );

필수 입력값 지정

값 입력을 필수로 만들려면 required 인자를 전달합니다:

$story = textarea( label: '당신의 이야기를 들려주세요.', required: true );

검증 실패 메시지를 직접 지정하려면 문자열을 전달하면 됩니다:

$story = textarea( label: '당신의 이야기를 들려주세요.', required: '이야기 내용은 필수 입력 항목입니다.' );

추가 유효성 검증

더 복잡한 검증이 필요하다면 validate 인자에 클로저를 전달할 수 있습니다:

$story = textarea( label: '당신의 이야기를 들려주세요.', validate: fn (string $value) => match (true) { strlen($value) < 250 => '이야기는 최소 250자 이상이어야 합니다.', strlen($value) > 10000 => '이야기는 10,000자를 초과할 수 없습니다.', default => null } );

이 클로저는 입력된 값을 전달받으며, 에러 메시지를 반환하거나 검증 통과 시 null을 반환합니다.

또는 라라벨의 Validator를 활용할 수도 있습니다. validate 인자에 속성 이름과 검증 규칙 배열을 전달하면 됩니다:

$story = textarea( label: '당신의 이야기를 들려주세요.', validate: ['story' => 'required|max:10000'] );

number — 숫자 입력

number 함수는 사용자에게 질문을 표시하고 숫자 입력값을 받아 반환합니다. 사용자는 위/아래 방향키로 숫자를 조정할 수도 있습니다:

use function Laravel\Prompts\number; $number = number('몇 부를 원하시나요?');

플레이스홀더, 기본값, 안내 문구도 지정할 수 있습니다:

$name = number( label: '몇 부를 원하시나요?', placeholder: '5', default: 1, hint: '생성할 사본의 개수를 결정합니다.' );

필수 입력값 지정

값 입력을 필수로 만들려면 required 인자를 전달합니다:

$copies = number( label: '몇 부를 원하시나요?', required: true );

검증 메시지를 직접 지정하려면 문자열을 전달하면 됩니다:

$copies = number( label: '몇 부를 원하시나요?', required: '부수를 입력해야 합니다.' );

추가 유효성 검증

더 복잡한 검증이 필요하다면 validate 인자에 클로저를 전달할 수 있습니다:

$copies = number( label: '몇 부를 원하시나요?', validate: fn (?int $value) => match (true) { $value < 1 => '최소 1부 이상이어야 합니다.', $value > 100 => '100부를 초과해서 생성할 수 없습니다.', default => null } );

이 클로저는 입력된 값을 전달받으며, 에러 메시지를 반환하거나 검증을 통과했다면 null을 반환합니다.

또는 라라벨의 Validator를 활용해도 됩니다. validate 인자에 속성 이름과 검증 규칙 배열을 전달하세요:

$copies = number( label: '몇 부를 원하시나요?', validate: ['copies' => 'required|integer|min:1|max:100'] );

password — 비밀번호 입력

password 함수는 text 함수와 비슷하지만, 콘솔에 입력값이 표시되지 않고 마스킹 처리됩니다. 비밀번호와 같이 민감한 정보를 입력받을 때 유용합니다:

use function Laravel\Prompts\password; $password = password('비밀번호를 입력해주세요.');

플레이스홀더와 안내 문구도 지정할 수 있습니다:

$password = password( label: '비밀번호를 입력해주세요.', placeholder: 'password', hint: '최소 8자 이상이어야 합니다.' );

필수 입력값 지정

값 입력을 필수로 만들려면 required 인자를 전달합니다:

$password = password( label: '비밀번호를 입력해주세요.', required: true );

검증 메시지를 직접 지정하려면 문자열을 전달하면 됩니다:

$password = password( label: '비밀번호를 입력해주세요.', required: '비밀번호는 필수 입력 항목입니다.' );

추가 유효성 검증

더 복잡한 검증이 필요하다면 validate 인자에 클로저를 전달할 수 있습니다:

$password = password( label: '비밀번호를 입력해주세요.', validate: fn (string $value) => match (true) { strlen($value) < 8 => '비밀번호는 8자 이상이어야 합니다.', default => null } );

이 클로저는 입력된 값을 전달받으며, 에러 메시지를 반환하거나 검증 통과 시 null을 반환합니다.

또는 라라벨의 Validator를 활용할 수도 있습니다. validate 인자에 속성 이름과 검증 규칙 배열을 전달하세요:

$password = password( label: '비밀번호를 입력해주세요.', validate: ['password' => 'min:8'] );

confirm — 예/아니오 확인

사용자에게 "예/아니오" 형태의 확인을 받고 싶다면 confirm 함수를 사용하세요. 사용자는 방향키를 이용하거나 y / n 키를 눌러 응답할 수 있습니다. 이 함수는 true 또는 false를 반환합니다.

use function Laravel\Prompts\confirm; $confirmed = confirm('이용약관에 동의하십니까?');

기본값, "예"/"아니오" 레이블 커스터마이징, 안내 문구도 지정할 수 있습니다:

$confirmed = confirm( label: '이용약관에 동의하십니까?', default: false, yes: '동의합니다', no: '동의하지 않습니다', hint: '계속 진행하려면 이용약관에 동의해야 합니다.' );

"예" 응답 필수화

필요한 경우, required 인자를 전달해 사용자가 반드시 "예"를 선택하도록 강제할 수 있습니다:

$confirmed = confirm( label: '이용약관에 동의하십니까?', required: true );

검증 메시지를 직접 지정하려면 문자열을 전달하면 됩니다:

$confirmed = confirm( label: '이용약관에 동의하십니까?', required: '계속 진행하려면 이용약관에 동의해야 합니다.' );

select — 단일 선택

미리 정의된 선택지 중 하나를 고르게 하려면 select 함수를 사용하세요:

use function Laravel\Prompts\select; $role = select( label: '사용자에게 어떤 역할을 부여할까요?', options: ['Member', 'Contributor', 'Owner'] );

기본 선택값과 안내 문구도 지정할 수 있습니다:

$role = select( label: '사용자에게 어떤 역할을 부여할까요?', options: ['Member', 'Contributor', 'Owner'], default: 'Owner', hint: '역할은 언제든지 변경할 수 있습니다.' );

options에 연관 배열을 전달하면 선택된 값 대신 해당 키가 반환됩니다:

$role = select( label: '사용자에게 어떤 역할을 부여할까요?', options: [ 'member' => 'Member', 'contributor' => 'Contributor', 'owner' => 'Owner', ], default: 'owner' );

기본적으로 최대 5개의 옵션이 표시되고, 그 이상은 스크롤됩니다. scroll 인자로 이 개수를 조정할 수 있습니다:

$role = select( label: '어떤 카테고리를 지정하시겠습니까?', options: Category::pluck('name', 'id'), scroll: 10 );

부가 정보 표시

info 인자를 사용하면 현재 강조된 옵션에 대한 추가 정보를 보여줄 수 있습니다. 클로저를 전달하면 현재 강조된 옵션의 값을 인자로 받아 문자열 또는 null을 반환하면 됩니다:

$role = select( label: '사용자에게 어떤 역할을 부여할까요?', options: [ 'member' => 'Member', 'contributor' => 'Contributor', 'owner' => 'Owner', ], info: fn (string $value) => match ($value) { 'member' => '조회 및 댓글 작성이 가능합니다.', 'contributor' => '조회, 댓글 작성, 수정이 가능합니다.', 'owner' => '모든 리소스에 대한 전체 권한을 가집니다.', default => null, } );

강조된 옵션과 무관하게 항상 같은 정보를 보여주고 싶다면 정적인 문자열을 전달해도 됩니다:

$role = select( label: '사용자에게 어떤 역할을 부여할까요?', options: ['Member', 'Contributor', 'Owner'], info: '역할은 언제든지 변경할 수 있습니다.' );

추가 유효성 검증

select 함수는 아무것도 선택하지 않는 상태가 애초에 불가능하므로 다른 함수와 달리 required 인자를 지원하지 않습니다. 다만 특정 옵션을 화면에는 표시하되 선택하지는 못하게 막고 싶다면 validate 인자에 클로저를 전달할 수 있습니다:

$role = select( label: '사용자에게 어떤 역할을 부여할까요?', options: [ 'member' => 'Member', 'contributor' => 'Contributor', 'owner' => 'Owner', ], validate: fn (string $value) => $value === 'owner' && User::where('role', 'owner')->exists() ? '이미 owner 역할을 가진 사용자가 존재합니다.' : null );

options가 연관 배열이면 클로저는 선택된 키를 전달받고, 그렇지 않으면 선택된 값을 전달받습니다. 클로저는 에러 메시지를 반환하거나, 검증 통과 시 null을 반환하면 됩니다.

multiselect — 다중 선택

사용자가 여러 옵션을 동시에 선택할 수 있게 하려면 multiselect 함수를 사용하세요:

use function Laravel\Prompts\multiselect; $permissions = multiselect( label: '어떤 권한을 부여할까요?', options: ['Read', 'Create', 'Update', 'Delete'] );

기본 선택값들과 안내 문구도 지정할 수 있습니다:

use function Laravel\Prompts\multiselect; $permissions = multiselect( label: '어떤 권한을 부여할까요?', options: ['Read', 'Create', 'Update', 'Delete'], default: ['Read', 'Create'], hint: '권한은 언제든지 변경할 수 있습니다.' );

options에 연관 배열을 전달하면 선택된 값 대신 해당 키들이 반환됩니다:

$permissions = multiselect( label: '어떤 권한을 부여할까요?', options: [ 'read' => 'Read', 'create' => 'Create', 'update' => 'Update', 'delete' => 'Delete', ], default: ['read', 'create'] );

기본적으로 최대 5개의 옵션이 표시되고, 그 이상은 스크롤됩니다. scroll 인자로 조정할 수 있습니다:

$categories = multiselect( label: '어떤 카테고리를 지정하시겠습니까?', options: Category::pluck('name', 'id'), scroll: 10 );

부가 정보 표시

info 인자를 사용하면 현재 강조된 옵션에 대한 추가 정보를 표시할 수 있습니다. 클로저를 전달하면 현재 강조된 옵션의 값을 전달받아 문자열 또는 null을 반환합니다:

$permissions = multiselect( label: '어떤 권한을 부여할까요?', options: [ 'read' => 'Read', 'create' => 'Create', 'update' => 'Update', 'delete' => 'Delete', ], info: fn (string $value) => match ($value) { 'read' => '리소스와 그 속성을 조회할 수 있습니다.', 'create' => '새로운 리소스를 생성할 수 있습니다.', 'update' => '기존 리소스를 수정할 수 있습니다.', 'delete' => '리소스를 영구적으로 삭제할 수 있습니다.', default => null, } );

필수 선택 지정

기본적으로 사용자는 아무것도 선택하지 않아도 됩니다. 최소 하나 이상의 선택을 강제하려면 required 인자를 전달하세요:

$categories = multiselect( label: '어떤 카테고리를 지정하시겠습니까?', options: Category::pluck('name', 'id'), required: true );

검증 메시지를 직접 지정하려면 required에 문자열을 전달할 수 있습니다:

$categories = multiselect( label: '어떤 카테고리를 지정하시겠습니까?', options: Category::pluck('name', 'id'), required: '카테고리를 최소 하나 이상 선택해야 합니다.' );

추가 유효성 검증

특정 옵션을 표시는 하되 선택되지 못하게 막으려면 validate 인자에 클로저를 전달할 수 있습니다:

$permissions = multiselect( label: '사용자에게 어떤 권한을 부여할까요?', options: [ 'read' => 'Read', 'create' => 'Create', 'update' => 'Update', 'delete' => 'Delete', ], validate: fn (array $values) => ! in_array('read', $values) ? '모든 사용자는 read 권한을 가지고 있어야 합니다.' : null );

options가 연관 배열이면 클로저는 선택된 키 목록을 전달받고, 그렇지 않으면 선택된 값 목록을 전달받습니다. 클로저는 에러 메시지를 반환하거나, 검증 통과 시 null을 반환합니다.

suggest — 자동완성 제안

suggest 함수는 선택 가능한 항목에 대한 자동완성 기능을 제공합니다. 자동완성 힌트와 무관하게 사용자는 어떤 값이든 직접 입력할 수 있습니다:

use function Laravel\Prompts\suggest; $name = suggest('이름이 어떻게 되시나요?', ['Taylor', 'Dayle']);

또는 두 번째 인자로 클로저를 전달할 수도 있습니다. 이 클로저는 사용자가 입력할 때마다 호출되며, 지금까지 입력된 값을 문자열 인자로 받아 자동완성용 옵션 배열을 반환해야 합니다:

$name = suggest( label: '이름이 어떻게 되시나요?', options: fn ($value) => collect(['Taylor', 'Dayle']) ->filter(fn ($name) => Str::contains($name, $value, ignoreCase: true)) );

플레이스홀더, 기본값, 안내 문구도 지정할 수 있습니다:

$name = suggest( label: '이름이 어떻게 되시나요?', options: ['Taylor', 'Dayle'], placeholder: '예: Taylor', default: $user?->name, hint: '입력하신 이름은 프로필에 표시됩니다.' );

부가 정보 표시

info 인자로 현재 강조된 옵션에 대한 추가 정보를 표시할 수 있습니다. 클로저를 전달하면 현재 강조된 옵션의 값을 전달받아 문자열 또는 null을 반환합니다:

$name = suggest( label: '이름이 어떻게 되시나요?', options: ['Taylor', 'Dayle'], info: fn (string $value) => match ($value) { 'Taylor' => '관리자', 'Dayle' => '컨트리뷰터', default => null, } );

필수 입력값 지정

값 입력을 필수로 만들려면 required 인자를 전달합니다:

$name = suggest( label: '이름이 어떻게 되시나요?', options: ['Taylor', 'Dayle'], required: true );

검증 메시지를 직접 지정하려면 문자열을 전달하면 됩니다:

$name = suggest( label: '이름이 어떻게 되시나요?', options: ['Taylor', 'Dayle'], required: '이름은 필수 입력 항목입니다.' );

추가 유효성 검증

더 복잡한 검증이 필요하다면 validate 인자에 클로저를 전달할 수 있습니다:

$name = suggest( label: '이름이 어떻게 되시나요?', options: ['Taylor', 'Dayle'], validate: fn (string $value) => match (true) { strlen($value) < 3 => '이름은 3자 이상이어야 합니다.', strlen($value) > 255 => '이름은 255자를 초과할 수 없습니다.', default => null } );

이 클로저는 입력된 값을 전달받으며, 에러 메시지를 반환하거나 검증 통과 시 null을 반환합니다.

또는 라라벨의 Validator를 활용할 수도 있습니다. validate 인자에 속성 이름과 검증 규칙 배열을 전달하세요:

$name = suggest( label: '이름이 어떻게 되시나요?', options: ['Taylor', 'Dayle'], validate: ['name' => 'required|min:3|max:255'] );

search — 검색 후 단일 선택

선택지 개수가 매우 많다면, search 함수를 사용해 사용자가 검색어를 입력해 결과를 필터링한 뒤 방향키로 하나를 선택하게 할 수 있습니다:

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 메서드를 사용해야 합니다:

$names = collect(['Taylor', 'Abigail']); $selected = search( label: '메일을 받을 사용자를 검색하세요', options: fn (string $value) => $names ->filter(fn ($name) => Str::contains($name, $value, ignoreCase: true)) ->values() ->all(), );

플레이스홀더와 안내 문구도 지정할 수 있습니다:

$id = search( label: '메일을 받을 사용자를 검색하세요', placeholder: '예: 홍길동', options: fn (string $value) => strlen($value) > 0 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all() : [], hint: '해당 사용자에게 즉시 메일이 발송됩니다.' );

기본적으로 최대 5개의 옵션이 표시되고, 그 이상은 스크롤됩니다. scroll 인자로 조정할 수 있습니다:

$id = search( label: '메일을 받을 사용자를 검색하세요', options: fn (string $value) => strlen($value) > 0 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all() : [], scroll: 10 );

부가 정보 표시

info 인자로 현재 강조된 옵션에 대한 추가 정보를 표시할 수 있습니다. 클로저를 전달하면 현재 강조된 옵션의 값을 전달받아 문자열 또는 null을 반환합니다:

$id = search( label: '메일을 받을 사용자를 검색하세요', options: fn (string $value) => strlen($value) > 0 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all() : [], info: fn (int $userId) => User::find($userId)?->email );

추가 유효성 검증

더 복잡한 검증이 필요하다면 validate 인자에 클로저를 전달할 수 있습니다:

$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 — 검색 후 다중 선택

검색 대상이 많고, 여러 항목을 동시에 선택해야 한다면 multisearch 함수를 사용하세요. 사용자는 검색어로 결과를 필터링한 뒤 방향키와 스페이스바로 여러 항목을 선택할 수 있습니다:

use function Laravel\Prompts\multisearch; $ids = multisearch( '메일을 받을 사용자들을 검색하세요', fn (string $value) => strlen($value) > 0 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all() : [] );

이 클로저는 지금까지 입력된 텍스트를 전달받으며 옵션 배열을 반환해야 합니다. 연관 배열을 반환하면 선택된 옵션들의 키가, 그렇지 않으면 값들이 반환됩니다.

값을 반환하기 위해 배열을 필터링하는 경우, 배열이 연관 배열이 되지 않도록 array_values 함수나 컬렉션의 values 메서드를 사용해야 합니다:

$names = collect(['Taylor', 'Abigail']); $selected = multisearch( label: '메일을 받을 사용자들을 검색하세요', options: fn (string $value) => $names ->filter(fn ($name) => Str::contains($name, $value, ignoreCase: true)) ->values() ->all(), );

플레이스홀더와 안내 문구도 지정할 수 있습니다:

$ids = multisearch( label: '메일을 받을 사용자들을 검색하세요', placeholder: '예: 홍길동', options: fn (string $value) => strlen($value) > 0 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all() : [], hint: '선택한 사용자들에게 즉시 메일이 발송됩니다.' );

기본적으로 최대 5개의 옵션이 표시되고, 그 이상은 스크롤됩니다. scroll 인자로 조정할 수 있습니다:

$ids = multisearch( label: '메일을 받을 사용자들을 검색하세요', options: fn (string $value) => strlen($value) > 0 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all() : [], scroll: 10 );

부가 정보 표시

info 인자로 현재 강조된 옵션에 대한 추가 정보를 표시할 수 있습니다. 클로저를 전달하면 현재 강조된 옵션의 값을 전달받아 문자열 또는 null을 반환합니다:

$ids = multisearch( label: '메일을 받을 사용자들을 검색하세요', options: fn (string $value) => strlen($value) > 0 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all() : [], info: fn (int $userId) => User::find($userId)?->email );

필수 선택 지정

기본적으로 사용자는 아무것도 선택하지 않아도 됩니다. 최소 하나 이상의 선택을 강제하려면 required 인자를 전달하세요:

$ids = multisearch( label: '메일을 받을 사용자들을 검색하세요', options: fn (string $value) => strlen($value) > 0 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all() : [], required: true );

검증 메시지를 직접 지정하려면 문자열을 전달할 수 있습니다:

$ids = multisearch( label: '메일을 받을 사용자들을 검색하세요', options: fn (string $value) => strlen($value) > 0 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all() : [], required: '최소 한 명 이상의 사용자를 선택해야 합니다.' );

추가 유효성 검증

더 복잡한 검증이 필요하다면 validate 인자에 클로저를 전달할 수 있습니다:

$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(', ', ', and ').'님은 메일 수신을 거부했습니다.'; } } );

options 클로저가 연관 배열을 반환하면 검증 클로저는 선택된 키들을 전달받고, 그렇지 않으면 선택된 값들을 전달받습니다. 클로저는 에러 메시지를 반환하거나, 검증 통과 시 null을 반환합니다.

pause — 일시 정지

pause 함수는 사용자에게 안내 텍스트를 보여주고, Enter(또는 Return) 키를 눌러야 다음 단계로 진행하도록 대기시킬 때 사용합니다:

use function Laravel\Prompts\pause; pause('계속하려면 ENTER 키를 누르세요.');

autocomplete — 인라인 자동완성

autocomplete 함수는 선택 가능한 항목에 대해 인라인 방식의 자동완성을 제공합니다. 사용자가 입력하는 동안 일치하는 제안이 회색 텍스트(ghost text)로 표시되며, Tab 키나 오른쪽 방향키로 수락할 수 있습니다:

use function Laravel\Prompts\autocomplete; $name = autocomplete( label: '이름이 어떻게 되시나요?', options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim'] );

플레이스홀더, 기본값, 안내 문구도 지정할 수 있습니다:

$name = autocomplete( label: '이름이 어떻게 되시나요?', options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim'], placeholder: '예: Taylor', default: $user?->name, hint: 'Tab 키로 수락하고, 위/아래 방향키로 이동하세요.' );

동적 옵션 생성

클로저를 전달해 사용자의 입력값에 따라 동적으로 옵션을 생성할 수도 있습니다. 이 클로저는 사용자가 문자를 입력할 때마다 호출되며, 자동완성용 옵션 배열을 반환해야 합니다:

$file = autocomplete( label: '어떤 파일인가요?', options: fn (string $value) => collect($files) ->filter(fn ($file) => str_starts_with(strtolower($file), strtolower($value))) ->values() ->all(), );

필수 입력값 지정

값 입력을 필수로 만들려면 required 인자를 전달합니다:

$name = autocomplete( label: '이름이 어떻게 되시나요?', options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim'], required: true );

검증 메시지를 직접 지정하려면 문자열을 전달하면 됩니다:

$name = autocomplete( label: '이름이 어떻게 되시나요?', options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim'], required: '이름은 필수 입력 항목입니다.' );

추가 유효성 검증

더 복잡한 검증이 필요하다면 validate 인자에 클로저를 전달할 수 있습니다:

$name = autocomplete( label: '이름이 어떻게 되시나요?', options: ['Taylor', 'Dayle', 'Jess', 'Nuno', 'Tim'], validate: fn (string $value) => match (true) { strlen($value) < 3 => '이름은 3자 이상이어야 합니다.', strlen($value) > 255 => '이름은 255자를 초과할 수 없습니다.', default => null } );

이 클로저는 입력된 값을 전달받으며, 에러 메시지를 반환하거나 검증 통과 시 null을 반환합니다.

여러 개의 프롬프트를 순서대로 표시해서 정보를 수집해야 하는 경우가 많습니다. 특히 어떤 액션을 수행하기 전에 일련의 입력 값을 차례로 받고 싶을 때 유용합니다. 이를 위해 Laravel\Prompts\form 함수를 사용하면 여러 프롬프트를 하나의 "폼"처럼 묶어서 처리할 수 있습니다.

use function Laravel\Prompts\form; $responses = form() ->text('이름이 무엇인가요?', required: true) ->password('비밀번호를 입력해주세요', validate: ['password' => 'min:8']) ->confirm('약관에 동의하시나요?') ->submit();

form 함수는 폼에 정의된 모든 프롬프트의 응답을, 각 프롬프트의 이름 또는 순서에 해당하는 인덱스를 키로 갖는 숫자 배열로 반환합니다. 각 프롬프트마다 이름을 지정할 수도 있는데, 이름을 지정하면 해당 프롬프트의 응답에 더 쉽게 접근할 수 있습니다.

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 함수를 사용할 때 알아두어야 할 가장 중요한 점은, 각 프롬프트 메서드에 클로저를 전달할 수 있다는 것입니다. 이 클로저는 폼에서 이전에 수집된 응답들을 인자로 받으므로, 이전 답변을 바탕으로 다음 프롬프트의 내용을 동적으로 구성할 수 있습니다.

use function Laravel\Prompts\form; use function Laravel\Prompts\outro; $responses = form() ->text('이름이 무엇인가요?', required: true, name: 'name') ->select( label: '어떤 언어를 가장 좋아하시나요?', options: ['PHP', 'Ruby', 'Python'], name: 'language' ) ->text( label: fn ($responses) => "{$responses['language']}에서 가장 좋아하는 프레임워크는 무엇인가요?", name: 'framework' ) ->submit(); outro("{$responses['name']}님, {$responses['framework']}를 선택하셨네요!");

NOTE

form 안에서 사용하는 프롬프트 메서드들은 각각 개별적으로 호출할 때와 동일한 옵션을 모두 지원합니다.

폼(Form)

작업을 실행하기 전에 여러 개의 프롬프트를 순서대로 띄워서 정보를 수집해야 하는 경우가 많습니다. 이럴 때는 form 함수를 사용해 여러 개의 프롬프트를 하나의 그룹으로 묶어 사용자에게 순차적으로 입력받을 수 있습니다.

use function Laravel\Prompts\form; $responses = form() ->text('이름이 무엇인가요?', required: true) ->password('비밀번호를 입력하세요', validate: ['password' => 'min:8']) ->confirm('약관에 동의하시나요?') ->submit();

submit 메서드는 폼에 포함된 모든 프롬프트의 응답을 숫자 인덱스 배열 형태로 반환합니다. 하지만 각 프롬프트에 name 인자를 지정하면, 해당 이름으로 응답 값에 접근할 수 있어 훨씬 편리합니다.

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 메서드에 전달되는 콜백 함수는 그때까지 사용자가 입력한 모든 응답을 인자로 전달받습니다.

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']}세이시군요.");

Prompts

정보 메시지

note, info, warning, error, alert 함수를 사용하면 사용자에게 간단한 정보성 메시지를 보여줄 수 있습니다:

use function Laravel\Prompts\info; info('패키지가 성공적으로 설치되었습니다.');

NOTE

각 함수는 메시지의 성격에 맞는 색상과 스타일로 출력됩니다. 예를 들어 error는 오류를, warning은 주의가 필요한 상황을, infonote는 일반적인 안내 메시지를 나타낼 때 사용하면 됩니다. 상황에 맞는 함수를 골라 쓰면 콘솔 출력만 보고도 메시지의 중요도를 한눈에 파악할 수 있습니다.

프롬프트 (Prompts)

콜아웃 (Callouts)

callout 함수는 라벨과 내용을 포함한 박스 형태의 메시지를 화면에 출력합니다. 배포 결과 요약, 에러 상세 정보, 상태 업데이트 등 눈에 띄게 강조해서 보여줘야 하는 중요한 정보를 표시할 때 유용합니다.

use function Laravel\Prompts\callout; callout( label: 'Environment Configured', content: 'Your application is running in production mode with 4 workers.', );

type 인자에 warning 또는 error를 전달하면 콜아웃의 시각적 스타일을 변경할 수 있습니다.

callout( label: 'Deprecation Notice', content: 'The `--prefer-stable` flag will be removed in v4.0. Use `--stability=stable` instead.', type: 'warning', ); callout( label: 'Database Connection Failed', content: 'Could not connect to MySQL on 127.0.0.1:3306.', type: 'error', );

info 인자를 사용하면 콜아웃 하단에 부가 정보를 한 줄 추가할 수 있습니다. 배포 ID나 타임스탬프 같은 메타데이터를 표시할 때 유용합니다.

callout( label: 'Deployment Summary', content: 'Your application was deployed to production.', info: 'deploy-id: d4f8a2c', );

풍부한 콘텐츠 구성하기

content에 단순 문자열 대신 문자열과 엘리먼트가 섞인 배열을 전달하면, 구조화된 형태의 콜아웃을 구성할 수 있습니다. Element 클래스는 제목, 글머리 목록, 번호 목록, 키-값 목록, 링크 등을 생성하는 팩토리 메서드를 제공합니다.

use Laravel\Prompts\Elements\Element; use function Laravel\Prompts\callout; callout('Deployment Summary', [ 'Your application was deployed to production at 2024-03-15 14:32 UTC.', Element::heading('What Changed'), Element::bulletedList([ 'Migrated 3 pending database migrations', 'Cleared and rebuilt route cache', 'Restarted 4 queue workers', ]), Element::heading('Next Steps'), Element::numberedList([ 'Verify the health check endpoint at /up', 'Monitor error rates for the next 15 minutes', 'Confirm background jobs are processing', ]), ]);

Element::keyValueList를 사용하면 라벨이 붙은 키-값 데이터를 표시할 수도 있습니다.

callout('Database Connection Failed', [ 'Could not connect to the database server.', Element::keyValueList([ 'Host' => '127.0.0.1', 'Port' => '3306', 'Database' => 'forge', 'Status' => 'Connection refused', ]), ], type: 'error');

Element::link 메서드는 OSC 8을 지원하는 터미널에서 클릭 가능한 하이퍼링크를 생성합니다. URL만 전달하거나, URL과 함께 원하는 라벨을 지정할 수도 있습니다.

callout('Server Health Check', [ 'Multiple services are reporting degraded performance.', Element::heading('Affected Services'), 'Look here: '.Element::link('https://example.com/health', 'Health Dashboard'), Element::link('https://example.com/health'), ]);

라벨을 지정하지 않으면 URL 자체가 링크 텍스트로 표시됩니다.

NOTE

대부분의 최신 터미널(iTerm2, Windows Terminal 등)은 OSC 8 하이퍼링크를 지원하지만, 일부 구형 터미널이나 CI 환경에서는 링크가 일반 텍스트처럼 보일 수 있습니다.

Prompts

테이블

여러 행과 열로 구성된 데이터를 표 형태로 출력하고 싶다면 table 함수를 사용하면 됩니다. 컬럼 이름과 실제 데이터만 전달하면 나머지는 알아서 정렬해서 보여줍니다.

use function Laravel\Prompts\table; table( headers: ['이름', '이메일'], rows: User::all(['name', 'email'])->toArray() );

예를 들어 사용자 목록을 관리자용 CLI 명령어로 조회할 때, table 함수를 사용하면 별도의 포맷팅 코드 없이도 보기 좋은 표를 터미널에 출력할 수 있습니다.

Prompts

스피너 (Spin)

spin 함수는 지정한 콜백을 실행하는 동안 스피너와 선택적인 메시지를 함께 화면에 보여줍니다. 시간이 걸리는 작업이 진행 중임을 사용자에게 알려주는 용도이며, 콜백 실행이 끝나면 그 결과값을 그대로 반환합니다:

use function Laravel\Prompts\spin; $response = spin( callback: fn () => Http::get('http://example.com'), message: '응답을 가져오는 중...' );

WARNING

spin 함수가 스피너를 애니메이션으로 표시하려면 PCNTL PHP 확장 모듈이 필요합니다. 이 확장 모듈이 설치되어 있지 않은 환경에서는 애니메이션 대신 정적인(멈춰 있는) 형태의 스피너가 표시됩니다.

진행률 표시줄(Progress Bars)

오래 걸리는 작업을 실행할 때는 진행률 표시줄을 보여주면 사용자가 작업이 얼마나 진행되었는지 파악할 수 있어 유용합니다. progress 함수를 사용하면 Laravel이 진행률 표시줄을 화면에 표시하고, 주어진 반복 가능한(iterable) 값을 순회할 때마다 진행 상태를 자동으로 갱신해줍니다:

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

progress 함수는 map 함수처럼 동작하며, 콜백을 각 반복마다 실행한 결과값을 모아 배열로 반환합니다.

콜백은 Laravel\Prompts\Progress 인스턴스를 인자로 받을 수도 있는데, 이를 활용하면 반복마다 라벨(label)과 힌트(hint)를 동적으로 변경할 수 있습니다:

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

NOTE

진행률 표시줄이 필요할 정도로 오래 걸리는 작업이라면, 실제로는 큐(Queue)를 활용해 백그라운드에서 처리하는 편이 더 적합할 수도 있습니다. 다만 Artisan 명령어처럼 사용자가 직접 실행하고 결과를 즉시 확인해야 하는 CLI 작업에는 진행률 표시줄이 훌륭한 선택입니다.

Task

task 함수는 콜백이 실행되는 동안 스피너와 스크롤되는 실시간 출력 영역을 함께 보여주는 라벨 붙은 작업 화면을 표시합니다. 의존성 설치나 배포 스크립트처럼 시간이 오래 걸리는 작업을 감싸서, 지금 무슨 일이 일어나고 있는지 실시간으로 보여주기에 적합합니다.

use function Laravel\Prompts\task; task( label: 'Installing dependencies', callback: function ($logger) { // 오래 걸리는 작업... } );

콜백은 Logger 인스턴스를 전달받으며, 이를 사용해 로그 라인, 상태 메시지, 스트리밍 텍스트 등을 작업의 출력 영역에 표시할 수 있습니다.

WARNING

task 함수가 스피너를 애니메이션으로 보여주려면 PCNTL PHP 확장이 필요합니다. 이 확장을 사용할 수 없는 환경에서는 정적인(애니메이션 없는) 형태로 작업이 표시됩니다.

로그 라인 출력하기

line 메서드는 작업의 스크롤 출력 영역에 한 줄의 로그를 기록합니다.

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

상태 메시지

success, warning, error 메서드를 사용해 상태 메시지를 표시할 수 있습니다. 이 메시지들은 스크롤되는 로그 영역 위쪽에 고정되어 강조 표시됩니다.

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 메서드를 사용하면 작업이 실행되는 도중에 라벨 텍스트를 변경할 수 있습니다.

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

서브 라벨 표시하기

subLabel 메서드는 작업의 메인 라벨 아래에 흐리게 표시되는 한 줄을 보여줍니다. 현재 진행 중인 단계처럼 일시적인 상태를 알려줄 때 유용합니다. 빈 문자열을 전달하면 서브 라벨을 지울 수 있습니다.

task( label: 'Deploying', callback: function ($logger) { $logger->subLabel('Building assets...'); // ... $logger->subLabel('Running migrations...'); // ... $logger->subLabel(''); } );

subLabel 인자를 통해 초기 서브 라벨 값을 지정할 수도 있습니다.

task( label: 'Deploying', callback: function ($logger) { // ... }, subLabel: 'Preparing...' );

텍스트 스트리밍

AI가 생성하는 응답처럼 결과가 점진적으로 만들어지는 프로세스의 경우, partial 메서드를 사용해 단어 단위나 청크 단위로 텍스트를 스트리밍할 수 있습니다. 스트리밍이 끝나면 commitPartial을 호출해 출력을 확정합니다.

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

NOTE

partial로 조금씩 흘려보낸 텍스트는 아직 임시 상태이며, commitPartial을 호출해야 완성된 한 줄의 로그로 확정된다는 점을 기억하세요.

출력 줄 수 제한 커스터마이징하기

기본적으로 작업은 최대 10줄의 스크롤 출력을 표시합니다. limit 인자를 통해 이 값을 원하는 대로 조정할 수 있습니다.

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

요약 정보 유지하기

기본적으로 콜백 실행이 끝나면 작업의 출력 내용은 화면에서 지워집니다. 작업 완료 후에도 상태 메시지를 화면에 그대로 남겨두고 싶다면 keepSummary 인자를 전달하면 됩니다.

task( label: 'Deploying', callback: function ($logger) { $logger->success('Assets built'); // ... $logger->success('Migrations complete'); }, keepSummary: true, );

스트리밍 출력

stream 함수는 텍스트를 터미널에 점진적으로 흘려보내며 출력합니다. AI가 생성한 콘텐츠나 조금씩 도착하는 텍스트를 표시할 때 유용합니다:

use function Laravel\Prompts\stream; $stream = stream(); foreach ($words as $word) { $stream->append($word . ' '); usleep(25_000); // 청크 사이의 지연을 시뮬레이션... } $stream->close();

append 메서드는 스트림에 텍스트를 추가하며, 서서히 나타나는(fade-in) 효과와 함께 렌더링합니다. 모든 콘텐츠 전송이 끝나면 close 메서드를 호출해 출력을 마무리하고 커서를 원래 상태로 복원해야 합니다.

터미널 창 제목

title 함수는 사용자의 터미널 창 또는 탭 제목을 변경합니다:

use function Laravel\Prompts\title; title('의존성 설치 중');

터미널 제목을 기본값으로 되돌리려면 빈 문자열을 전달하면 됩니다:

title('');

NOTE

작업이 오래 걸리는 커맨드를 실행할 때 진행 상황을 터미널 탭 제목에 표시해두면, 여러 터미널 탭을 오가며 작업하는 사용자가 상태를 한눈에 파악하는 데 유용합니다.

프롬프트

터미널 지우기

clear 함수를 사용하면 사용자의 터미널 화면을 지울 수 있습니다:

use function Laravel\Prompts\clear; clear();

터미널 관련 고려 사항

터미널 너비

레이블, 옵션, 유효성 검사 메시지의 길이가 사용자 터미널의 "컬럼 수"를 초과하면 자동으로 잘려서 표시됩니다. 사용자가 좁은 터미널을 사용할 가능성이 있다면 이러한 문자열의 길이를 최대한 짧게 유지하는 것이 좋습니다. 80컬럼 터미널을 기준으로 안전하게 사용할 수 있는 최대 길이는 일반적으로 74자입니다.

터미널 높이

scroll 인자를 지원하는 프롬프트의 경우, 설정된 값은 유효성 검사 메시지가 표시될 공간까지 고려하여 사용자 터미널의 높이에 맞게 자동으로 조정됩니다.

Prompts (프롬프트)

지원되지 않는 환경과 폴백(Fallback)

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에 불리언 값을 전달하면 됩니다.

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

NOTE

폴백은 프롬프트 클래스마다 개별적으로 설정해야 합니다. 전달한 클로저는 해당 프롬프트 클래스의 인스턴스를 인자로 받으며, 그 프롬프트에 맞는 적절한 타입의 값을 반환해야 합니다.

테스트

라라벨은 명령어가 예상한 Prompt 메시지를 정상적으로 출력하는지 테스트할 수 있는 다양한 메서드를 제공합니다:

Pest

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

PHPUnit

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

NOTE

위 예시처럼 expectsPromptsInfo, expectsPromptsWarning, expectsPromptsError, expectsPromptsAlert, expectsPromptsIntro, expectsPromptsOutro, expectsPromptsTable 등의 메서드를 사용하면, 명령어 실행 중 info, warning, error, alert, intro, outro, table 형태의 Prompt 출력이 실제로 발생했는지 어서션(assertion)할 수 있습니다. 테스트 코드에서 각 메서드에 전달하는 문자열이나 데이터는 명령어가 실제로 출력한 내용과 정확히 일치해야 테스트가 통과합니다.

이 외에도 text, password, confirm, select, multiselect, suggest 등 사용자 입력을 받는 Prompt에 대해서는 expectsQuestion 메서드를 사용해 사용자의 답변을 시뮬레이션할 수 있습니다. Prompt를 활용하는 콘솔 명령어를 작성했다면, 반드시 이러한 테스트 메서드들을 활용해 명령어의 동작을 검증하는 것을 권장합니다.

NOTE

Prompt를 테스트하는 방법에 대한 더 자세한 내용은 콘솔 테스트 문서를 참고하세요.

이 문서는 Laravel 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 9월 17일