Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
- Remove middleware reference from Gitea Traefik labels (caused routing issues) - Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s) - Add explicit service reference in Traefik labels - Fix intermittent 504 timeouts by improving PostgreSQL connection handling Fixes Gitea unreachability via git.michaelschiemer.de
241 lines
6.0 KiB
PHP
241 lines
6.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\Display\Components\Console;
|
|
|
|
use App\Framework\Console\ConsoleColor;
|
|
use App\Framework\Console\ConsoleFormat;
|
|
use App\Framework\Console\ConsoleStyle;
|
|
use App\Framework\Display\Components\DisplayComponentInterface;
|
|
use App\Framework\Display\ValueObjects\ArrayStructure;
|
|
use App\Framework\Display\ValueObjects\OutputFormat;
|
|
|
|
/**
|
|
* Rendert eine Tabelle in der Konsole.
|
|
*/
|
|
final class Table implements DisplayComponentInterface
|
|
{
|
|
private array $headers = [];
|
|
|
|
private array $rows = [];
|
|
|
|
private array $columnWidths = [];
|
|
|
|
private int $padding = 1;
|
|
|
|
public function __construct(
|
|
private ?ConsoleStyle $headerStyle = null,
|
|
private ?ConsoleStyle $rowStyle = null,
|
|
private ?ConsoleStyle $borderStyle = null,
|
|
private readonly bool $showBorders = true
|
|
) {
|
|
$this->headerStyle ??= ConsoleStyle::create(color: ConsoleColor::BRIGHT_WHITE, format: ConsoleFormat::BOLD);
|
|
$this->rowStyle ??= ConsoleStyle::create();
|
|
$this->borderStyle ??= ConsoleStyle::create(color: ConsoleColor::GRAY);
|
|
}
|
|
|
|
/**
|
|
* Setzt die Spaltenüberschriften der Tabelle.
|
|
*/
|
|
public function setHeaders(array $headers): self
|
|
{
|
|
$this->headers = $headers;
|
|
$this->calculateColumnWidths();
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Fügt eine Zeile zur Tabelle hinzu.
|
|
*/
|
|
public function addRow(array $row): self
|
|
{
|
|
$this->rows[] = $row;
|
|
$this->calculateColumnWidths();
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Setzt alle Zeilen der Tabelle.
|
|
*/
|
|
public function setRows(array $rows): self
|
|
{
|
|
$this->rows = $rows;
|
|
$this->calculateColumnWidths();
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Setzt den Innenabstand der Zellen.
|
|
*/
|
|
public function setPadding(int $padding): self
|
|
{
|
|
$this->padding = max(0, $padding);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Rendert die Tabelle und gibt den Text zurück.
|
|
*/
|
|
public function render(): string
|
|
{
|
|
if (empty($this->headers) && empty($this->rows)) {
|
|
return '';
|
|
}
|
|
|
|
$output = '';
|
|
|
|
if ($this->showBorders) {
|
|
$output .= $this->renderBorder('top') . "\n";
|
|
}
|
|
|
|
// Header
|
|
if (! empty($this->headers)) {
|
|
$output .= $this->renderRow($this->headers, $this->headerStyle) . "\n";
|
|
|
|
if ($this->showBorders) {
|
|
$output .= $this->renderBorder('middle') . "\n";
|
|
}
|
|
}
|
|
|
|
// Zeilen
|
|
foreach ($this->rows as $index => $row) {
|
|
$output .= $this->renderRow($row, $this->rowStyle) . "\n";
|
|
}
|
|
|
|
if ($this->showBorders) {
|
|
$output .= $this->renderBorder('bottom') . "\n";
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Rendert eine Zeile der Tabelle.
|
|
*/
|
|
private function renderRow(array $cells, ConsoleStyle $style): string
|
|
{
|
|
$output = '';
|
|
|
|
if ($this->showBorders) {
|
|
$output .= $this->borderStyle->apply('│');
|
|
}
|
|
|
|
foreach ($cells as $index => $cell) {
|
|
$width = $this->columnWidths[$index] ?? 10;
|
|
$cellText = (string)$cell;
|
|
|
|
// Linksbündige Ausrichtung mit exakter Breite
|
|
$paddedCell = str_pad($cellText, $width, ' ', STR_PAD_RIGHT);
|
|
|
|
// Padding hinzufügen
|
|
$padding = str_repeat(' ', $this->padding);
|
|
$finalCell = $padding . $paddedCell . $padding;
|
|
|
|
$output .= $style->apply($finalCell);
|
|
|
|
if ($this->showBorders) {
|
|
$output .= $this->borderStyle->apply('│');
|
|
}
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Rendert eine Trennlinie der Tabelle.
|
|
*/
|
|
private function renderBorder(string $type): string
|
|
{
|
|
$left = match($type) {
|
|
'top' => '┌',
|
|
'middle' => '├',
|
|
'row' => '├',
|
|
'bottom' => '└',
|
|
default => '│'
|
|
};
|
|
|
|
$right = match($type) {
|
|
'top' => '┐',
|
|
'middle' => '┤',
|
|
'row' => '┤',
|
|
'bottom' => '┘',
|
|
default => '│'
|
|
};
|
|
|
|
$horizontal = '─';
|
|
|
|
$junction = match($type) {
|
|
'top' => '┬',
|
|
'middle' => '┼',
|
|
'row' => '┼',
|
|
'bottom' => '┴',
|
|
default => '│'
|
|
};
|
|
|
|
$border = $left;
|
|
|
|
foreach ($this->columnWidths as $index => $width) {
|
|
$cellWidth = $width + ($this->padding * 2);
|
|
$border .= str_repeat($horizontal, $cellWidth);
|
|
|
|
if ($index < count($this->columnWidths) - 1) {
|
|
$border .= $junction;
|
|
}
|
|
}
|
|
|
|
$border .= $right;
|
|
|
|
return $this->borderStyle->apply($border);
|
|
}
|
|
|
|
/**
|
|
* Berechnet die Breite jeder Spalte basierend auf dem Inhalt.
|
|
*/
|
|
private function calculateColumnWidths(): void
|
|
{
|
|
$this->columnWidths = [];
|
|
|
|
// Header-Breiten
|
|
foreach ($this->headers as $index => $header) {
|
|
$this->columnWidths[$index] = mb_strlen((string)$header);
|
|
}
|
|
|
|
// Zeilen-Breiten
|
|
foreach ($this->rows as $row) {
|
|
foreach ($row as $index => $cell) {
|
|
$length = mb_strlen((string)$cell);
|
|
$this->columnWidths[$index] = max($this->columnWidths[$index] ?? 0, $length);
|
|
}
|
|
}
|
|
}
|
|
|
|
public function getOutputFormat(): OutputFormat
|
|
{
|
|
return OutputFormat::CONSOLE;
|
|
}
|
|
|
|
/**
|
|
* Build table from Display ArrayStructure
|
|
*/
|
|
public function fromArrayStructure(ArrayStructure $structure): self
|
|
{
|
|
$headers = $structure->isAssociative ? ['Key', 'Value'] : ['Index', 'Value'];
|
|
$this->setHeaders($headers);
|
|
|
|
$rows = [];
|
|
foreach ($structure->items as $key => $value) {
|
|
$valueStr = is_scalar($value) ? (string) $value : get_debug_type($value);
|
|
$rows[] = [(string) $key, $valueStr];
|
|
}
|
|
$this->setRows($rows);
|
|
|
|
return $this;
|
|
}
|
|
}
|
|
|