chore: complete update

This commit is contained in:
2025-07-17 16:24:20 +02:00
parent 899227b0a4
commit 64a7051137
1300 changed files with 85570 additions and 2756 deletions

View File

@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace App\Framework\QueryBus;
use App\Framework\DI\DefaultContainer;
final readonly class DefaultQueryBus implements QueryBus
{
public function __construct(
private array $eventHandlers,
private DefaultContainer $container
) {}
/**
* Dispatcht ein Event an alle registrierten Handler
*
* @param object $event Das zu dispatchende Event
* @return void
*/
public function dispatch(object $event): mixed {
$eventClass = get_class($event);
// Prüfe, ob Handler für diesen Event-Typ registriert sind
if (empty($this->eventHandlers) || !isset($this->eventHandlers[$eventClass])) {
return null;
}
// Führe alle Handler für diesen Event-Typ aus
foreach ($this->eventHandlers[$eventClass] as $handler) {
try {
$handlerClass = $this->container->get($handler['class']);
$method = $handler['method'];
return $handlerClass->$method($event);
// Stoppe die Propagation, wenn der Handler dies anfordert
if (isset($handler['stopPropagation']) && $handler['stopPropagation']) {
break;
}
} catch (\Throwable $e) {
// Fehler in Event-Handlern sollten die Anwendung nicht abstürzen lassen
// In einer echten Anwendung würde hier ein Logger verwendet
error_log('Fehler bei der Ausführung des Event-Handlers: ' . $e->getMessage());
}
}
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace App\Framework\QueryBus;
interface QueryBus
{
public function dispatch(object $event): mixed;
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Framework\QueryBus;
use App\Framework\DI\Container;
use App\Framework\DI\Initializer;
use App\Framework\Discovery\Results\DiscoveryResults;
final readonly class QueryBusInitializer
{
public function __construct(
private Container $container,
private DiscoveryResults $results
){}
#[Initializer]
public function __invoke(): QueryBus
{
$handlers = $this->results->get(QueryHandler::class);
return new DefaultQueryBus($handlers, $this->container);
}
}

View File

@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace App\Framework\QueryBus;
/**
* Attribut, das eine Methode als Event-Handler kennzeichnet.
*
* Beispiel:
* #[EventHandler]
* public function handleUserRegistered(UserRegistered $event): void { ... }
*/
#[\Attribute(\Attribute::TARGET_METHOD)]
final readonly class QueryHandler
{
/**
* @param int|null $priority Priorität des Handlers (höhere Werte werden zuerst ausgeführt)
* @param bool $stopPropagation Gibt an, ob die Event-Propagation nach diesem Handler gestoppt werden soll
*/
public function __construct(
public ?int $priority = null,
public bool $stopPropagation = false
) {}
}

View File

@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
namespace App\Framework\QueryBus;
use App\Framework\Core\AttributeCompiler;
use App\Framework\QueryBus\QueryHandler;
/**
* Compiler für Event-Handler
*/
final readonly class QueryHandlerCompiler implements AttributeCompiler
{
/**
* Gibt die Attributklasse zurück, die dieser Compiler verarbeitet
*/
public function getAttributeClass(): string
{
return QueryHandler::class;
}
/**
* Kompiliert die Event-Handler
*
* @param array $handlers Array mit Attributdaten aus dem Mapper
* @return array Kompilierte Event-Handler
*/
public function compile(array $handlers): array
{
$compiledHandlers = [];
// Wenn keine Handler vorhanden sind, leeres Array zurückgeben
if (empty($handlers)) {
return $compiledHandlers;
}
foreach ($handlers as $handler) {
$className = $handler['class'] ?? null;
$methodName = $handler['method'] ?? null;
$eventClass = $handler['event_class'] ?? null;
$priority = $handler['attribute_data']['priority'] ?? 0;
$stopPropagation = $handler['attribute_data']['stopPropagation'] ?? false;
// Prüfe, ob alle erforderlichen Daten vorhanden sind
if (!$className || !$methodName || !$eventClass) {
continue;
}
// Füge den Handler zur Liste der Handler für diesen Event-Typ hinzu
if (!isset($compiledHandlers[$eventClass])) {
$compiledHandlers[$eventClass] = [];
}
$compiledHandlers[$eventClass][] = [
'class' => $className,
'method' => $methodName,
'priority' => $priority,
'stopPropagation' => $stopPropagation
];
}
// Sortiere die Handler nach Priorität für jeden Event-Typ
foreach ($compiledHandlers as $eventClass => $eventHandlers) {
usort($compiledHandlers[$eventClass], function ($a, $b) {
return $b['priority'] <=> $a['priority'];
});
}
return $compiledHandlers;
}
}

View File

@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace App\Framework\QueryBus;
use App\Framework\Core\AttributeMapper;
use ReflectionClass;
use ReflectionMethod;
/**
* Mapper für das EventHandler-Attribut
*/
final class QueryHandlerMapper implements AttributeMapper
{
/**
* Gibt die Attributklasse zurück, die dieser Mapper verarbeitet
*/
public function getAttributeClass(): string
{
return QueryHandler::class;
}
/**
* Implementiert die map-Methode aus dem AttributeMapper-Interface
*
* @param object $reflectionTarget Das Reflektionsobjekt (ReflectionClass|ReflectionMethod)
* @param object $attributeInstance Die Attributinstanz
* @return array|null Die Attributdaten oder null, wenn nicht verarbeitet werden kann
*/
public function map(object $reflectionTarget, object $attributeInstance): ?array
{
if (!($reflectionTarget instanceof ReflectionMethod)) {
return null;
}
$parameters = $reflectionTarget->getParameters();
// Event-Handler müssen mindestens einen Parameter haben (das Event)
if (count($parameters) < 1) {
return null;
}
$eventType = $parameters[0]->getType();
if (!$eventType || $eventType->isBuiltin()) {
return null;
}
$eventClassName = $eventType->getName();
return [
'class' => $reflectionTarget->getDeclaringClass()->getName(),
'method' => $reflectionTarget->getName(),
'event_class' => $eventClassName,
'attribute_data' => [
'priority' => $attributeInstance->priority ?? 0,
'stopPropagation' => $attributeInstance->stopPropagation ?? false
],
];
}
}