feat(di): improve initializer error handling with FailedInitializerRegistry

- Add FailedInitializerRegistry to track failed initializers
- Add FailedInitializer value object to store failure context
- Enhance exception messages with failed initializer context
- Improve ClassNotInstantiable and ClassResolutionException with detailed context
- Update InitializerProcessor to register failed initializers
This commit is contained in:
2025-11-03 16:48:13 +01:00
parent c4a4f6de07
commit 8c264f3781
7 changed files with 348 additions and 22 deletions

View File

@@ -10,9 +10,11 @@ use App\Framework\Core\ValueObjects\ClassName;
use App\Framework\Core\ValueObjects\MethodName;
use App\Framework\DI\Container;
use App\Framework\DI\Exceptions\InitializerCycleException;
use App\Framework\DI\FailedInitializerRegistry;
use App\Framework\DI\Initializer;
use App\Framework\DI\InitializerDependencyGraph;
use App\Framework\DI\ValueObjects\DependencyGraphNode;
use App\Framework\DI\ValueObjects\FailedInitializer;
use App\Framework\Discovery\Results\DiscoveryRegistry;
use App\Framework\Logging\Logger;
use App\Framework\Logging\ValueObjects\LogContext;
@@ -46,6 +48,8 @@ final readonly class InitializerProcessor
$logger->debug("InitializerProcessor: Processing " . count($initializerResults) . " initializers");
$dependencyGraph = new InitializerDependencyGraph($this->reflectionProvider);
/** @var FailedInitializer[] */
$failedInitializers = [];
// Phase 1: Setup-Initializer sofort ausführen & Service-Initializer zum Graph hinzufügen
foreach ($initializerResults as $discoveredAttribute) {
@@ -94,18 +98,35 @@ final readonly class InitializerProcessor
])
);
// Track fehlgeschlagene Initializer für spätere Diagnose
if ($returnType !== null && $returnType !== 'void') {
$failedInitializers[] = new FailedInitializer(
initializerClass: $discoveredAttribute->className,
returnType: ClassName::create($returnType),
errorMessage: $e->getMessage(),
exceptionClass: ClassName::create(get_class($e))
);
}
// Skip failed initializers to prevent breaking the entire application
}
}
// Phase 2: Service-Initializer in optimaler Reihenfolge registrieren
$this->registerServicesWithDependencyGraph($dependencyGraph);
$this->registerServicesWithDependencyGraph($dependencyGraph, $failedInitializers);
// Phase 3: Registry für fehlgeschlagene Initializer im Container registrieren
if (! empty($failedInitializers)) {
$registry = new FailedInitializerRegistry(...$failedInitializers);
$this->container->instance(FailedInitializerRegistry::class, $registry);
}
}
/**
* Registriert Services basierend auf Dependency-Graph in optimaler Reihenfolge
* @param FailedInitializer[] $failedInitializers
*/
private function registerServicesWithDependencyGraph(InitializerDependencyGraph $graph): void
private function registerServicesWithDependencyGraph(InitializerDependencyGraph $graph, array &$failedInitializers): void
{
try {
$executionOrder = $graph->getExecutionOrder();
@@ -118,7 +139,8 @@ final readonly class InitializerProcessor
$this->registerLazyService(
$returnType,
$node->getClassName(),
$node->getMethodName()
$node->getMethodName(),
$failedInitializers
);
}
}
@@ -139,7 +161,8 @@ final readonly class InitializerProcessor
$this->registerLazyService(
$returnType,
$node->getClassName(),
$node->getMethodName()
$node->getMethodName(),
$failedInitializers
);
}
} catch (\Throwable $e) {
@@ -155,7 +178,8 @@ final readonly class InitializerProcessor
$this->registerLazyService(
$returnType,
$node->getClassName(),
$node->getMethodName()
$node->getMethodName(),
$failedInitializers
);
}
}
@@ -186,8 +210,9 @@ final readonly class InitializerProcessor
/**
* Registriert einen Service lazy im Container mit Dual-Registration für Interfaces
* @param FailedInitializer[] $failedInitializers
*/
private function registerLazyService(string $returnType, string $className, string $methodName): void
private function registerLazyService(string $returnType, string $className, string $methodName, array &$failedInitializers): void
{
$factory = function ($container) use ($className, $methodName, $returnType) {
try {
@@ -222,6 +247,14 @@ final readonly class InitializerProcessor
])
);
// Track fehlgeschlagenen Initializer für spätere Diagnose
$failedInitializers[] = new FailedInitializer(
initializerClass: ClassName::create($className),
returnType: ClassName::create($returnType),
errorMessage: $e->getMessage(),
exceptionClass: ClassName::create(get_class($e))
);
// Service registration failed - continue to prevent breaking the entire application
}
}