Skip to content

Commit

Permalink
CLI: Prompt: Introduce promptByKey method
Browse files Browse the repository at this point in the history
  • Loading branch information
element-code committed Aug 2, 2021
1 parent 2a90f33 commit 5ec0fc7
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 6 deletions.
49 changes: 44 additions & 5 deletions system/CLI/CLI.php
Original file line number Diff line number Diff line change
Expand Up @@ -251,25 +251,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);
}

//--------------------------------------------------------------------
Expand Down
34 changes: 33 additions & 1 deletion user_guide_src/source/cli/cli_library.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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::

Expand All @@ -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 too complex to select via their value.
``promptByKey()`` allows the user to select an 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 <validation>` rules to the answer input as the third parameter, the acceptable answers are automatically restricted to the passed options.

Providing Feedback
==================

Expand Down

0 comments on commit 5ec0fc7

Please sign in to comment.