Skip to content

Commit dadf570

Browse files
committed
bug symfony#19100 [Console] Fixed SymfonyQuestionHelper multi-choice with defaults (sstok)
This PR was submitted for the 2.8 branch but it was merged into the 2.7 branch instead (closes symfony#19100). Discussion ---------- [Console] Fixed SymfonyQuestionHelper multi-choice with defaults |Q |A | |--- |---| |Bug Fix? |yes| |New Feature? |no | |BC Breaks? |no | |Deprecations?|no | |Tests Pass? |yes| |Fixed Tickets| | |License |MIT| |Doc PR | | When you use the SymfonyStyle with a multi-choice question and multiple defaults. You get an notice because the key is used as-is `0,1` instead of splitting the value. This pull-request changes the SymfonyQuestionHelper to checks if the Choice is a multi-choice and displays the selected values correctly `[blue, yellow]`. Note: Tests are missing, but both the SymfonyStyle and SymfonyQuestionHelper classes have almost no tests. Making it really hard 😇 hopefully symfony#19097 will make this easier 👍 Commits ------- a8f6f85 Fixed SymfonyQuestionHelper multi-choice with defaults
2 parents 80057b0 + a8f6f85 commit dadf570

File tree

3 files changed

+131
-0
lines changed

3 files changed

+131
-0
lines changed

src/Symfony/Component/Console/Helper/SymfonyQuestionHelper.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,18 @@ protected function writePrompt(OutputInterface $output, Question $question)
6666

6767
break;
6868

69+
case $question instanceof ChoiceQuestion && $question->isMultiSelect():
70+
$choices = $question->getChoices();
71+
$default = explode(',', $default);
72+
73+
foreach ($default as $key => $value) {
74+
$default[$key] = $choices[trim($value)];
75+
}
76+
77+
$text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, implode(', ', $default));
78+
79+
break;
80+
6981
case $question instanceof ChoiceQuestion:
7082
$choices = $question->getChoices();
7183
$text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, $choices[$default]);

src/Symfony/Component/Console/Question/ChoiceQuestion.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,16 @@ public function setMultiselect($multiselect)
6666
return $this;
6767
}
6868

69+
/**
70+
* Returns whether the choices are multiselect.
71+
*
72+
* @return bool
73+
*/
74+
public function isMultiselect()
75+
{
76+
return $this->multiselect;
77+
}
78+
6979
/**
7080
* Gets the prompt for choices.
7181
*
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?php
2+
3+
namespace Symfony\Component\Console\Tests\Helper;
4+
5+
use Symfony\Component\Console\Helper\FormatterHelper;
6+
use Symfony\Component\Console\Helper\HelperSet;
7+
use Symfony\Component\Console\Helper\SymfonyQuestionHelper;
8+
use Symfony\Component\Console\Output\StreamOutput;
9+
use Symfony\Component\Console\Question\ChoiceQuestion;
10+
11+
/**
12+
* @group tty
13+
*/
14+
class SymfonyQuestionHelperTest extends \PHPUnit_Framework_TestCase
15+
{
16+
public function testAskChoice()
17+
{
18+
$questionHelper = new SymfonyQuestionHelper();
19+
20+
$helperSet = new HelperSet(array(new FormatterHelper()));
21+
$questionHelper->setHelperSet($helperSet);
22+
23+
$heroes = array('Superman', 'Batman', 'Spiderman');
24+
25+
$questionHelper->setInputStream($this->getInputStream("\n1\n 1 \nFabien\n1\nFabien\n1\n0,2\n 0 , 2 \n\n\n"));
26+
27+
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '2');
28+
$question->setMaxAttempts(1);
29+
// first answer is an empty answer, we're supposed to receive the default value
30+
$this->assertEquals('Spiderman', $questionHelper->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), $question));
31+
$this->assertOutputContains('What is your favorite superhero? [Spiderman]', $output);
32+
33+
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes);
34+
$question->setMaxAttempts(1);
35+
$this->assertEquals('Batman', $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
36+
$this->assertEquals('Batman', $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
37+
38+
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes);
39+
$question->setErrorMessage('Input "%s" is not a superhero!');
40+
$question->setMaxAttempts(2);
41+
$this->assertEquals('Batman', $questionHelper->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), $question));
42+
$this->assertOutputContains('Input "Fabien" is not a superhero!', $output);
43+
44+
try {
45+
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '1');
46+
$question->setMaxAttempts(1);
47+
$questionHelper->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), $question);
48+
$this->fail();
49+
} catch (\InvalidArgumentException $e) {
50+
$this->assertEquals('Value "Fabien" is invalid', $e->getMessage());
51+
}
52+
53+
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes, null);
54+
$question->setMaxAttempts(1);
55+
$question->setMultiselect(true);
56+
57+
$this->assertEquals(array('Batman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
58+
$this->assertEquals(array('Superman', 'Spiderman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
59+
$this->assertEquals(array('Superman', 'Spiderman'), $questionHelper->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
60+
61+
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes, '0,1');
62+
$question->setMaxAttempts(1);
63+
$question->setMultiselect(true);
64+
65+
$this->assertEquals(array('Superman', 'Batman'), $questionHelper->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), $question));
66+
$this->assertOutputContains('What is your favorite superhero? [Superman, Batman]', $output);
67+
68+
$question = new ChoiceQuestion('What is your favorite superhero?', $heroes, ' 0 , 1 ');
69+
$question->setMaxAttempts(1);
70+
$question->setMultiselect(true);
71+
72+
$this->assertEquals(array('Superman', 'Batman'), $questionHelper->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), $question));
73+
$this->assertOutputContains('What is your favorite superhero? [Superman, Batman]', $output);
74+
}
75+
76+
protected function getInputStream($input)
77+
{
78+
$stream = fopen('php://memory', 'r+', false);
79+
fwrite($stream, $input);
80+
rewind($stream);
81+
82+
return $stream;
83+
}
84+
85+
protected function createOutputInterface()
86+
{
87+
$output = new StreamOutput(fopen('php://memory', 'r+', false));
88+
$output->setDecorated(false);
89+
90+
return $output;
91+
}
92+
93+
protected function createInputInterfaceMock($interactive = true)
94+
{
95+
$mock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
96+
$mock->expects($this->any())
97+
->method('isInteractive')
98+
->will($this->returnValue($interactive));
99+
100+
return $mock;
101+
}
102+
103+
private function assertOutputContains($expected, StreamOutput $output)
104+
{
105+
rewind($output->getStream());
106+
$stream = stream_get_contents($output->getStream());
107+
$this->assertContains($expected, $stream);
108+
}
109+
}

0 commit comments

Comments
 (0)