8000 feature #18999 [Console] Centralize input stream in base Input class … · symfony/symfony@9759a35 · GitHub
[go: up one dir, main page]

Skip to content

Commit 9759a35

Browse files
committed
feature #18999 [Console] Centralize input stream in base Input class (chalasr)
This PR was merged into the 3.2-dev branch. Discussion ---------- [Console] Centralize input stream in base Input class | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | yes | Tests pass? | yes | Fixed tickets | #10844 | License | MIT | Doc PR | not yet Actually we have two classes that have an `inputStream` property with its getter+setter: the QuestionHelper ('question' helper) and the SymfonyQuestionHelper (used via SymfonyStyle, that inherits the inputStream from the QuestionHelper class). This situation makes command testing really hard. ATM we can't test a command that uses `SymfonyStyle::ask` without ugly hacks, and we can't find a generic way to set the inputs passed to a command from the CommandTester, as it need to be done on a specific helper that may not be the one used by the command (SymfonyStyle case). What I propose here is to add a `stream` property (and its getter+setter) to the abstract `Symfony\Component\Console\Input\Input` class. For now I just made the two helpers setting their `inputStream` from `Input::getStream`, as both QuestionHelper and SymfonyQuestionHelper classes have an `ask` method that takes the command Input as argument. In a next time (4.0), we could remove the `getInputStream` and `setInputStream` methods from the QuestionHelper class (this only deprecates them in favor of Input `setStream` and `getStream`). This would close PR #18902 (trying to make interactive command testing with SymfonyStyle easier). This would also make PR #18710 widely better by setting the input stream in a generic way (working for both helpers without caring about if they are used and which one is used). Please give me your opinions. Commits ------- 54d3d63 Centralize input stream in base Input class
2 parents 614d6ba + 54d3d63 commit 9759a35

File tree

7 files changed

+502
-52
lines changed

7 files changed

+502
-52
lines changed

src/Symfony/Component/Console/Application.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\Console\Helper\ProcessHelper;
1717
use Symfony\Component\Console\Helper\QuestionHelper;
1818
use Symfony\Component\Console\Input\InputInterface;
19+
use Symfony\Component\Console\Input\StreamableInputInterface;
1920
use Symfony\Component\Console\Input\ArgvInput;
2021
use Symfony\Component\Console\Input\ArrayInput;
2122
use Symfony\Component\Console\Input\InputDefinition;
@@ -777,8 +778,19 @@ protected function configureIO(InputInterface $input, OutputInterface $output)
777778

