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:
@@ -12,6 +12,8 @@ use App\Framework\DI\Exceptions\ContainerException;
|
||||
use App\Framework\DI\Exceptions\CyclicDependencyException;
|
||||
use App\Framework\DI\Exceptions\LazyLoadingException;
|
||||
use App\Framework\Discovery\Results\DiscoveryRegistry;
|
||||
use App\Framework\DI\FailedInitializerRegistry;
|
||||
use App\Framework\DI\ValueObjects\FailedInitializer;
|
||||
use App\Framework\Logging\Logger;
|
||||
use App\Framework\Logging\ValueObjects\LogContext;
|
||||
use App\Framework\Metrics\FrameworkMetricsCollector;
|
||||
@@ -217,6 +219,10 @@ final class DefaultContainer implements Container
|
||||
|
||||
// Try to get DiscoveryRegistry from container and include discovered initializers
|
||||
$discoveredInitializers = [];
|
||||
$matchingInitializers = [];
|
||||
$suggestedInitializer = null;
|
||||
$failedInitializer = null;
|
||||
|
||||
if ($this->has(DiscoveryRegistry::class)) {
|
||||
try {
|
||||
$discoveryRegistry = $this->get(DiscoveryRegistry::class);
|
||||
@@ -227,17 +233,53 @@ final class DefaultContainer implements Container
|
||||
fn($attr) => $attr->className->getFullyQualified(),
|
||||
$initializerResults
|
||||
);
|
||||
|
||||
// Spezielle Behandlung für Interfaces: Suche nach Initializern die dieses Interface zurückgeben
|
||||
if (interface_exists($class)) {
|
||||
foreach ($initializerResults as $initializer) {
|
||||
$returnType = $initializer->additionalData['return'] ?? null;
|
||||
if ($returnType === $class) {
|
||||
$matchingInitializers[] = $initializer->className->getFullyQualified();
|
||||
}
|
||||
}
|
||||
|
||||
// Vorschlag basierend auf Interface-Name (z.B. ComponentRegistryInterface -> ComponentRegistryInitializer)
|
||||
$interfaceName = basename(str_replace('\\', '/', $class));
|
||||
$suggestedName = str_replace('Interface', '', $interfaceName) . 'Initializer';
|
||||
|
||||
foreach ($discoveredInitializers as $initializer) {
|
||||
if (str_contains($initializer, $suggestedName)) {
|
||||
$suggestedInitializer = $initializer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// Silently ignore errors when trying to access DiscoveryRegistry to avoid masking the original error
|
||||
}
|
||||
}
|
||||
|
||||
// Prüfe ob ein Initializer für dieses Interface fehlgeschlagen ist
|
||||
if ($this->has(FailedInitializerRegistry::class)) {
|
||||
try {
|
||||
$failedRegistry = $this->get(FailedInitializerRegistry::class);
|
||||
if ($failedRegistry->hasFailedInitializer($class)) {
|
||||
$failedInitializer = $failedRegistry->getFailedInitializer($class);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// Silently ignore errors when trying to access FailedInitializerRegistry
|
||||
}
|
||||
}
|
||||
|
||||
throw ClassNotInstantiable::fromContainerContext(
|
||||
class: $class,
|
||||
dependencyChain: $this->resolving,
|
||||
availableBindings: $availableBindings,
|
||||
discoveredInitializers: $discoveredInitializers
|
||||
discoveredInitializers: $discoveredInitializers,
|
||||
matchingInitializers: $matchingInitializers,
|
||||
suggestedInitializer: $suggestedInitializer,
|
||||
failedInitializer: $failedInitializer
|
||||
);
|
||||
}
|
||||
|
||||
@@ -261,12 +303,52 @@ final class DefaultContainer implements Container
|
||||
default => 'object'
|
||||
};
|
||||
|
||||
// Für callable bindings: Prüfe ob ein Initializer fehlgeschlagen ist
|
||||
$failedInitializer = null;
|
||||
$matchingInitializer = null;
|
||||
|
||||
if ($bindingType === 'callable') {
|
||||
// Prüfe ob ein fehlgeschlagener Initializer für diese Klasse existiert
|
||||
if ($this->has(FailedInitializerRegistry::class)) {
|
||||
try {
|
||||
$failedRegistry = $this->get(FailedInitializerRegistry::class);
|
||||
if ($failedRegistry->hasFailedInitializer($class)) {
|
||||
$failedInitializer = $failedRegistry->getFailedInitializer($class);
|
||||
}
|
||||
} catch (\Throwable $registryError) {
|
||||
// Silently ignore errors when trying to access FailedInitializerRegistry
|
||||
}
|
||||
}
|
||||
|
||||
// Suche auch in DiscoveryRegistry nach Initializern die diese Klasse zurückgeben
|
||||
if ($failedInitializer === null && $this->has(DiscoveryRegistry::class)) {
|
||||
try {
|
||||
$discoveryRegistry = $this->get(DiscoveryRegistry::class);
|
||||
$initializerResults = $discoveryRegistry->attributes->get(Initializer::class);
|
||||
|
||||
if (! empty($initializerResults)) {
|
||||
foreach ($initializerResults as $initializer) {
|
||||
$returnType = $initializer->additionalData['return'] ?? null;
|
||||
if ($returnType === $class) {
|
||||
$matchingInitializer = $initializer->className->getFullyQualified();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $registryError) {
|
||||
// Silently ignore errors when trying to access DiscoveryRegistry
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw ClassResolutionException::fromBindingResolution(
|
||||
class: $class,
|
||||
previous: $e,
|
||||
availableBindings: array_keys($this->bindings->getAllBindings()),
|
||||
dependencyChain: $this->resolving,
|
||||
bindingType: $bindingType
|
||||
bindingType: $bindingType,
|
||||
failedInitializer: $failedInitializer,
|
||||
matchingInitializer: $matchingInitializer
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user