<?php declare(strict_types=1);
namespace Inhere\Console\Component\Formatter;
use Inhere\Console\Component\MessageFormatter;
use Inhere\Console\Console;
use Toolkit\Cli\ColorTag;
use Toolkit\Stdlib\Str;
use Toolkit\Stdlib\Str\StrBuffer;
use function array_keys;
use function array_merge;
use function array_sum;
use function ceil;
use function count;
use function is_string;
use function mb_strlen;
use function ucwords;
class Table extends MessageFormatter
{
public $data = [];
public $columns = [];
public $body;
public $title = '';
public $titleBorder = '-';
public $titleStyle = '-';
public $titleAlign = self::ALIGN_LEFT;
public static function show(array $data, string $title = 'Data Table', array $opts = []): int
{
if (!$data) {
return -2;
}
$buf = new StrBuffer();
$opts = array_merge([
'showBorder' => true,
'leftIndent' => ' ',
'titlePos' => self::POS_LEFT,
'titleStyle' => 'bold',
'headStyle' => 'comment',
'headBorderChar' => self::CHAR_EQUAL, 'bodyStyle' => '',
'rowBorderChar' => self::CHAR_HYPHEN, 'colBorderChar' => self::CHAR_VERTICAL, 'columns' => [], ], $opts);
$hasHead = false;
$rowIndex = 0;
$head = [];
$tableHead = $opts['columns'];
$leftIndent = $opts['leftIndent'];
$showBorder = $opts['showBorder'];
$rowBorderChar = $opts['rowBorderChar'];
$colBorderChar = $opts['colBorderChar'];
$info = [
'rowCount' => count($data),
'columnCount' => 0, 'columnMaxWidth' => [], 'tableWidth' => 0, ];
foreach ($data as $row) {
if ($rowIndex === 0) {
$head = $tableHead ?: array_keys($row);
$info['columnCount'] = count($row);
foreach ($head as $index => $name) {
if (is_string($name)) $hasHead = true;
}
$info['columnMaxWidth'][$index] = mb_strlen($name, 'UTF-8');
}
}
$colIndex = 0;
foreach ((array)$row as $value) {
if (isset($info['columnMaxWidth'][$colIndex])) {
$colWidth = mb_strlen($value, 'UTF-8');
if ($colWidth > $info['columnMaxWidth'][$colIndex]) {
$info['columnMaxWidth'][$colIndex] = $colWidth;
}
} else {
$info['columnMaxWidth'][$colIndex] = mb_strlen($value, 'UTF-8');
}
$colIndex++;
}
$rowIndex++;
}
$tableWidth = $info['tableWidth'] = array_sum($info['columnMaxWidth']);
$columnCount = $info['columnCount'];
if ($title) {
$tStyle = $opts['titleStyle'] ?: 'bold';
$title = ucwords(trim($title));
$titleLength = mb_strlen($title, 'UTF-8');
$indentSpace = Str::pad(' ', ceil($tableWidth / 2) - ceil($titleLength / 2) + ($columnCount * 2), ' ');
$buf->write(" {$indentSpace}<$tStyle>{$title}</$tStyle>\n");
}
$border = $leftIndent . Str::pad($rowBorderChar, $tableWidth + ($columnCount * 3) + 2, $rowBorderChar);
if ($showBorder) {
$buf->write($border . "\n");
} else {
$colBorderChar = '' }
if ($hasHead) {
$headStr = "{$leftIndent}{$colBorderChar} ";
foreach ($head as $index => $name) {
$colMaxWidth = $info['columnMaxWidth'][$index];
$name = Str::pad($name, $colMaxWidth, ' ');
$name = ColorTag::wrap($name, $opts['headStyle']);
$headStr .= " {$name} {$colBorderChar}";
}
$buf->write($headStr . "\n");
if ($headBorderChar = $opts['headBorderChar']) {
$headBorder = $leftIndent . Str::pad(
$headBorderChar,
$tableWidth + ($columnCount * 3) + 2,
$headBorderChar
);
$buf->write($headBorder . "\n");
}
}
$rowIndex = 0;
foreach ($data as $row) {
$colIndex = 0;
$rowStr = " $colBorderChar ";
foreach ((array)$row as $value) {
$colMaxWidth = $info['columnMaxWidth'][$colIndex];
$value = Str::pad($value, $colMaxWidth, ' ');
$value = ColorTag::wrap($value, $opts['bodyStyle']);
$rowStr .= " {$value} {$colBorderChar}";
$colIndex++;
}
$buf->write($rowStr . "\n");
$rowIndex++;
}
if ($showBorder) {
$buf->write($border . "\n");
}
return Console::write($buf);
}
}