chore: update staging branch with current changes
This commit is contained in:
@@ -8,6 +8,7 @@ use App\Framework\Auth\RouteAuthorizationService;
|
||||
use App\Framework\Config\TypedConfiguration;
|
||||
use App\Framework\DI\Container;
|
||||
use App\Framework\Http\HttpMiddleware;
|
||||
use App\Framework\Http\HttpRequest;
|
||||
use App\Framework\Http\MiddlewareContext;
|
||||
use App\Framework\Http\MiddlewarePriority;
|
||||
use App\Framework\Http\MiddlewarePriorityAttribute;
|
||||
@@ -27,6 +28,7 @@ use App\Framework\Router\Result\ViewResult;
|
||||
use App\Framework\Router\RouteContext;
|
||||
use App\Framework\Router\RouteDispatcher;
|
||||
use App\Framework\Router\Router;
|
||||
use App\Framework\Router\ValueObjects\RouteParameters;
|
||||
|
||||
#[MiddlewarePriorityAttribute(MiddlewarePriority::ROUTING)]
|
||||
final readonly class RoutingMiddleware implements HttpMiddleware
|
||||
@@ -54,7 +56,7 @@ final readonly class RoutingMiddleware implements HttpMiddleware
|
||||
*/
|
||||
public function __invoke(MiddlewareContext $context, Next $next, RequestStateManager $stateManager): MiddlewareContext
|
||||
{
|
||||
error_log("DEBUG RoutingMiddleware: __invoke() called - Path: " . $context->request->path);
|
||||
#error_log("DEBUG RoutingMiddleware: __invoke() called - Path: " . $context->request->path);
|
||||
|
||||
$request = $context->request;
|
||||
|
||||
@@ -98,7 +100,7 @@ final readonly class RoutingMiddleware implements HttpMiddleware
|
||||
$route = $routeContext->match->route;
|
||||
if ($route instanceof \App\Framework\Core\DynamicRoute && ! empty($route->paramValues)) {
|
||||
error_log("DEBUG: Route param values extracted: " . json_encode($route->paramValues));
|
||||
$request = new \App\Framework\Http\HttpRequest(
|
||||
$request = new HttpRequest(
|
||||
method: $request->method,
|
||||
headers: $request->headers,
|
||||
body: $request->body,
|
||||
@@ -109,13 +111,13 @@ final readonly class RoutingMiddleware implements HttpMiddleware
|
||||
server: $request->server,
|
||||
id: $request->id,
|
||||
parsedBody: $request->parsedBody,
|
||||
routeParameters: \App\Framework\Router\ValueObjects\RouteParameters::fromArray($route->paramValues)
|
||||
routeParameters: RouteParameters::fromArray($route->paramValues)
|
||||
);
|
||||
$context = new MiddlewareContext($request, $context->response);
|
||||
|
||||
// Update request in container so dispatcher gets the updated request
|
||||
$this->container->instance(Request::class, $request);
|
||||
$this->container->instance(\App\Framework\Http\HttpRequest::class, $request);
|
||||
$this->container->instance(HttpRequest::class, $request);
|
||||
}
|
||||
|
||||
// Perform route authorization checks
|
||||
|
||||
@@ -20,7 +20,7 @@ final readonly class RouteDebugger
|
||||
public function __construct(
|
||||
private McpToolContext $context,
|
||||
private CompiledRoutes $compiledRoutes,
|
||||
private Router $router,
|
||||
#private Router $router,
|
||||
private MiddlewareManager $middlewareManager
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -9,9 +9,11 @@ use App\Framework\Context\ContextType;
|
||||
use App\Framework\Core\PathProvider;
|
||||
use App\Framework\Core\RouteCache;
|
||||
use App\Framework\Core\RouteCompiler;
|
||||
use App\Framework\DI\Container;
|
||||
use App\Framework\DI\DefaultContainer;
|
||||
use App\Framework\DI\Initializer;
|
||||
use App\Framework\Discovery\Results\DiscoveryRegistry;
|
||||
use App\Framework\Http\Method;
|
||||
|
||||
/**
|
||||
* Verantwortlich für die Einrichtung des Routers
|
||||
@@ -19,11 +21,10 @@ use App\Framework\Discovery\Results\DiscoveryRegistry;
|
||||
final readonly class RouterSetup
|
||||
{
|
||||
public function __construct(
|
||||
private DefaultContainer $container,
|
||||
private Container $container,
|
||||
private RouteCompiler $routeCompiler,
|
||||
private DiscoveryRegistry $results,
|
||||
) {
|
||||
}
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Richtet den Router basierend auf den verarbeiteten Attributen ein
|
||||
@@ -57,12 +58,12 @@ final readonly class RouterSetup
|
||||
error_log("🚦 ROUTER SETUP: HTTP Methods count = " . count($staticRoutes));
|
||||
|
||||
// Check GET method subdomain keys
|
||||
$getSubdomainKeys = $optimizedRoutes->getSubdomainKeys(\App\Framework\Http\Method::GET);
|
||||
$getSubdomainKeys = $optimizedRoutes->getSubdomainKeys(Method::GET);
|
||||
error_log("🚦 ROUTER SETUP: GET method has subdomain keys: " . json_encode($getSubdomainKeys));
|
||||
|
||||
// Log routes per subdomain for GET
|
||||
foreach ($getSubdomainKeys as $subdomainKey) {
|
||||
$routes = $optimizedRoutes->getStaticRoutesForSubdomain(\App\Framework\Http\Method::GET, $subdomainKey);
|
||||
$routes = $optimizedRoutes->getStaticRoutesForSubdomain(Method::GET, $subdomainKey);
|
||||
error_log("🚦 ROUTER SETUP: GET subdomain '{$subdomainKey}' has " . count($routes) . " routes");
|
||||
foreach ($routes as $path => $route) {
|
||||
error_log("🚦 ROUTER SETUP: - {$path}");
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace App\Framework\Storage;
|
||||
|
||||
interface ObjectStorage
|
||||
{
|
||||
public function put(string $bucket, string $key, string|mixed $body, array $opts = []): ObjectInfo;
|
||||
public function put(string $bucket, string $key, string $body, array $opts = []): ObjectInfo;
|
||||
public function get(string $bucket, string $key): string;
|
||||
public function stream(string $bucket, string $key); // resource|StreamInterface
|
||||
public function head(string $bucket, string $key): ObjectInfo;
|
||||
|
||||
155
src/Framework/Storage/STREAMING_IMPLEMENTATION_PLAN.md
Normal file
155
src/Framework/Storage/STREAMING_IMPLEMENTATION_PLAN.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# Streaming-Implementationsliste (Option 2) – Storage Modul
|
||||
|
||||
Ziel: Dedizierte Streaming-Methoden in der Object Storage API implementieren – ohne externe Dependencies. Fokus auf speichereffiziente Downloads/Uploads großer Dateien via Streams (memory-safe).
|
||||
|
||||
## 1) Interface-Erweiterung (ObjectStorage)
|
||||
- Ergänze folgende Methoden im ObjectStorage-Interface:
|
||||
- get(string $bucket, string $key): string
|
||||
- put(string $bucket, string $key, string|mixed $body, array $opts = []): ObjectInfo
|
||||
- getToStream(string $bucket, string $key, mixed $destination): int
|
||||
- Erwartet eine schreibbare PHP-Stream-Resource als $destination
|
||||
- Rückgabewert: Anzahl geschriebener Bytes
|
||||
- putFromStream(string $bucket, string $key, mixed $source, array $opts = []): ObjectInfo
|
||||
- Erwartet eine lesbare PHP-Stream-Resource als $source
|
||||
- openReadStream(string $bucket, string $key)
|
||||
- Gibt eine lesbare PHP-Stream-Resource zurück
|
||||
- head(string $bucket, string $key): ObjectInfo
|
||||
- delete(string $bucket, string $key): void
|
||||
- exists(string $bucket, string $key): bool
|
||||
- url(string $bucket, string $key): ?string
|
||||
- temporaryUrl(string $bucket, string $key, \DateInterval $ttl, array $opts = []): string
|
||||
|
||||
Hinweise:
|
||||
- Signaturen mit mixed für Stream-Parameter (PHP-Resource), genaue Validierung in den Implementierungen.
|
||||
- Bestehende Methoden get/put bleiben kompatibel; Streaming ist ergänzend.
|
||||
|
||||
## 2) Filesystem-Adapter (lokales Backend)
|
||||
Ziel: ObjectStorage-Implementierung auf Basis des bestehenden Filesystem-Backends.
|
||||
|
||||
- Neue Klasse: src/Framework/Storage/FilesystemObjectStorage.php
|
||||
- Verantwortlichkeiten:
|
||||
- Pfadaufbau: basePath/bucket/key
|
||||
- get/put über Filesystem (kleine Dateien)
|
||||
- Streaming:
|
||||
- getToStream: Datei lesen und via stream_copy_to_stream in $destination schreiben
|
||||
- putFromStream: Stream-Inhalt in Datei schreiben (Chunked Copy)
|
||||
- openReadStream: lesbaren Stream auf die Datei öffnen
|
||||
- head/exists/delete/url/temporaryUrl:
|
||||
- head: Dateigröße, mtime, mimetype (falls verfügbar)
|
||||
- url: für lokales Storage in der Regel null (oder optionaler lokaler URL-Generator)
|
||||
- temporaryUrl: nicht unterstützt -> Exception oder leer lassen mit Doku
|
||||
- Fehlerbehandlung:
|
||||
- File not found, Permission, Read/Write-Errors sauber abbilden
|
||||
- Performance:
|
||||
- Buffersize bei stream_copy_to_stream kontrollierbar machen (Optionen)
|
||||
|
||||
## 3) MinIO-Backend (ohne Dependencies)
|
||||
Ziel: S3-kompatibler MinIO-Client mittels nativer PHP-Funktionen (HTTP-Streams und AWS SigV4) + ObjectStorage-Adapter.
|
||||
|
||||
- Dateien:
|
||||
- src/Framework/Storage/Clients/MinioClient.php
|
||||
- Funktionen: putObject, getObject, headObject, deleteObject, createPresignedUrl
|
||||
- Streaming-Funktionen:
|
||||
- getObjectToStream($bucket, $key, $destination): int
|
||||
- putObjectFromStream($bucket, $key, $source, array $opts = []): array
|
||||
- openStream($bucket, $key) -> resource
|
||||
- Interne Helfer:
|
||||
- AWS SigV4 Signierung (kanonische Anfrage, Header, Query, Hashes)
|
||||
- Response-Parsing (Headers, Status, Fehler-XML)
|
||||
- Chunked Transfer wenn keine Content-Length verfügbar
|
||||
- src/Framework/Storage/MinioObjectStorage.php
|
||||
- Implementiert ObjectStorage
|
||||
- get/put: kleinere Dateien
|
||||
- getToStream/putFromStream/openReadStream: nutzen die Streaming-APIs des MinioClient
|
||||
- head/delete/exists/url/temporaryUrl:
|
||||
- temporaryUrl via createPresignedUrl
|
||||
- Sicherheit:
|
||||
- TTL-Limits für temporaryUrl (z. B. max 24h)
|
||||
- Path-Style vs. Virtual Host Style konfigurierbar
|
||||
- Keine externen Pakete
|
||||
|
||||
## 4) Manager/Factory/DI
|
||||
- Option A: StorageManager für ObjectStorage-Driver (local/minio)
|
||||
- src/Framework/Storage/StorageManager.php
|
||||
- driver(string $name): ObjectStorage
|
||||
- bucket(string $name): Bucket (Convenience)
|
||||
- Option B (einfach): Container-Bindings direkt
|
||||
- Default ObjectStorage anhand ENV
|
||||
- Initializer:
|
||||
- src/Framework/Storage/StorageInitializer.php
|
||||
- Konfig aus ENV (DEFAULT_DRIVER, MINIO_ENDPOINT, KEYS, LOCAL_ROOT, PATH_STYLE etc.)
|
||||
- Registriere:
|
||||
- FilesystemObjectStorage (als "local")
|
||||
- MinioClient + MinioObjectStorage (als "minio")
|
||||
- ObjectStorage (Default: ENV)
|
||||
- Bucket-API (optional aber DX-freundlich):
|
||||
- src/Framework/Storage/Bucket.php
|
||||
- wrappt ObjectStorage für festen Bucket-Namen
|
||||
|
||||
## 5) Konfiguration
|
||||
- ENV Variablen vorschlagen (Beispiele):
|
||||
- STORAGE_DRIVER=local|minio
|
||||
- STORAGE_LOCAL_ROOT=/var/www/html/storage/objects
|
||||
- MINIO_ENDPOINT=http://minio:9000
|
||||
- MINIO_ACCESS_KEY=...
|
||||
- MINIO_SECRET_KEY=...
|
||||
- MINIO_REGION=us-east-1
|
||||
- MINIO_USE_PATH_STYLE=true
|
||||
- StorageConfig Klasse (optional) für strukturierte Konfig-Verwaltung
|
||||
|
||||
## 6) Tests (kritisch, da streaming-sensitiv)
|
||||
- Unit-Tests FilesystemObjectStorage:
|
||||
- put/get mit Strings
|
||||
- putFromStream/getToStream mit temp Streams (php://temp)
|
||||
- openReadStream und sequentielles Lesen
|
||||
- head/exists/delete
|
||||
- Unit-Tests MinioClient (Signierung) – isoliert:
|
||||
- Signatur-Konsistenz (Golden Master)
|
||||
- Parsing von Fehlern/Headers
|
||||
- Integration-Tests (optional, per docker-compose mit MinIO):
|
||||
- Upload/Download großer Dateien (z. B. >100MB) per Streams
|
||||
- temporaryUrl Zugriff (GET) mit TTL
|
||||
- Edge Cases:
|
||||
- fehlende Read-/Write-Berechtigungen (Filesystem)
|
||||
- Netzwerkfehler (MinIO)
|
||||
- Nicht existierende Objekte
|
||||
- Streams ohne bekannte Länge (Chunked Transfer)
|
||||
|
||||
## 7) Fehler- und Ausnahmebehandlung
|
||||
- Konsistente Exceptions im Storage-Namespace (z. B. StorageException)
|
||||
- Filesystem-spezifische Fehler sauber mappen
|
||||
- Aussagekräftige Meldungen (inkl. Pfad/Bucket/Key)
|
||||
|
||||
## 8) Performance/Robustheit
|
||||
- Stream-Buffer konfigurierbar (z. B. 8192 Bytes Default)
|
||||
- Keine vollständigen Dateiladungen in Memory bei Streams
|
||||
- Zeitouts/Retry-Strategie (MinIO) minimal vorsehen (optional)
|
||||
- Sauberes Schließen aller Streams (try/finally)
|
||||
|
||||
## 9) Sicherheit
|
||||
- Path-Sanitizing im Filesystem-Adapter (keine Directory-Traversal)
|
||||
- Eindeutige Handhabung von public URL vs. presigned URL
|
||||
- Limitierung der Presign-Dauer und Validierung von Eingaben
|
||||
|
||||
## 10) Dokumentation
|
||||
- README/HowTo:
|
||||
- Beispiel für lokale und MinIO-Nutzung
|
||||
- Beispiele für Streaming (Upload/Download)
|
||||
- Hinweise zu großen Dateien, Memory-Effizienz
|
||||
- PHPDoc ausführlich an allen Public-APIs
|
||||
|
||||
## 11) Milestones (Reihenfolge)
|
||||
1. Interface-Änderungen (ObjectStorage)
|
||||
2. FilesystemObjectStorage (inkl. Streaming)
|
||||
3. MinioClient (Basis + Signierung)
|
||||
4. MinioObjectStorage (inkl. Streaming)
|
||||
5. Initializer/DI und Konfig
|
||||
6. Tests (Unit), danach optional Integration
|
||||
7. Doku + Beispiele
|
||||
|
||||
## 12) Definition of Done
|
||||
- Alle neuen Methoden implementiert und getestet
|
||||
- Große Dateien via Streams funktionieren, ohne OOM
|
||||
- Kein externer Dependency-Einsatz
|
||||
- Doku und Beispiele vorhanden
|
||||
- CI-Tests grün (Unit; Integration optional)
|
||||
@@ -6,6 +6,7 @@ namespace App\Infrastructure\Database\Migrations;
|
||||
|
||||
use App\Framework\Database\Migration\Migration;
|
||||
use App\Framework\Database\ConnectionInterface;
|
||||
use App\Framework\Database\Migration\MigrationVersion;
|
||||
use App\Framework\Database\Schema\Schema;
|
||||
|
||||
/**
|
||||
@@ -67,9 +68,9 @@ final readonly class CreateComponentStateHistoryTable implements Migration
|
||||
$schema->execute();
|
||||
}
|
||||
|
||||
public function getVersion(): string
|
||||
public function getVersion(): MigrationVersion
|
||||
{
|
||||
return '2024_12_20_120100';
|
||||
return MigrationVersion::fromTimestamp('2024_12_20_120000');
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace App\Infrastructure\Database\Migrations;
|
||||
|
||||
use App\Framework\Database\Migration\Migration;
|
||||
use App\Framework\Database\ConnectionInterface;
|
||||
use App\Framework\Database\Migration\MigrationVersion;
|
||||
use App\Framework\Database\Schema\Schema;
|
||||
|
||||
/**
|
||||
@@ -53,9 +54,9 @@ final readonly class CreateComponentStateTable implements Migration
|
||||
$schema->execute();
|
||||
}
|
||||
|
||||
public function getVersion(): string
|
||||
public function getVersion(): MigrationVersion
|
||||
{
|
||||
return '2024_12_20_120000';
|
||||
return MigrationVersion::fromString('2024_12_20_120000');
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
|
||||
Reference in New Issue
Block a user