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