Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Components;
|
||||
|
||||
use App\Framework\Console\ConsoleColor;
|
||||
use App\Framework\Console\ConsoleOutput;
|
||||
use App\Framework\Console\ConsoleOutputInterface;
|
||||
|
||||
/**
|
||||
* Klasse für interaktive Menüs in der Konsole.
|
||||
@@ -14,12 +16,16 @@ use App\Framework\Console\ConsoleOutput;
|
||||
final class InteractiveMenu
|
||||
{
|
||||
private ConsoleOutput $output;
|
||||
|
||||
private array $menuItems = [];
|
||||
|
||||
private string $title = '';
|
||||
|
||||
private int $selectedIndex = 0;
|
||||
|
||||
private bool $showNumbers = true;
|
||||
|
||||
public function __construct(ConsoleOutput $output)
|
||||
public function __construct(ConsoleOutputInterface $output)
|
||||
{
|
||||
$this->output = $output;
|
||||
}
|
||||
@@ -30,6 +36,7 @@ final class InteractiveMenu
|
||||
public function setTitle(string $title): self
|
||||
{
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -45,8 +52,9 @@ final class InteractiveMenu
|
||||
$this->menuItems[] = [
|
||||
'label' => $label,
|
||||
'action' => $action,
|
||||
'value' => $value ?? $label
|
||||
'value' => $value ?? $label,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -59,8 +67,9 @@ final class InteractiveMenu
|
||||
'label' => '---',
|
||||
'action' => null,
|
||||
'value' => null,
|
||||
'separator' => true
|
||||
'separator' => true,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -70,6 +79,7 @@ final class InteractiveMenu
|
||||
public function showNumbers(bool $show = true): self
|
||||
{
|
||||
$this->showNumbers = $show;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -79,7 +89,7 @@ final class InteractiveMenu
|
||||
public function showSimple(): mixed
|
||||
{
|
||||
// Verwende den ScreenManager anstelle des direkten clearScreen()
|
||||
$this->output->screen()->newMenu();
|
||||
$this->output->screen->newMenu();
|
||||
|
||||
if ($this->title) {
|
||||
$this->output->writeLine($this->title, ConsoleColor::BRIGHT_CYAN);
|
||||
@@ -90,6 +100,7 @@ final class InteractiveMenu
|
||||
foreach ($this->menuItems as $index => $item) {
|
||||
if (isset($item['separator'])) {
|
||||
$this->output->writeLine($item['label'], ConsoleColor::GRAY);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -104,7 +115,7 @@ final class InteractiveMenu
|
||||
|
||||
if (is_numeric($input)) {
|
||||
$selectedIndex = (int)$input - 1;
|
||||
if (isset($this->menuItems[$selectedIndex]) && !isset($this->menuItems[$selectedIndex]['separator'])) {
|
||||
if (isset($this->menuItems[$selectedIndex]) && ! isset($this->menuItems[$selectedIndex]['separator'])) {
|
||||
$item = $this->menuItems[$selectedIndex];
|
||||
|
||||
if ($item['action']) {
|
||||
@@ -116,6 +127,7 @@ final class InteractiveMenu
|
||||
}
|
||||
|
||||
$this->output->writeError('Ungültige Auswahl!');
|
||||
|
||||
return $this->showSimple();
|
||||
}
|
||||
|
||||
@@ -124,7 +136,7 @@ final class InteractiveMenu
|
||||
*/
|
||||
public function showInteractive(): mixed
|
||||
{
|
||||
$this->output->screen()->setInteractiveMode();
|
||||
$this->output->screen->setInteractiveMode();
|
||||
|
||||
// Terminal in Raw-Modus setzen für Tastatur-Input
|
||||
$this->setRawMode(true);
|
||||
@@ -137,9 +149,11 @@ final class InteractiveMenu
|
||||
switch ($key) {
|
||||
case "\033[A": // Pfeil hoch
|
||||
$this->moveUp();
|
||||
|
||||
break;
|
||||
case "\033[B": // Pfeil runter
|
||||
$this->moveDown();
|
||||
|
||||
break;
|
||||
case "\n": // Enter
|
||||
case "\r":
|
||||
@@ -162,7 +176,7 @@ final class InteractiveMenu
|
||||
private function renderMenu(): void
|
||||
{
|
||||
// Verwende den ScreenManager anstelle des direkten clearScreen()
|
||||
$this->output->screen()->newMenu();
|
||||
$this->output->screen->newMenu();
|
||||
|
||||
if ($this->title) {
|
||||
$this->output->writeLine($this->title, ConsoleColor::BRIGHT_CYAN);
|
||||
@@ -173,6 +187,7 @@ final class InteractiveMenu
|
||||
foreach ($this->menuItems as $index => $item) {
|
||||
if (isset($item['separator'])) {
|
||||
$this->output->writeLine($item['label'], ConsoleColor::GRAY);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -229,6 +244,11 @@ final class InteractiveMenu
|
||||
{
|
||||
$key = fgetc(STDIN);
|
||||
|
||||
// Handle Docker/non-interactive environment
|
||||
if ($key === false) {
|
||||
return 'q'; // Auto-quit in non-interactive mode
|
||||
}
|
||||
|
||||
// Behandle Escape-Sequenzen
|
||||
if ($key === "\033") {
|
||||
$key .= fgetc(STDIN);
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Components;
|
||||
|
||||
use App\Framework\Console\ConsoleStyle;
|
||||
use App\Framework\Console\ConsoleColor;
|
||||
use App\Framework\Console\ConsoleFormat;
|
||||
use App\Framework\Console\ConsoleStyle;
|
||||
|
||||
/**
|
||||
* Rendert eine Tabelle in der Konsole.
|
||||
@@ -13,8 +14,11 @@ use App\Framework\Console\ConsoleFormat;
|
||||
final class Table
|
||||
{
|
||||
private array $headers = [];
|
||||
|
||||
private array $rows = [];
|
||||
|
||||
private array $columnWidths = [];
|
||||
|
||||
private int $padding = 1;
|
||||
|
||||
public function __construct(
|
||||
@@ -35,6 +39,7 @@ final class Table
|
||||
{
|
||||
$this->headers = $headers;
|
||||
$this->calculateColumnWidths();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -45,6 +50,7 @@ final class Table
|
||||
{
|
||||
$this->rows[] = $row;
|
||||
$this->calculateColumnWidths();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -55,6 +61,7 @@ final class Table
|
||||
{
|
||||
$this->rows = $rows;
|
||||
$this->calculateColumnWidths();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -64,6 +71,7 @@ final class Table
|
||||
public function setPadding(int $padding): self
|
||||
{
|
||||
$this->padding = max(0, $padding);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -83,7 +91,7 @@ final class Table
|
||||
}
|
||||
|
||||
// Header
|
||||
if (!empty($this->headers)) {
|
||||
if (! empty($this->headers)) {
|
||||
$output .= $this->renderRow($this->headers, $this->headerStyle) . "\n";
|
||||
|
||||
if ($this->showBorders) {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Components;
|
||||
|
||||
use App\Framework\Console\ConsoleStyle;
|
||||
use App\Framework\Console\ConsoleColor;
|
||||
use App\Framework\Console\ConsoleFormat;
|
||||
use App\Framework\Console\ConsoleStyle;
|
||||
|
||||
/**
|
||||
* Rendert eine Textbox in der Konsole.
|
||||
@@ -19,7 +19,8 @@ final readonly class TextBox
|
||||
private ?ConsoleStyle $borderStyle = null,
|
||||
private ?ConsoleStyle $contentStyle = null,
|
||||
private ?string $title = null
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
@@ -104,7 +105,7 @@ final readonly class TextBox
|
||||
if (mb_strlen($testLine) <= $width) {
|
||||
$currentLine = $testLine;
|
||||
} else {
|
||||
if (!empty($currentLine)) {
|
||||
if (! empty($currentLine)) {
|
||||
$lines[] = $currentLine;
|
||||
$currentLine = $word;
|
||||
} else {
|
||||
@@ -115,7 +116,7 @@ final readonly class TextBox
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($currentLine)) {
|
||||
if (! empty($currentLine)) {
|
||||
$lines[] = $currentLine;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Components;
|
||||
|
||||
use App\Framework\Console\ConsoleStyle;
|
||||
use App\Framework\Console\ConsoleColor;
|
||||
use App\Framework\Console\ConsoleFormat;
|
||||
use App\Framework\Console\ConsoleOutput;
|
||||
use App\Framework\Console\ConsoleStyle;
|
||||
|
||||
/**
|
||||
* TreeHelper zum Anzeigen hierarchischer Baumstrukturen in der Konsole.
|
||||
@@ -15,9 +16,13 @@ use App\Framework\Console\ConsoleOutput;
|
||||
final class TreeHelper
|
||||
{
|
||||
private string $prefix = '';
|
||||
|
||||
private bool $isLastElement = true;
|
||||
|
||||
private ?ConsoleStyle $nodeStyle = null;
|
||||
|
||||
private ?ConsoleStyle $leafStyle = null;
|
||||
|
||||
private ?ConsoleStyle $lineStyle = null;
|
||||
|
||||
/**
|
||||
@@ -40,6 +45,7 @@ final class TreeHelper
|
||||
public function setNodeStyle(?ConsoleStyle $style): self
|
||||
{
|
||||
$this->nodeStyle = $style;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -49,6 +55,7 @@ final class TreeHelper
|
||||
public function setLeafStyle(?ConsoleStyle $style): self
|
||||
{
|
||||
$this->leafStyle = $style;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -58,6 +65,7 @@ final class TreeHelper
|
||||
public function setLineStyle(?ConsoleStyle $style): self
|
||||
{
|
||||
$this->lineStyle = $style;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -67,6 +75,7 @@ final class TreeHelper
|
||||
public function setTitle(string $title): self
|
||||
{
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -83,7 +92,7 @@ final class TreeHelper
|
||||
$this->nodes[] = [
|
||||
'title' => $title,
|
||||
'node' => $node,
|
||||
'isLeaf' => false
|
||||
'isLeaf' => false,
|
||||
];
|
||||
|
||||
return $node;
|
||||
@@ -97,7 +106,7 @@ final class TreeHelper
|
||||
$this->nodes[] = [
|
||||
'title' => $title,
|
||||
'node' => null,
|
||||
'isLeaf' => true
|
||||
'isLeaf' => true,
|
||||
];
|
||||
|
||||
return $this;
|
||||
@@ -108,7 +117,7 @@ final class TreeHelper
|
||||
*/
|
||||
public function display(): void
|
||||
{
|
||||
if (!empty($this->title)) {
|
||||
if (! empty($this->title)) {
|
||||
$this->output->writeLine($this->title, $this->nodeStyle);
|
||||
}
|
||||
|
||||
@@ -122,7 +131,7 @@ final class TreeHelper
|
||||
{
|
||||
$output = '';
|
||||
|
||||
if (!empty($this->title)) {
|
||||
if (! empty($this->title)) {
|
||||
$output .= $this->nodeStyle->apply($this->title) . "\n";
|
||||
}
|
||||
|
||||
@@ -139,6 +148,7 @@ final class TreeHelper
|
||||
{
|
||||
$this->prefix = $prefix;
|
||||
$this->isLastElement = $isLastElement;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -168,7 +178,7 @@ final class TreeHelper
|
||||
);
|
||||
|
||||
// Unterelemente rekursiv anzeigen
|
||||
if (!$item['isLeaf'] && $item['node'] !== null) {
|
||||
if (! $item['isLeaf'] && $item['node'] !== null) {
|
||||
$item['node']
|
||||
->setPrefix($nodePrefix, $isLast)
|
||||
->displayTree();
|
||||
@@ -201,7 +211,7 @@ final class TreeHelper
|
||||
$style->apply($title) . "\n";
|
||||
|
||||
// Unterelemente rekursiv rendern
|
||||
if (!$item['isLeaf'] && $item['node'] !== null) {
|
||||
if (! $item['isLeaf'] && $item['node'] !== null) {
|
||||
$childOutput = $item['node']
|
||||
->setPrefix($nodePrefix, $isLast)
|
||||
->renderTree();
|
||||
|
||||
14
src/Framework/Console/Console.php
Normal file
14
src/Framework/Console/Console.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console;
|
||||
|
||||
final readonly class Console
|
||||
{
|
||||
public function __construct(
|
||||
public ConsoleInputInterface $input,
|
||||
public ConsoleOutputInterface $output,
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console;
|
||||
@@ -6,7 +7,8 @@ namespace App\Framework\Console;
|
||||
use App\Framework\Console\Components\InteractiveMenu;
|
||||
use App\Framework\Console\Exceptions\CommandNotFoundException;
|
||||
use App\Framework\DI\Container;
|
||||
use App\Framework\Discovery\Results\DiscoveryResults;
|
||||
use App\Framework\Discovery\Results\DiscoveryRegistry;
|
||||
use App\Framework\Discovery\ValueObjects\DiscoveredAttribute;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use Throwable;
|
||||
@@ -14,6 +16,7 @@ use Throwable;
|
||||
final class ConsoleApplication
|
||||
{
|
||||
private array $commands = [];
|
||||
|
||||
private ConsoleOutputInterface $output;
|
||||
|
||||
public function __construct(
|
||||
@@ -21,22 +24,33 @@ final class ConsoleApplication
|
||||
private readonly string $scriptName = 'console',
|
||||
private readonly string $title = 'Console Application',
|
||||
?ConsoleOutputInterface $output = null,
|
||||
|
||||
) {
|
||||
$this->output = $output ?? new ConsoleOutput();
|
||||
|
||||
// Setze den Fenstertitel
|
||||
$this->output->writeWindowTitle($this->title);
|
||||
|
||||
$results = $this->container->get(DiscoveryResults::class);
|
||||
$registry = $this->container->get(DiscoveryRegistry::class);
|
||||
|
||||
foreach($results->get(ConsoleCommand::class) as $command) {
|
||||
/** @var DiscoveredAttribute $discoveredAttribute */
|
||||
foreach ($registry->attributes->get(ConsoleCommand::class) as $discoveredAttribute) {
|
||||
|
||||
$this->commands[$command['attribute_data']['name']] = [
|
||||
'instance' => $this->container->get($command['class']),
|
||||
'method' => $command['method'],
|
||||
'description' => $command['attribute_data']['description'] ?? ['Keine Beschreibung verfügbar'],
|
||||
'reflection' => new ReflectionMethod($command['class'], $command['method'])
|
||||
/** @var ConsoleCommand $command */
|
||||
$command = $discoveredAttribute->createAttributeInstance();
|
||||
|
||||
// Extract attribute data and class name from Value Object
|
||||
$attributeData = $discoveredAttribute->arguments ?? [];
|
||||
$className = $discoveredAttribute->className->getFullyQualified();
|
||||
|
||||
if ($command->name === '') {
|
||||
continue; // Skip commands without proper attribute data
|
||||
}
|
||||
|
||||
$this->commands[$command->name] = [
|
||||
'instance' => $this->container->get($className),
|
||||
'method' => $discoveredAttribute->methodName?->toString() ?? '__invoke',
|
||||
'description' => $attributeData['description'] ?? 'Keine Beschreibung verfügbar',
|
||||
'reflection' => new ReflectionMethod($className, $discoveredAttribute->methodName?->toString() ?? '__invoke'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -44,7 +58,6 @@ final class ConsoleApplication
|
||||
/**
|
||||
* Registriert alle Kommandos aus einer Klasse
|
||||
*/
|
||||
|
||||
public function registerCommands(object $commandClass): void
|
||||
{
|
||||
$reflection = new ReflectionClass($commandClass);
|
||||
@@ -60,13 +73,12 @@ final class ConsoleApplication
|
||||
'instance' => $commandClass,
|
||||
'method' => $method->getName(),
|
||||
'description' => $command->description,
|
||||
'reflection' => $method
|
||||
'reflection' => $method,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Führt ein Kommando aus
|
||||
*/
|
||||
@@ -74,6 +86,7 @@ final class ConsoleApplication
|
||||
{
|
||||
if (count($argv) < 2) {
|
||||
$this->showHelp();
|
||||
|
||||
return ExitCode::SUCCESS->value;
|
||||
}
|
||||
|
||||
@@ -82,12 +95,14 @@ final class ConsoleApplication
|
||||
|
||||
if (in_array($commandName, ['help', '--help', '-h'])) {
|
||||
$this->showHelp();
|
||||
|
||||
return ExitCode::SUCCESS->value;
|
||||
}
|
||||
|
||||
if (!isset($this->commands[$commandName])) {
|
||||
if (! isset($this->commands[$commandName])) {
|
||||
$this->output->writeError("Kommando '{$commandName}' nicht gefunden.");
|
||||
$this->showHelp();
|
||||
|
||||
return ExitCode::COMMAND_NOT_FOUND->value;
|
||||
}
|
||||
|
||||
@@ -124,6 +139,7 @@ final class ConsoleApplication
|
||||
|
||||
} catch (CommandNotFoundException $e) {
|
||||
$this->output->writeError("Kommando nicht gefunden: " . $e->getMessage());
|
||||
|
||||
return ExitCode::COMMAND_NOT_FOUND;
|
||||
} catch (Throwable $e) {
|
||||
$this->output->writeError("Fehler beim Ausführen des Kommandos: " . $e->getMessage());
|
||||
@@ -149,6 +165,10 @@ final class ConsoleApplication
|
||||
$menu = new InteractiveMenu($this->output);
|
||||
$menu->setTitle("Kommandos");
|
||||
|
||||
if (empty($this->commands)) {
|
||||
// TODO Add Default Commands
|
||||
}
|
||||
|
||||
foreach ($this->commands as $name => $command) {
|
||||
|
||||
$description = $command['description'] ?: 'Keine Beschreibung verfügbar';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console;
|
||||
@@ -48,5 +49,4 @@ enum ConsoleColor: string
|
||||
{
|
||||
return "\033[{$this->value}m";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(\Attribute::TARGET_METHOD)]
|
||||
#[Attribute(Attribute::TARGET_METHOD)]
|
||||
final readonly class ConsoleCommand
|
||||
{
|
||||
public function __construct(
|
||||
public string $name,
|
||||
public string $description = ''
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console;
|
||||
|
||||
use App\Framework\Core\AttributeMapper;
|
||||
use App\Framework\Reflection\WrappedReflectionClass;
|
||||
use App\Framework\Reflection\WrappedReflectionMethod;
|
||||
|
||||
final readonly class ConsoleCommandMapper implements AttributeMapper
|
||||
{
|
||||
@@ -12,12 +15,18 @@ final readonly class ConsoleCommandMapper implements AttributeMapper
|
||||
return ConsoleCommand::class;
|
||||
}
|
||||
|
||||
public function map(object $reflectionTarget, object $attributeInstance): ?array
|
||||
public function map(WrappedReflectionClass|WrappedReflectionMethod $reflectionTarget, object $attributeInstance): ?array
|
||||
{
|
||||
if (! $reflectionTarget instanceof WrappedReflectionMethod) {
|
||||
return null; // ConsoleCommand can only be applied to methods
|
||||
}
|
||||
|
||||
return [
|
||||
'name' => $attributeInstance->name,
|
||||
'description' => $attributeInstance->description,
|
||||
'class' => $reflectionTarget->getDeclaringClass()->getName(),
|
||||
'attribute_data' => [
|
||||
'name' => $attributeInstance->name,
|
||||
'description' => $attributeInstance->description,
|
||||
],
|
||||
'class' => $reflectionTarget->getDeclaringClass(),
|
||||
'method' => $reflectionTarget->getName(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console;
|
||||
|
||||
enum ConsoleFormat: string
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console;
|
||||
@@ -10,7 +11,9 @@ use App\Framework\Console\Components\InteractiveMenu;
|
||||
final class ConsoleInput implements ConsoleInputInterface
|
||||
{
|
||||
private array $arguments;
|
||||
|
||||
private array $options = [];
|
||||
|
||||
private ?ConsoleOutputInterface $output = null;
|
||||
|
||||
public function __construct(array $arguments, ?ConsoleOutputInterface $output = null)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console;
|
||||
|
||||
interface ConsoleInputInterface
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console;
|
||||
@@ -10,7 +11,9 @@ use App\Framework\Console\Screen\ScreenManager;
|
||||
final readonly class ConsoleOutput implements ConsoleOutputInterface
|
||||
{
|
||||
public Cursor $cursor;
|
||||
|
||||
public Display $display;
|
||||
|
||||
public ScreenManager $screen;
|
||||
|
||||
public function __construct()
|
||||
@@ -20,30 +23,6 @@ final readonly class ConsoleOutput implements ConsoleOutputInterface
|
||||
$this->screen = new ScreenManager($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt den Cursor-Controller zurück.
|
||||
*/
|
||||
public function cursor(): Cursor
|
||||
{
|
||||
return $this->cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt den Display-Controller zurück.
|
||||
*/
|
||||
public function display(): Display
|
||||
{
|
||||
return $this->display;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt den ScreenManager zurück.
|
||||
*/
|
||||
public function screen(): ScreenManager
|
||||
{
|
||||
return $this->screen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schreibt Text mit optionalem Stil.
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console;
|
||||
@@ -12,7 +13,7 @@ interface ConsoleOutputInterface
|
||||
/**
|
||||
* Schreibt Text in die Konsole
|
||||
*/
|
||||
public function write(string $message, ?ConsoleColor $color = null): void;
|
||||
public function write(string $message, null|ConsoleColor|ConsoleStyle $style = null): void;
|
||||
|
||||
/**
|
||||
* Schreibt Text mit Zeilenumbruch in die Konsole
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console;
|
||||
|
||||
final readonly class ConsoleStyle
|
||||
@@ -8,7 +10,8 @@ final readonly class ConsoleStyle
|
||||
public ?ConsoleColor $color = null,
|
||||
public ?ConsoleFormat $format = null,
|
||||
public ?ConsoleColor $background = null,
|
||||
){}
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt einen Style mit den gewünschten Eigenschaften.
|
||||
@@ -40,6 +43,7 @@ final readonly class ConsoleStyle
|
||||
if (empty($codes)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return "\033[" . implode(';', $codes) . 'm';
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console;
|
||||
@@ -7,7 +8,7 @@ use App\Framework\Console\Components\InteractiveMenu;
|
||||
|
||||
final readonly class DemoCommand
|
||||
{
|
||||
#[ConsoleCommand('demo:hello', 'Zeigt eine einfache Hallo-Welt-Nachricht')]
|
||||
##[ConsoleCommand('demo:hello', 'Zeigt eine einfache Hallo-Welt-Nachricht')]
|
||||
public function hello(ConsoleInput $input, ConsoleOutput $output): int
|
||||
{
|
||||
$output->writeWindowTitle('Help Title', 2);
|
||||
@@ -23,7 +24,7 @@ final readonly class DemoCommand
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[ConsoleCommand('demo:colors', 'Zeigt alle verfügbaren Farben')]
|
||||
##[ConsoleCommand('demo:colors', 'Zeigt alle verfügbaren Farben')]
|
||||
public function colors(ConsoleInput $input, ConsoleOutput $output): int
|
||||
{
|
||||
$output->writeLine('Verfügbare Farben:', ConsoleColor::BRIGHT_WHITE);
|
||||
@@ -55,7 +56,7 @@ final readonly class DemoCommand
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[ConsoleCommand('demo:interactive', 'Interaktive Demo mit Benutzereingaben')]
|
||||
##[ConsoleCommand('demo:interactive', 'Interaktive Demo mit Benutzereingaben')]
|
||||
public function interactive(ConsoleInput $input, ConsoleOutput $output): int
|
||||
{
|
||||
$output->writeLine('Interaktive Demo', ConsoleColor::BRIGHT_CYAN);
|
||||
@@ -75,27 +76,30 @@ final readonly class DemoCommand
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[ConsoleCommand('demo:menu', 'Zeigt ein interaktives Menü')]
|
||||
##[ConsoleCommand('demo:menu', 'Zeigt ein interaktives Menü')]
|
||||
public function menu(ConsoleInput $input, ConsoleOutput $output): int
|
||||
{
|
||||
$menu = new InteractiveMenu($output);
|
||||
|
||||
$result = $menu
|
||||
->setTitle('Hauptmenü - Demo Application')
|
||||
->addItem('Benutzer verwalten', function() use ($output) {
|
||||
->addItem('Benutzer verwalten', function () use ($output) {
|
||||
return $this->userMenu($output);
|
||||
})
|
||||
->addItem('Einstellungen', function() use ($output) {
|
||||
->addItem('Einstellungen', function () use ($output) {
|
||||
$output->writeInfo('Einstellungen werden geöffnet...');
|
||||
|
||||
return 'settings';
|
||||
})
|
||||
->addSeparator()
|
||||
->addItem('Hilfe anzeigen', function() use ($output) {
|
||||
->addItem('Hilfe anzeigen', function () use ($output) {
|
||||
$output->writeInfo('Hilfe wird angezeigt...');
|
||||
|
||||
return 'help';
|
||||
})
|
||||
->addItem('Beenden', function() use ($output) {
|
||||
->addItem('Beenden', function () use ($output) {
|
||||
$output->writeSuccess('Auf Wiedersehen!');
|
||||
|
||||
return 'exit';
|
||||
})
|
||||
->showInteractive();
|
||||
@@ -107,7 +111,7 @@ final readonly class DemoCommand
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[ConsoleCommand('demo:simple-menu', 'Zeigt ein einfaches Nummern-Menü')]
|
||||
##[ConsoleCommand('demo:simple-menu', 'Zeigt ein einfaches Nummern-Menü')]
|
||||
public function simpleMenu(ConsoleInput $input, ConsoleOutput $output): int
|
||||
{
|
||||
$menu = new InteractiveMenu($output);
|
||||
@@ -120,10 +124,11 @@ final readonly class DemoCommand
|
||||
->showSimple();
|
||||
|
||||
$output->writeSuccess("Sie haben gewählt: {$result}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[ConsoleCommand('demo:wizard', 'Zeigt einen Setup-Wizard')]
|
||||
##[ConsoleCommand('demo:wizard', 'Zeigt einen Setup-Wizard')]
|
||||
public function wizard(ConsoleInput $input, ConsoleOutput $output): int
|
||||
{
|
||||
$output->writeInfo('🧙 Setup-Wizard gestartet');
|
||||
@@ -150,7 +155,7 @@ final readonly class DemoCommand
|
||||
'Logging',
|
||||
'Email-Versand',
|
||||
'API-Schnittstelle',
|
||||
'Admin-Panel'
|
||||
'Admin-Panel',
|
||||
]);
|
||||
|
||||
// Zusammenfassung
|
||||
@@ -182,12 +187,12 @@ final readonly class DemoCommand
|
||||
|
||||
return $menu
|
||||
->setTitle('Benutzer-Verwaltung')
|
||||
->addItem('Benutzer auflisten', fn() => 'list_users')
|
||||
->addItem('Neuen Benutzer erstellen', fn() => 'create_user')
|
||||
->addItem('Benutzer bearbeiten', fn() => 'edit_user')
|
||||
->addItem('Benutzer löschen', fn() => 'delete_user')
|
||||
->addItem('Benutzer auflisten', fn () => 'list_users')
|
||||
->addItem('Neuen Benutzer erstellen', fn () => 'create_user')
|
||||
->addItem('Benutzer bearbeiten', fn () => 'edit_user')
|
||||
->addItem('Benutzer löschen', fn () => 'delete_user')
|
||||
->addSeparator()
|
||||
->addItem('← Zurück zum Hauptmenü', fn() => 'back')
|
||||
->addItem('← Zurück zum Hauptmenü', fn () => 'back')
|
||||
->showInteractive() ?? 'back';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\DemoCommand;
|
||||
@@ -8,18 +9,24 @@ use App\Framework\Console\ConsoleInput;
|
||||
use App\Framework\Console\ConsoleOutput;
|
||||
use App\Framework\Console\ConsoleStyle;
|
||||
use App\Framework\Console\Screen\ScreenType;
|
||||
|
||||
use App\Framework\Core\ValueObjects\Duration;
|
||||
use App\Framework\DateTime\Timer;
|
||||
|
||||
final class ScreenDemoCommand
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Timer $timer
|
||||
) {
|
||||
}
|
||||
|
||||
#[ConsoleCommand('demo:screen', 'Zeigt die verschiedenen Screen-Management-Funktionen')]
|
||||
public function __invoke(ConsoleInput $input, ConsoleOutput $output): int
|
||||
{
|
||||
// Aktiviere interaktiven Modus
|
||||
$output->screen()->setInteractiveMode(true);
|
||||
$output->screen->setInteractiveMode(true);
|
||||
|
||||
// Zeige ein Menü
|
||||
$output->screen()->newMenu();
|
||||
$output->screen->newMenu();
|
||||
$output->writeLine('=== Screen-Management Demo ===', ConsoleStyle::success());
|
||||
$output->writeLine('');
|
||||
$output->writeLine('1. Cursor-Bewegungen');
|
||||
@@ -33,15 +40,19 @@ final class ScreenDemoCommand
|
||||
switch ($choice) {
|
||||
case '1':
|
||||
$this->demoCursor($input, $output);
|
||||
|
||||
break;
|
||||
case '2':
|
||||
$this->demoDisplay($input, $output);
|
||||
|
||||
break;
|
||||
case '3':
|
||||
$this->demoProgress($input, $output);
|
||||
|
||||
break;
|
||||
case '4':
|
||||
$this->demoTypeset($input, $output);
|
||||
|
||||
break;
|
||||
default:
|
||||
$output->writeError('Ungültige Auswahl!');
|
||||
@@ -52,37 +63,37 @@ final class ScreenDemoCommand
|
||||
|
||||
private function demoCursor(ConsoleInput $input, ConsoleOutput $output): void
|
||||
{
|
||||
$output->screen()->newScreen(ScreenType::CONTENT);
|
||||
$output->screen->new(ScreenType::CONTENT);
|
||||
$output->writeLine('=== Cursor-Bewegungs-Demo ===', ConsoleStyle::success());
|
||||
$output->writeLine('');
|
||||
|
||||
// Cursor-Bewegungen
|
||||
$output->writeLine('Der Cursor wird jetzt bewegt...');
|
||||
sleep(1);
|
||||
$this->timer->sleep(Duration::fromSeconds(1));
|
||||
|
||||
$output->cursor()->down(2)->right(5);
|
||||
$output->cursor->down(2)->right(5);
|
||||
$output->write('Hallo!', ConsoleStyle::success());
|
||||
sleep(1);
|
||||
$this->timer->sleep(Duration::fromSeconds(1));
|
||||
|
||||
$output->cursor()->down(1)->left(5);
|
||||
$output->cursor->down(1)->left(5);
|
||||
$output->write('Welt!', ConsoleStyle::info());
|
||||
sleep(1);
|
||||
$this->timer->sleep(Duration::fromSeconds(1));
|
||||
|
||||
$output->cursor()->moveTo(10, 20);
|
||||
$output->cursor->moveTo(10, 20);
|
||||
$output->write('Position 10,20', ConsoleStyle::warning());
|
||||
sleep(1);
|
||||
$this->timer->sleep(Duration::fromSeconds(1));
|
||||
|
||||
$output->cursor()->home();
|
||||
$output->cursor->home();
|
||||
$output->writeLine("\nZurück zum Anfang!", ConsoleStyle::error());
|
||||
sleep(1);
|
||||
$this->timer->sleep(Duration::fromSeconds(1));
|
||||
|
||||
$output->writeLine("\nDrücken Sie eine Taste, um fortzufahren...");
|
||||
$output->screen()->waitForInput();
|
||||
$output->screen->waitForInput();
|
||||
}
|
||||
|
||||
private function demoDisplay(ConsoleInput $input, ConsoleOutput $output): void
|
||||
{
|
||||
$output->screen()->newScreen(ScreenType::CONTENT);
|
||||
$output->screen->new(ScreenType::CONTENT);
|
||||
$output->writeLine('=== Bildschirmlöschungs-Demo ===', ConsoleStyle::success());
|
||||
$output->writeLine('');
|
||||
|
||||
@@ -91,36 +102,36 @@ final class ScreenDemoCommand
|
||||
$output->writeLine("Zeile $i: Dies ist ein Test");
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
$this->timer->sleep(Duration::fromSeconds(1));
|
||||
$output->writeLine("\nLösche in 3 Sekunden den Bildschirm...");
|
||||
sleep(3);
|
||||
$this->timer->sleep(Duration::fromSeconds(3));
|
||||
|
||||
// Bildschirm löschen
|
||||
$output->display()->clear();
|
||||
$output->display->clear();
|
||||
$output->writeLine('Bildschirm wurde gelöscht!');
|
||||
sleep(1);
|
||||
$this->timer->sleep(Duration::fromSeconds(1));
|
||||
|
||||
// Zeilen hinzufügen
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
$output->writeLine("Neue Zeile $i");
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
$this->timer->sleep(Duration::fromSeconds(1));
|
||||
$output->writeLine("\nLösche nur die aktuelle Zeile in 2 Sekunden...");
|
||||
sleep(2);
|
||||
$this->timer->sleep(Duration::fromSeconds(2));
|
||||
|
||||
// Zeile löschen
|
||||
$output->display()->clearLine();
|
||||
$output->display->clearLine();
|
||||
$output->writeLine('Die Zeile wurde gelöscht und durch diese ersetzt!');
|
||||
|
||||
sleep(1);
|
||||
$this->timer->sleep(Duration::fromSeconds(1));
|
||||
$output->writeLine("\nDrücken Sie eine Taste, um fortzufahren...");
|
||||
$output->screen()->waitForInput();
|
||||
$output->screen->waitForInput();
|
||||
}
|
||||
|
||||
private function demoProgress(ConsoleInput $input, ConsoleOutput $output): void
|
||||
{
|
||||
$output->screen()->newScreen(ScreenType::PROGRESS);
|
||||
$output->screen->new(ScreenType::PROGRESS);
|
||||
$output->writeLine('=== Fortschrittsanzeige-Demo ===', ConsoleStyle::success());
|
||||
$output->writeLine('');
|
||||
|
||||
@@ -131,22 +142,22 @@ final class ScreenDemoCommand
|
||||
$bar = str_repeat('█', $i) . str_repeat('░', $total - $i);
|
||||
|
||||
// Zeile löschen und neue Fortschrittsanzeige
|
||||
$output->display()->clearLine();
|
||||
$output->display->clearLine();
|
||||
$output->write("Fortschritt: [{$bar}] {$percent}%");
|
||||
|
||||
usleep(200000); // 200ms pause
|
||||
$this->timer->sleep(Duration::fromMilliseconds(200));
|
||||
}
|
||||
|
||||
$output->writeLine("\n\nFortschritt abgeschlossen!");
|
||||
sleep(1);
|
||||
$this->timer->sleep(Duration::fromSeconds(1));
|
||||
|
||||
$output->writeLine("\nDrücken Sie eine Taste, um fortzufahren...");
|
||||
$output->screen()->waitForInput();
|
||||
$output->screen->waitForInput();
|
||||
}
|
||||
|
||||
private function demoTypeset(ConsoleInput $input, ConsoleOutput $output): void
|
||||
{
|
||||
$output->screen()->newScreen(ScreenType::CONTENT);
|
||||
$output->screen->new(ScreenType::CONTENT);
|
||||
$output->writeLine('=== Typensatz-Demo ===', ConsoleStyle::success());
|
||||
$output->writeLine('');
|
||||
|
||||
@@ -157,17 +168,17 @@ final class ScreenDemoCommand
|
||||
// Typensatz-Effekt
|
||||
foreach (str_split($text) as $char) {
|
||||
$output->write($char);
|
||||
usleep(rand(50000, 150000)); // 50-150ms zufällige Pause
|
||||
$this->timer->sleep(Duration::fromMicroseconds(rand(50000, 150000)));
|
||||
}
|
||||
|
||||
$output->writeLine("\n\nTypensatz abgeschlossen!");
|
||||
sleep(1);
|
||||
$this->timer->sleep(Duration::fromSeconds(1));
|
||||
|
||||
$output->writeLine("\nDrücken Sie eine Taste, um zurückzukehren...");
|
||||
$output->screen()->waitForInput();
|
||||
$output->screen->waitForInput();
|
||||
|
||||
// Zurück zum Hauptmenü
|
||||
$output->screen()->newMenu();
|
||||
$output->screen->newMenu();
|
||||
$this->__invoke($input, $output);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Examples;
|
||||
|
||||
use App\Framework\Console\ConsoleCommand;
|
||||
use App\Framework\Console\ConsoleInput;
|
||||
use App\Framework\Console\ConsoleOutput;
|
||||
use App\Framework\Console\ProgressBar;
|
||||
use App\Framework\Core\ValueObjects\Duration;
|
||||
use App\Framework\DateTime\Timer;
|
||||
|
||||
class ProgressBarExample
|
||||
{
|
||||
#[ConsoleCommand(name: 'demo:progressbar', description: 'Zeigt eine Demonstration der Fortschrittsanzeige')]
|
||||
public function __construct(
|
||||
private readonly Timer $timer
|
||||
) {
|
||||
}
|
||||
|
||||
##[ConsoleCommand(name: 'demo:progressbar', description: 'Zeigt eine Demonstration der Fortschrittsanzeige')]
|
||||
public function showProgressBarDemo(ConsoleInput $input, ConsoleOutput $output): int
|
||||
{
|
||||
$output->writeInfo('Demonstration der Fortschrittsanzeige');
|
||||
@@ -22,7 +31,7 @@ class ProgressBarExample
|
||||
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
// Simuliere Arbeit
|
||||
usleep(200000);
|
||||
$this->timer->sleep(Duration::fromMilliseconds(200));
|
||||
$progress->advance();
|
||||
}
|
||||
|
||||
@@ -37,7 +46,7 @@ class ProgressBarExample
|
||||
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
// Simuliere Arbeit
|
||||
usleep(500000);
|
||||
$this->timer->sleep(Duration::fromMilliseconds(500));
|
||||
$progress->advance();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Examples;
|
||||
|
||||
use App\Framework\Console\ConsoleCommand;
|
||||
@@ -7,10 +9,17 @@ use App\Framework\Console\ConsoleInput;
|
||||
use App\Framework\Console\ConsoleOutput;
|
||||
use App\Framework\Console\Spinner;
|
||||
use App\Framework\Console\SpinnerStyle;
|
||||
use App\Framework\Core\ValueObjects\Duration;
|
||||
use App\Framework\DateTime\Timer;
|
||||
|
||||
class SpinnerExample
|
||||
{
|
||||
#[ConsoleCommand(name: 'demo:spinner', description: 'Zeigt eine Demonstration der Spinner-Komponente')]
|
||||
public function __construct(
|
||||
private readonly Timer $timer
|
||||
) {
|
||||
}
|
||||
|
||||
##[ConsoleCommand(name: 'demo:spinner', description: 'Zeigt eine Demonstration der Spinner-Komponente')]
|
||||
public function showSpinnerDemo(ConsoleInput $input, ConsoleOutput $output): int
|
||||
{
|
||||
$output->writeInfo('Demonstration der Spinner-Komponente');
|
||||
@@ -22,7 +31,7 @@ class SpinnerExample
|
||||
|
||||
// Simuliere Arbeit
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
usleep(100000);
|
||||
$this->timer->sleep(Duration::fromMilliseconds(100));
|
||||
$spinner->update();
|
||||
}
|
||||
|
||||
@@ -33,7 +42,7 @@ class SpinnerExample
|
||||
SpinnerStyle::DOTS,
|
||||
SpinnerStyle::LINE,
|
||||
SpinnerStyle::BOUNCE,
|
||||
SpinnerStyle::ARROW
|
||||
SpinnerStyle::ARROW,
|
||||
];
|
||||
|
||||
foreach ($styles as $style) {
|
||||
@@ -42,7 +51,7 @@ class SpinnerExample
|
||||
$spinner->start();
|
||||
|
||||
for ($i = 0; $i < 15; $i++) {
|
||||
usleep(100000);
|
||||
$this->timer->sleep(Duration::fromMilliseconds(100));
|
||||
|
||||
if ($i === 5) {
|
||||
$spinner->setMessage('Fast fertig...');
|
||||
@@ -59,7 +68,7 @@ class SpinnerExample
|
||||
$spinner->start();
|
||||
|
||||
for ($i = 0; $i < 8; $i++) {
|
||||
usleep(150000);
|
||||
$this->timer->sleep(Duration::fromMilliseconds(150));
|
||||
$spinner->update();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Examples;
|
||||
|
||||
use App\Framework\Console\Components\Table;
|
||||
use App\Framework\Console\ConsoleCommand;
|
||||
use App\Framework\Console\ConsoleColor;
|
||||
use App\Framework\Console\ConsoleCommand;
|
||||
use App\Framework\Console\ConsoleFormat;
|
||||
use App\Framework\Console\ConsoleInput;
|
||||
use App\Framework\Console\ConsoleOutput;
|
||||
@@ -13,7 +14,7 @@ use App\Framework\Console\ConsoleStyle;
|
||||
|
||||
final class TableExample
|
||||
{
|
||||
#[ConsoleCommand('demo:table', 'Zeigt eine Beispiel-Tabelle')]
|
||||
##[ConsoleCommand('demo:table', 'Zeigt eine Beispiel-Tabelle')]
|
||||
public function showTable(ConsoleInput $input, ConsoleOutput $output): int
|
||||
{
|
||||
$output->writeLine('Beispiel für die Table-Komponente', ConsoleStyle::create(
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Examples;
|
||||
|
||||
use App\Framework\Console\Components\TextBox;
|
||||
use App\Framework\Console\ConsoleCommand;
|
||||
use App\Framework\Console\ConsoleColor;
|
||||
use App\Framework\Console\ConsoleCommand;
|
||||
use App\Framework\Console\ConsoleFormat;
|
||||
use App\Framework\Console\ConsoleInput;
|
||||
use App\Framework\Console\ConsoleOutput;
|
||||
@@ -13,7 +14,7 @@ use App\Framework\Console\ConsoleStyle;
|
||||
|
||||
final class TextBoxExample
|
||||
{
|
||||
#[ConsoleCommand('demo:textbox', 'Zeigt verschiedene TextBox-Beispiele')]
|
||||
##[ConsoleCommand('demo:textbox', 'Zeigt verschiedene TextBox-Beispiele')]
|
||||
public function showTextBox(ConsoleInput $input, ConsoleOutput $output): int
|
||||
{
|
||||
$output->writeLine('Beispiele für die TextBox-Komponente', ConsoleStyle::create(
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Examples;
|
||||
|
||||
use App\Framework\Console\Components\TreeHelper;
|
||||
use App\Framework\Console\ConsoleCommand;
|
||||
use App\Framework\Console\ConsoleColor;
|
||||
use App\Framework\Console\ConsoleCommand;
|
||||
use App\Framework\Console\ConsoleFormat;
|
||||
use App\Framework\Console\ConsoleInput;
|
||||
use App\Framework\Console\ConsoleOutput;
|
||||
@@ -13,7 +14,7 @@ use App\Framework\Console\ConsoleStyle;
|
||||
|
||||
final class TreeExample
|
||||
{
|
||||
#[ConsoleCommand('demo:tree', 'Zeigt ein Beispiel für die TreeHelper-Komponente')]
|
||||
##[ConsoleCommand('demo:tree', 'Zeigt ein Beispiel für die TreeHelper-Komponente')]
|
||||
public function showTreeExample(ConsoleInput $input, ConsoleOutput $output): int
|
||||
{
|
||||
$output->writeLine('Beispiel für den TreeHelper', ConsoleStyle::create(
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Exceptions;
|
||||
|
||||
class CommandNotFoundException extends ConsoleException
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Exceptions;
|
||||
|
||||
class ConsoleException extends \Exception
|
||||
use App\Framework\Exception\FrameworkException;
|
||||
|
||||
class ConsoleException extends FrameworkException
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console;
|
||||
@@ -69,6 +70,6 @@ enum ExitCode: int
|
||||
*/
|
||||
public function isError(): bool
|
||||
{
|
||||
return !$this->isSuccess();
|
||||
return ! $this->isSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console;
|
||||
|
||||
class ProgressBar
|
||||
{
|
||||
private ConsoleOutputInterface $output;
|
||||
|
||||
private int $total;
|
||||
|
||||
private int $current = 0;
|
||||
|
||||
private int $width;
|
||||
|
||||
private float $startTime;
|
||||
|
||||
private string $format = '%bar% %percent%%';
|
||||
|
||||
private string $barChar = '=';
|
||||
|
||||
private string $emptyBarChar = '-';
|
||||
|
||||
private string $progressChar = '>';
|
||||
|
||||
private int $redrawFrequency = 1;
|
||||
|
||||
private int $writeCount = 0;
|
||||
|
||||
private bool $firstRun = true;
|
||||
|
||||
public function __construct(ConsoleOutputInterface $output, int $total = 100, int $width = 50)
|
||||
@@ -38,6 +51,7 @@ class ProgressBar
|
||||
public function setFormat(string $format): self
|
||||
{
|
||||
$this->format = $format;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -49,6 +63,7 @@ class ProgressBar
|
||||
$this->barChar = $barChar;
|
||||
$this->emptyBarChar = $emptyBarChar;
|
||||
$this->progressChar = $progressChar;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -58,6 +73,7 @@ class ProgressBar
|
||||
public function setRedrawFrequency(int $frequency): self
|
||||
{
|
||||
$this->redrawFrequency = max(1, $frequency);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -67,6 +83,7 @@ class ProgressBar
|
||||
public function advance(int $step = 1): self
|
||||
{
|
||||
$this->setCurrent($this->current + $step);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -95,6 +112,7 @@ class ProgressBar
|
||||
$this->current = 0;
|
||||
$this->firstRun = true;
|
||||
$this->display();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -118,7 +136,7 @@ class ProgressBar
|
||||
*/
|
||||
private function display(): void
|
||||
{
|
||||
if (!$this->firstRun) {
|
||||
if (! $this->firstRun) {
|
||||
// Bewege den Cursor eine Zeile nach oben
|
||||
$this->output->write("\033[1A");
|
||||
// Lösche die aktuelle Zeile
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Screen;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Screen;
|
||||
@@ -8,11 +9,12 @@ use App\Framework\Console\ConsoleOutput;
|
||||
/**
|
||||
* Verantwortlich für Cursor-Positionierung.
|
||||
*/
|
||||
final class Cursor
|
||||
final readonly class Cursor
|
||||
{
|
||||
public function __construct(
|
||||
private ConsoleOutput $output
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Bewegt den Cursor zu einer bestimmten Position.
|
||||
@@ -22,6 +24,7 @@ final class Cursor
|
||||
if ($this->output->isTerminal()) {
|
||||
$this->output->writeRaw(CursorControlCode::POSITION->format($row, $col));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -34,6 +37,7 @@ final class Cursor
|
||||
// Die Home-Position ist 1,1 (obere linke Ecke)
|
||||
$this->output->writeRaw(CursorControlCode::POSITION->format(1, 1));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -45,6 +49,7 @@ final class Cursor
|
||||
if ($this->output->isTerminal() && $lines > 0) {
|
||||
$this->output->writeRaw(CursorControlCode::UP->format($lines));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -56,6 +61,7 @@ final class Cursor
|
||||
if ($this->output->isTerminal() && $lines > 0) {
|
||||
$this->output->writeRaw(CursorControlCode::DOWN->format($lines));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -67,6 +73,7 @@ final class Cursor
|
||||
if ($this->output->isTerminal() && $columns > 0) {
|
||||
$this->output->writeRaw(CursorControlCode::LEFT->format($columns));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -78,6 +85,7 @@ final class Cursor
|
||||
if ($this->output->isTerminal() && $columns > 0) {
|
||||
$this->output->writeRaw(CursorControlCode::RIGHT->format($columns));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -89,6 +97,7 @@ final class Cursor
|
||||
if ($this->output->isTerminal()) {
|
||||
$this->output->writeRaw(CursorControlCode::HIDE->format());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -100,6 +109,7 @@ final class Cursor
|
||||
if ($this->output->isTerminal()) {
|
||||
$this->output->writeRaw(CursorControlCode::SHOW->format());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -111,6 +121,7 @@ final class Cursor
|
||||
if ($this->output->isTerminal()) {
|
||||
$this->output->writeRaw(CursorControlCode::SAVE->format());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -122,6 +133,7 @@ final class Cursor
|
||||
if ($this->output->isTerminal()) {
|
||||
$this->output->writeRaw(CursorControlCode::RESTORE->format());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Screen;
|
||||
@@ -43,6 +44,7 @@ enum CursorControlCode: string
|
||||
|
||||
// Wenn Parameter vorhanden sind, formatieren
|
||||
$paramStr = implode(';', $params);
|
||||
|
||||
return "\033[{$paramStr}{$this->value}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Screen;
|
||||
@@ -12,7 +13,8 @@ final readonly class Display
|
||||
{
|
||||
public function __construct(
|
||||
private ConsoleOutput $output
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Löscht den gesamten Bildschirm und setzt den Cursor an den Anfang.
|
||||
@@ -24,6 +26,7 @@ final readonly class Display
|
||||
$this->output->writeRaw(ScreenControlCode::CLEAR_ALL->format());
|
||||
$this->output->writeRaw(CursorControlCode::POSITION->format(1, 1));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -36,6 +39,7 @@ final readonly class Display
|
||||
$this->output->writeRaw(ScreenControlCode::CLEAR_LINE->format());
|
||||
$this->output->writeRaw("\r"); // Cursor an den Zeilenanfang
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -47,6 +51,7 @@ final readonly class Display
|
||||
if ($this->output->isTerminal()) {
|
||||
$this->output->writeRaw(ScreenControlCode::CLEAR_BELOW->format());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -58,6 +63,7 @@ final readonly class Display
|
||||
if ($this->output->isTerminal()) {
|
||||
$this->output->writeRaw(ScreenControlCode::CLEAR_ABOVE->format());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -69,6 +75,7 @@ final readonly class Display
|
||||
if ($this->output->isTerminal()) {
|
||||
$this->output->writeRaw(ScreenControlCode::CLEAR_LINE_RIGHT->format());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -80,6 +87,7 @@ final readonly class Display
|
||||
if ($this->output->isTerminal()) {
|
||||
$this->output->writeRaw(ScreenControlCode::CLEAR_LINE_LEFT->format());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -91,6 +99,7 @@ final readonly class Display
|
||||
if ($this->output->isTerminal()) {
|
||||
$this->output->writeRaw(ScreenControlCode::ALTERNATE_BUFFER->format());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -102,6 +111,7 @@ final readonly class Display
|
||||
if ($this->output->isTerminal()) {
|
||||
$this->output->writeRaw(ScreenControlCode::MAIN_BUFFER->format());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Screen;
|
||||
@@ -33,6 +34,7 @@ enum ScreenControlCode: string
|
||||
|
||||
// Wenn Parameter vorhanden sind, formatieren
|
||||
$paramStr = implode(';', $params);
|
||||
|
||||
return "\033[{$paramStr}{$this->value}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Screen;
|
||||
|
||||
use App\Framework\Console\ConsoleOutput;
|
||||
use App\Framework\Core\ValueObjects\Duration;
|
||||
use App\Framework\DateTime\Timer;
|
||||
|
||||
/**
|
||||
* Verwaltet intelligentes Bildschirm-Management.
|
||||
@@ -11,13 +14,17 @@ use App\Framework\Console\ConsoleOutput;
|
||||
final class ScreenManager
|
||||
{
|
||||
private ClearStrategy $strategy = ClearStrategy::SMART;
|
||||
|
||||
private bool $interactiveMode = false;
|
||||
|
||||
private ?ScreenType $lastScreenType = null;
|
||||
|
||||
private int $screenCount = 0;
|
||||
|
||||
public function __construct(
|
||||
private ConsoleOutput $output
|
||||
) {}
|
||||
private readonly ConsoleOutput $output
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt die Löschstrategie.
|
||||
@@ -25,6 +32,7 @@ final class ScreenManager
|
||||
public function setStrategy(ClearStrategy $strategy): self
|
||||
{
|
||||
$this->strategy = $strategy;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -34,6 +42,7 @@ final class ScreenManager
|
||||
public function setInteractiveMode(bool $interactive = true): self
|
||||
{
|
||||
$this->interactiveMode = $interactive;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -41,10 +50,10 @@ final class ScreenManager
|
||||
* Markiert den Beginn eines neuen Bildschirms.
|
||||
* Diese Methode rufst du VOR der Ausgabe auf.
|
||||
*/
|
||||
public function newScreen(ScreenType $type = ScreenType::CONTENT): self
|
||||
public function new(ScreenType $type = ScreenType::CONTENT): self
|
||||
{
|
||||
if ($this->shouldClear($type)) {
|
||||
$this->output->display()->clear();
|
||||
$this->output->display->clear();
|
||||
}
|
||||
|
||||
$this->lastScreenType = $type;
|
||||
@@ -58,37 +67,38 @@ final class ScreenManager
|
||||
*/
|
||||
public function newMenu(): self
|
||||
{
|
||||
return $this->newScreen(ScreenType::MENU);
|
||||
return $this->new(ScreenType::MENU);
|
||||
}
|
||||
|
||||
public function newDialog(): self
|
||||
{
|
||||
return $this->newScreen(ScreenType::DIALOG);
|
||||
return $this->new(ScreenType::DIALOG);
|
||||
}
|
||||
|
||||
public function newContent(): self
|
||||
{
|
||||
return $this->newScreen(ScreenType::CONTENT);
|
||||
return $this->new(ScreenType::CONTENT);
|
||||
}
|
||||
|
||||
public function newLog(): self
|
||||
{
|
||||
return $this->newScreen(ScreenType::LOG);
|
||||
return $this->new(ScreenType::LOG);
|
||||
}
|
||||
|
||||
public function newProgress(): self
|
||||
{
|
||||
return $this->newScreen(ScreenType::PROGRESS);
|
||||
return $this->new(ScreenType::PROGRESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt eine temporäre Nachricht für eine bestimmte Zeit an.
|
||||
*/
|
||||
public function temporary(string $message, int $seconds = 2): self
|
||||
public function temporary(string $message, Timer $timer, int $seconds = 2): self
|
||||
{
|
||||
$this->output->writeLine($message);
|
||||
sleep($seconds);
|
||||
$this->output->display()->clearLine();
|
||||
$timer->sleep(Duration::fromSeconds($seconds));
|
||||
$this->output->display->clearLine();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -100,6 +110,7 @@ final class ScreenManager
|
||||
if ($this->output->isTerminal()) {
|
||||
fread(STDIN, 1);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -108,7 +119,7 @@ final class ScreenManager
|
||||
*/
|
||||
private function shouldClear(ScreenType $type): bool
|
||||
{
|
||||
if (!$this->output->isTerminal()) {
|
||||
if (! $this->output->isTerminal()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console\Screen;
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console;
|
||||
|
||||
class Spinner
|
||||
{
|
||||
private ConsoleOutputInterface $output;
|
||||
|
||||
private string $message;
|
||||
|
||||
private array $frames;
|
||||
|
||||
private int $currentFrame = 0;
|
||||
|
||||
private float $startTime;
|
||||
|
||||
private bool $active = false;
|
||||
|
||||
private float $interval;
|
||||
|
||||
private int $updateCount = 0;
|
||||
|
||||
public function __construct(
|
||||
@@ -33,6 +42,7 @@ class Spinner
|
||||
$this->startTime = microtime(true);
|
||||
$this->active = true;
|
||||
$this->update();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -78,6 +88,7 @@ class Spinner
|
||||
if ($this->active) {
|
||||
$this->update();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -86,7 +97,7 @@ class Spinner
|
||||
*/
|
||||
public function update(): self
|
||||
{
|
||||
if (!$this->active) {
|
||||
if (! $this->active) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Console;
|
||||
|
||||
enum SpinnerStyle: string
|
||||
|
||||
Reference in New Issue
Block a user