Skip to content
This repository was archived by the owner on Jan 31, 2020. It is now read-only.

Commit 9aaa0e6

Browse files
committed
Merge branch 'feature/console-helper' into develop
Close #63
2 parents aaa955c + 020a6d2 commit 9aaa0e6

File tree

5 files changed

+438
-1
lines changed

5 files changed

+438
-1
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ All notable changes to this project will be documented in this file, in reverse
66

77
### Added
88

9-
- Nothing.
9+
- [#63](https://github.com/zendframework/zend-stdlib/pull/63) adds a new
10+
`Zend\Stdlib\ConsoleHelper` class, providing minimal support for writing
11+
output to `STDOUT` and `STDERR`, with optional colorization, when the console
12+
supports that feature.
1013

1114
### Deprecated
1215

doc/book/console-helper.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Console Helper
2+
3+
Writing one-off scripts or vendor binaries for a package is often problematic:
4+
5+
- You need to parse arguments manually.
6+
- You need to send output to the console in a meaningful fashion:
7+
- Using `STDOUT` for meaningful, expected output
8+
- Using `STDERR` for error messages
9+
- Ensuring any line breaks are converted to `PHP_EOL`
10+
- Optionally, using console colors to provide context, which means:
11+
- Detecting whether or not the console supports colors in the first place
12+
- Providing appropriate escape sequences to produce color
13+
14+
`Zend\Stdlib\ConsoleHelper` helps to address the second major bullet point and
15+
all beneath it in a minimal fashion.
16+
17+
## Usage
18+
19+
Typical usage is to instantiate a `ConsoleHelper`, and call one of its methods:
20+
21+
```php
22+
use Zend\Stdlib\ConsoleHelper;
23+
24+
$helper = new ConsoleHelper();
25+
$helper->writeLine('This is output');
26+
```
27+
28+
You can optionally pass a PHP stream resource to the constructor, which will be
29+
used to determine whether or not color support is available:
30+
31+
```php
32+
$helper = new ConsoleHelper($stream);
33+
```
34+
35+
By default, it assumes `STDOUT`, and tests against that.
36+
37+
## Available methods
38+
39+
`ConsoleHelper` provides the following methods.
40+
41+
### colorize
42+
43+
- `colorize(string $string) : string`
44+
45+
`colorize()` accepts a formatted string, and will then apply ANSI color
46+
sequences to them, if color support is detected.
47+
48+
The following sequences are currently supported:
49+
50+
- `<info>...</info>` will apply a green color sequence around the provided text.
51+
- `<error>...</error>` will apply a red color sequence around the provided text.
52+
53+
You may mix multiple sequences within the same stream.
54+
55+
### write
56+
57+
- `write(string $string, bool $colorize = true, resource $stream = STDOUT) : void`
58+
59+
Emits the provided `$string` to the provided `$stream` (which defaults to
60+
`STDOUT` if not provided). Any EOL sequences are convered to `PHP_EOL`. If
61+
`$colorize` is `true`, the string is first passed to `colorize()` as well.
62+
63+
### writeline
64+
65+
- `writeLine(string $string, bool $colorize = true, resource $stream = STDOUT) : void`
66+
67+
Same as `write()`, except it also appends a `PHP_EOL` sequence to the `$string`.
68+
69+
### writeErrorMessage
70+
71+
- `writeErrorMessage(string $message)`
72+
73+
Wraps `$message` in an `<error></error>` sequence, and passes it to
74+
`writeLine()`, using `STDERR` as the `$stream`.
75+
76+
## Example
77+
78+
Below is an example class that accepts an argument list, and determines how and
79+
what to emit.
80+
81+
```php
82+
namespace Foo;
83+
84+
use Zend\Stdlib\ConsoleHelper;
85+
86+
class HelloWorld
87+
{
88+
private $helper;
89+
90+
public function __construct(ConsoleHelper $helper = null)
91+
{
92+
$this->helper = $helper ?: new ConsoleHelper();
93+
}
94+
95+
public function __invoke(array $args)
96+
{
97+
if (! count($args)) {
98+
$this->helper->writeErrorMessage('Missing arguments!');
99+
return;
100+
}
101+
102+
if (count($args) > 1) {
103+
$this->helper->writeErrorMessage('Too many arguments!');
104+
return;
105+
}
106+
107+
$target = array_shift($args);
108+
109+
$this->helper->writeLine(sprintf(
110+
'<info>Hello</info> %s',
111+
$target
112+
));
113+
}
114+
}
115+
```
116+
117+
## When to upgrade
118+
119+
`ConsoleHelper` is deliberately simple, and assumes that your primary need for
120+
console tooling is for output considerations.
121+
122+
If you need to parse complex argument strings, we recommend using
123+
[zend-console](https://docs.zendframework.com/zend-console/)/[zf-console](https://github.com/zfcampus/zf-console)
124+
or [symfony/console](http://symfony.com/doc/current/components/console.html),
125+
as these packages provide those capabilities, as well as far more colorization
126+
and console feature detection facilities.

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ docs_dir: doc/book
22
site_dir: doc/html
33
pages:
44
- index.md
5+
- Reference:
6+
- "Console Helper": console-helper.md
57
- Migration: migration.md
68
site_name: zend-stdlib
79
site_description: Zend\Stdlib

src/ConsoleHelper.php

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
<?php
2+
/**
3+
* @link http://github.com/zendframework/zend-stdlib for the canonical source repository
4+
* @copyright Copyright (c) 2016 Zend Technologies USA Inc. (http://www.zend.com)
5+
* @license http://framework.zend.com/license/new-bsd New BSD License
6+
*/
7+
8+
namespace Zend\Stdlib;
9+
10+
/**
11+
* Utilities for console tooling.
12+
*
13+
* Provides the following facilities:
14+
*
15+
* - Colorize strings using markup (e.g., `<info>message</info>`,
16+
* `<error>message</error>`)
17+
* - Write output to a specified stream, optionally with colorization.
18+
* - Write a line of output to a specified stream, optionally with
19+
* colorization, using the system EOL sequence..
20+
* - Write an error message to STDERR.
21+
*
22+
* Colorization will only occur when expected sequences are discovered, and
23+
* then, only if the console terminal allows it.
24+
*
25+
* Essentially, provides the bare minimum to allow you to provide messages to
26+
* the current console.
27+
*/
28+
class ConsoleHelper
29+
{
30+
const COLOR_GREEN = "\033[32m";
31+
const COLOR_RED = "\033[31m";
32+
const COLOR_RESET = "\033[0m";
33+
34+
const HIGHLIGHT_INFO = 'info';
35+
const HIGHLIGHT_ERROR = 'error';
36+
37+
private $highlightMap = [
38+
self::HIGHLIGHT_INFO => self::COLOR_GREEN,
39+
self::HIGHLIGHT_ERROR => self::COLOR_RED,
40+
];
41+
42+
/**
43+
* @var string Exists only for testing.
44+
*/
45+
private $eol = PHP_EOL;
46+
47+
/**
48+
* @var resource Exists only for testing.
49+
*/
50+
private $stderr = STDERR;
51+
52+
/**
53+
* @var bool
54+
*/
55+
private $supportsColor;
56+
57+
/**
58+
* @param resource $resource
59+
*/
60+
public function __construct($resource = STDOUT)
61+
{
62+
$this->supportsColor = $this->detectColorCapabilities($resource);
63+
}
64+
65+
/**
66+
* Colorize a string for use with the terminal.
67+
*
68+
* Takes strings formatted as `<key>string</key>` and formats them per the
69+
* $highlightMap; if color support is disabled, simply removes the formatting
70+
* tags.
71+
*
72+
* @param string $string
73+
* @return string
74+
*/
75+
public function colorize($string)
76+
{
77+
$reset = $this->supportsColor ? self::COLOR_RESET : '';
78+
foreach ($this->highlightMap as $key => $color) {
79+
$pattern = sprintf('#<%s>(.*?)</%s>#s', $key, $key);
80+
$color = $this->supportsColor ? $color : '';
81+
$string = preg_replace($pattern, $color . '$1' . $reset, $string);
82+
}
83+
return $string;
84+
}
85+
86+
/**
87+
* @param string $string
88+
* @param bool $colorize Whether or not to colorize the string
89+
* @param resource $resource Defaults to STDOUT
90+
* @return void
91+
*/
92+
public function write($string, $colorize = true, $resource = STDOUT)
93+
{
94+
if ($colorize) {
95+
$string = $this->colorize($string);
96+
}
97+
98+
$string = $this->formatNewlines($string);
99+
100+
fwrite($resource, $string);
101+
}
102+
103+
/**
104+
* @param string $string
105+
* @param bool $colorize Whether or not to colorize the line
106+
* @param resource $resource Defaults to STDOUT
107+
* @return void
108+
*/
109+
public function writeLine($string, $colorize = true, $resource = STDOUT)
110+
{
111+
$this->write($string . $this->eol, $colorize, $resource);
112+
}
113+
114+
/**
115+
* Emit an error message.
116+
*
117+
* Wraps the message in `<error></error>`, and passes it to `writeLine()`,
118+
* using STDERR as the resource; emits an additional empty line when done,
119+
* also to STDERR.
120+
*
121+
* @param string $message
122+
* @return void
123+
*/
124+
public function writeErrorMessage($message)
125+
{
126+
$this->writeLine(sprintf('<error>%s</error>', $message), true, $this->stderr);
127+
$this->writeLine('', false, $this->stderr);
128+
}
129+
130+
/**
131+
* @param resource $resource
132+
* @return bool
133+
*/
134+
private function detectColorCapabilities($resource = STDOUT)
135+
{
136+
if ('\\' === DIRECTORY_SEPARATOR) {
137+
// Windows
138+
return false !== getenv('ANSICON')
139+
|| 'ON' === getenv('ConEmuANSI')
140+
|| 'xterm' === getenv('TERM');
141+
}
142+
143+
return function_exists('posix_isatty') && posix_isatty($resource);
144+
}
145+
146+
/**
147+
* Ensure newlines are appropriate for the current terminal.
148+
*
149+
* @param string
150+
* @return string
151+
*/
152+
private function formatNewlines($string)
153+
{
154+
$string = str_replace($this->eol, "\0PHP_EOL\0", $string);
155+
$string = preg_replace("/(\r\n|\n|\r)/", $this->eol, $string);
156+
return str_replace("\0PHP_EOL\0", $this->eol, $string);
157+
}
158+
}

0 commit comments

Comments
 (0)