8000 [Console] added a better way to ask questions to the user by romainneutron · Pull Request #10606 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Console] added a better way to ask questions to the user #10606

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

Merged
merged 2 commits into from
Apr 2, 2014
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
[Console] Add docblocks and unit tests to QuestionHelper
  • Loading branch information
romainneutron committed Apr 2, 2014
commit 336bba2fd816184c2adf9721659b3c6fe36e708d
2 changes: 2 additions & 0 deletions src/Symfony/Component/Console/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use Symfony\Component\Console\Descriptor\TextDescriptor;
use Symfony\Component\Console\Descriptor\XmlDescriptor;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\ArrayInput;
Expand Down Expand Up @@ -968,6 +969,7 @@ protected function getDefaultHelperSet()
new DialogHelper(),
new ProgressHelper(),
new TableHelper(),
new QuestionHelper(),
));
}

Expand Down
96 changes: 65 additions & 31 deletions src/Symfony/Component/Console/Helper/QuestionHelper.php
6D40
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@

namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Dialog\Question;
use Symfony\Component\Console\Dialog\ChoiceQuestion;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Question\ChoiceQuestion;

/**
* The Question class provides helpers to interact with the user.
* The QuestionHelper class provides helpers to interact with the user.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
Expand All @@ -36,22 +36,27 @@ public function __construct()
/**
* Asks a question to the user.
*
* @param OutputInterface $output An Output instance
* @param InputInterface $input An InputInterface instance
* @param OutputInterface $output An OutputInterface instance
* @param Question $question The question to ask
*
* @return string The user answer
*
* @throws \RuntimeException If there is no data to read in the input stream
*/
public function ask(OutputInterface $output, Question $question)
public function ask(InputInterface $input, OutputInterface $output, Question $question)
{
$that = $this;
if (!$input->isInteractive()) {
return $question->getDefault();
}

if (!$question->getValidator()) {
return $that->doAsk($output, $question);
return $this->doAsk($output, $question);
}

$interviewer = function() use ($output, $question, $that) {
$that = $this;

$interviewer = function () use ($output, $question, $that) {
return $that->doAsk($output, $question);
};

Expand All @@ -64,23 +69,48 @@ public function ask(OutputInterface $output, Question $question)
* This is mainly useful for testing purpose.
*
* @param resource $stream The input stream
*
* @throws \InvalidArgumentException In case the stream is not a resource
*/
public function setInputStream($stream)
{
if (!is_resource($stream)) {
throw new \InvalidArgumentException('Input stream must be a valid resource.');
}

$this->inputStream = $stream;
}

/**
* Returns the helper's input stream
*
* @return string
* @return resource
*/
public function getInputStream()
{
return $this->inputStream;
}

private function doAsk($output, $question)
/**
* {@inheritdoc}
*/
public function getName()
{
return 'question';
}

/**
* Asks the question to the user.
*
* @param OutputInterface $output
* @param Question $question
*
* @return bool|mixed|null|string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't mixed imply the others?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

*
* @throws \Exception
* @throws \RuntimeException
*/
private function doAsk(OutputInterface $output, Question $question)
{
$message = $question->getQuestion();
if ($question instanceof ChoiceQuestion) {
Expand All @@ -98,12 +128,12 @@ private function doAsk($output, $question)

$output->write($message);

$autocomplete = $question->getAutocompleter();
$autocomplete = $question->getAutocompleterValues();
if (null === $autocomplete || !$this->hasSttyAvailable()) {
$ret = false;
if ($question->isHidden()) {
try {
$ret = trim($this->askHiddenResponse($output, $question));
$ret = trim($this->getHiddenResponse($output));
} catch (\RuntimeException $e) {
if (!$question->isHiddenFallback()) {
throw $e;
Expand All @@ -119,7 +149,7 @@ private function doAsk($output, $question)
$ret = trim($ret);
}
} else {
$ret = $this->autocomplete($output, $question);
$ret = trim($this->autocomplete($output, $question));
}

$ret = strlen($ret) > 0 ? $ret : $question->getDefault();
Expand All @@ -131,9 +161,17 @@ private function doAsk($output, $question)
return $ret;
}

/**
* Autocompletes a question.
*
* @param OutputInterface $output
* @param Question $question
*
* @return string
*/
private function autocomplete(OutputInterface $output, Question $question)
{
$autocomplete = $question->getAutocompleter();
$autocomplete = $question->getAutocompleterValues();
$ret = '';

$i = 0;
Expand Down Expand Up @@ -241,16 +279,15 @@ private function autocomplete(OutputInterface $output, Question $question)
}

/**
* Asks a question to the user, the response is hidden
* Gets a hidden response from user.
*
* @param OutputInterface $output An Output instance
* @param string|array $question The question
*
* @return string The answer
*
* @throws \RuntimeException In case the fallback is deactivated and the response can not be hidden
* @throws \RuntimeException In case the fallback is deactivated and the response cannot be hidden
*/
private function askHiddenResponse(OutputInterface $output, Question $question)
private function getHiddenResponse(OutputInterface $output)
{
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$exe = __DIR__.'/../Resources/bin/hiddeninput.exe';
Expand Down Expand Up @@ -298,7 +335,7 @@ private function askHiddenResponse(OutputInterface $output, Question $question)
return $value;
}

throw new \RuntimeException('Unable to hide the response');
throw new \RuntimeException('Unable to hide the response.');
}

/**
Expand All @@ -315,8 +352,8 @@ private function askHiddenResponse(OutputInterface $output, Question $question)
private function validateAttempts($interviewer, OutputInterface $output, Question $question)
{
$error = null;
$attempts = $question->getMaxAttemps();
while (false === $attempts || $attempts--) {
$attempts = $question->getMaxAttempts();
while (null === $attempts || $attempts--) {
if (null !== $error) {
$output->writeln($this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'));
}
Expand All @@ -331,7 +368,7 @@ private function validateAttempts($interviewer, OutputInterface $output, Questio
}

/**
* Return a valid unix shell
* Returns a valid unix shell.
*
* @return string|Boolean The valid shell name, false in case no valid shell is found
*/
Expand All @@ -357,6 +394,11 @@ private function getShell()
return self::$shell;
}

/**
* Returns whether Stty is available or not.
*
* @return Boolean
*/
private function hasSttyAvailable()
{
if (null !== self::$stty) {
Expand All @@ -367,12 +409,4 @@ private function hasSttyAvailable()

return self::$stty = $exitcode === 0;
}

/**
* {@inheritDoc}
*/
public function getName()
{
return 'question';
}
}
49 changes: 46 additions & 3 deletions src/Symfony/Component/Console/Question/ChoiceQuestion.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,32 +29,75 @@ public function __construct($question, array $choices, $default = null)

$this->choices = $choices;
$this->setValidator($this->getDefaultValidator());
$this->setAutocompleter(array_keys($choices));
$this->setAutocompleterValues(array_keys($choices));
}

/**
* Returns available choices.
*
* @return array
*/
public function getChoices()
{
return $this->choices;
}

/**
* Sets multiselect option.
*
* When multiselect is set to true, multiple choices can be answered.
*
* @param Boolean $multiselect
*
* @return ChoiceQuestion The current instance
*/
public function setMultiselect($multiselect)
{
$this->multiselect = $multiselect;
$this->setValidator($this->getDefaultValidator());

return $this;
}

/**
* Gets the prompt for choices.
*
* @return string
*/
public function getPrompt()
{
return $this->prompt;
}

/**
* Sets the prompt for choices.
*
* @param string $prompt
*
* @return ChoiceQuestion The current instance
*/
public function setPrompt($prompt)
{
$this->prompt = $prompt;

return $this;
}

/**
* Sets the error message for invalid values.
*
* The error message has a string placeholder (%s) for the invalid value.
*
* @param string $errorMessage
*
* @return ChoiceQuestion The current instance
*/
public function setErrorMessage($errorMessage)
{
$this->errorMessage = $errorMessage;
$this->setValidator($this->getDefaultValidator());

return $this;
}

private function getDefaultValidator()
Expand Down Expand Up @@ -82,14 +125,14 @@ private function getDefaultValidator()
if (empty($choices[$value])) {
throw new \InvalidArgumentException(sprintf($errorMessage, $value));
}
array_push($multiselectChoices, $value);
array_push($multiselectChoices, $choices[$value]);
}

if ($multiselect) {
return $multiselectChoices;
}

return $selected;
return $choices[$selected];
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
*/
class ConfirmationQuestion extends Question
{
public function __construct($question, $default = false)
public function __construct($question, $default = true)
{
parent::__construct($question, $default);
parent::__construct($question, (Boolean) $default);

$this->setNormalizer($this->getDefaultNormalizer());
}
Expand All @@ -35,10 +35,10 @@ private function getDefaultNormalizer()
}

if (false === $default) {
return $answer && 'y' == strtolower($answer[0]);
return $answer && 'y' === strtolower($answer[0]);
}

return !$answer || 'y' == strtolower($answer[0]);
return !$answer || 'y' === strtolower($answer[0]);
};
}
}
Loading
0