778779
if (true === $input->hasParameterOption(array('--no-interaction', '-n'), true)) {
779780
$input->setInteractive(false);
780-
} elseif (function_exists('posix_isatty') && $this->getHelperSet()->has('question')) {
781-
$inputStream = $this->getHelperSet()->get('question')->getInputStream();
781+
} elseif (function_exists('posix_isatty')) {
782+
$inputStream = null;
783+
784+
if ($input instanceof StreamableInputInterface) {
785+
$inputStream = $input->getStream();
786+
}
787+
788+
// This check ensures that calling QuestionHelper::setInputStream() works
789+
// To be removed in 4.0 (in the same time as QuestionHelper::setInputStream)
790+
if (!$inputStream && $this->getHelperSet()->has('question')) {
791+
$inputStream = $this->getHelperSet()->get('question')->getInputStream(false);
792+
}
793+
782794
if (!@posix_isatty($inputStream) && false === getenv('SHELL_INTERACTIVE')) {
783795
$input->setInteractive(false);
784796
}

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

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\Console\Exception\InvalidArgumentException;
1515
use Symfony\Component\Console\Exception\RuntimeException;
1616
use Symfony\Component\Console\Input\InputInterface;
17+
use Symfony\Component\Console\Input\StreamableInputInterface;
1718
use Symfony\Component\Console\Output\ConsoleOutputInterface;
1819
use Symfony\Component\Console\Output\OutputInterface;
1920
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
@@ -52,6 +53,10 @@ public function ask(InputInterface $input, OutputInterface $output, Question $qu
5253
return $question->getDefault();
5354
}
5455

56+
if ($input instanceof StreamableInputInterface && $stream = $input->getStream()) {
57+
$this->inputStream = $stream;
58+
}
59+
5560
if (!$question->getValidator()) {
5661
return $this->doAsk($output, $question);
5762
}
@@ -68,12 +73,17 @@ public function ask(InputInterface $input, OutputInterface $output, Question $qu
6873
*
6974
* This is mainly useful for testing purpose.
7075
*
76+
* @deprecated since version 3.2, to be removed in 4.0. Use
77+
* StreamableInputInterface::setStream() instead.
78+
*
7179
* @param resource $stream The input stream
7280
*
7381
* @throws InvalidArgumentException In case the stream is not a resource
7482
*/
7583
public function setInputStream($stream)
7684
{
85+
@trigger_error(sprintf('The %s() method is deprecated since version 3.2 and will be removed in 4.0. Use %s:setStream() instead.', __METHOD__, StreamableInputInterface::class), E_USER_DEPRECATED);
86+
7787
if (!is_resource($stream)) {
7888
throw new InvalidArgumentException('Input stream must be a valid resource.');
7989
}
@@ -84,10 +94,17 @@ public function setInputStream($stream)
8494
/**
8595
* Returns the helper's input stream.
8696
*
97+
* @deprecated since version 3.2, to be removed in 4.0. Use
98+
* StreamableInputInterface::getStream() instead.
99+
*
87100
* @return resource
88101
*/
89-
public function getInputStream()
102+
public function getInputStream($triggerDeprecationError = true)
90103
{
104+
if ($triggerDeprecationError) {
105+
@trigger_error(sprintf('The %s() method is deprecated since version 3.2 and will be removed in 4.0. Use %s:getStream() instead.', __METHOD__, StreamableInputInterface::class), E_USER_DEPRECATED);
106+
}
107+
91108
return $this->inputStream;
92109
}
93110

src/Symfony/Component/Console/Input/Input.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@
2525
*
2626
* @author Fabien Potencier <fabien@symfony.com>
2727
*/
28-
abstract class Input implements InputInterface
28+
abstract class Input implements InputInterface, StreamableInputInterface
2929
{
3030
/**
3131
* @var InputDefinition
3232
*/
3333
protected $definition;
34+
protected $stream;
3435
protected $options = array();
3536
protected $arguments = array();
3637
protected $interactive = true;
@@ -233,4 +234,20 @@ public function escapeToken($token)
233234
{
234235
return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token);
235236
}
237+
238+
/**
239+
* {@inheritdoc}
240+
*/
241+
public function setStream($stream)
242+
{
243+
$this->stream = $stream;
244+
}
245+
246+
/**
247+
* {@inheritdoc}
248+
*/
249+
public function getStream()
250+
{
251+
return $this->stream;
252+
}
236253
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Console\Input;
13+
14+
/**
15+
* StreamableInputInterface is the interface implemented by all input classes
16+
* that have an input stream.
17+
*
18+
* @author Robin Chalas <robin.chalas@gmail.com>
19+
*/
20+
interface StreamableInputInterface extends InputInterface
21+
{
22+
/**
23+
* Sets the input stream to read from when interacting with the user.
24+
*
25+
* This is mainly useful for testing purpose.
26+
*
27+
* @param resource $stream The input stream
28+
*/
29+
public function setStream($stream);
30+
31+
/**
32+
* Returns the input stream.
33+
*
34+
* @return resource|null
35+
*/
36+
public function getStream();
37+
}

src/Symfony/Component/Console/Tests/ApplicationTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1117,7 +1117,7 @@ public function testCanCheckIfTerminalIsInteractive()
11171117

11181118
$this->assertFalse($tester->getInput()->hasParameterOption(array('--no-interaction', '-n')));
11191119

1120-
$inputStream = $application->getHelperSet()->get('question')->getInputStream();
1120+
$inputStream = $tester->getInput()->getStream();
11211121
$this->assertEquals($tester->getInput()->isInteractive(), @posix_isatty($inputStream));
11221122
}
11231123
}

0 commit comments

Comments
 (0)
0