From 8ddaa20b29caa7aeb505681f12e86a7a444ae8b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Ostroluck=C3=BD?= Date: Wed, 11 Mar 2020 19:41:03 +0100 Subject: [PATCH 1/3] [Console] Fallback to default answers when unable to read input --- .../Exception/MissingInputException.php | 21 +++++ .../Console/Helper/QuestionHelper.php | 87 +++++++++++-------- .../Tests/Helper/QuestionHelperTest.php | 6 +- .../phpt/uses_stdin_as_interactive_input.phpt | 4 +- 4 files changed, 80 insertions(+), 38 deletions(-) create mode 100644 src/Symfony/Component/Console/Exception/MissingInputException.php diff --git a/src/Symfony/Component/Console/Exception/MissingInputException.php b/src/Symfony/Component/Console/Exception/MissingInputException.php new file mode 100644 index 0000000000..04f02ade45 --- /dev/null +++ b/src/Symfony/Component/Console/Exception/MissingInputException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Exception; + +/** + * Represents failure to read input from stdin. + * + * @author Gabriel Ostrolucký + */ +class MissingInputException extends RuntimeException implements ExceptionInterface +{ +} diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php index 40709cedd9..b383252c5a 100644 --- a/src/Symfony/Component/Console/Helper/QuestionHelper.php +++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Console\Helper; +use Symfony\Component\Console\Exception\MissingInputException; use Symfony\Component\Console\Exception\RuntimeException; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Formatter\OutputFormatterStyle; @@ -48,44 +49,32 @@ class QuestionHelper extends Helper } if (!$input->isInteractive()) { - $default = $question->getDefault(); - - if (null === $default) { - return $default; - } - - if ($validator = $question->getValidator()) { - return \call_user_func($question->getValidator(), $default); - } elseif ($question instanceof ChoiceQuestion) { - $choices = $question->getChoices(); - - if (!$question->isMultiselect()) { - return isset($choices[$default]) ? $choices[$default] : $default; - } - - $default = explode(',', $default); - foreach ($default as $k => $v) { - $v = $question->isTrimmable() ? trim($v) : $v; - $default[$k] = isset($choices[$v]) ? $choices[$v] : $v; - } - } - - return $default; + return $this->getDefaultAnswer($question); } if ($input instanceof StreamableInputInterface && $stream = $input->getStream()) { $this->inputStream = $stream; } - if (!$question->getValidator()) { - return $this->doAsk($output, $question); + try { + if (!$question->getValidator()) { + return $this->doAsk($output, $question); + } + + $interviewer = function () use ($output, $question) { + return $this->doAsk($output, $question); + }; + + return $this->validateAttempts($interviewer, $output, $question); + } catch (MissingInputException $exception) { + $input->setInteractive(false); + + if (null === $fallbackOutput = $this->getDefaultAnswer($question)) { + throw $exception; + } + + return $fallbackOutput; } - - $interviewer = function () use ($output, $question) { - return $this->doAsk($output, $question); - }; - - return $this->validateAttempts($interviewer, $output, $question); } /** @@ -134,7 +123,7 @@ class QuestionHelper extends Helper if (false === $ret) { $ret = fgets($inputStream, 4096); if (false === $ret) { - throw new RuntimeException('Aborted.'); + throw new MissingInputException('Aborted.'); } if ($question->isTrimmable()) { $ret = trim($ret); @@ -158,6 +147,36 @@ class QuestionHelper extends Helper return $ret; } + /** + * @return mixed + */ + private function getDefaultAnswer(Question $question) + { + $default = $question->getDefault(); + + if (null === $default) { + return $default; + } + + if ($validator = $question->getValidator()) { + return \call_user_func($question->getValidator(), $default); + } elseif ($question instanceof ChoiceQuestion) { + $choices = $question->getChoices(); + + if (!$question->isMultiselect()) { + return isset($choices[$default]) ? $choices[$default] : $default; + } + + $default = explode(',', $default); + foreach ($default as $k => $v) { + $v = $question->isTrimmable() ? trim($v) : $v; + $default[$k] = isset($choices[$v]) ? $choices[$v] : $v; + } + } + + return $default; + } + /** * Outputs the question prompt. */ @@ -240,7 +259,7 @@ class QuestionHelper extends Helper // as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false. if (false === $c || ('' === $ret && '' === $c && null === $question->getDefault())) { shell_exec(sprintf('stty %s', $sttyMode)); - throw new RuntimeException('Aborted.'); + throw new MissingInputException('Aborted.'); } elseif ("\177" === $c) { // Backspace Character if (0 === $numMatches && 0 !== $i) { --$i; @@ -406,7 +425,7 @@ class QuestionHelper extends Helper shell_exec(sprintf('stty %s', $sttyMode)); if (false === $value) { - throw new RuntimeException('Aborted.'); + throw new MissingInputException('Aborted.'); } if ($trimmable) { $value = trim($value); diff --git a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php index fcba3b3b2f..461318efe7 100644 --- a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php @@ -696,7 +696,7 @@ class QuestionHelperTest extends AbstractQuestionHelperTest public function testAskThrowsExceptionOnMissingInput() { - $this->expectException('Symfony\Component\Console\Exception\RuntimeException'); + $this->expectException('Symfony\Component\Console\Exception\MissingInputException'); $this->expectExceptionMessage('Aborted.'); $dialog = new QuestionHelper(); $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), new Question('What\'s your name?')); @@ -704,7 +704,7 @@ class QuestionHelperTest extends AbstractQuestionHelperTest public function testAskThrowsExceptionOnMissingInputForChoiceQuestion() { - $this->expectException('Symfony\Component\Console\Exception\RuntimeException'); + $this->expectException('Symfony\Component\Console\Exception\MissingInputException'); $this->expectExceptionMessage('Aborted.'); $dialog = new QuestionHelper(); $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), new ChoiceQuestion('Choice', ['a', 'b'])); @@ -712,7 +712,7 @@ class QuestionHelperTest extends AbstractQuestionHelperTest public function testAskThrowsExceptionOnMissingInputWithValidator() { - $this->expectException('Symfony\Component\Console\Exception\RuntimeException'); + $this->expectException('Symfony\Component\Console\Exception\MissingInputException'); $this->expectExceptionMessage('Aborted.'); $dialog = new QuestionHelper(); diff --git a/src/Symfony/Component/Console/Tests/phpt/uses_stdin_as_interactive_input.phpt b/src/Symfony/Component/Console/Tests/phpt/uses_stdin_as_interactive_input.phpt index db1bb4ce43..3f329cc73f 100644 --- a/src/Symfony/Component/Console/Tests/phpt/uses_stdin_as_interactive_input.phpt +++ b/src/Symfony/Component/Console/Tests/phpt/uses_stdin_as_interactive_input.phpt @@ -18,7 +18,8 @@ require $vendor.'/vendor/autoload.php'; (new Application()) ->register('app') ->setCode(function(InputInterface $input, OutputInterface $output) { - $output->writeln((new QuestionHelper())->ask($input, $output, new Question('Foo?'))); + $output->writeln((new QuestionHelper())->ask($input, $output, new Question('Foo?', 'foo'))); + $output->writeln((new QuestionHelper())->ask($input, $output, new Question('Bar?', 'bar'))); }) ->getApplication() ->setDefaultCommand('app', true) @@ -26,3 +27,4 @@ require $vendor.'/vendor/autoload.php'; ; --EXPECT-- Foo?Hello World +Bar?bar From 5688f97bad42bccb96914f27e0d7d041480025bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Bogusz?= Date: Tue, 10 Mar 2020 20:39:57 +0100 Subject: [PATCH 2/3] [Validator] Remove commas in translations --- .../Validator/Resources/translations/validators.es.xlf | 2 +- .../Validator/Resources/translations/validators.pl.xlf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf index 08ec74c05b..24ef5548da 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini. - Ninguna carpeta temporal fue configurada en php.ini. + Ninguna carpeta temporal fue configurada en php.ini o la carpeta configurada no existe. Cannot write temporary file to disk. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf index 5c1e472ab5..df93abd0b9 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini. - Nie skonfigurowano folderu tymczasowego w php.ini, lub skonfigurowany folder nie istnieje. + Nie skonfigurowano folderu tymczasowego w php.ini lub skonfigurowany folder nie istnieje. Cannot write temporary file to disk. From e8b4d356164ad1eee73460f13914c1448f22bcb2 Mon Sep 17 00:00:00 2001 From: William Arslett Date: Fri, 13 Mar 2020 17:09:22 +0000 Subject: [PATCH 3/3] [FrameworkBundle] start session on flashbag injection --- .../Resources/config/session.xml | 10 +++--- .../InjectedFlashbagSessionController.php | 36 +++++++++++++++++++ .../TestBundle/Resources/config/routing.yml | 4 +++ .../Tests/Functional/SessionTest.php | 23 ++++++++++++ .../Tests/Functional/app/Session/config.yml | 4 +++ 5 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/InjectedFlashbagSessionController.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml index 8b68d9e846..9f3a5b78c1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml @@ -13,8 +13,6 @@ - - @@ -37,10 +35,14 @@ - + + + - + + + %kernel.cache_dir%/sessions diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/InjectedFlashbagSessionController.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/InjectedFlashbagSessionController.php new file mode 100644 index 0000000000..20c33a17e4 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/InjectedFlashbagSessionController.php @@ -0,0 +1,36 @@ +flashBag = $flashBag; + $this->router = $router; + } + + public function setFlashAction(Request $request, $message) + { + $this->flashBag->add('notice', $message); + + return new RedirectResponse($this->router->generate('session_showflash')); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml index 923204ab0f..3ae5669c90 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml @@ -18,6 +18,10 @@ session_setflash: path: /session_setflash/{message} defaults: { _controller: TestBundle:Session:setFlash} +injected_flashbag_session_setflash: + path: injected_flashbag/session_setflash/{message} + defaults: { _controller: TestBundle:InjectedFlashbagSession:setFlash} + session_showflash: path: /session_showflash defaults: { _controller: TestBundle:Session:showFlash} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SessionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SessionTest.php index 3a87f7e4e6..1b1ef9ffc0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SessionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SessionTest.php @@ -69,6 +69,29 @@ class SessionTest extends AbstractWebTestCase $this->assertStringContainsString('No flash was set.', $crawler->text()); } + /** + * Tests flash messages work when flashbag service is injected to the constructor. + * + * @dataProvider getConfigs + */ + public function testFlashOnInjectedFlashbag($config, $insulate) + { + $client = $this->createClient(['test_case' => 'Session', 'root_config' => $config]); + if ($insulate) { + $client->insulate(); + } + + // set flash + $client->request('GET', '/injected_flashbag/session_setflash/Hello%20world.'); + + // check flash displays on redirect + $this->assertStringContainsString('Hello world.', $client->followRedirect()->text()); + + // check flash is gone + $crawler = $client->request('GET', '/session_showflash'); + $this->assertStringContainsString('No flash was set.', $crawler->text()); + } + /** * See if two separate insulated clients can run without * polluting each other's session data. diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Session/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Session/config.yml index ad6bdb691c..4807c42d1e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Session/config.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Session/config.yml @@ -5,3 +5,7 @@ services: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\SubRequestController: tags: - { name: controller.service_arguments, action: indexAction, argument: handler, id: fragment.handler } + + Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\InjectedFlashbagSessionController: + autowire: true + tags: ['controller.service_arguments']