buildMiddlewareStack(); // Debug logging mit strukturiertem Logger falls verfügbar if ($this->container->has(Logger::class)) { try { $logger = $this->container->get(Logger::class); $logger->debug('Middleware stack initialized', LogContext::withData([ 'middleware_count' => count($middlewares), 'middleware_stack' => array_map(fn ($m) => basename($m), $middlewares), 'component' => 'MiddlewareManager', ])); } catch (\Throwable $e) { // Ignore logger errors during initialization } } $this->chain = new HttpMiddlewareChain( $middlewares, $this->container ); } /** * @return array */ private function buildMiddlewareStack(): array { // Explizite Reihenfolge definieren - wichtigste zuerst /** @var array */ $explicitOrder = [ // 0. Exception Handling - MUSS absolut zuerst kommen, um alle Exceptions zu fangen \App\Framework\Http\Middlewares\ExceptionHandlingMiddleware::class, // 1. System und Error Handling \App\Framework\Http\Middlewares\RequestIdMiddleware::class, // 2. Production Security - MUST come early to block routes \App\Framework\Http\Middlewares\ProductionSecurityMiddleware::class, // 3. Security und DDoS Protection DDoSProtectionMiddleware::class, WafMiddleware::class, // 4. Session - MUSS vor Auth und CSRF kommen! \App\Framework\Http\Session\SessionMiddleware::class, // 5. Security und Rate Limiting //RateLimitMiddleware::class, #\App\Application\Security\Middleware\SecurityEventMiddleware::class, // 6. Headers und CORS \App\Framework\Http\Middlewares\SecurityHeaderMiddleware::class, \App\Framework\Http\Middlewares\RemovePoweredByMiddleware::class, \App\Framework\Http\Middlewares\CORSMiddleware::class, // 7. Authentication und CSRF (brauchen Session) \App\Framework\Http\Middlewares\AuthMiddleware::class, \App\Framework\Http\Middlewares\CsrfMiddleware::class, \App\Framework\Http\Middlewares\HoneypotMiddleware::class, // 8. Routing und Request Processing \App\Framework\Http\Middlewares\RoutingMiddleware::class, \App\Framework\Http\Middlewares\ControllerRequestMiddleware::class, // 9. Content und Static Files #\App\Framework\Http\Middlewares\ServeStaticFilesMiddleware::class, \App\Framework\Http\Middlewares\ResponseGeneratorMiddleware::class, \App\Framework\Http\Middlewares\FormDataResponseMiddleware::class, // Temporarily disabled // 10. Monitoring und Analytics \App\Framework\Analytics\Middleware\AnalyticsMiddleware::class, \App\Framework\Performance\Middleware\RequestPerformanceMiddleware::class, \App\Framework\Performance\Middleware\RoutingPerformanceMiddleware::class, \App\Framework\Performance\Middleware\ControllerPerformanceMiddleware::class, \App\Framework\Tracing\TracingMiddleware::class, // 11. Logging (am Ende) \App\Framework\Http\Middlewares\RequestLoggingMiddleware::class, \App\Framework\Http\Middlewares\LoggingMiddleware::class, \App\Framework\Performance\Middleware\PerformanceDebugMiddleware::class, \App\Framework\Security\RequestSigning\RequestSigningMiddleware::class, // 12. FALLBACK - Absolut letztes Middleware (nur wenn keine Response vorhanden) \App\Framework\Http\Middlewares\DefaultResponseMiddleware::class, ]; // Use the refactored robust dependency resolution try { $resolved = $this->resolveDependencies($explicitOrder); #error_log("MiddlewareManager: Using dependency resolution - Count: " . count($resolved)); // WICHTIG: Array umkehren, da die Liste in gewünschter Ausführungsreihenfolge definiert ist // aber die Middleware-Chain sie in der gegebenen Reihenfolge abarbeitet return array_reverse($resolved); } catch (\Throwable $e) { #error_log("MiddlewareManager: Dependency resolution failed: " . $e->getMessage()); #error_log("MiddlewareManager: Falling back to explicit order - Count: " . count($explicitOrder)); #foreach ($explicitOrder as $i => $middleware) { # error_log("MiddlewareManager: Explicit #{$i}: " . basename($middleware)); #} // WICHTIG: Array umkehren, da die Liste in gewünschter Ausführungsreihenfolge definiert ist return array_reverse($explicitOrder); } } /** * Resolve middleware dependencies using constructor analysis * @param array $middlewares * @return array */ private function resolveDependencies(array $middlewares): array { $logger = $this->container->get(Logger::class); $resolver = new MiddlewareDependencyResolver( $this->reflectionProvider, $this->container, $logger ); $resolved = $resolver->resolve($middlewares); // Log dependency resolution info #error_log("MiddlewareManager: Dependency resolution completed"); #error_log("MiddlewareManager: Resolved " . $resolved->count() . " middlewares"); #error_log("MiddlewareManager: Execution order: " . implode(' → ', array_map(fn ($m) => basename($m), $resolved->getMiddlewares()))); // Log dependency chains for debugging $info = $resolved->getResolutionInfo(); #if (! empty($info['dependency_chains'])) { # error_log("MiddlewareManager: Dependency chains: " . json_encode($info['dependency_chains'])); #} #if (! empty($info['circular_dependencies'])) { # error_log("MiddlewareManager: WARNING - Circular dependencies detected: " . json_encode($info['circular_dependencies'])); #} return $resolved->getMiddlewares(); } /** * Get middleware dependency information for debugging */ /** * @return array */ public function getDependencyInfo(): array { $explicitOrder = $this->getExplicitOrder(); $classNameObjects = array_map(fn ($class) => ClassName::create($class), $explicitOrder); $logger = $this->container->get(Logger::class); $resolver = new MiddlewareDependencyResolver( $this->reflectionProvider, $this->container, $logger ); return $resolver->getDependencyInfo($classNameObjects); } /** * Get the explicit order array (for testing and debugging) * @return array */ private function getExplicitOrder(): array { // Return the same explicit order array return [ // 1. System und Error Handling \App\Framework\Http\Middlewares\RequestIdMiddleware::class, \App\Framework\Http\Middlewares\ExceptionHandlingMiddleware::class, // 4. Session - MUSS vor Auth und CSRF kommen! \App\Framework\Http\Session\SessionMiddleware::class, // 2. Security und Rate Limiting //RateLimitMiddleware::class, #\App\Application\Security\Middleware\SecurityEventMiddleware::class, // 3. Headers und CORS \App\Framework\Http\Middlewares\SecurityHeaderMiddleware::class, \App\Framework\Http\Middlewares\RemovePoweredByMiddleware::class, \App\Framework\Http\Middlewares\CORSMiddleware::class, // 5. Authentication und CSRF (brauchen Session) \App\Framework\Http\Middlewares\AuthMiddleware::class, \App\Framework\Http\Middlewares\CsrfMiddleware::class, \App\Framework\Http\Middlewares\HoneypotMiddleware::class, // 6. Routing und Request Processing \App\Framework\Http\Middlewares\RoutingMiddleware::class, \App\Framework\Http\Middlewares\ControllerRequestMiddleware::class, // 7. Content und Static Files #\App\Framework\Http\Middlewares\ServeStaticFilesMiddleware::class, \App\Framework\Http\Middlewares\ResponseGeneratorMiddleware::class, \App\Framework\Http\Middlewares\FormDataResponseMiddleware::class, // Temporarily disabled // 8. Monitoring und Analytics \App\Framework\Analytics\Middleware\AnalyticsMiddleware::class, \App\Framework\Performance\Middleware\RequestPerformanceMiddleware::class, \App\Framework\Performance\Middleware\RoutingPerformanceMiddleware::class, \App\Framework\Performance\Middleware\ControllerPerformanceMiddleware::class, \App\Framework\Tracing\TracingMiddleware::class, // 9. Logging (am Ende) \App\Framework\Http\Middlewares\RequestLoggingMiddleware::class, \App\Framework\Http\Middlewares\LoggingMiddleware::class, \App\Framework\Performance\Middleware\PerformanceDebugMiddleware::class, \App\Framework\Security\RequestSigning\RequestSigningMiddleware::class, // 10. FALLBACK - Absolut letztes Middleware (nur wenn keine Response vorhanden) \App\Framework\Http\Middlewares\DefaultResponseMiddleware::class, ]; } public function getPriorityForClass(object|string $middlewareClass): int { $className = is_string($middlewareClass) ? $middlewareClass : $middlewareClass::class; $className = ltrim($className, '\\'); $cacheKey = CacheKey::fromString("middleware_priority:{$className}"); $cacheItem = $this->cache->remember($cacheKey, function () use ($className) { return $this->resolvePriorityFromReflection($className); }, Duration::fromSeconds(3600)); return is_int($cacheItem->value) ? $cacheItem->value : MiddlewarePriority::BUSINESS_LOGIC->value; } private function resolvePriorityFromReflection(string $className): int { try { $classNameObj = ClassName::create($className); $attrs = $this->reflectionProvider->getAttributes($classNameObj, MiddlewarePriorityAttribute::class); if ($attrs->count() > 0) { /** @var MiddlewarePriorityAttribute|null $attr */ $attr = $attrs->getFirstByType(MiddlewarePriorityAttribute::class)?->newInstance(); if ($attr instanceof MiddlewarePriorityAttribute) { $basePriority = $attr->priority->value; $offset = $attr->offset ?? 0; return $basePriority + $offset; } } } catch (\ReflectionException $e) { // Class doesn't exist or can't be reflected, use default } // Default priority return MiddlewarePriority::BUSINESS_LOGIC->value; } // Legacy static method for backward compatibility public static function getPriority(object|string $middlewareClass): int { // This is a fallback for any code that still uses the static method $className = is_string($middlewareClass) ? $middlewareClass : $middlewareClass::class; $className = ltrim($className, '\\'); try { $reflection = new \ReflectionClass($className); $attrs = $reflection->getAttributes(MiddlewarePriorityAttribute::class); if ($attrs) { /** @var MiddlewarePriorityAttribute $attr */ $attr = $attrs[0]->newInstance(); $basePriority = $attr->priority->value; $offset = $attr->offset ?? 0; return $basePriority + $offset; } } catch (\ReflectionException $e) { // Class doesn't exist or can't be reflected, use default } return MiddlewarePriority::BUSINESS_LOGIC->value; } /** * Methode zum Sortieren der Middleware nach Priorität * @param array $middlewares * @return array */ private function sortMiddlewaresByPriority(array $middlewares): array { usort($middlewares, function (object|string $a, object|string $b) { $priorityA = $this->getMiddlewarePriority($a); $priorityB = $this->getMiddlewarePriority($b); return $priorityB <=> $priorityA; // Höhere Priorität zuerst }); return $middlewares; } // Hilfsmethode zum Abrufen der Middleware-Priorität private function getMiddlewarePriority(object|string $middlewareClass): int { $className = is_string($middlewareClass) ? $middlewareClass : $middlewareClass::class; $className = ltrim($className, '\\'); $cacheKey = CacheKey::fromString("middleware_priority_discovery:{$className}"); $cacheItem = $this->cache->remember($cacheKey, function () use ($className) { // Use discovery registry to find priority $priorities = $this->discoveryRegistry->attributes()->get(MiddlewarePriorityAttribute::class); foreach ($priorities as $discoveredAttribute) { if ($discoveredAttribute->className->getFullyQualified() === $className) { $additionalData = $discoveredAttribute->additionalData; $priority = $additionalData['priority'] ?? null; if (! is_int($priority)) { $priority = $priority->value; } return $priority + ($additionalData['offset'] ?? 0); } } // Default priority return MiddlewarePriority::BUSINESS_LOGIC->value; }, Duration::fromSeconds(3600)); return is_int($cacheItem->value) ? $cacheItem->value : MiddlewarePriority::BUSINESS_LOGIC->value; } /** * Clear the priority cache (useful for testing) */ public function clearPriorityCache(): void { // Clear cache entries that start with our middleware priority prefix $this->cache->forget('middleware_priority:*'); $this->cache->forget('middleware_priority_discovery:*'); } /** * Get cache statistics for debugging * * @return array */ public function getCacheStats(): array { return [ 'cache_implementation' => get_class($this->cache), 'reflection_provider' => get_class($this->reflectionProvider), ]; } }