From 7d571b684b422d6a787ead80b72303de1940f70e Mon Sep 17 00:00:00 2001 From: David Badura Date: Wed, 27 Mar 2024 12:32:14 +0100 Subject: [PATCH] upgrade event sourcing lib --- config/routes.yaml | 34 +++++++----- src/Controller/EventController.php | 29 +++++----- src/Controller/InspectionController.php | 5 +- ...troller.php => SubscriptionController.php} | 31 +++++++---- src/Decorator/RequestIdDecorator.php | 2 + .../PatchlevelEventSourcingAdminExtension.php | 4 +- src/Twig/EventSourcingAdminExtension.php | 7 ++- templates/event/index.html.twig | 20 ++----- templates/inspection/show.html.twig | 6 +- templates/layout.html.twig | 2 +- templates/store/detail.html.twig | 16 ++++-- templates/store/show.html.twig | 21 ++++--- .../detail.html.twig | 22 ++++---- .../show.html.twig | 55 ++++++++++--------- 14 files changed, 137 insertions(+), 117 deletions(-) rename src/Controller/{ProjectionController.php => SubscriptionController.php} (83%) rename templates/{projection => subscription}/detail.html.twig (80%) rename templates/{projection => subscription}/show.html.twig (81%) diff --git a/config/routes.yaml b/config/routes.yaml index b31f367..e6344f5 100644 --- a/config/routes.yaml +++ b/config/routes.yaml @@ -10,25 +10,29 @@ patchlevel_event_sourcing_admin_store_show: path: /store controller: Patchlevel\EventSourcingAdminBundle\Controller\StoreController::showAction -patchlevel_event_sourcing_admin_projection_show: - path: /projection - controller: Patchlevel\EventSourcingAdminBundle\Controller\ProjectionController::showAction +patchlevel_event_sourcing_admin_subscription_show: + path: /subscription + controller: Patchlevel\EventSourcingAdminBundle\Controller\SubscriptionController::showAction -patchlevel_eventsourcingadmin_projection_rebuild: - path: /projection/{id}/rebuild - controller: Patchlevel\EventSourcingAdminBundle\Controller\ProjectionController::rebuildAction +patchlevel_eventsourcingadmin_subscription_rebuild: + path: /subscription/{id}/rebuild + controller: Patchlevel\EventSourcingAdminBundle\Controller\SubscriptionController::rebuildAction -patchlevel_eventsourcingadmin_projection_pause: - path: /projection/{id}/pause - controller: Patchlevel\EventSourcingAdminBundle\Controller\ProjectionController::pauseAction +patchlevel_eventsourcingadmin_subscription_pause: + path: /subscription/{id}/pause + controller: Patchlevel\EventSourcingAdminBundle\Controller\SubscriptionController::pauseAction -patchlevel_eventsourcingadmin_projection_reactivate: - path: /projection/{id}/reactivate - controller: Patchlevel\EventSourcingAdminBundle\Controller\ProjectionController::reactivateAction +patchlevel_eventsourcingadmin_subscription_setup: + path: /subscription/{id}/setup + controller: Patchlevel\EventSourcingAdminBundle\Controller\SubscriptionController::setupAction -patchlevel_eventsourcingadmin_projection_remove: - path: /projection/{id}/remove - controller: Patchlevel\EventSourcingAdminBundle\Controller\ProjectionController::removeAction +patchlevel_eventsourcingadmin_subscription_reactivate: + path: /subscription/{id}/reactivate + controller: Patchlevel\EventSourcingAdminBundle\Controller\SubscriptionController::reactivateAction + +patchlevel_eventsourcingadmin_subscription_remove: + path: /subscription/{id}/remove + controller: Patchlevel\EventSourcingAdminBundle\Controller\SubscriptionController::removeAction patchlevel_event_sourcing_admin_inspection_index: path: /inspection diff --git a/src/Controller/EventController.php b/src/Controller/EventController.php index 6ff0535..9fd2258 100644 --- a/src/Controller/EventController.php +++ b/src/Controller/EventController.php @@ -8,24 +8,22 @@ use Patchlevel\EventSourcing\EventBus\ListenerDescriptor; use Patchlevel\EventSourcing\EventBus\ListenerProvider; use Patchlevel\EventSourcing\Metadata\Event\EventRegistry; -use Patchlevel\EventSourcing\Metadata\Projector\ProjectorMetadataFactory; +use Patchlevel\EventSourcing\Metadata\Subscriber\SubscriberMetadataFactory; use Patchlevel\EventSourcingAdminBundle\Projection\Node; -use Patchlevel\EventSourcingAdminBundle\Projection\TraceProjector; use Symfony\Component\HttpFoundation\Response; use Twig\Environment; final class EventController { /** - * @param iterable $projectors + * @param iterable $subscribers */ public function __construct( - private readonly Environment $twig, - private readonly EventRegistry $eventRegistry, - private readonly ListenerProvider $listenerProvider, - private readonly iterable $projectors, - private readonly ProjectorMetadataFactory $projectorMetadataFactory, - private readonly TraceProjector|null $traceProjector, + private readonly Environment $twig, + private readonly EventRegistry $eventRegistry, + private readonly ListenerProvider $listenerProvider, + private readonly iterable $subscribers, + private readonly SubscriberMetadataFactory $subscriberMetadataFactory, ) { } @@ -39,8 +37,7 @@ public function indexAction(): Response 'name' => $eventName, 'class' => $eventClass, 'listeners' => $this->listenerMethods($eventClass), - 'projectors' => $this->projectorsMethods($eventClass), - 'sources' => $this->source($eventClass), + 'subscribers' => $this->subscribersMethods($eventClass), ]; } @@ -57,22 +54,22 @@ private function listenerMethods(string $eventClass): array ); } - private function projectorsMethods(string $eventClass): array + private function subscribersMethods(string $eventClass): array { $result = []; - foreach ($this->projectors as $projector) { - $metadata = $this->projectorMetadataFactory->metadata($projector::class); + foreach ($this->subscribers as $subscriber) { + $metadata = $this->subscriberMetadataFactory->metadata($subscriber::class); if (array_key_exists($eventClass, $metadata->subscribeMethods)) { foreach ($metadata->subscribeMethods[$eventClass] as $method) { - $result[] = sprintf('%s::%s', $projector::class, $method); + $result[] = sprintf('%s::%s', $subscriber::class, $method->name); } } if (array_key_exists(Subscribe::ALL, $metadata->subscribeMethods)) { foreach ($metadata->subscribeMethods[Subscribe::ALL] as $method) { - $result[] = sprintf('%s::%s', $projector::class, $method); + $result[] = sprintf('%s::%s', $subscriber::class, $method->name); } } } diff --git a/src/Controller/InspectionController.php b/src/Controller/InspectionController.php index 558bbd7..ff64031 100644 --- a/src/Controller/InspectionController.php +++ b/src/Controller/InspectionController.php @@ -4,6 +4,7 @@ namespace Patchlevel\EventSourcingAdminBundle\Controller; +use Patchlevel\EventSourcing\Aggregate\AggregateHeader; use Patchlevel\EventSourcing\Aggregate\AggregateRoot; use Patchlevel\EventSourcing\Aggregate\CustomId; use Patchlevel\EventSourcing\Metadata\AggregateRoot\AggregateRootMetadataFactory; @@ -158,7 +159,7 @@ private function aggregate(string $aggregateName, string $aggregateId, int|null return $aggregateClass::createFromEvents( $this->unpack($stream, $until), - $firstMessage->playhead() - 1, + $firstMessage->header(AggregateHeader::class)->playhead - 1, ); } finally { $stream?->close(); @@ -169,7 +170,7 @@ private function aggregate(string $aggregateName, string $aggregateId, int|null private function unpack(Stream $stream, int|null $until = null): Traversable { foreach ($stream as $message) { - if ($until !== null && $message->playhead() > $until) { + if ($until !== null && $message->header(AggregateHeader::class)->playhead > $until) { break; } diff --git a/src/Controller/ProjectionController.php b/src/Controller/SubscriptionController.php similarity index 83% rename from src/Controller/ProjectionController.php rename to src/Controller/SubscriptionController.php index b73d0e0..8670e20 100644 --- a/src/Controller/ProjectionController.php +++ b/src/Controller/SubscriptionController.php @@ -15,7 +15,7 @@ use Symfony\Component\Routing\RouterInterface; use Twig\Environment; -final class ProjectionController +final class SubscriptionController { public function __construct( private readonly Environment $twig, @@ -36,7 +36,7 @@ public function showAction(Request $request): Response $groups[$subscription->group()] = true; } - $filteredProjections = []; + $filteredSubscriptions = []; $search = $request->get('search'); $group = $request->get('group'); $mode = $request->get('mode'); @@ -60,12 +60,12 @@ public function showAction(Request $request): Response continue; } - $filteredProjections[] = $subscription; + $filteredSubscriptions[] = $subscription; } return new Response( - $this->twig->render('@PatchlevelEventSourcingAdmin/projection/show.html.twig', [ - 'projections' => $filteredProjections, + $this->twig->render('@PatchlevelEventSourcingAdmin/subscription/show.html.twig', [ + 'subscriptions' => $filteredSubscriptions, 'messageCount' => $messageCount, 'statuses' => array_map(fn (Status $status) => $status->value, Status::cases()), 'modes' => array_map(fn (RunMode $mode) => $mode->value, RunMode::cases()), @@ -82,7 +82,7 @@ public function rebuildAction(string $id): Response $this->engine->boot($criteria); return new RedirectResponse( - $this->router->generate('patchlevel_event_sourcing_admin_projection_show'), + $this->router->generate('patchlevel_event_sourcing_admin_subscription_show'), ); } @@ -93,7 +93,7 @@ public function pauseAction(string $id): Response $this->engine->pause($criteria); return new RedirectResponse( - $this->router->generate('patchlevel_event_sourcing_admin_projection_show'), + $this->router->generate('patchlevel_event_sourcing_admin_subscription_show'), ); } @@ -104,7 +104,18 @@ public function bootAction(string $id): Response $this->engine->boot($criteria); return new RedirectResponse( - $this->router->generate('patchlevel_event_sourcing_admin_projection_show'), + $this->router->generate('patchlevel_event_sourcing_admin_subscription_show'), + ); + } + + public function setupAction(string $id): Response + { + $criteria = new SubscriptionEngineCriteria([$id]); + + $this->engine->setup($criteria); + + return new RedirectResponse( + $this->router->generate('patchlevel_event_sourcing_admin_subscription_show'), ); } @@ -115,7 +126,7 @@ public function reactivateAction(string $id): Response $this->engine->reactivate($criteria); return new RedirectResponse( - $this->router->generate('patchlevel_event_sourcing_admin_projection_show'), + $this->router->generate('patchlevel_event_sourcing_admin_subscription_show'), ); } @@ -126,7 +137,7 @@ public function removeAction(string $id): Response $this->engine->remove($criteria); return new RedirectResponse( - $this->router->generate('patchlevel_event_sourcing_admin_projection_show'), + $this->router->generate('patchlevel_event_sourcing_admin_subscription_show'), ); } } diff --git a/src/Decorator/RequestIdDecorator.php b/src/Decorator/RequestIdDecorator.php index 64cbb60..782c805 100644 --- a/src/Decorator/RequestIdDecorator.php +++ b/src/Decorator/RequestIdDecorator.php @@ -17,6 +17,8 @@ public function __construct( public function __invoke(Message $message): Message { + return $message; + $request = $this->requestStack->getMainRequest(); if (!$request) { diff --git a/src/DependencyInjection/PatchlevelEventSourcingAdminExtension.php b/src/DependencyInjection/PatchlevelEventSourcingAdminExtension.php index 4dece91..502cf5e 100644 --- a/src/DependencyInjection/PatchlevelEventSourcingAdminExtension.php +++ b/src/DependencyInjection/PatchlevelEventSourcingAdminExtension.php @@ -17,7 +17,7 @@ use Patchlevel\EventSourcingAdminBundle\Controller\EventController; use Patchlevel\EventSourcingAdminBundle\Controller\GraphController; use Patchlevel\EventSourcingAdminBundle\Controller\InspectionController; -use Patchlevel\EventSourcingAdminBundle\Controller\ProjectionController; +use Patchlevel\EventSourcingAdminBundle\Controller\SubscriptionController; use Patchlevel\EventSourcingAdminBundle\Controller\StoreController; use Patchlevel\EventSourcingAdminBundle\Decorator\RequestIdDecorator; use Patchlevel\EventSourcingAdminBundle\Listener\RequestIdListener; @@ -82,7 +82,7 @@ public function load(array $configs, ContainerBuilder $container): void ]) ->addTag('controller.service_arguments'); - $container->register(ProjectionController::class) + $container->register(SubscriptionController::class) ->setArguments([ new Reference('twig'), new Reference(SubscriptionEngine::class), diff --git a/src/Twig/EventSourcingAdminExtension.php b/src/Twig/EventSourcingAdminExtension.php index f227a62..ad5c419 100644 --- a/src/Twig/EventSourcingAdminExtension.php +++ b/src/Twig/EventSourcingAdminExtension.php @@ -4,7 +4,8 @@ namespace Patchlevel\EventSourcingAdminBundle\Twig; -use Patchlevel\EventSourcing\EventBus\Message; +use Patchlevel\EventSourcing\Aggregate\AggregateHeader; +use Patchlevel\EventSourcing\Message\Message; use Patchlevel\EventSourcing\Metadata\AggregateRoot\AggregateRootRegistry; use Patchlevel\EventSourcing\Metadata\Event\EventRegistry; use Patchlevel\EventSourcing\Serializer\Encoder\JsonEncoder; @@ -50,7 +51,7 @@ public function shortId(string $id): string /** @return class-string */ public function aggregateClass(Message $message): string { - return $this->aggregateRootRegistry->aggregateClass($message->aggregateName()); + return $this->aggregateRootRegistry->aggregateClass($message->header(AggregateHeader::class)->aggregateName); } /** @return class-string */ @@ -76,6 +77,8 @@ public function eventPayload(Message $message): string public function profilerToken(Message $message): ?string { + return null; + $headers = $message->customHeaders(); $requestId = $headers['requestId'] ?? null; diff --git a/templates/event/index.html.twig b/templates/event/index.html.twig index 481859e..7d7fd22 100644 --- a/templates/event/index.html.twig +++ b/templates/event/index.html.twig @@ -64,26 +64,14 @@
- Sources ({{ event.sources|length }}) + Projectors ({{ event.subscribers|length }})
    - {% for node in event.sources|sort((a, b) => a.name <=> b.name)|sort((a, b) => a.category <=> b.category) %} - {{ _self.node(node) }} + {% for subscriber in event.subscribers %} + {{ _self.subscriber(subscriber) }} {% else %} -
  • unknown sources
  • - {% endfor %} -
- -
- Projectors ({{ event.projectors|length }}) -
- -
    - {% for projector in event.projectors %} - {{ _self.subscriber(projector) }} - {% else %} -
  • no projectors
  • +
  • no subscriber
  • {% endfor %}
diff --git a/templates/inspection/show.html.twig b/templates/inspection/show.html.twig index c0f6f5a..7912670 100644 --- a/templates/inspection/show.html.twig +++ b/templates/inspection/show.html.twig @@ -158,6 +158,8 @@
- {{ _self.text('Aggregate Playhead', message.playhead) }} + {{ _self.text('Aggregate Playhead', aggregateHeader.playhead) }}
Event Name
@@ -34,7 +36,7 @@
- {{ _self.text('Recorded on', message.recordedOn|date('Y-m-d H:i:s')) }} + {{ _self.text('Recorded on', aggregateHeader.recordedOn|date('Y-m-d H:i:s')) }}
Profiler Token
@@ -49,7 +51,9 @@
{{ _self.json('Event Payload', eventsourcing_event_payload(message)) }} - {% if message.customHeaders %} + + + {% if message.customHeaders|default(false) %} {{ _self.json('Custom Headers', message.customHeaders|json_encode(constant('JSON_PRETTY_PRINT'))) }} {% else %} {{ _self.text('Custom Headers', '-') }} diff --git a/templates/store/show.html.twig b/templates/store/show.html.twig index 4032b8a..8498b92 100644 --- a/templates/store/show.html.twig +++ b/templates/store/show.html.twig @@ -78,31 +78,33 @@ {% for message in messages %} + {% set aggregateHeader = message.header("Patchlevel\\EventSourcing\\Aggregate\\AggregateHeader") %} + {{ messages.index }} - {{ message.aggregateName }} - - - {{ eventsourcing_short_id(message.aggregateId) }} - + {{ eventsourcing_short_id(aggregateHeader.aggregateId) }} + - - - {{ message.playhead }} + {{ aggregateHeader.playhead }} {{ eventsourcing_event_name(message) }} - {{ message.recordedOn|date('Y-m-d H:i:s') }} + {{ aggregateHeader.recordedOn|date('Y-m-d H:i:s') }} @@ -127,6 +129,7 @@ {{ include('@PatchlevelEventSourcingAdmin/store/detail.html.twig', { message: message, }) }} + diff --git a/templates/projection/detail.html.twig b/templates/subscription/detail.html.twig similarity index 80% rename from templates/projection/detail.html.twig rename to templates/subscription/detail.html.twig index 124b8d4..ad8d616 100644 --- a/templates/projection/detail.html.twig +++ b/templates/subscription/detail.html.twig @@ -1,18 +1,18 @@
- {{ _self.text('ID', projection.id) }} - {{ _self.text('Group', projection.group) }} - {{ _self.text('Run mode', projection.runMode.value|replace({'_': ' '})) }} + {{ _self.text('ID', subscription.id) }} + {{ _self.text('Group', subscription.group) }} + {{ _self.text('Run mode', subscription.runMode.value|replace({'_': ' '})) }} {# { _self.text('Class', 'unknown') } #} - {{ _self.text('Position', projection.position) }} - {{ _self.text('Status', projection.status.value) }} + {{ _self.text('Position', subscription.position) }} + {{ _self.text('Status', subscription.status.value) }} - {{ _self.text('Retry attempt', projection.retryAttempt) }} + {{ _self.text('Retry attempt', subscription.retryAttempt) }} - {{ _self.text('Updated at', projection.lastSavedAt|date('Y-m-d H:i:s')) }} + {{ _self.text('Updated at', subscription.lastSavedAt|date('Y-m-d H:i:s')) }} - {% if projection.projectionError %} - {% if projection.projectionError.errorContext %} - {% for context in projection.projectionError.errorContext %} + {% if subscription.subscriptionError %} + {% if subscription.subscriptionError.errorContext %} + {% for context in subscription.subscriptionError.errorContext %}
@@ -51,7 +51,7 @@ {{ heroicon('exclamation-circle', class='h-5 w-5 text-red-800') }}
-

{{ projection.projectionError.errorMessage }}

+

{{ subscription.subscriptionError.errorMessage }}

diff --git a/templates/projection/show.html.twig b/templates/subscription/show.html.twig similarity index 81% rename from templates/projection/show.html.twig rename to templates/subscription/show.html.twig index 152a5f5..aeec54e 100644 --- a/templates/projection/show.html.twig +++ b/templates/subscription/show.html.twig @@ -5,11 +5,11 @@
- Projections + Subscriptions
-
+
@@ -71,7 +71,7 @@ {% if app.request.get('search') or app.request.get('group') or app.request.get('mode') or app.request.get('status') %} + href="{{ path('patchlevel_event_sourcing_admin_subscription_show') }}"> {{ heroicon('backspace', 'h-6 w-6') }} {% endif %} @@ -109,39 +109,39 @@ - {% for projection in projections|sort((a, b) => a.id <=> b.id) %} + {% for subscription in subscriptions|sort((a, b) => a.id <=> b.id) %} - {{ projection.id }} + {{ subscription.id }} - {{ projection.group }} + {{ subscription.group }} - {{ projection.runMode.value|replace({'_': ' '}) }} + {{ subscription.runMode.value|replace({'_': ' '}) }} - - {{ projection.position }} + + {{ subscription.position }} - {% if projection.status.value == 'new' %} + {% if subscription.status.value == 'new' %} {{ _self.badge('New', 'fill-blue-500') }} - {% elseif projection.status.value == 'booting' %} + {% elseif subscription.status.value == 'booting' %} {{ _self.badge('Booting', 'fill-yellow-500') }} - {% elseif projection.status.value == 'active' %} + {% elseif subscription.status.value == 'active' %} {{ _self.badge('Active', 'fill-green-500') }} - {% elseif projection.status.value == 'finished' %} + {% elseif subscription.status.value == 'finished' %} {{ _self.badge('Finished', 'fill-green-500') }} - {% elseif projection.status.value == 'paused' %} + {% elseif subscription.status.value == 'paused' %} {{ _self.badge('Paused', 'fill-gray-500') }} - {% elseif projection.status.value == 'outdated' %} + {% elseif subscription.status.value == 'outdated' %} {{ _self.badge('Outdated', 'fill-gray-500') }} - {% elseif projection.status.value == 'error' %} + {% elseif subscription.status.value == 'error' %} {{ _self.badge('Error', 'fill-red-500') }} {% endif %} - {{ projection.lastSavedAt|date('Y-m-d H:i:s') }} + {{ subscription.lastSavedAt|date('Y-m-d H:i:s') }} - {{ include('@PatchlevelEventSourcingAdmin/projection/detail.html.twig', { - projection: projection, + {{ include('@PatchlevelEventSourcingAdmin/subscription/detail.html.twig', { + subscription: subscription, }) }} - {% if projection.status.value in ['active', 'error'] %} - + {% if subscription.status.value in ['active', 'error'] %} + {{ heroicon('pause-circle', 'h-5 w-5') }} {% endif %} - {% if projection.status.value in ['paused', 'error', 'finished', 'outdated'] %} - + {% if subscription.status.value in ['new'] %} + {{ heroicon('play-circle', 'h-5 w-5') }} {% endif %} - {% if projection.status.value in ['paused', 'error', 'outdated'] %} - + {% if subscription.status.value in ['paused', 'error', 'finished', 'outdated'] %} + + {{ heroicon('play-circle', 'h-5 w-5') }} + + {% endif %} + {% if subscription.status.value in ['paused', 'error', 'outdated'] %} + {{ heroicon('trash', 'h-5 w-5') }} {% endif %}