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

new feature: ConsoleHelper #63

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions doc/book/console-helper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Console Helper

Writing one-off scripts or vendor binaries for a package is often problematic:

- You need to parse arguments manually.
- You need to send output to the console in a meaningful fashion:
- Using `STDOUT` for meaningful, expected output
- Using `STDERR` for error messages
- Ensuring any line breaks are converted to `PHP_EOL`
- Optionally, using console colors to provide context, which means:
- Detecting whether or not the console supports colors in the first place
- Providing appropriate escape sequences to produce color

`Zend\Stdlib\ConsoleHelper` helps to address the second major bullet point and
all beneath it in a minimal fashion.

## Usage

Typical usage is to instantiate a `ConsoleHelper`, and call one of its methods:

```php
use Zend\Stdlib\ConsoleHelper;

$helper = new ConsoleHelper();
$helper->writeLine('This is output');
```

You can optionally pass a PHP stream resource to the constructor, which will be
used to determine whether or not color support is available:

```php
$helper = new ConsoleHelper($stream);
```

By default, it assumes `STDOUT`, and tests against that.

## Available methods

`ConsoleHelper` provides the following methods.

### colorize

- `colorize(string $string) : string`

`colorize()` accepts a formatted string, and will then apply ANSI color
sequences to them, if color support is detected.

The following sequences are currently supported:

- `<info>...</info>` will apply a green color sequence around the provided text.
- `<error>...</error>` will apply a red color sequence around the provided text.

You may mix multiple sequences within the same stream.

### write

- `write(string $string, bool $colorize = true, resource $stream = STDOUT) : void`

Emits the provided `$string` to the provided `$stream` (which defaults to
`STDOUT` if not provided). Any EOL sequences are convered to `PHP_EOL`. If
`$colorize` is `true`, the string is first passed to `colorize()` as well.

### writeline

- `writeLine(string $string, bool $colorize = true, resource $stream = STDOUT) : void`

Same as `write()`, except it also appends a `PHP_EOL` sequence to the `$string`.

### writeErrorMessage

- `writeErrorMessage(string $message)`

Wraps `$message` in an `<error></error>` sequence, and passes it to
`writeLine()`, using `STDERR` as the `$stream`.

## Example

Below is an example class that accepts an argument list, and determines how and
what to emit.

```php
namespace Foo;

use Zend\Stdlib\ConsoleHelper;

class HelloWorld
{
private $helper;

public function __construct(ConsoleHelper $helper = null)
{
$this->helper = $helper ?: new ConsoleHelper();
}

public function __invoke(array $args)
{
if (! count($args)) {
$this->helper->writeErrorMessage('Missing arguments!');
return;
}

if (count($args) > 1) {
$this->helper->writeErrorMessage('Too many arguments!');
return;
}

$target = array_shift($args);

$this->helper->writeLine(sprintf(
'<info>Hello</info> %s',
$target
));
}
}
```

## When to upgrade

`ConsoleHelper` is deliberately simple, and assumes that your primary need for
console tooling is for output considerations.

If you need to parse complex argument strings, we recommend using
[zend-console](https://docs.zendframework.com/zend-console/)/[zf-console](https://github.com/zfcampus/zf-console)
or [symfony/console](http://symfony.com/doc/current/components/console.html),
as these packages provide those capabilities, as well as far more colorization
and console feature detection facilities.
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ docs_dir: doc/book
site_dir: doc/html
pages:
- index.md
- Reference:
- "Console Helper": console-helper.md
- Migration: migration.md
site_name: zend-stdlib
site_description: Zend\Stdlib
Expand Down
158 changes: 158 additions & 0 deletions src/ConsoleHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
<?php
/**
* @link http://github.com/zendframework/zend-stdlib for the canonical source repository
* @copyright Copyright (c) 2016 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

namespace Zend\Stdlib;

/**
* Utilities for console tooling.
*
* Provides the following facilities:
*
* - Colorize strings using markup (e.g., `<info>message</info>`,
* `<error>message</error>`)
* - Write output to a specified stream, optionally with colorization.
* - Write a line of output to a specified stream, optionally with
* colorization, using the system EOL sequence..
* - Write an error message to STDERR.
*
* Colorization will only occur when expected sequences are discovered, and
* then, only if the console terminal allows it.
*
* Essentially, provides the bare minimum to allow you to provide messages to
* the current console.
*/
class ConsoleHelper
{
const COLOR_GREEN = "\033[32m";
const COLOR_RED = "\033[31m";
const COLOR_RESET = "\033[0m";

const HIGHLIGHT_INFO = 'info';
const HIGHLIGHT_ERROR = 'error';

private $highlightMap = [
self::HIGHLIGHT_INFO => self::COLOR_GREEN,
self::HIGHLIGHT_ERROR => self::COLOR_RED,
];

/**
* @var string Exists only for testing.
*/
private $eol = PHP_EOL;

/**
* @var resource Exists only for testing.
*/
private $stderr = STDERR;

/**
* @var bool
*/
private $supportsColor;

/**
* @param resource $resource
*/
public function __construct($resource = STDOUT)
{
$this->supportsColor = $this->detectColorCapabilities($resource);
}

/**
* Colorize a string for use with the terminal.
*
* Takes strings formatted as `<key>string</key>` and formats them per the
* $highlightMap; if color support is disabled, simply removes the formatting
* tags.
*
* @param string $string
* @return string
*/
public function colorize($string)
{
$reset = $this->supportsColor ? self::COLOR_RESET : '';
foreach ($this->highlightMap as $key => $color) {
$pattern = sprintf('#<%s>(.*?)</%s>#s', $key, $key);
$color = $this->supportsColor ? $color : '';
$string = preg_replace($pattern, $color . '$1' . $reset, $string);
}
return $string;
}

/**
* @param string $string
* @param bool $colorize Whether or not to colorize the string
* @param resource $resource Defaults to STDOUT
* @return void
*/
public function write($string, $colorize = true, $resource = STDOUT)
{
if ($colorize) {
$string = $this->colorize($string);
}

$string = $this->formatNewlines($string);

fwrite($resource, $string);
}

/**
* @param string $string
* @param bool $colorize Whether or not to colorize the line
* @param resource $resource Defaults to STDOUT
* @return void
*/
public function writeLine($string, $colorize = true, $resource = STDOUT)
{
$this->write($string . $this->eol, $colorize, $resource);
}

/**
* Emit an error message.
*
* Wraps the message in `<error></error>`, and passes it to `writeLine()`,
* using STDERR as the resource; emits an additional empty line when done,
* also to STDERR.
*
* @param string $message
* @return void
*/
public function writeErrorMessage($message)
{
$this->writeLine(sprintf('<error>%s</error>', $message), true, $this->stderr);
$this->writeLine('', false, $this->stderr);
}

/**
* @param resource $resource
* @return bool
*/
private function detectColorCapabilities($resource = STDOUT)
{
if ('\\' === DIRECTORY_SEPARATOR) {
// Windows
return false !== getenv('ANSICON')
|| 'ON' === getenv('ConEmuANSI')
|| 'xterm' === getenv('TERM');
}

return function_exists('posix_isatty') && posix_isatty($resource);
}

/**
* Ensure newlines are appropriate for the current terminal.
*
* @param string
* @return string
*/
private function formatNewlines($string)
{
$string = str_replace($this->eol, "\0PHP_EOL\0", $string);
$string = preg_replace("/(\r\n|\n|\r)/", $this->eol, $string);
return str_replace("\0PHP_EOL\0", $this->eol, $string);
}
}
Loading