findByDefaultImplementation($interface); if ($result !== null) { return $result; } // 2. Namenskonvention $result = $this->findByName($interface); if ($result !== null) { return $result; } // 3. Selber Ordner $result = $this->findInDirectory($interface); if ($result !== null) { return $result; } // 4. Unterordner $result = $this->findInSubdirectories($interface); if ($result !== null) { return $result; } // 5. Ganzes Modul return $this->findInModule($interface); } /** * Sucht nach Initializer basierend auf DefaultImplementation Attribut */ private function findByDefaultImplementation(string $interface): ?InitializerInfo { try { // Suche in DiscoveryRegistry nach DefaultImplementation Attributen $defaultImplResults = $this->discoveryRegistry->attributes->get(DefaultImplementation::class); if (empty($defaultImplResults)) { return null; } foreach ($defaultImplResults as $defaultImpl) { $implClassName = $defaultImpl->className; // Prüfe ob das Attribut das richtige Interface spezifiziert $defaultImplAttr = $defaultImpl->createAttributeInstance(); if ($defaultImplAttr instanceof DefaultImplementation) { // Wenn Interface explizit angegeben, muss es übereinstimmen if ($defaultImplAttr->interface !== null && $defaultImplAttr->interface !== $interface) { continue; } } // Prüfe ob die Klasse das Interface implementiert $reflection = $this->reflectionProvider->getClass($implClassName); if (!$reflection->implementsInterface($interface)) { continue; } // Prüfe ob die Klasse auch Initializer Attribut hat $initializerInfo = $this->checkInitializerAttribute($implClassName, $interface); if ($initializerInfo !== null) { return $initializerInfo; } } } catch (\Throwable $e) { // Silently ignore errors } return null; } /** * Sucht nach Initializer basierend auf Namenskonvention * SomeClassInterface -> SomeClassInitializer */ private function findByName(string $interface): ?InitializerInfo { try { $interfaceName = ClassName::create($interface); $shortName = $interfaceName->getShortName(); // Entferne "Interface" Suffix if (!str_ends_with($shortName, 'Interface')) { return null; } $baseName = substr($shortName, 0, -9); // "Interface" = 9 Zeichen $initializerName = $baseName . 'Initializer'; // Konstruiere vollständigen Klassennamen $namespace = $interfaceName->getNamespaceObject(); $initializerClassName = ClassName::fromNamespace($namespace, $initializerName); // Prüfe ob Klasse existiert if (!$initializerClassName->exists()) { return null; } // Prüfe Initializer Attribut return $this->checkInitializerAttribute($initializerClassName, $interface); } catch (\Throwable $e) { // Silently ignore errors } return null; } /** * Sucht nach Initializer im selben Ordner wie das Interface */ private function findInDirectory(string $interface): ?InitializerInfo { try { $interfaceName = ClassName::create($interface); $namespace = $interfaceName->getNamespaceObject(); $directoryPath = $this->namespaceToDirectoryPath($namespace); if ($directoryPath === null) { return null; } return $this->searchInPath(FilePath::create($directoryPath), $interface, false); } catch (\Throwable $e) { // Silently ignore errors } return null; } /** * Sucht nach Initializer in Unterordnern des Interface-Ordners */ private function findInSubdirectories(string $interface): ?InitializerInfo { try { $interfaceName = ClassName::create($interface); $namespace = $interfaceName->getNamespaceObject(); $directoryPath = $this->namespaceToDirectoryPath($namespace); if ($directoryPath === null) { return null; } return $this->searchInPath(FilePath::create($directoryPath), $interface, true); } catch (\Throwable $e) { // Silently ignore errors } return null; } /** * Sucht nach Initializer im ganzen Modul */ private function findInModule(string $interface): ?InitializerInfo { try { $interfaceName = ClassName::create($interface); $namespace = $interfaceName->getNamespaceObject(); // Bestimme Modul-Namespace (Parent-Namespace) $moduleNamespace = $namespace->parent(); if ($moduleNamespace === null) { return null; } $directoryPath = $this->namespaceToDirectoryPath($moduleNamespace); if ($directoryPath === null) { return null; } return $this->searchInPath(FilePath::create($directoryPath), $interface, true); } catch (\Throwable $e) { // Silently ignore errors } return null; } /** * Durchsucht einen Pfad nach Initializern */ private function searchInPath(FilePath $path, string $interface, bool $recursive): ?InitializerInfo { try { foreach ($this->fileScanner->streamFiles($path, FilePattern::php()) as $file) { $classes = $this->classExtractor->extractFromFile($file); foreach ($classes as $className) { if (!$className->exists()) { continue; } $initializerInfo = $this->checkInitializerAttribute($className, $interface); if ($initializerInfo !== null) { return $initializerInfo; } } } } catch (\Throwable $e) { // Silently ignore errors } return null; } /** * Prüft ob eine Klasse ein Initializer Attribut hat und das Interface zurückgibt */ private function checkInitializerAttribute(ClassName $className, string $interface): ?InitializerInfo { try { $reflection = $this->reflectionProvider->getClass($className); $methods = $reflection->getMethods(); foreach ($methods as $method) { // Prüfe ob Methode Initializer Attribut hat if (!$method->hasAttribute(Initializer::class)) { continue; } // Prüfe Return-Type $returnType = $method->getReturnType(); if ($returnType === null) { continue; } // Normalisiere Return-Type (entferne leading backslash, handle nullable) $returnType = ltrim($returnType, '\\?'); // Prüfe ob Return-Type das Interface ist if ($returnType !== $interface && $returnType !== '\\' . $interface) { continue; } // Gefunden! return new InitializerInfo( initializerClass: $className, methodName: MethodName::create($method->getName()), returnType: ClassName::create($interface) ); } } catch (\Throwable $e) { // Silently ignore errors } return null; } /** * Konvertiert einen PhpNamespace in ein Verzeichnis */ private function namespaceToDirectoryPath(PhpNamespace $namespace): ?string { // Nutze PathProvider um Namespace zu Pfad zu konvertieren $filePath = $this->pathProvider->namespaceToPath($namespace); if ($filePath === null) { return null; } // Entferne .php Extension und Dateiname - wir wollen das Verzeichnis return dirname($filePath); } }