'...'] public ?string $layout = null, // Optionales Layout public array $slots = [], // Benannte Slots wie ['main' => '

...

'] public ?string $controllerClass = null, public ?string $route = null, // Route name for form ID generation public ProcessingMode $processingMode = ProcessingMode::FULL, public bool $isPartial = false, // Deprecated: Use processingMode instead ?ScopeStack $scopes = null, // Stack von Scopes für verschachtelte Loops ) { // Initialize empty ScopeStack if not provided $this->scopes = $scopes ?? ScopeStack::empty(); } /** * Erstellt einen neuen RenderContext mit zusätzlichem Scope * * Der neue Scope wird am Anfang des Scope-Stacks eingefügt (höchste Priorität). * Dies ermöglicht verschachtelte Loops, bei denen innere Loop-Variablen * äußere Variablen überschreiben können. * * @param array|\App\Framework\View\ValueObjects\TemplateScope $variables * Variablen für den neuen Scope (z.B. ['item' => $item]) oder TemplateScope * @return self Neuer RenderContext mit erweitertem Scope-Stack */ public function withScope(array|\App\Framework\View\ValueObjects\TemplateScope $variables): self { return new self( template: $this->template, metaData: $this->metaData, data: $this->data, layout: $this->layout, slots: $this->slots, controllerClass: $this->controllerClass, route: $this->route, processingMode: $this->processingMode, isPartial: $this->isPartial, scopes: $this->scopes->push($variables), ); } /** * Löst eine Variable aus allen verfügbaren Scopes auf * * Sucht die Variable zuerst in den Scopes (von innen nach außen), * dann in den globalen Daten. * * @param string $name Variablenname (ohne $) * @return mixed Wert der Variable oder null wenn nicht gefunden */ public function resolveVariable(string $name): mixed { // Suche in Scopes (von innen nach außen) $value = $this->scopes->resolve($name); if ($value !== null) { return $value; } // Fallback zu globalen Daten if (array_key_exists($name, $this->data)) { return $this->data[$name]; } return null; } /** * Gibt alle verfügbaren Variablen zurück (alle Scopes + globale Daten) * * Die Variablen werden gemerged, wobei innerste Scopes Priorität haben. * Dies ist nützlich für ExpressionEvaluator, der einen flachen Array erwartet. * * @return array Alle Variablen mit Scope-Priorität (innerste Scope überschreibt äußere) */ public function getAllVariables(): array { // Beginne mit globalen Daten $allVariables = $this->data; // Merge Scopes (ScopeStack handles priority: inner scopes override outer) $scopeVariables = $this->scopes->getAllVariables(); $allVariables = array_merge($allVariables, $scopeVariables); return $allVariables; } }