Files
michaelschiemer/docs/ERROR-RENDERER-REFACTORING-PLAN.md
Michael Schiemer 36ef2a1e2c
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
fix: Gitea Traefik routing and connection pool optimization
- 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
2025-11-09 14:46:15 +01:00

7.1 KiB

ErrorRenderer Refactoring - Unified Interface & Template Integration

Problem-Analyse

Aktuelle Probleme

  1. Interface-Hierarchie ist nicht optimal:

    • ErrorRenderer (base) → HttpErrorRenderer extends → CliErrorRenderer extends
    • Verschiedene Interfaces mit unterschiedlichen Methoden
    • Factory muss spezifische Interfaces prüfen (HttpErrorRenderer, CliErrorRenderer)
  2. HTTP Renderer verwendet kein Template System:

    • Hardcoded HTML-Strings in ResponseErrorRenderer
    • Sollte Engine und RenderContext aus Template-System verwenden
    • Template-basierte Error-Pages wären besser wartbar
  3. HttpEmitter Kontext:

    • Klarstellung: HTML-Rendering sollte nur im Middleware-Kontext passieren
    • Renderer erstellt nur HttpResponse, Emitter bleibt in Application/Middleware
    • Außerhalb Middleware (z.B. Bootstrap): Fallback auf einfaches HTML

Lösungsvorschlag

1. Unified ErrorRenderer Interface (OHNE Hierarchie)

Neue Struktur:

interface ErrorRenderer
{
    /**
     * Check if this renderer can handle the exception
     */
    public function canRender(\Throwable $exception): bool;
    
    /**
     * Render exception to appropriate output format
     * 
     * @return mixed HttpResponse for HTTP context, void for CLI context
     */
    public function render(
        \Throwable $exception,
        ?ExceptionContextProvider $contextProvider = null
    ): mixed;
}

Alle Renderer implementieren das gleiche Interface:

  • ResponseErrorRendererHttpResponse zurückgeben
  • ConsoleErrorRenderervoid (gibt direkt auf Console aus)

2. HTTP Renderer mit Template System

ResponseErrorRenderer sollte:

  • Template System (Engine, RenderContext) für HTML-Rendering verwenden
  • Error-Templates mit .view.php Endung (auto-discovered)
  • JSON-Responses direkt erstellen (bleibt gleich)
  • Template-Namen: errors/error, errors/404, errors/500

Template-Struktur (mit .view.php Endung):

resources/views/errors/
├── error.view.php           # Basis Error-Template
├── 404.view.php            # 404-spezifisches Template
├── 500.view.php            # 500-spezifisches Template
└── debug.view.php          # Debug-Informationen (nur wenn debug=true)

Wichtig: Templates werden auto-discovered über Discovery-System

3. HttpEmitter & Rendering-Kontext

Architektur:

Exception im Middleware-Stack
  → ExceptionHandlingMiddleware fängt Exception
  → ErrorKernel->createHttpResponse()
  → ResponseErrorRenderer.render() (Template-System für HTML)
  → HttpResponse zurückgegeben
  → ResponseEmitter emittet Response (in Application)

Exception außerhalb Middleware (z.B. Bootstrap)
  → GlobalExceptionHandler->handle()
  → ErrorKernel->handle() (nur Logging, kein Response)
  → Oder: Fallback HTML direkt (ohne Template-System)

Prinzip:

  • Renderer erstellt nur HttpResponse - kein direkter HttpEmitter-Aufruf
  • HTML-Rendering mit Templates nur im Middleware-Kontext
  • Außerhalb Middleware: Fallback auf einfache HTML-Strings

4. Entfernung der Interface-Hierarchie

Zu entfernen:

  • HttpErrorRenderer Interface
  • CliErrorRenderer Interface

Zu behalten/ändern:

  • ErrorRenderer Interface (einheitlich)
  • ResponseErrorRenderer → implementiert ErrorRenderer
  • ConsoleErrorRenderer → implementiert ErrorRenderer

5. Factory-Anpassung

