Skip to content

Commit

Permalink
[Console] Add docblocks and unit tests to QuestionHelper
Browse files Browse the repository at this point in the history
  • Loading branch information
romainneutron committed Apr 2, 2014
1 parent c413f89 commit 336bba2
Show file tree
Hide file tree
Showing 6 changed files with 483 additions and 49 deletions.
2 changes: 2 additions & 0 deletions src/Symfony/Component/Console/Application.php
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
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
*
* @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
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];
};
}
}
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]);
};
}
}

0 comments on commit 336bba2

Please sign in to comment.