1313
1414namespace CodeIgniter \CLI ;
1515
16- use CodeIgniter \Exceptions \InvalidArgumentException ;
1716use WeakMap ;
1817
1918/**
@@ -202,6 +201,14 @@ public static function setOutput(Output $output): void
202201 self ::$ output = $ output ;
203202 }
204203
204+ /**
205+ * Returns a prompt reading through the current output.
206+ */
207+ public static function getPrompt (): Prompt
208+ {
209+ return new Prompt (static ::getOutput ());
210+ }
211+
205212 /**
206213 * Get input from the shell, using readline or the standard STDIN
207214 *
@@ -240,53 +247,7 @@ public static function input(?string $prefix = null): string
240247 */
241248 public static function prompt (string $ field , $ options = null , $ validation = null ): string
242249 {
243- $ extraOutput = '' ;
244- $ default = '' ;
245-
246- if (isset ($ validation ) && ! is_array ($ validation ) && ! is_string ($ validation )) {
247- throw new InvalidArgumentException ('$rules can only be of type string|array ' );
248- }
249-
250- if (! is_array ($ validation )) {
251- $ validation = ($ validation !== null ) ? explode ('| ' , $ validation ) : [];
252- }
253-
254- if (is_string ($ options )) {
255- $ extraOutput = ' [ ' . static ::color ($ options , 'green ' ) . '] ' ;
256- $ default = $ options ;
257- }
258-
259- if (is_array ($ options ) && $ options !== []) {
260- $ opts = $ options ;
261- $ extraOutputDefault = static ::color ((string ) $ opts [0 ], 'green ' );
262-
263- unset($ opts [0 ]);
264-
265- if ($ opts === []) {
266- $ extraOutput = $ extraOutputDefault ;
267- } else {
268- $ extraOutput = '[ ' . $ extraOutputDefault . ', ' . implode (', ' , $ opts ) . '] ' ;
269- $ validation [] = 'in_list[ ' . implode (', ' , $ options ) . '] ' ;
270- }
271-
272- $ default = $ options [0 ];
273- }
274-
275- $ output = static ::getOutput ();
276- $ output ->setCursorAtLineStart (true );
277-
278- // The reader renders the prompt itself, so readline redraws repaint it instead of erasing it.
279- $ prompt = sprintf ('%s%s%s: ' , $ field , trim ($ field ) !== '' ? ' ' : '' , $ extraOutput );
280- $ input = trim ($ output ->getInputOutput ()->input ($ prompt ));
281- $ input = $ input === '' ? (string ) $ default : $ input ;
282-
283- if ($ validation !== []) {
284- while (! static ::validate ('" ' . trim ($ field ) . '" ' , $ input , $ validation )) {
285- $ input = static ::prompt ($ field , $ options , $ validation );
286- }
287- }
288-
289- return $ input ;
250+ return static ::getPrompt ()->ask ($ field , $ options , $ validation );
290251 }
291252
292253 /**
@@ -301,21 +262,7 @@ public static function prompt(string $field, $options = null, $validation = null
301262 */
302263 public static function promptByKey ($ text , array $ options , $ validation = null ): string
303264 {
304- if (is_string ($ text )) {
305- $ text = [$ text ];
306- } elseif (! is_array ($ text )) {
307- throw new InvalidArgumentException ('$text can only be of type string|array ' );
308- }
309-
310- self ::isZeroOptions ($ options );
311-
312- if (($ line = array_shift ($ text )) !== null ) {
313- static ::write ($ line );
314- }
315-
316- self ::printKeysAndValues ($ options );
317-
318- return static ::prompt (PHP_EOL . array_shift ($ text ), array_keys ($ options ), $ validation );
265+ return static ::getPrompt ()->askByKey ($ text , $ options , $ validation );
319266 }
320267
321268 /**
@@ -329,102 +276,26 @@ public static function promptByKey($text, array $options, $validation = null): s
329276 */
330277 public static function promptByMultipleKeys (string $ text , array $ options ): array
331278 {
332- self ::isZeroOptions ($ options );
333-
334- $ extraOutputDefault = static ::color ('0 ' , 'green ' );
335- $ opts = $ options ;
336- unset($ opts [0 ]);
337-
338- if ($ opts === []) {
339- $ extraOutput = $ extraOutputDefault ;
340- } else {
341- $ optsKey = array_keys ($ opts );
342- $ extraOutput = '[ ' . $ extraOutputDefault . ', ' . implode (', ' , $ optsKey ) . '] ' ;
343- $ extraOutput = 'You can specify multiple values separated by commas. ' . PHP_EOL . $ extraOutput ;
344- }
345-
346- static ::write ($ text );
347- self ::printKeysAndValues ($ options );
348- static ::newLine ();
349-
350- $ input = static ::prompt ($ extraOutput );
351- $ input = ($ input === '' ) ? '0 ' : $ input ; // 0 is default
352-
353- // validation
354- while (true ) {
355- $ pattern = preg_match_all ('/^\d+(,\d+)*$/ ' , trim ($ input ));
356-
357- // separate input by comma and convert all to an int[]
358- $ inputToArray = array_map (static fn ($ value ): int => (int ) $ value , explode (', ' , $ input ));
359- // find max from key of $options
360- $ maxOptions = array_key_last ($ options );
361- // find max from input
362- $ maxInput = max ($ inputToArray );
363-
364- // return the prompt again if $input contain(s) non-numeric character, except a comma.
365- // And if max from $options less than max from input,
366- // it means user tried to access null value in $options
367- if ($ pattern < 1 || $ maxOptions < $ maxInput ) {
368- static ::error ('Please select correctly. ' );
369- static ::newLine ();
370-
371- $ input = static ::prompt ($ extraOutput );
372- $ input = ($ input === '' ) ? '0 ' : $ input ;
373- } else {
374- break ;
375- }
376- }
377-
378- $ input = [];
379-
380- foreach ($ options as $ key => $ description ) {
381- foreach ($ inputToArray as $ inputKey ) {
382- if ($ key === $ inputKey ) {
383- $ input [$ key ] = $ description ;
384- }
385- }
386- }
387-
388- return $ input ;
389- }
390-
391- /**
392- * Validation for $options in promptByKey() and promptByMultipleKeys(). Return an error if $options is an empty array.
393- *
394- * @param array<array-key, string> $options
395- */
396- private static function isZeroOptions (array $ options ): void
397- {
398- if ($ options === []) {
399- throw new InvalidArgumentException ('No options to select from were provided ' );
400- }
401- }
402-
403- /**
404- * Print each key and value one by one
405- *
406- * @param array<array-key, string> $options
407- */
408- private static function printKeysAndValues (array $ options ): void
409- {
410- // +2 for the square brackets around the key
411- $ keyMaxLength = max (array_map (mb_strwidth (...), array_keys ($ options ))) + 2 ;
412-
413- foreach ($ options as $ key => $ description ) {
414- $ name = str_pad (' [ ' . $ key . '] ' , $ keyMaxLength + 4 , ' ' );
415- static ::write (static ::color ($ name , 'green ' ) . static ::wrap ($ description , 125 , $ keyMaxLength + 4 ));
416- }
279+ return static ::getPrompt ()->askByMultipleKeys ($ text , $ options );
417280 }
418281
419282 /**
420283 * Validate one prompt "field" at a time
421284 *
285+ * @deprecated 4.8.0 Override `Prompt::validate()` instead.
286+ *
422287 * @param string $field Prompt "field" output
423288 * @param string $value Input value
424289 * @param list<string>|string $rules Validation rules
425290 */
426291 protected static function validate (string $ field , string $ value , $ rules ): bool
427292 {
293+ @trigger_error (sprintf (
294+ 'Since v4.8.0, "%s()" is deprecated. Override "%s::validate()" instead. ' ,
295+ __METHOD__ ,
296+ Prompt::class,
297+ ), E_USER_DEPRECATED );
298+
428299 $ label = $ field ;
429300 $ field = 'temp ' ;
430301 $ validation = service ('validation ' , null , false );
0 commit comments