refactor(di): clean up imports and improve formatting in CyclicDependencyException
This commit is contained in:
@@ -4,9 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\DI\Exceptions;
|
||||
|
||||
use App\Framework\DI\Initializer;
|
||||
use App\Framework\DI\Container;
|
||||
use App\Framework\DI\InitializerDependencyAnalyzer;
|
||||
use App\Framework\Discovery\Results\DiscoveryRegistry;
|
||||
use App\Framework\Exception\ExceptionContext;
|
||||
|
||||
final class CyclicDependencyException extends ContainerException
|
||||
@@ -108,10 +107,10 @@ final class CyclicDependencyException extends ContainerException
|
||||
// Spezifische Hinweise für Initializer-Zyklen
|
||||
if ($initializerInfo['isInitializerCycle']) {
|
||||
$message .= "⚠️ Initializer-Zyklus erkannt!\n\n";
|
||||
|
||||
|
||||
$dependencyAnalysis = $initializerInfo['dependencyAnalysis'] ?? null;
|
||||
$hasContainerGetCalls = $dependencyAnalysis !== null && $dependencyAnalysis['hasContainerGetCalls'];
|
||||
|
||||
|
||||
// Warnung über container->get() Anti-Pattern
|
||||
if ($hasContainerGetCalls) {
|
||||
$message .= " ⚠️ WICHTIG: Initializer verwendet container->get() Aufrufe!\n\n";
|
||||
@@ -123,19 +122,19 @@ final class CyclicDependencyException extends ContainerException
|
||||
$message .= " • Das macht Dependencies explizit und nachvollziehbar\n";
|
||||
$message .= " • Erleichtert die Dependency-Analyse und Fehlerdiagnose\n\n";
|
||||
}
|
||||
|
||||
|
||||
// Finde welche Dependency das Interface benötigt
|
||||
$problematicInfo = $this->findProblematicDependency(
|
||||
$initializerInfo['initializerDependencies'] ?? [],
|
||||
$this->cycleStart
|
||||
);
|
||||
|
||||
|
||||
$problematicDependency = $problematicInfo['problematicDependency'];
|
||||
$fullPath = $problematicInfo['fullPath'] ?? null;
|
||||
|
||||
|
||||
if ($problematicDependency !== null) {
|
||||
$message .= " ✅ Problem-Dependency identifiziert: '{$problematicDependency}'\n\n";
|
||||
|
||||
|
||||
// Zeige vollständigen Pfad wenn verfügbar
|
||||
if ($fullPath !== null && count($fullPath) > 2) {
|
||||
$pathStr = implode(' → ', $fullPath);
|
||||
@@ -161,7 +160,7 @@ final class CyclicDependencyException extends ContainerException
|
||||
}
|
||||
$message .= "\n";
|
||||
}
|
||||
|
||||
|
||||
$message .= "🔧 Spezifische Lösung für Initializer-Zyklen:\n";
|
||||
$message .= " • Initializer sollte das Interface NICHT im Constructor benötigen\n";
|
||||
if ($problematicDependency !== null) {
|
||||
@@ -211,19 +210,19 @@ final class CyclicDependencyException extends ContainerException
|
||||
|
||||
if (!empty($allDependencies)) {
|
||||
$message .= " ↓ benötigt folgende Dependencies:\n";
|
||||
|
||||
|
||||
// Finde problematische Dependency für Hervorhebung
|
||||
$problematicInfo = $this->findProblematicDependency($allDependencies, $interface);
|
||||
$problematicDependency = $problematicInfo['problematicDependency'];
|
||||
$fullPath = $problematicInfo['fullPath'] ?? null;
|
||||
|
||||
|
||||
$constructorDeps = $dependencyAnalysis !== null ? $dependencyAnalysis['constructorDeps'] : [];
|
||||
$containerGetDeps = $dependencyAnalysis !== null ? $dependencyAnalysis['containerGetDeps'] : [];
|
||||
|
||||
|
||||
foreach ($allDependencies as $index => $dependency) {
|
||||
$isLast = $index === count($allDependencies) - 1;
|
||||
$arrow = $isLast ? '└─→' : '├─→';
|
||||
|
||||
|
||||
// Bestimme Quelle der Dependency
|
||||
$source = '';
|
||||
if (in_array($dependency, $containerGetDeps, true)) {
|
||||
@@ -231,7 +230,7 @@ final class CyclicDependencyException extends ContainerException
|
||||
} elseif (in_array($dependency, $constructorDeps, true)) {
|
||||
$source = ' (Constructor)';
|
||||
}
|
||||
|
||||
|
||||
$highlight = ($dependency === $problematicDependency) ? ' ⚠️ (benötigt Interface!)' : '';
|
||||
$message .= " {$arrow} '{$dependency}'{$source}{$highlight}\n";
|
||||
}
|
||||
@@ -261,14 +260,14 @@ final class CyclicDependencyException extends ContainerException
|
||||
{
|
||||
// Verwende Analyzer aus Exception (wenn verfügbar)
|
||||
$analyzer = $this->dependencyAnalyzer ?? new InitializerDependencyAnalyzer();
|
||||
|
||||
|
||||
// Methode 1: Rekursive Suche - Finde vollständigen Pfad für jede Dependency
|
||||
foreach ($initializerDependencies as $dependency) {
|
||||
// Überspringe Container selbst
|
||||
if ($dependency === Container::class || $dependency === 'App\Framework\DI\Container') {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$path = $analyzer->findDependencyPathToInterface($dependency, $interface);
|
||||
if ($path !== null && !empty($path)) {
|
||||
// Der erste Eintrag im Pfad ist die Dependency, die das Interface benötigt
|
||||
@@ -279,7 +278,7 @@ final class CyclicDependencyException extends ContainerException
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Methode 2: Prüfe welche Dependency in der dependency chain vor dem Interface vorkommt
|
||||
foreach ($this->chainBeforeCycle as $classInChain) {
|
||||
if (in_array($classInChain, $initializerDependencies, true)) {
|
||||
@@ -312,7 +311,7 @@ final class CyclicDependencyException extends ContainerException
|
||||
if ($dependency === Container::class || $dependency === 'App\Framework\DI\Container') {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if ($this->dependencyNeedsInterface($dependency, $interface)) {
|
||||
return [
|
||||
'problematicDependency' => $dependency,
|
||||
@@ -349,18 +348,18 @@ final class CyclicDependencyException extends ContainerException
|
||||
// Prüfe alle Constructor-Parameter
|
||||
foreach ($constructor->getParameters() as $parameter) {
|
||||
$type = $parameter->getType();
|
||||
|
||||
|
||||
if ($type === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Direkter NamedType
|
||||
if ($type instanceof \ReflectionNamedType && !$type->isBuiltin()) {
|
||||
if ($type->getName() === $interface) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Union Types (PHP 8.0+)
|
||||
if ($type instanceof \ReflectionUnionType) {
|
||||
foreach ($type->getTypes() as $subType) {
|
||||
@@ -371,7 +370,7 @@ final class CyclicDependencyException extends ContainerException
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Intersection Types (PHP 8.1+)
|
||||
if ($type instanceof \ReflectionIntersectionType) {
|
||||
foreach ($type->getTypes() as $subType) {
|
||||
@@ -445,7 +444,7 @@ final class CyclicDependencyException extends ContainerException
|
||||
// Analysiere Dependencies des Initializers
|
||||
$analyzer = $this->dependencyAnalyzer ?? new InitializerDependencyAnalyzer();
|
||||
$dependencyAnalysis = $analyzer->analyze($initializerClass);
|
||||
|
||||
|
||||
// Kombiniere Constructor- und container->get() Dependencies
|
||||
$allDependencies = array_merge(
|
||||
$dependencyAnalysis['constructorDeps'],
|
||||
@@ -477,13 +476,13 @@ final class CyclicDependencyException extends ContainerException
|
||||
$interfaceName = basename(str_replace('\\', '/', $interface));
|
||||
$suggestedName = str_replace('Interface', '', $interfaceName) . 'Initializer';
|
||||
$namespace = substr($interface, 0, strrpos($interface, '\\'));
|
||||
|
||||
|
||||
// Strategie 1: Suche im gleichen Namespace (falls Interface nicht in Contracts ist)
|
||||
$suggestedClass = $namespace . '\\' . $suggestedName;
|
||||
if (class_exists($suggestedClass)) {
|
||||
return $suggestedClass;
|
||||
}
|
||||
|
||||
|
||||
// Strategie 2: Entferne "Contracts" aus dem Namespace (Initializer sind normalerweise nicht im Contracts-Namespace)
|
||||
// App\Framework\LiveComponents\Contracts\ComponentRegistryInterface
|
||||
// -> App\Framework\LiveComponents\ComponentRegistryInitializer
|
||||
@@ -494,7 +493,7 @@ final class CyclicDependencyException extends ContainerException
|
||||
return $suggestedClass;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Strategie 3: Suche im übergeordneten Namespace (einen Level höher)
|
||||
if (strrpos($namespace, '\\') !== false) {
|
||||
$parentNamespace = substr($namespace, 0, strrpos($namespace, '\\'));
|
||||
@@ -503,7 +502,7 @@ final class CyclicDependencyException extends ContainerException
|
||||
return $suggestedClass;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Strategie 4: Suche mit vollständigem App\Framework\ Präfix
|
||||
// Für: App\Framework\LiveComponents\Contracts\ComponentRegistryInterface
|
||||
// Suche: App\Framework\LiveComponents\ComponentRegistryInitializer
|
||||
@@ -512,7 +511,7 @@ final class CyclicDependencyException extends ContainerException
|
||||
// Entferne 'Contracts' falls vorhanden
|
||||
$filteredParts = array_filter($interfaceParts, fn($part) => $part !== 'Contracts');
|
||||
$filteredParts = array_values($filteredParts);
|
||||
|
||||
|
||||
// Baue Namespace ohne Interface-Name, aber mit Initializer-Name
|
||||
$baseNamespace = implode('\\', array_slice($filteredParts, 0, -1));
|
||||
$suggestedClass = $baseNamespace . '\\' . $suggestedName;
|
||||
|
||||
Reference in New Issue
Block a user