Files
michaelschiemer/src/Framework/Attributes/Execution/HandlerAttributeExecutor.php
2025-11-24 21:28:25 +01:00

193 lines
5.7 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\Attributes\Execution;
use App\Framework\Core\ValueObjects\ClassName;
use App\Framework\Core\ValueObjects\MethodName;
use App\Framework\DI\Container;
use App\Framework\Discovery\Results\DiscoveryRegistry;
use ReflectionMethod;
/**
* Handler Attribute Executor - Führt Attribute auf Handler-Methoden aus
*
* Speziell für Command/Query-Handler optimiert.
* Unterstützt Before/After/OnError Attribute.
*/
final readonly class HandlerAttributeExecutor
{
public function __construct(
private DiscoveryRegistry $discoveryRegistry,
private Container $container,
private AttributeRunner $attributeRunner
) {
}
/**
* Führt "Before"-Attribute für einen Handler aus
*
* @param string $handlerClass Handler-Klasse
* @param string $handlerMethod Handler-Methode
* @param object $command Command/Query-Objekt
*/
public function executeBefore(
string $handlerClass,
string $handlerMethod,
object $command
): void {
$this->executeHandlerAttributes(
$handlerClass,
$handlerMethod,
BeforeExecute::class,
$command
);
}
/**
* Führt "After"-Attribute für einen Handler aus
*
* @param string $handlerClass Handler-Klasse
* @param string $handlerMethod Handler-Methode
* @param object $command Command/Query-Objekt
* @param mixed $result Ergebnis der Handler-Ausführung
*/
public function executeAfter(
string $handlerClass,
string $handlerMethod,
object $command,
mixed $result
): void {
$context = AttributeExecutionContext::forMethod(
$this->container,
ClassName::create($handlerClass),
MethodName::create($handlerMethod)
);
// Füge Result zum Context hinzu
$context = new AttributeExecutionContext(
container: $context->container,
targetClass: $context->targetClass,
targetMethod: $context->targetMethod,
targetProperty: $context->targetProperty,
targetValue: $result,
additionalData: array_merge($context->additionalData, [
'command' => $command,
'result' => $result,
])
);
$this->executeHandlerAttributesForContext(
$handlerClass,
$handlerMethod,
AfterExecute::class,
$context
);
}
/**
* Führt "OnError"-Attribute für einen Handler aus
*
* @param string $handlerClass Handler-Klasse
* @param string $handlerMethod Handler-Methode
* @param object $command Command/Query-Objekt
* @param \Throwable $exception Aufgetretene Exception
*/
public function executeOnError(
string $handlerClass,
string $handlerMethod,
object $command,
\Throwable $exception
): void {
$context = AttributeExecutionContext::forMethod(
$this->container,
ClassName::create($handlerClass),
MethodName::create($handlerMethod)
);
// Füge Exception zum Context hinzu
$context = new AttributeExecutionContext(
container: $context->container,
targetClass: $context->targetClass,
targetMethod: $context->targetMethod,
targetProperty: $context->targetProperty,
targetValue: null,
additionalData: array_merge($context->additionalData, [
'command' => $command,
'exception' => $exception,
])
);
$this->executeHandlerAttributesForContext(
$handlerClass,
$handlerMethod,
OnError::class,
$context
);
}
/**
* Führt Attribute eines bestimmten Typs für einen Handler aus
*/
private function executeHandlerAttributes(
string $handlerClass,
string $handlerMethod,
string $attributeClass,
object $command
): void {
$context = AttributeExecutionContext::forMethod(
$this->container,
ClassName::create($handlerClass),
MethodName::create($handlerMethod)
);
// Füge Command zum Context hinzu
$context = new AttributeExecutionContext(
container: $context->container,
targetClass: $context->targetClass,
targetMethod: $context->targetMethod,
targetProperty: $context->targetProperty,
targetValue: $command,
additionalData: array_merge($context->additionalData, [
'command' => $command,
])
);
$this->executeHandlerAttributesForContext(
$handlerClass,
$handlerMethod,
$attributeClass,
$context
);
}
/**
* Führt Attribute für einen Handler mit gegebenem Context aus
*/
private function executeHandlerAttributesForContext(
string $handlerClass,
string $handlerMethod,
string $attributeClass,
AttributeExecutionContext $context
): void {
$attributes = $this->discoveryRegistry->attributes->get($attributeClass);
foreach ($attributes as $discovered) {
// Prüfe ob Attribut zu diesem Handler gehört
if (!$discovered->className->equals(ClassName::create($handlerClass))) {
continue;
}
if ($discovered->methodName === null ||
!$discovered->methodName->equals(MethodName::create($handlerMethod))) {
continue;
}
// Führe Attribut aus
$this->attributeRunner->executeAttribute($discovered, $context);
}
}
}