From 69cf05962e673a6b5fadfdd1b38e7d98d9ebf364 Mon Sep 17 00:00:00 2001 From: Wolf Date: Mon, 2 Aug 2021 14:16:47 +0200 Subject: [PATCH] CLI: Prompt: Introduce promptByKey method --- system/CLI/CLI.php | 49 ++++++++++++++++++++--- user_guide_src/source/cli/cli_library.rst | 34 +++++++++++++++- 2 files changed, 77 insertions(+), 6 deletions(-) diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index b463aa6a3016..3ddd544c229c 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -241,25 +241,64 @@ public static function prompt(string $field, $options = null, $validation = null if (empty($opts)) { $extraOutput = $extraOutputDefault; } else { - $extraOutput = ' [' . $extraOutputDefault . ', ' . implode(', ', $opts) . ']'; - $validation[] = 'in_list[' . implode(',', $options) . ']'; + $extraOutput = '[' . $extraOutputDefault . ', ' . implode(', ', $opts) . ']'; + $validation[] = 'in_list[' . implode(', ', $options) . ']'; } $default = $options[0]; } - static::fwrite(STDOUT, $field . $extraOutput . ': '); + static::fwrite(STDOUT, $field . (trim($field) ? ' ' : '') . $extraOutput . ': '); // Read the input from keyboard. $input = trim(static::input()) ?: $default; if ($validation) { - while (! static::validate($field, $input, $validation)) { + while (! static::validate(trim($field), $input, $validation)) { $input = static::prompt($field, $options, $validation); } } - return empty($input) ? '' : $input; + return $input; + } + + /** + * prompt(), but based on the option's key + * + * @param array|string $text Output "field" text or an one or two value array where the first value is the text before listing the options + * and the second value the text before asking to select one option. Provide empty string to omit + * @param array $options A list of options (array(key => description)), the first option will be the default value + * @param array|string|null $validation Validation rules + * + * @return string The selected key of $options + * + * @codeCoverageIgnore + */ + public static function promptByKey($text, array $options, $validation = null): string + { + if (is_string($text)) { + $text = [$text]; + } elseif (! is_array($text)) { + throw new InvalidArgumentException('$text can only be of type string|array'); + } + + if (! $options) { + throw new InvalidArgumentException('No options to select from were provided'); + } + + if ($line = array_shift($text)) { + CLI::write($line); + } + + // +2 for the square brackets around the key + $keyMaxLength = max(array_map('mb_strwidth', array_keys($options))) + 2; + + foreach ($options as $key => $description) { + $name = str_pad(' [' . $key . '] ', $keyMaxLength + 4, ' '); + CLI::write(CLI::color($name, 'green') . CLI::wrap($description, 125, $keyMaxLength + 4)); + } + + return static::prompt(PHP_EOL . array_shift($text), array_keys($options), $validation); } /** diff --git a/user_guide_src/source/cli/cli_library.rst b/user_guide_src/source/cli/cli_library.rst index 1697c8409358..98f507e6bbb5 100644 --- a/user_guide_src/source/cli/cli_library.rst +++ b/user_guide_src/source/cli/cli_library.rst @@ -38,7 +38,7 @@ Getting Input from the User Sometimes you need to ask the user for more information. They might not have provided optional command-line arguments, or the script may have encountered an existing file and needs confirmation before overwriting. This is -handled with the ``prompt()`` method. +handled with the ``prompt()`` or ``promptByKey()`` method. You can provide a question by passing it in as the first parameter:: @@ -61,6 +61,38 @@ Validation rules can also be written in the array syntax.:: $email = CLI::prompt('What is your email?', null, ['required', 'valid_email']); + +**promptByKey()** + +Predefined answers (options) for prompt sometimes need to be described or are to complex to select via their value. +``promptByKey()`` allows the user to select a option by its key instead of its value:: + + $fruit = CLI::promptByKey('These are your choices:', ['The red apple', 'The plump orange', 'The ripe banana']); + + //These are your choices: + // [0] The red apple + // [1] The plump orange + // [2] The ripe banana + // + //[0, 1, 2]: + +Named keys are also possible:: + + $fruit = CLI::promptByKey(['These are your choices:', 'Which would you like?'], [ + 'apple' => 'The red apple', + 'orange' => 'The plump orange', + 'banana' => 'The ripe banana' + ]); + + //These are your choices: + // [apple] The red apple + // [orange] The plump orange + // [banana] The ripe banana + // + //Which would you like? [apple, orange, banana]: + +Finally, you can pass :ref:`validation ` rules to the answer input as the third parameter, the acceptable answers are automatically restricted to the passed options. + Providing Feedback ==================