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

@@ -0,0 +1,168 @@
<?php
declare(strict_types=1);
namespace App\Framework\Discovery;
use App\Framework\Context\ContextType;
use App\Framework\Context\ExecutionContext;
use App\Framework\Core\ValueObjects\ClassName;
use App\Framework\Core\ValueObjects\MethodName;
use App\Framework\DI\Container;
use App\Framework\DI\Initializer;
use App\Framework\DI\InitializerDependencyGraph;
use App\Framework\DI\ValueObjects\DependencyGraphNode;
use App\Framework\Discovery\Results\DiscoveryRegistry;
use App\Framework\Reflection\ReflectionProvider;
/**
* Processes and executes Initializers discovered by the Discovery system
*
* Handles context filtering, dependency graph construction, and lazy service registration.
* Separated from DiscoveryServiceBootstrapper for Single Responsibility Principle.
*/
final readonly class InitializerProcessor
{
public function __construct(
private Container $container,
private ReflectionProvider $reflectionProvider,
private ExecutionContext $executionContext,
) {
}
/**
* Intelligente Initializer-Verarbeitung mit Dependency-Graph:
* - Context-Filter: Nur für passende Execution-Contexts
* - void/null Return: Sofort ausführen (Setup)
* - Konkreter Return-Type: Dependency-Graph basierte Registrierung
*/
public function processInitializers(DiscoveryRegistry $results): void
{
$initializerResults = $results->attributes->get(Initializer::class);
$dependencyGraph = new InitializerDependencyGraph($this->reflectionProvider);
// Phase 1: Setup-Initializer sofort ausführen & Service-Initializer zum Graph hinzufügen
foreach ($initializerResults as $discoveredAttribute) {
/** @var Initializer $initializer */
$initializer = $discoveredAttribute->createAttributeInstance();
// Get mapped data from additionalData (was mappedData in AttributeMapping)
$initializerData = $discoveredAttribute->additionalData;
// The actual initializer data is in the additionalData from the InitializerMapper
if (! $initializerData) {
continue;
}
// Context-Filter: Prüfe ob Initializer für aktuellen Context erlaubt ist
// The contexts data is directly in the additionalData
// Wenn contexts null ist, ist der Initializer für alle Contexts verfügbar
if (isset($initializerData['contexts']) && $initializerData['contexts'] !== null && ! $this->isContextAllowed(...$initializerData['contexts'])) {
continue;
}
$methodName = $discoveredAttribute->methodName ?? MethodName::invoke();
// The return type is directly in the additionalData from the InitializerMapper
$returnType = $initializerData['return'] ?? null;
try {
// Setup-Initializer: void/null Return → Sofort ausführen
if ($returnType === null || $returnType === 'void') {
$this->container->invoker->invoke($discoveredAttribute->className, $methodName->toString());
}
// Service-Initializer: Konkreter Return-Type → Zum Dependency-Graph hinzufügen
else {
$dependencyGraph->addInitializer($returnType, $discoveredAttribute->className, $methodName);
}
} catch (\Throwable $e) {
// Skip failed initializers
}
}
// Phase 2: Service-Initializer in optimaler Reihenfolge registrieren
$this->registerServicesWithDependencyGraph($dependencyGraph);
}
/**
* Registriert Services basierend auf Dependency-Graph in optimaler Reihenfolge
*/
private function registerServicesWithDependencyGraph(InitializerDependencyGraph $graph): void
{
try {
$executionOrder = $graph->getExecutionOrder();
foreach ($executionOrder as $returnType) {
if ($graph->hasNode($returnType)) {
/** @var DependencyGraphNode $node */
$node = $graph->getNode($returnType);
$this->registerLazyService(
$returnType,
$node->getClassName(),
$node->getMethodName()
);
}
}
} catch (\Throwable $e) {
// Fallback: Registriere alle Services ohne spezielle Reihenfolge
/** @var string $returnType */
foreach ($graph->getNodes() as $returnType => $node) {
$this->registerLazyService(
$returnType,
$node->getClassName(),
$node->getMethodName()
);
}
}
unset($graph);
}
/**
* Prüft ob ein Initializer im aktuellen Context ausgeführt werden darf
*/
private function isContextAllowed(mixed ...$contexts): bool
{
$currentContext = $this->executionContext->getType();
foreach ($contexts as $context) {
// Handle both ContextType objects and string values (from cache deserialization)
if ($context instanceof ContextType) {
if ($currentContext === $context) {
return true;
}
} elseif (is_string($context)) {
if ($currentContext->value === $context) {
return true;
}
}
}
return false;
}
/**
* Registriert einen Service lazy im Container mit Dual-Registration für Interfaces
*/
private function registerLazyService(string $returnType, string $className, string $methodName): void
{
$factory = function ($container) use ($className, $methodName, $returnType) {
$instance = $container->invoker->invoke(ClassName::create($className), $methodName);
// Wenn das ein Interface ist, registriere auch die konkrete Klasse automatisch
if (interface_exists($returnType)) {
$concreteClass = get_class($instance);
if (! $container->has($concreteClass)) {
$container->instance($concreteClass, $instance);
}
}
return $instance;
};
// Registriere den Return-Type (Interface oder konkrete Klasse)
$this->container->singleton($returnType, $factory);
}
}