Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new method promptByMultipleKeys() in CLI class #6302

Merged
106 changes: 54 additions & 52 deletions system/CLI/CLI.php
Original file line number Diff line number Diff line change
Expand Up @@ -282,21 +282,13 @@ public static function promptByKey($text, array $options, $validation = null): s
throw new InvalidArgumentException('$text can only be of type string|array');
}

if (! $options) {
throw new InvalidArgumentException('No options to select from were provided');
}
CLI::isZeroOptions($options);

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));
}
CLI::printKeysAndValues($options);

return static::prompt(PHP_EOL . array_shift($text), array_keys($options), $validation);
}
Expand All @@ -308,59 +300,38 @@ public static function promptByKey($text, array $options, $validation = null): s
* 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
*
* @return array The selected key and value of $options
* @return array The selected key(s) and value(s) of $options
*/
public static function promptByMultipleKeys($text, array $options)
{
if (is_string($text)) {
$text = [$text];
} elseif (! is_array($text)) {
throw new InvalidArgumentException('$text can only be string');
}

if (is_array($options) && $options) {
$opts = $options;
$extraOutputDefault = static::color('0', 'green');
CLI::isZeroOptions($options);

unset($opts[0]);

if (empty($opts)) {
$extraOutput = $extraOutputDefault;
} else {
$optsKey = [];

foreach (array_keys($opts) as $key) {
$optsKey[] = $key;
}
$extraOutput = '[' . $extraOutputDefault . ', ' . implode(', ', $optsKey) . ']';
}
$extraOutputDefault = static::color('0', 'green');
$opts = $options;
unset($opts[0]);

$default = 0;
if (empty($opts)) {
$extraOutput = $extraOutputDefault;
} else {
throw new InvalidArgumentException('$options can only be array');
}

if ($line = array_shift($text)) {
CLI::newLine();
CLI::write($line);
$optsKey = [];
foreach (array_keys($opts) as $key) {
$optsKey[] = $key;
}
$extraOutput = '[' . $extraOutputDefault . ', ' . implode(', ', $optsKey) . ']';
}

// +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));
}
CLI::newLine();
CLI::write($text);
CLI::printKeysAndValues($options);
static::fwrite(STDOUT, (trim((string) ((int) $text)) ? ' ' : '') . $extraOutput . ': ');
$input = trim(static::input()) ?: $default;
$input = trim(static::input()) ?: 0; // 0 is default

// search alphabetic character
// search alphabetic character in $input
// return the prompt again if it is true because the key of $options is number
if (preg_match_all('/[a-zA-Z]/i', trim($input))) {
static::error('Please select correctly');

return $input = static::promptByMultipleKeys($line, $options);
return static::promptByMultipleKeys($text, $options);
}

// separate input by comma and convert all to an int[]
Expand All @@ -369,17 +340,16 @@ public static function promptByMultipleKeys($text, array $options)
// find max from key of $options
$maxOptions = array_key_last($options);
// find max from input
$maxInput = max($inputToArray);
$maxInput = max($inputToArray);
// if max from $options less than max from input
// it is mean user tried to access null value in $options
if ($maxOptions < $maxInput) {
static::error('Please select correctly');

return $input = static::promptByMultipleKeys($line, $options);
return static::promptByMultipleKeys($text, $options);
}

$input = [];

foreach ($options as $key => $description) {
foreach ($inputToArray as $inputKey) {
if ($key === $inputKey) {
Expand All @@ -391,6 +361,38 @@ public static function promptByMultipleKeys($text, array $options)
return $input;
}

//--------------------------------------------------------------------
// Utility for promptBy...
//--------------------------------------------------------------------

/**
* Validation for $options in promptByKey() and promptByMultipleKeys(). Return an error if $options is an empty array.
*/
private static function isZeroOptions(array $options) : void
{
if(!$options){
throw new InvalidArgumentException('No options to select from were provided');
}
}

/**
* Print each key and value one by one
*/
private static function printKeysAndValues(array $options) : void
{
// +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));
}
}

//--------------------------------------------------------------------
// End Utility for promptBy...
//--------------------------------------------------------------------

/**
* Validate one prompt "field" at a time
*
Expand Down
15 changes: 0 additions & 15 deletions tests/system/CLI/CLITest.php
Original file line number Diff line number Diff line change
Expand Up @@ -526,19 +526,4 @@ public function testStrlen()
$this->assertSame(0, CLI::strlen(null));
}

public function testPromptByMultipleKeys()
{
$options = ['one', 'two', 'three'];
CLI::promptByMultipleKeys('Is this a question?', $options);

$expected = '' . PHP_EOL . 'Is this a question?' . PHP_EOL;

foreach ($options as $key => $description) {
$name = str_pad(' [' . $key . '] ', 7, ' ');
$expected .= '' . CLI::color($name, 'green') . CLI::wrap($description, 125, 7) . PHP_EOL;
}
$expected .= '[' . CLI::color('0', 'green') . ', 1, 2]: ';

$this->assertSame($expected, $this->getStreamFilterBuffer());
}
}
2 changes: 1 addition & 1 deletion user_guide_src/source/changelogs/v4.3.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Enhancements

CLI
===
- Added methods ``CLI::promptByMultipleKey()`` to support multiple value in input, unlike ``promptByKey()``. See :ref:`prompt-by-multiple-key` for details.
- Added methods ``CLI::promptByMultipleKeys()`` to support multiple value in input, unlike ``promptByKey()``. See :ref:`prompt-by-multiple-keys` for details.

Others
======
Expand Down
4 changes: 2 additions & 2 deletions user_guide_src/source/cli/cli_library.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ Named keys are also possible:

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.

.. _prompt-by-multiple-key:
.. _prompt-by-multiple-keys:

promptByMultipleKey()
promptByMultipleKeys()
=====================

This method is the same as ``promptByKey()``, but it supports multiple value.
Expand Down
2 changes: 1 addition & 1 deletion user_guide_src/source/cli/cli_library/023.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

$hobby = CLI::promptByKey('Select your hobbies:', ['Playing game', 'Sleep', 'Badminton']);
$hobby = CLI::promptByMultipleKeys('Select your hobbies:', ['Playing game', 'Sleep', 'Badminton']);
/*
* Select your hobbies:
* [0] Playing game
Expand Down