Some checks failed
Deploy Application / deploy (push) Has been cancelled
130 lines
4.9 KiB
Markdown
130 lines
4.9 KiB
Markdown
# Session Binding Initializer
|
|
|
|
## Übersicht
|
|
|
|
Der `SessionBindingInitializer` löst das Problem, dass `SessionInterface` während der Bootstrap-Phase noch nicht verfügbar ist, wenn Initializer ausgeführt werden, die `SessionInterface` als Dependency benötigen.
|
|
|
|
## Problem
|
|
|
|
**Timing-Problem**: `SessionInterface` wird normalerweise von `SessionMiddleware` während der Request-Verarbeitung gebunden. Initializer laufen jedoch während der Bootstrap-Phase, bevor ein Request verarbeitet wird. Dies führt zu Dependency-Injection-Fehlern, wenn Initializer `SessionInterface` als Dependency benötigen.
|
|
|
|
**Beispiel**: `ActionAuthorizationCheckerInitializer` benötigt `SessionInterface`, um `SessionBasedAuthorizationChecker` zu erstellen. Ohne `SessionBindingInitializer` würde die Dependency-Injection fehlschlagen.
|
|
|
|
## Lösung
|
|
|
|
Der `SessionBindingInitializer` registriert `SessionInterface` als **lazy binding** im Container:
|
|
|
|
```php
|
|
#[Initializer]
|
|
public function __invoke(): void
|
|
{
|
|
$sessionManager = $this->sessionManager;
|
|
$this->container->singleton(SessionInterface::class, function(Container $c) use ($sessionManager) {
|
|
// Check if Session is already bound (by Middleware)
|
|
if ($c->has(Session::class)) {
|
|
return $c->get(Session::class);
|
|
}
|
|
|
|
// Fallback: Create new session without request context
|
|
// This will be overridden by SessionMiddleware when request is available
|
|
return $sessionManager->createNewSession();
|
|
});
|
|
}
|
|
```
|
|
|
|
## Funktionsweise
|
|
|
|
1. **Lazy Binding**: `SessionInterface` wird als Closure registriert, die erst ausgeführt wird, wenn `SessionInterface` tatsächlich benötigt wird.
|
|
|
|
2. **Fallback-Mechanismus**:
|
|
- Wenn `SessionMiddleware` bereits gelaufen ist, wird die bereits gebundene `Session` verwendet.
|
|
- Andernfalls wird eine neue Session ohne Request-Context erstellt.
|
|
|
|
3. **Override durch Middleware**: `SessionMiddleware` überschreibt das lazy binding mit der tatsächlichen Session-Instanz, wenn ein Request verarbeitet wird.
|
|
|
|
## Verwendung
|
|
|
|
Initializer, die `SessionInterface` benötigen, können es einfach als Dependency injizieren:
|
|
|
|
```php
|
|
final readonly class ActionAuthorizationCheckerInitializer
|
|
{
|
|
public function __construct(
|
|
private Container $container
|
|
) {
|
|
}
|
|
|
|
#[Initializer]
|
|
public function __invoke(): ActionAuthorizationChecker
|
|
{
|
|
// SessionInterface wird automatisch vom lazy binding bereitgestellt
|
|
$session = $this->container->get(SessionInterface::class);
|
|
|
|
$checker = new SessionBasedAuthorizationChecker($session);
|
|
$this->container->singleton(ActionAuthorizationChecker::class, $checker);
|
|
|
|
return $checker;
|
|
}
|
|
}
|
|
```
|
|
|
|
## Wichtige Hinweise
|
|
|
|
### Kein ContextType-Filter
|
|
|
|
**Wichtig**: Der `SessionBindingInitializer` hat **keinen** `ContextType`-Filter:
|
|
|
|
```php
|
|
#[Initializer] // ✅ Kein ContextType::WEB Filter
|
|
public function __invoke(): void
|
|
```
|
|
|
|
**Grund**: Die Discovery läuft während der Bootstrap-Phase, wenn der Context noch `cli-script` ist. Ein `ContextType::WEB` Filter würde dazu führen, dass der Initializer übersprungen wird und `SessionInterface` nicht registriert wird.
|
|
|
|
### Discovery-Timing
|
|
|
|
Die Discovery scannt Initializer während der Bootstrap-Phase, bevor Requests verarbeitet werden. Initializer mit ContextType-Filtern werden nur ausgeführt, wenn der aktuelle Context passt. Da die Bootstrap-Phase im `cli-script` Context läuft, werden Initializer mit `ContextType::WEB` Filter übersprungen.
|
|
|
|
**Lösung**: Initializer, die für die Dependency-Registrierung benötigt werden, sollten **keinen** ContextType-Filter haben, auch wenn sie nur für WEB-Contexts verwendet werden.
|
|
|
|
## Dateien
|
|
|
|
- **Initializer**: `src/Framework/Http/Session/SessionBindingInitializer.php`
|
|
- **Verwendet von**: `src/Framework/LiveComponents/Security/ActionAuthorizationCheckerInitializer.php`
|
|
- **Middleware**: `src/Framework/Http/Session/SessionMiddleware.php`
|
|
|
|
## Troubleshooting
|
|
|
|
### Problem: "Cannot instantiate interface SessionInterface"
|
|
|
|
**Ursache**: `SessionBindingInitializer` wurde nicht gefunden oder nicht ausgeführt.
|
|
|
|
**Lösung**:
|
|
1. Prüfe, ob `SessionBindingInitializer` das `#[Initializer]` Attribut hat (ohne ContextType-Filter).
|
|
2. Leere den Discovery-Cache: `php console.php discovery:clear-cache`
|
|
3. Prüfe die Logs, ob der Initializer gefunden wurde.
|
|
|
|
### Problem: Initializer wird nicht gefunden
|
|
|
|
**Ursache**: ContextType-Filter verhindert, dass der Initializer während der Bootstrap-Phase gefunden wird.
|
|
|
|
**Lösung**: Entferne den `ContextType`-Filter vom `#[Initializer]` Attribut:
|
|
|
|
```php
|
|
// ❌ Falsch: Wird während Bootstrap übersprungen
|
|
#[Initializer(ContextType::WEB)]
|
|
|
|
// ✅ Richtig: Wird während Bootstrap gefunden
|
|
#[Initializer]
|
|
```
|
|
|
|
## Siehe auch
|
|
|
|
- [Dependency Injection](../features/dependency-injection.md)
|
|
- [Session Management](../features/session-management.md)
|
|
- [Initializer System](../features/initializer-system.md)
|
|
|
|
|
|
|
|
|