*/ private array $nodes = []; public function __construct( private string $title = '', private ConsoleOutput $output = new ConsoleOutput(), ) { $this->nodeStyle = ConsoleStyle::create(color: ConsoleColor::BRIGHT_YELLOW, format: ConsoleFormat::BOLD); $this->leafStyle = ConsoleStyle::create(color: ConsoleColor::WHITE); $this->lineStyle = ConsoleStyle::create(color: ConsoleColor::GRAY); } /** * Setzt den Stil für Knotentitel (Verzeichnisse/Kategorien). */ public function setNodeStyle(?ConsoleStyle $style): self { $this->nodeStyle = $style; return $this; } /** * Setzt den Stil für Blätter/Endpunkte. */ public function setLeafStyle(?ConsoleStyle $style): self { $this->leafStyle = $style; return $this; } /** * Setzt den Stil für Baumlinien. */ public function setLineStyle(?ConsoleStyle $style): self { $this->lineStyle = $style; return $this; } /** * Setzt den Haupttitel des Baums. */ public function setTitle(string $title): self { $this->title = $title; return $this; } /** * Fügt einen Unterknoten (z.B. Unterverzeichnis) hinzu. */ public function addNode(string $title): self { $node = new self($title); $node->nodeStyle = $this->nodeStyle; $node->leafStyle = $this->leafStyle; $node->lineStyle = $this->lineStyle; $this->nodes[] = [ 'title' => $title, 'node' => $node, 'isLeaf' => false, ]; return $node; } /** * Fügt einen Endpunkt (z.B. Datei) hinzu. */ public function addLeaf(string $title): self { $this->nodes[] = [ 'title' => $title, 'node' => null, 'isLeaf' => true, ]; return $this; } /** * Zeigt die vollständige Baumstruktur an. */ public function display(): void { if (! empty($this->title)) { $this->output->writeLine($this->title, $this->nodeStyle); } $this->displayTree(); } /** * Rendert die Baumstruktur und gibt den Text zurück. */ public function render(): string { $output = ''; if (! empty($this->title)) { $output .= $this->nodeStyle->apply($this->title) . "\n"; } $output .= $this->renderTree(); return $output; } /** * Setzt den Präfix für die aktuelle Ebene. * (Interne Methode für rekursives Rendern) */ private function setPrefix(string $prefix, bool $isLastElement): self { $this->prefix = $prefix; $this->isLastElement = $isLastElement; return $this; } /** * Zeigt die Baumstruktur mit dem aktuellen Präfix an. * (Interne Methode für rekursives Rendern) */ private function displayTree(): void { $count = count($this->nodes); foreach ($this->nodes as $index => $item) { $isLast = ($index === $count - 1); $nodePrefix = $this->prefix . ($this->isLastElement ? ' ' : '│ '); // Baumlinien und Verbindungen $connector = $isLast ? '└── ' : '├── '; $linePrefix = $this->prefix . $connector; // Titel anzeigen $style = $item['isLeaf'] ? $this->leafStyle : $this->nodeStyle; $title = $linePrefix . $item['title']; $this->output->writeLine( $this->lineStyle->apply($linePrefix) . $style->apply($item['title']) ); // Unterelemente rekursiv anzeigen if (! $item['isLeaf'] && $item['node'] !== null) { $item['node'] ->setPrefix($nodePrefix, $isLast) ->displayTree(); } } } /** * Rendert die Baumstruktur mit dem aktuellen Präfix und gibt den Text zurück. * (Interne Methode für rekursives Rendern) */ private function renderTree(): string { $output = ''; $count = count($this->nodes); foreach ($this->nodes as $index => $item) { $isLast = ($index === $count - 1); $nodePrefix = $this->prefix . ($this->isLastElement ? ' ' : '│ '); // Baumlinien und Verbindungen $connector = $isLast ? '└── ' : '├── '; $linePrefix = $this->prefix . $connector; // Titel formatieren $style = $item['isLeaf'] ? $this->leafStyle : $this->nodeStyle; $title = $item['title']; $output .= $this->lineStyle->apply($linePrefix) . $style->apply($title) . "\n"; // Unterelemente rekursiv rendern if (! $item['isLeaf'] && $item['node'] !== null) { $childOutput = $item['node'] ->setPrefix($nodePrefix, $isLast) ->renderTree(); $output .= $childOutput; } } return $output; } }