ErrorRendererFactory:

  • Nutzt nur noch ErrorRenderer Interface
  • Keine spezifischen Interface-Prüfungen mehr nötig
  • Einfacher und konsistenter

Implementierungs-Plan

Phase 1: Interface-Vereinheitlichung

  1. ErrorRenderer Interface refactoren

    • render() Methode mit mixed Return-Type
    • canRender() bleibt gleich
  2. ResponseErrorRenderer anpassen

    • Implementiert nur noch ErrorRenderer
    • render() gibt HttpResponse zurück
    • createResponse() entfernen (wird zu render())
  3. ConsoleErrorRenderer anpassen

    • Implementiert nur noch ErrorRenderer
    • render() gibt void zurück
    • renderToConsole() entfernen (wird zu render())
  4. HttpErrorRenderer & CliErrorRenderer Interfaces löschen

Phase 2: Template System Integration

  1. Error Templates erstellen (mit .view.php Endung)

    • resources/views/errors/error.view.php - Basis Error-Template
    • resources/views/errors/404.view.php - 404 Template
    • resources/views/errors/500.view.php - 500 Template
    • resources/views/errors/debug.view.php - Debug Template (optional)
  2. ResponseErrorRenderer mit Template System

    • Engine über DI injizieren
    • RenderContext für Template-Rendering erstellen
    • HTML-Rendering über Templates (auto-discovered)
    • JSON-Responses bleiben direkt (kein Template nötig)
    • Fallback auf einfaches HTML wenn Template nicht gefunden
  3. Template-Discovery Integration

    • Templates werden automatisch über Discovery-System gefunden
    • Template-Namen: errors/error, errors/404, etc.
    • Template-Loader findet Templates automatisch

Phase 3: Factory & Integration

  1. ErrorRendererFactory vereinfachen

    • Nur noch ErrorRenderer Interface verwenden
    • Spezifische Methoden (getHttpRenderer(), getCliRenderer()) entfernen
  2. ErrorKernel anpassen

    • Nutzt einheitliches ErrorRenderer Interface
    • createHttpResponse() verwendet render() Methode
  3. Tests aktualisieren

    • Alle Renderer-Tests anpassen
    • Template-System-Tests hinzufügen

Dateien zu ändern

Zu ändern:

  • src/Framework/ExceptionHandling/ErrorRenderer.php - Interface vereinheitlichen
  • src/Framework/ExceptionHandling/Renderers/ResponseErrorRenderer.php - Template System integrieren
  • src/Framework/ExceptionHandling/Renderers/ConsoleErrorRenderer.php - Interface anpassen
  • src/Framework/ExceptionHandling/ErrorRendererFactory.php - Vereinfachen
  • src/Framework/ExceptionHandling/ErrorKernel.php - Renderer-Aufruf anpassen

Zu löschen:

  • src/Framework/ExceptionHandling/HttpErrorRenderer.php - Interface entfernen
  • src/Framework/ExceptionHandling/CliErrorRenderer.php - Interface entfernen

Neu zu erstellen:

  • resources/views/errors/error.view.php - Basis Error-Template (auto-discovered)
  • resources/views/errors/404.view.php - 404 Template
  • resources/views/errors/500.view.php - 500 Template
  • resources/views/errors/debug.view.php - Debug Template (optional)

Vorteile

Einheitliches Interface: Alle Renderer verwenden das gleiche Interface Keine Interface-Hierarchie: Einfacher und klarer Template-basierte Error-Pages: Wartbarer und konsistenter Framework-Integration: Nutzt vorhandenes Template-System Bessere Testbarkeit: Einheitliche Interface-Struktur Auto-Discovery: Templates werden automatisch gefunden

Zusammenfassung

  1. Templates haben .view.php Endung und werden auto-discovered
  2. HTML-Rendering nur im Middleware-Kontext (mit Templates)
  3. Außerhalb Middleware: Fallback auf einfaches HTML
  4. Renderer erstellt nur Response, Emitter bleibt in Application
  5. Einheitliches ErrorRenderer Interface ohne Hierarchie