getLogger(); $initializerResults = $results->attributes->get(Initializer::class); $logger->debug("InitializerProcessor: Processing " . count($initializerResults) . " initializers"); $dependencyGraph = new InitializerDependencyGraph($this->reflectionProvider); // Phase 1: Setup-Initializer sofort ausführen & Service-Initializer zum Graph hinzufügen foreach ($initializerResults as $discoveredAttribute) { /** @var Initializer $initializer */ $initializer = $discoveredAttribute->createAttributeInstance(); // The actual initializer data is in the additionalData from the InitializerMapper $initializerData = $discoveredAttribute->additionalData; if (! $initializerData) { continue; } // Context-Filter: Prüfe ob Initializer für aktuellen Context erlaubt ist // The contexts data is directly in the additionalData // Wenn contexts null ist, ist der Initializer für alle Contexts verfügbar if ( isset($initializerData['contexts']) && $initializerData['contexts'] !== null && ! $this->isContextAllowed(...$initializerData['contexts']) ) { continue; } $methodName = $discoveredAttribute->methodName ?? MethodName::invoke(); // The return type is directly in the additionalData from the InitializerMapper $returnType = $initializerData['return'] ?? null; try { // Setup-Initializer: void/null Return → Sofort ausführen if ($returnType === null || $returnType === 'void') { $this->container->invoker->invoke($discoveredAttribute->className, $methodName->toString()); } // Service-Initializer: Konkreter Return-Type → Zum Dependency-Graph hinzufügen else { $dependencyGraph->addInitializer($returnType, $discoveredAttribute->className, $methodName); } } catch (\Throwable $e) { $logger->error( "Failed to register initializer: {$discoveredAttribute->className->toString()}::{$methodName->toString()}", LogContext::withExceptionAndData($e, [ 'class' => $discoveredAttribute->className->toString(), 'method' => $methodName->toString(), 'return_type' => $returnType, ]) ); // Skip failed initializers to prevent breaking the entire application } } // Phase 2: Service-Initializer in optimaler Reihenfolge registrieren $this->registerServicesWithDependencyGraph($dependencyGraph); } /** * Registriert Services basierend auf Dependency-Graph in optimaler Reihenfolge */ private function registerServicesWithDependencyGraph(InitializerDependencyGraph $graph): void { try { $executionOrder = $graph->getExecutionOrder(); foreach ($executionOrder as $returnType) { if ($graph->hasNode($returnType)) { /** @var DependencyGraphNode $node */ $node = $graph->getNode($returnType); $this->registerLazyService( $returnType, $node->getClassName(), $node->getMethodName() ); } } } catch (\Throwable $e) { // Fallback: Registriere alle Services ohne spezielle Reihenfolge $logger = $this->getLogger(); $logger->warning( "Failed to register services with dependency graph, falling back to unordered registration", LogContext::withException($e) ); /** @var string $returnType */ foreach ($graph->getNodes() as $returnType => $node) { $this->registerLazyService( $returnType, $node->getClassName(), $node->getMethodName() ); } } } /** * Prüft ob ein Initializer im aktuellen Context ausgeführt werden darf */ private function isContextAllowed(mixed ...$contexts): bool { $currentContext = $this->executionContext->getType(); foreach ($contexts as $context) { // Handle both ContextType objects and string values (from cache deserialization) if ($context instanceof ContextType) { if ($currentContext === $context) { return true; } } elseif (is_string($context)) { if ($currentContext->value === $context) { return true; } } } return false; } /** * Registriert einen Service lazy im Container mit Dual-Registration für Interfaces */ private function registerLazyService(string $returnType, string $className, string $methodName): void { $factory = function ($container) use ($className, $methodName, $returnType) { try { $instance = $container->invoker->invoke(ClassName::create($className), $methodName); } catch (\Throwable $e) { $container->get(Logger::class)->error("Failed to invoke initializer method {$methodName} for class {$className}: {$e->getMessage()}"); throw $e; } // Wenn das ein Interface ist, registriere auch die konkrete Klasse automatisch if (interface_exists($returnType)) { $concreteClass = get_class($instance); if (! $container->has($concreteClass)) { $container->instance($concreteClass, $instance); } } return $instance; }; try { // Registriere den Return-Type (Interface oder konkrete Klasse) $this->container->singleton($returnType, $factory); } catch (\Throwable $e) { $logger = $this->getLogger(); $logger->error( "Failed to register lazy service for return type: {$returnType}", LogContext::withExceptionAndData($e, [ 'return_type' => $returnType, 'class' => $className, 'method' => $methodName, ]) ); // Service registration failed - continue to prevent breaking the entire application } } /** * Gibt den Logger zurück (ist im Framework immer verfügbar) */ private function getLogger(): Logger { return $this->container->get(Logger::class); } }