Enable Discovery debug logging for production troubleshooting

- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
2025-08-11 20:13:26 +02:00
parent 59fd3dd3b1
commit 55a330b223
3683 changed files with 2956207 additions and 16948 deletions

View File

@@ -1,25 +1,34 @@
<?php
declare(strict_types=1);
namespace App\Framework\Core;
use App\Framework\Cache\Cache;
use App\Framework\Cache\CacheKey;
use App\Framework\Core\ValueObjects\ClassName;
use App\Framework\Discovery\FileVisitor;
use App\Framework\Discovery\ReflectionAwareVisitor;
use App\Framework\Filesystem\FilePath;
use App\Framework\Reflection\WrappedReflectionClass;
/**
* Visitor zum Auffinden von Interface-Implementierungen
*/
final class InterfaceImplementationVisitor implements FileVisitor
final class InterfaceImplementationVisitor implements FileVisitor, ReflectionAwareVisitor
{
private array $interfaces = [];
private array $implementations = [];
private array $implementationsByClass = [];
/**
* @param array $targetInterfaces Die zu suchenden Interfaces
*/
public function __construct(private readonly array $targetInterfaces = [])
{
public function __construct(
private readonly array $targetInterfaces = []
) {
}
public function onScanStart(): void
@@ -40,44 +49,46 @@ final class InterfaceImplementationVisitor implements FileVisitor
$this->sortImplementations();
}
public function visitClass(string $className, string $filePath): void
public function visitClass(ClassName $className, FilePath $filePath): void
{
if (!class_exists($className)) {
return;
}
// This method is kept for backward compatibility but should not be used
// when ReflectionProvider is available. The UnifiedDiscoveryService will
// prefer visitClassWithReflection() when possible.
}
public function visitClassWithReflection(ClassName $className, FilePath $filePath, WrappedReflectionClass $reflection): void
{
try {
$reflection = new \ReflectionClass($className);
// Abstrakte Klassen und Interfaces überspringen
if ($reflection->isAbstract() || $reflection->isInterface()) {
// Skip abstract classes and interfaces - only process instantiable classes
if (! $reflection->isInstantiable()) {
return;
}
// Alte Einträge für diese Klasse entfernen (wichtig für inkrementelle Scans)
$this->removeImplementationsForClass($className);
$classNameStr = $className->getFullyQualified();
$this->removeImplementationsForClass($classNameStr);
// Prüfe, ob die Klasse eines der Ziel-Interfaces implementiert
foreach ($this->targetInterfaces as $interface) {
if ($reflection->implementsInterface($interface)) {
if (!isset($this->implementations[$interface])) {
if (! isset($this->implementations[$interface])) {
$this->implementations[$interface] = [];
}
// Prüfe auf Duplikate
if (!in_array($className, $this->implementations[$interface])) {
$this->implementations[$interface][] = $className;
if (! in_array($classNameStr, $this->implementations[$interface])) {
$this->implementations[$interface][] = $classNameStr;
// Umgekehrten Index für schnelleren Zugriff aufbauen
if (!isset($this->implementationsByClass[$className])) {
$this->implementationsByClass[$className] = [];
if (! isset($this->implementationsByClass[$classNameStr])) {
$this->implementationsByClass[$classNameStr] = [];
}
$this->implementationsByClass[$className][] = $interface;
$this->implementationsByClass[$classNameStr][] = $interface;
}
}
}
} catch (\Throwable $e) {
error_log("Fehler beim Prüfen der Interface-Implementierung für {$className}: " . $e->getMessage());
// Silent failure - skip this class and continue with discovery
}
}
@@ -86,7 +97,7 @@ final class InterfaceImplementationVisitor implements FileVisitor
*/
private function removeImplementationsForClass(string $className): void
{
if (!isset($this->implementationsByClass[$className])) {
if (! isset($this->implementationsByClass[$className])) {
return;
}
@@ -131,16 +142,16 @@ final class InterfaceImplementationVisitor implements FileVisitor
}
}
public function getCacheKey(): string
public function getCacheKey(): CacheKey
{
return 'interface_implementations';
return CacheKey::fromString('interface_implementations');
}
public function getCacheableData(): mixed
public function getCacheableData(): array
{
return [
'implementations' => $this->implementations,
'byClass' => $this->implementationsByClass
'byClass' => $this->implementationsByClass,
];
}