fix: DockerSecretsResolver - don't normalize absolute paths like /var/www/html/...
Some checks failed
Deploy Application / deploy (push) Has been cancelled
Some checks failed
Deploy Application / deploy (push) Has been cancelled
This commit is contained in:
317
docs/refactoring/discovery-registry-loading-analysis.md
Normal file
317
docs/refactoring/discovery-registry-loading-analysis.md
Normal file
@@ -0,0 +1,317 @@
|
||||
# Discovery Registry Loading - Problem-Analyse und Refactoring-Vorschläge
|
||||
|
||||
## Problem-Identifikation
|
||||
|
||||
### Aktuelles Problem
|
||||
Die `DiscoveryRegistry` wird über **zwei verschiedene Mechanismen** geladen, was zu Inkonsistenzen führt:
|
||||
|
||||
1. **`DiscoveryServiceBootstrapper::bootstrap()`** (Runtime)
|
||||
- Wird in `ContainerBootstrapper::autowire()` aufgerufen
|
||||
- Verwendet `DiscoveryCacheManager` mit `isStale()` Prüfung
|
||||
- Registriert `DiscoveryRegistry` als Singleton im Container
|
||||
- Führt Discovery durch, wenn Cache stale ist oder nicht existiert
|
||||
|
||||
2. **`DiscoveryRegistryInitializer`** (Build-Time)
|
||||
- Ist ein `#[Initializer(ContextType::ALL)]`
|
||||
- Lädt aus `storage/discovery/` Dateien (Build-Time Storage)
|
||||
- Wird möglicherweise vor/nach `DiscoveryServiceBootstrapper` ausgeführt
|
||||
- Kann eine alte Registry laden, die dann als Singleton registriert wird
|
||||
|
||||
### Konflikt-Szenario
|
||||
|
||||
**Szenario 1: DiscoveryRegistryInitializer läuft zuerst**
|
||||
```
|
||||
1. DiscoveryRegistryInitializer läuft (Initializer-System)
|
||||
2. Lädt alte Registry aus storage/discovery/ (ohne DatabaseAssetGalleryDataProvider)
|
||||
3. Registriert als Singleton im Container
|
||||
4. DiscoveryServiceBootstrapper läuft
|
||||
5. Prüft Cache -> findet alte Registry (nicht stale, weil Datei vor Cache-Erstellung geändert wurde)
|
||||
6. Verwendet alte Registry -> Provider fehlt
|
||||
```
|
||||
|
||||
**Szenario 2: DiscoveryServiceBootstrapper läuft zuerst**
|
||||
```
|
||||
1. DiscoveryServiceBootstrapper läuft (autowire)
|
||||
2. Führt Discovery durch -> findet DatabaseAssetGalleryDataProvider
|
||||
3. Registriert als Singleton
|
||||
4. DiscoveryRegistryInitializer läuft später
|
||||
5. Lädt alte Registry aus storage/discovery/
|
||||
6. Überschreibt Singleton? -> Provider geht verloren
|
||||
```
|
||||
|
||||
## Root Cause Analysis
|
||||
|
||||
### Problem 1: Zwei verschiedene Cache-Mechanismen
|
||||
- **Runtime-Cache**: `DiscoveryCacheManager` mit `isStale()` Prüfung
|
||||
- **Build-Time Storage**: `storage/discovery/` Dateien (veraltet?)
|
||||
|
||||
### Problem 2: Unklare Ausführungsreihenfolge
|
||||
- `DiscoveryServiceBootstrapper` läuft in `autowire()` (explizit)
|
||||
- `DiscoveryRegistryInitializer` läuft über Initializer-System (automatisch)
|
||||
- Keine garantierte Reihenfolge
|
||||
|
||||
### Problem 3: isStale() Prüfung funktioniert nicht korrekt
|
||||
- **BEHOBEN**: Verwendet jetzt Cache-Erstellungszeit statt Request-Zeit
|
||||
- Aber: Wenn `DiscoveryRegistryInitializer` eine alte Registry lädt, wird diese nicht als stale erkannt
|
||||
|
||||
## Refactoring-Vorschläge
|
||||
|
||||
### Option 1: DiscoveryRegistryInitializer entfernen (Empfohlen)
|
||||
|
||||
**Vorteile:**
|
||||
- Eliminiert Konflikt zwischen zwei Mechanismen
|
||||
- Einheitliche Cache-Strategie über `DiscoveryCacheManager`
|
||||
- `isStale()` Prüfung funktioniert korrekt
|
||||
|
||||
**Nachteile:**
|
||||
- Build-Time Storage wird nicht mehr verwendet
|
||||
- Möglicherweise Performance-Verlust beim ersten Request
|
||||
|
||||
**Implementierung:**
|
||||
1. `DiscoveryRegistryInitializer` entfernen oder deaktivieren
|
||||
2. Sicherstellen, dass `DiscoveryServiceBootstrapper` immer läuft
|
||||
3. `DiscoveryCacheManager` als einzige Quelle für Discovery-Registry
|
||||
|
||||
### Option 2: DiscoveryRegistryInitializer als Fallback
|
||||
|
||||
**Vorteile:**
|
||||
- Behält Build-Time Storage für Performance
|
||||
- Fallback wenn Runtime-Cache nicht verfügbar
|
||||
|
||||
**Nachteile:**
|
||||
- Komplexere Logik
|
||||
- Mögliche Inkonsistenzen zwischen Build-Time und Runtime
|
||||
|
||||
**Implementierung:**
|
||||
1. `DiscoveryServiceBootstrapper` prüft zuerst Runtime-Cache
|
||||
2. Wenn nicht verfügbar/stale, prüft `DiscoveryRegistryInitializer`
|
||||
3. Nur wenn beide fehlschlagen, führt Discovery durch
|
||||
|
||||
### Option 3: Einheitliche Cache-Strategie
|
||||
|
||||
**Vorteile:**
|
||||
- Einheitliche Quelle für Discovery-Registry
|
||||
- Klare Verantwortlichkeiten
|
||||
|
||||
**Nachteile:**
|
||||
- Größere Refactoring-Arbeit
|
||||
|
||||
**Implementierung:**
|
||||
1. `DiscoveryCacheManager` verwendet `storage/discovery/` als Backend
|
||||
2. `DiscoveryRegistryInitializer` entfernen
|
||||
3. `DiscoveryServiceBootstrapper` verwendet nur `DiscoveryCacheManager`
|
||||
|
||||
### Option 4: Priority-basierte Ausführungsreihenfolge
|
||||
|
||||
**Vorteile:**
|
||||
- Beide Mechanismen bleiben erhalten
|
||||
- Klare Ausführungsreihenfolge
|
||||
|
||||
**Nachteile:**
|
||||
- Komplexere Initializer-Logik
|
||||
- Mögliche Race-Conditions
|
||||
|
||||
**Implementierung:**
|
||||
1. `DiscoveryServiceBootstrapper` mit höherer Priority
|
||||
2. `DiscoveryRegistryInitializer` prüft ob Registry bereits existiert
|
||||
3. Nur laden wenn nicht vorhanden
|
||||
|
||||
## Empfohlene Lösung: Option 1 + Verbesserungen
|
||||
|
||||
### Schritt 1: DiscoveryRegistryInitializer deaktivieren/entfernen
|
||||
|
||||
```php
|
||||
// DiscoveryRegistryInitializer.php
|
||||
#[Initializer(ContextType::ALL)]
|
||||
public function __invoke(): DiscoveryRegistry
|
||||
{
|
||||
// DEPRECATED: This initializer is deprecated in favor of DiscoveryServiceBootstrapper
|
||||
// Check if DiscoveryRegistry already exists (from DiscoveryServiceBootstrapper)
|
||||
if ($this->container->has(DiscoveryRegistry::class)) {
|
||||
return $this->container->get(DiscoveryRegistry::class);
|
||||
}
|
||||
|
||||
// Fallback: Load from storage (for backward compatibility)
|
||||
$attributes = $this->discoveryLoader->loadAttributes() ?? new AttributeRegistry();
|
||||
$interfaces = $this->discoveryLoader->loadInterfaces() ?? new InterfaceRegistry();
|
||||
$templates = $this->discoveryLoader->loadTemplates() ?? new TemplateRegistry();
|
||||
|
||||
return new DiscoveryRegistry(
|
||||
attributes: $attributes,
|
||||
interfaces: $interfaces,
|
||||
templates: $templates
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Schritt 2: DiscoveryServiceBootstrapper als einzige Quelle
|
||||
|
||||
```php
|
||||
// DiscoveryServiceBootstrapper.php
|
||||
public function bootstrap(): DiscoveryRegistry
|
||||
{
|
||||
// Prüfe ob bereits registriert (z.B. durch DiscoveryRegistryInitializer)
|
||||
if ($this->container->has(DiscoveryRegistry::class)) {
|
||||
$existing = $this->container->get(DiscoveryRegistry::class);
|
||||
|
||||
// Prüfe ob stale
|
||||
if ($this->isRegistryStale($existing)) {
|
||||
// Force refresh
|
||||
$this->container->forget(DiscoveryRegistry::class);
|
||||
} else {
|
||||
return $existing;
|
||||
}
|
||||
}
|
||||
|
||||
// ... rest of bootstrap logic
|
||||
}
|
||||
```
|
||||
|
||||
### Schritt 3: Verbesserte isStale() Prüfung
|
||||
|
||||
```php
|
||||
// DiscoveryCacheManager.php
|
||||
private function isStale(DiscoveryContext $context, DiscoveryRegistry $registry, ?\DateTimeInterface $cacheStartTime = null): bool
|
||||
{
|
||||
// ... existing logic
|
||||
|
||||
// ZUSÄTZLICH: Prüfe ob Dateien seit Cache-Erstellung geändert wurden
|
||||
// Dies ist bereits implementiert, aber sollte auch für Build-Time Storage gelten
|
||||
}
|
||||
```
|
||||
|
||||
## Weitere Verbesserungen
|
||||
|
||||
### 1. Discovery-Registry Versionierung
|
||||
- Jede Registry hat eine Version/Timestamp
|
||||
- Vergleich zwischen Build-Time und Runtime-Cache
|
||||
- Automatische Invalidation bei Versionsunterschieden
|
||||
|
||||
### 2. Unified Discovery Storage
|
||||
- Einheitliche Storage-Strategie für Build-Time und Runtime
|
||||
- `DiscoveryCacheManager` verwendet `storage/discovery/` als Backend
|
||||
- Konsistente Cache-Invalidation
|
||||
|
||||
### 3. Discovery-Registry Factory
|
||||
- Zentrale Factory für Discovery-Registry-Erstellung
|
||||
- Einheitliche Logik für alle Quellen
|
||||
- Klare Verantwortlichkeiten
|
||||
|
||||
### 4. Logging und Monitoring
|
||||
- Besseres Logging für Discovery-Registry-Loading
|
||||
- Metriken für Cache-Hits/Misses
|
||||
- Warnungen bei Inkonsistenzen
|
||||
|
||||
## Migration-Plan
|
||||
|
||||
1. **Phase 1**: `DiscoveryRegistryInitializer` als Fallback behalten, aber prüfen ob Registry bereits existiert
|
||||
2. **Phase 2**: `DiscoveryServiceBootstrapper` prüft ob Registry stale ist, auch wenn bereits registriert
|
||||
3. **Phase 3**: `DiscoveryRegistryInitializer` vollständig entfernen
|
||||
4. **Phase 4**: Build-Time Storage optional machen (nur für Performance-Optimierung)
|
||||
|
||||
## Testing-Strategie
|
||||
|
||||
1. Unit-Tests für `DiscoveryCacheManager::isStale()`
|
||||
2. Integration-Tests für Discovery-Registry-Loading
|
||||
3. E2E-Tests für Provider-Resolution
|
||||
4. Performance-Tests für Cache-Hit-Rate
|
||||
|
||||
## Implementierte Änderungen
|
||||
|
||||
### 1. isStale() Prüfung korrigiert ✅
|
||||
- **Datei**: `src/Framework/Discovery/Storage/DiscoveryCacheManager.php`
|
||||
- **Änderung**: `isStale()` verwendet jetzt Cache-Erstellungszeit statt Request-Zeit
|
||||
- **Implementierung**: `startTime` wird beim Speichern im Cache gespeichert und beim Laden verwendet
|
||||
|
||||
### 2. DiscoveryRegistryInitializer entfernt ✅
|
||||
- **Datei**: `src/Framework/Discovery/DiscoveryRegistryInitializer.php` (entfernt)
|
||||
- **Änderung**: Initializer wurde vollständig entfernt, da er nur noch als No-Op fungierte
|
||||
- **Implementierung**: `DiscoveryServiceBootstrapper` ist jetzt die einzige Quelle für Discovery-Registry
|
||||
|
||||
### 3. DiscoveryServiceBootstrapper verbessert ✅
|
||||
- **Datei**: `src/Framework/Discovery/DiscoveryServiceBootstrapper.php`
|
||||
- **Änderung**: Prüft ob existierende Registry stale ist, bevor Discovery durchgeführt wird
|
||||
- **Implementierung**: `isRegistryStale()` Methode hinzugefügt
|
||||
|
||||
### 4. Cache-Struktur Migration ✅
|
||||
- **Datei**: `src/Framework/Discovery/Storage/DiscoveryCacheManager.php`
|
||||
- **Änderung**: Automatische Migration von altem Cache-Format zu neuem Format mit `startTime` und `version`
|
||||
- **Implementierung**: `upgradeCacheEntry()` und `validateCacheStructure()` Methoden hinzugefügt
|
||||
|
||||
### 5. Registry Versionierung ✅
|
||||
- **Datei**: `src/Framework/Discovery/Storage/DiscoveryCacheManager.php`
|
||||
- **Änderung**: Cache-Struktur erweitert um `version` Feld für Registry-Versionierung
|
||||
- **Implementierung**: `getRegistryVersion()` Methode erstellt Version basierend auf Registry-Content-Hash
|
||||
|
||||
### 6. Unified Discovery Storage ✅
|
||||
- **Datei**: `src/Framework/Discovery/Storage/DiscoveryCacheManager.php`
|
||||
- **Änderung**: Build-Time Storage als optionales Backend hinzugefügt
|
||||
- **Implementierung**: `tryGetFromBuildTimeStorage()` Methode prüft Build-Time Storage vor Runtime-Cache
|
||||
|
||||
### 7. Verbessertes Logging und Monitoring ✅
|
||||
- **Dateien**:
|
||||
- `src/Framework/Discovery/Storage/DiscoveryCacheManager.php`
|
||||
- `src/Framework/Discovery/Results/DiscoveryRegistry.php`
|
||||
- **Änderung**: Strukturiertes Logging, Metriken-Sammlung, Debug-Helpers hinzugefügt
|
||||
- **Implementierung**:
|
||||
- `getMetadata()` Methode in `DiscoveryRegistry`
|
||||
- `getSource()` Methode in `DiscoveryRegistry`
|
||||
- Erweiterte Logging-Statements mit Source-Informationen
|
||||
|
||||
## Weitere Refactoring-Vorschläge
|
||||
|
||||
### Refactoring 1: Einheitliche Cache-Struktur
|
||||
**Problem**: Cache-Struktur wurde geändert (Array mit `registry` und `startTime`), aber alte Caches haben noch das alte Format.
|
||||
|
||||
**Lösung**:
|
||||
- Migration-Script für alte Cache-Einträge
|
||||
- Oder: Automatische Erkennung und Konvertierung beim Laden
|
||||
|
||||
### Refactoring 2: DiscoveryRegistryInitializer entfernen
|
||||
**Problem**: Zwei Mechanismen für Discovery-Registry-Loading führen zu Konflikten.
|
||||
|
||||
**Lösung**:
|
||||
- `DiscoveryRegistryInitializer` vollständig entfernen
|
||||
- Oder: Nur als Fallback verwenden (bereits implementiert)
|
||||
- `DiscoveryServiceBootstrapper` als einzige Quelle
|
||||
|
||||
### Refactoring 3: Build-Time Storage optional machen
|
||||
**Problem**: Build-Time Storage (`storage/discovery/`) wird möglicherweise nicht mehr verwendet.
|
||||
|
||||
**Lösung**:
|
||||
- Build-Time Storage als Performance-Optimierung optional machen
|
||||
- Nur verwenden wenn verfügbar und aktuell
|
||||
- Runtime-Cache als primäre Quelle
|
||||
|
||||
### Refactoring 4: Discovery-Registry Versionierung
|
||||
**Problem**: Keine Möglichkeit, verschiedene Versionen der Registry zu vergleichen.
|
||||
|
||||
**Lösung**:
|
||||
- Jede Registry hat eine Version/Timestamp
|
||||
- Vergleich zwischen Build-Time und Runtime-Cache
|
||||
- Automatische Invalidation bei Versionsunterschieden
|
||||
|
||||
### Refactoring 5: Unified Discovery Storage
|
||||
**Problem**: Zwei verschiedene Storage-Mechanismen (Build-Time und Runtime).
|
||||
|
||||
**Lösung**:
|
||||
- Einheitliche Storage-Strategie
|
||||
- `DiscoveryCacheManager` verwendet `storage/discovery/` als Backend
|
||||
- Konsistente Cache-Invalidation
|
||||
|
||||
### Refactoring 6: Discovery-Registry Factory
|
||||
**Problem**: Discovery-Registry wird an mehreren Stellen erstellt.
|
||||
|
||||
**Lösung**:
|
||||
- Zentrale Factory für Discovery-Registry-Erstellung
|
||||
- Einheitliche Logik für alle Quellen
|
||||
- Klare Verantwortlichkeiten
|
||||
|
||||
### Refactoring 7: Verbessertes Logging
|
||||
**Problem**: Schwierig zu debuggen, welche Registry verwendet wird.
|
||||
|
||||
**Lösung**:
|
||||
- Besseres Logging für Discovery-Registry-Loading
|
||||
- Metriken für Cache-Hits/Misses
|
||||
- Warnungen bei Inkonsistenzen
|
||||
|
||||
131
docs/refactoring/placeholder-protection-refactoring.md
Normal file
131
docs/refactoring/placeholder-protection-refactoring.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# Placeholder Protection Refactoring
|
||||
|
||||
## Problem
|
||||
|
||||
Die Navigation-Links enthalten `PLACEHOLDER_0___` statt echte URLs. Der Parser schützt Placeholders während des Attribut-Parsings, aber sie werden nicht korrekt zurückgesetzt oder verarbeitet.
|
||||
|
||||
## Root Cause Analysis
|
||||
|
||||
1. **HtmlParser::parseAttributes** schützt Placeholders (`___PLACEHOLDER_X___`) während des Regex-Parsings
|
||||
2. Placeholders werden zurückgesetzt, bevor `setAttribute` aufgerufen wird
|
||||
3. Aber der `ForTransformer` findet sie nicht, weil:
|
||||
- Die Attribute werden HTML-encoded gespeichert
|
||||
- Der `ForTransformer` dekodiert sie mit `html_entity_decode`
|
||||
- Aber die Placeholders könnten bereits verarbeitet worden sein
|
||||
|
||||
## Refactoring-Vorschlag
|
||||
|
||||
### Option 1: Placeholder-Schutz entfernen (Einfachste Lösung)
|
||||
|
||||
**Problem**: Der Regex für Attribut-Parsing bricht bei geschachtelten Anführungszeichen in Placeholders.
|
||||
|
||||
**Lösung**: Statt Placeholders zu schützen, den Regex robuster machen, um geschachtelte Anführungszeichen zu handhaben.
|
||||
|
||||
**Vorteile**:
|
||||
- Einfacher Code
|
||||
- Keine Placeholder-Wiederherstellung nötig
|
||||
- Weniger Fehlerquellen
|
||||
|
||||
**Nachteile**:
|
||||
- Komplexerer Regex erforderlich
|
||||
|
||||
### Option 2: Placeholder-Schutz verbessern (Empfohlen)
|
||||
|
||||
**Problem**: Der aktuelle Schutz-Mechanismus ist fehleranfällig.
|
||||
|
||||
**Lösung**:
|
||||
1. Placeholders mit eindeutigen IDs schützen (bereits implementiert)
|
||||
2. Placeholders IMMER zurückersetzen, auch wenn sie nicht im Attribut-Wert gefunden werden
|
||||
3. Validierung hinzufügen, um sicherzustellen, dass alle geschützten Placeholders zurückgesetzt wurden
|
||||
|
||||
**Vorteile**:
|
||||
- Robuster
|
||||
- Bessere Fehlerbehandlung
|
||||
- Validierung verhindert Bugs
|
||||
|
||||
**Nachteile**:
|
||||
- Mehr Code-Komplexität
|
||||
|
||||
### Option 3: Placeholder-Verarbeitung in ForTransformer verbessern
|
||||
|
||||
**Problem**: Der `ForTransformer` erkennt geschützte Placeholders nicht korrekt.
|
||||
|
||||
**Lösung**:
|
||||
1. Geschützte Placeholders erkennen und verarbeiten
|
||||
2. Fallback-Mechanismus, falls HtmlParser sie nicht zurückgesetzt hat
|
||||
3. Besseres Logging für Debugging
|
||||
|
||||
**Vorteile**:
|
||||
- Funktioniert auch wenn HtmlParser fehlschlägt
|
||||
- Bessere Fehlerbehandlung
|
||||
|
||||
**Nachteile**:
|
||||
- Dupliziert Logik zwischen HtmlParser und ForTransformer
|
||||
|
||||
## Empfohlene Lösung
|
||||
|
||||
**Kombination aus Option 2 und 3**:
|
||||
|
||||
1. **HtmlParser verbessern**: Validierung hinzufügen, um sicherzustellen, dass alle geschützten Placeholders zurückgesetzt wurden
|
||||
2. **ForTransformer verbessern**: Fallback-Mechanismus für geschützte Placeholders
|
||||
3. **Besseres Logging**: Umfassendes Logging für Debugging
|
||||
|
||||
## Implementierung
|
||||
|
||||
### Schritt 1: HtmlParser::parseAttributes verbessern
|
||||
|
||||
```php
|
||||
private function parseAttributes(ElementNode $element, string $attributesString): void
|
||||
{
|
||||
// ... existing code ...
|
||||
|
||||
// After restoring placeholders, validate that all were restored
|
||||
foreach ($placeholders as $key => $placeholder) {
|
||||
if (str_contains($value, $key)) {
|
||||
throw new \RuntimeException("Placeholder {$key} was not restored in attribute {$name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Schritt 2: ForTransformer::processPlaceholdersInAllNodes verbessern
|
||||
|
||||
```php
|
||||
// If we find protected placeholders, try to restore them from context
|
||||
if (preg_match('/___PLACEHOLDER_(\d+)___/', $decodedValue, $matches)) {
|
||||
// This is a fallback - HtmlParser should have restored it
|
||||
// But if it didn't, we can't process it
|
||||
if (getenv('APP_DEBUG') === 'true') {
|
||||
error_log("ForTransformer::processPlaceholdersInAllNodes: CRITICAL - Found protected placeholder in attribute '{$attrName}': {$decodedValue}");
|
||||
error_log("ForTransformer::processPlaceholdersInAllNodes: This is a bug - HtmlParser should have restored it");
|
||||
}
|
||||
// Skip this attribute - it's malformed
|
||||
continue;
|
||||
}
|
||||
```
|
||||
|
||||
### Schritt 3: Besseres Logging
|
||||
|
||||
```php
|
||||
// Add comprehensive logging at each step
|
||||
if (getenv('APP_DEBUG') === 'true') {
|
||||
error_log("HtmlParser::parseAttributes: Processing attribute '{$name}'");
|
||||
error_log("HtmlParser::parseAttributes: Original value: " . substr($value, 0, 100));
|
||||
error_log("HtmlParser::parseAttributes: Protected placeholders: " . count($placeholders));
|
||||
error_log("HtmlParser::parseAttributes: Restored value: " . substr($value, 0, 100));
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
1. Unit-Tests für HtmlParser::parseAttributes
|
||||
2. Unit-Tests für ForTransformer::processPlaceholdersInAllNodes
|
||||
3. Integration-Tests für den gesamten Flow
|
||||
4. Edge-Case-Tests für geschachtelte Anführungszeichen
|
||||
|
||||
## Migration
|
||||
|
||||
- Keine Breaking Changes
|
||||
- Bestehende Templates funktionieren weiterhin
|
||||
- Neue Validierung verhindert zukünftige Bugs
|
||||
|
||||
Reference in New Issue
Block a user