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\Output;
13:
14: use Symfony\Component\Console\Formatter\OutputFormatterInterface;
15:
16: /**
17: * StreamOutput writes the output to a given stream.
18: *
19: * Usage:
20: *
21: * $output = new StreamOutput(fopen('php://stdout', 'w'));
22: *
23: * As `StreamOutput` can use any stream, you can also use a file:
24: *
25: * $output = new StreamOutput(fopen('/path/to/output.log', 'a', false));
26: *
27: * @author Fabien Potencier <fabien@symfony.com>
28: *
29: * @api
30: */
31: class StreamOutput extends Output
32: {
33: private $stream;
34:
35: /**
36: * Constructor.
37: *
38: * @param mixed $stream A stream resource
39: * @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL,
40: * self::VERBOSITY_VERBOSE)
41: * @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing)
42: * @param OutputFormatterInterface $formatter Output formatter instance
43: *
44: * @throws \InvalidArgumentException When first argument is not a real stream
45: *
46: * @api
47: */
48: public function __construct($stream, $verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
49: {
50: if (!is_resource($stream) || 'stream' !== get_resource_type($stream)) {
51: throw new \InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
52: }
53:
54: $this->stream = $stream;
55:
56: if (null === $decorated) {
57: $decorated = $this->hasColorSupport();
58: }
59:
60: parent::__construct($verbosity, $decorated, $formatter);
61: }
62:
63: /**
64: * Gets the stream attached to this StreamOutput instance.
65: *
66: * @return resource A stream resource
67: */
68: public function getStream()
69: {
70: return $this->stream;
71: }
72:
73: /**
74: * Writes a message to the output.
75: *
76: * @param string $message A message to write to the output
77: * @param Boolean $newline Whether to add a newline or not
78: *
79: * @throws \RuntimeException When unable to write output (should never happen)
80: */
81: protected function doWrite($message, $newline)
82: {
83: if (false === @fwrite($this->stream, $message.($newline ? PHP_EOL : ''))) {
84: // @codeCoverageIgnoreStart
85: // should never happen
86: throw new \RuntimeException('Unable to write output.');
87: // @codeCoverageIgnoreEnd
88: }
89:
90: fflush($this->stream);
91: }
92:
93: /**
94: * Returns true if the stream supports colorization.
95: *
96: * Colorization is disabled if not supported by the stream:
97: *
98: * - windows without ansicon and ConEmu
99: * - non tty consoles
100: *
101: * @return Boolean true if the stream supports colorization, false otherwise
102: */
103: protected function hasColorSupport()
104: {
105: // @codeCoverageIgnoreStart
106: if (DIRECTORY_SEPARATOR == '\\') {
107: return false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI');
108: }
109:
110: return function_exists('posix_isatty') && @posix_isatty($this->stream);
111: // @codeCoverageIgnoreEnd
112: }
113: }
114: