ConsoleOutput::format()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
/**
4
 * League.Period (https://period.thephpleague.com)
5
 *
6
 * (c) Ignace Nyamagana Butera <[email protected]>
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
declare(strict_types=1);
13
14
namespace League\Period\Chart;
15
16
use function array_keys;
17
use function chr;
18
use function fflush;
19
use function fwrite;
20
use function implode;
21
use function preg_replace;
22
use function preg_replace_callback;
23
use function stripos;
24
use function strtolower;
25
use const PHP_EOL;
26
use const PHP_OS;
27
28
final class ConsoleOutput implements Output
29
{
30
    private const REGEXP_POSIX_PLACEHOLDER = '/(\s+)/msi';
31
32
    private const POSIX_COLOR_CODES = [
33
        self::COLOR_DEFAULT => '0',
34
        self::COLOR_BLACK   => '30',
35
        self::COLOR_RED     => '31',
36
        self::COLOR_GREEN   => '32',
37
        self::COLOR_YELLOW  => '33',
38
        self::COLOR_BLUE    => '34',
39
        self::COLOR_MAGENTA => '35',
40
        self::COLOR_CYAN    => '36',
41
        self::COLOR_WHITE   => '37',
42
    ];
43
44
    /**
45
     * @var callable
46
     */
47
    private static $formatter;
48
49
    /**
50
     * @var string
51
     */
52
    private static $regexp;
53
54
    /**
55
     * @var resource
56
     */
57
    private $stream;
58
59
    /**
60
     * Stdout constructor.
61
     *
62
     * @param resource|mixed $resource
63
     */
64 315
    public function __construct($resource)
65
    {
66 315
        if (!is_resource($resource)) {
67 3
            throw new \TypeError(sprintf('Argument passed must be a stream resource, %s given', gettype($resource)));
68
        }
69
70 312
        if ('stream' !== ($type = get_resource_type($resource))) {
71 3
            throw new \TypeError(sprintf('Argument passed must be a stream resource, %s resource given', $type));
72
        }
73
74 309
        $this->stream = $resource;
75 309
    }
76
77
    /**
78
     * {@inheritDoc}
79
     */
80 12
    public function writeln(string $message = '', string $color = self::COLOR_DEFAULT): void
81
    {
82 12
        $line = $this->format($this->colorize($message, $color)).PHP_EOL;
83 12
        fwrite($this->stream, $line);
84 12
        fflush($this->stream);
85 12
    }
86
87
    /**
88
     * Colorizes the given string.
89
     */
90 12
    private function colorize(string $characters, string $color): string
91
    {
92 12
        if (!isset(self::POSIX_COLOR_CODES[strtolower($color)])) {
93 3
            return $characters;
94
        }
95
96 9
        return "<<$color>>$characters<<".Output::COLOR_DEFAULT.'>>';
97
    }
98
99
    /**
100
     * Returns a formatted line.
101
     */
102 12
    private function format(string $str): string
103
    {
104 12
        self::$formatter = self::$formatter ?? $this->formatter();
105 12
        self::$regexp = self::$regexp ?? ',<<\s*((('.implode('|', array_keys(self::POSIX_COLOR_CODES)).')(\s*))+)>>,Umsi';
106
107 12
        return (string) preg_replace_callback(self::$regexp, self::$formatter, $str);
108
    }
109
110
    /**
111
     * Return a writer formatter depending on the OS.
112
     */
113 9
    private function formatter(): callable
114
    {
115 3
        if (0 !== stripos(PHP_OS, 'WIN')) {
116
            return function (array $matches): string {
117 9
                $str = (string) preg_replace(self::REGEXP_POSIX_PLACEHOLDER, ';', (string) $matches[1]);
118
119 9
                return chr(27).'['.strtr($str, self::POSIX_COLOR_CODES).'m';
120 3
            };
121
        }
122
123
        return function (array $matches): string {
124
            return (string) $matches[0];
125
        };
126
    }
127
}
128