From 78b4ccbf568155260ffc5a71d11cb5545e7e704b Mon Sep 17 00:00:00 2001 From: David Badura Date: Tue, 26 Mar 2024 18:35:31 +0100 Subject: [PATCH] add traces --- config/routes.yaml | 4 + public/build/app.css | 28 +-- src/Controller/EventController.php | 87 +++++++- src/Controller/ProjectionController.php | 52 ++--- src/Decorator/RequestIdDecorator.php | 2 +- .../PatchlevelEventSourcingAdminExtension.php | 20 +- src/Projection/Link.php | 30 +++ src/Projection/Node.php | 31 +++ src/Projection/TraceProjector.php | 203 ++++++++++++++++++ templates/event/index.html.twig | 37 +++- 10 files changed, 432 insertions(+), 62 deletions(-) create mode 100644 src/Projection/Link.php create mode 100644 src/Projection/Node.php create mode 100644 src/Projection/TraceProjector.php diff --git a/config/routes.yaml b/config/routes.yaml index 7c2f1f9..b31f367 100644 --- a/config/routes.yaml +++ b/config/routes.yaml @@ -41,3 +41,7 @@ patchlevel_event_sourcing_admin_inspection_show: patchlevel_event_sourcing_admin_event_index: path: /event controller: Patchlevel\EventSourcingAdminBundle\Controller\EventController::indexAction + +patchlevel_event_sourcing_admin_graph_index: + path: /graph + controller: Patchlevel\EventSourcingAdminBundle\Controller\GraphController::indexAction diff --git a/public/build/app.css b/public/build/app.css index 2563d7d..156531a 100644 --- a/public/build/app.css +++ b/public/build/app.css @@ -1173,10 +1173,6 @@ select { --tw-bg-opacity: 1; background-color: rgb(67 56 202 / var(--tw-bg-opacity)); } -.bg-red-200 { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); -} .bg-red-50 { --tw-bg-opacity: 1; background-color: rgb(254 242 242 / var(--tw-bg-opacity)); @@ -1192,18 +1188,6 @@ select { .bg-white\/10 { background-color: rgb(255 255 255 / 0.1); } -.bg-red-300 { - --tw-bg-opacity: 1; - background-color: rgb(252 165 165 / var(--tw-bg-opacity)); -} -.bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); -} -.bg-red-700 { - --tw-bg-opacity: 1; - background-color: rgb(185 28 28 / var(--tw-bg-opacity)); -} .bg-opacity-75 { --tw-bg-opacity: 0.75; } @@ -1301,6 +1285,9 @@ select { padding-top: 1.5rem; padding-bottom: 1.5rem; } +.pb-2 { + padding-bottom: 0.5rem; +} .pb-4 { padding-bottom: 1rem; } @@ -1328,6 +1315,9 @@ select { .pt-1\.5 { padding-top: 0.375rem; } +.pt-4 { + padding-top: 1rem; +} .pt-5 { padding-top: 1.25rem; } @@ -1414,10 +1404,6 @@ select { --tw-text-opacity: 1; color: rgb(255 255 255 / var(--tw-text-opacity)); } -.text-gray-600 { - --tw-text-opacity: 1; - color: rgb(75 85 99 / var(--tw-text-opacity)); -} .text-yellow-500 { --tw-text-opacity: 1; color: rgb(234 179 8 / var(--tw-text-opacity)); @@ -1756,4 +1742,4 @@ select { } -/*# sourceMappingURL=data:application/json;charset=utf-8;base64,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bUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBLHFCQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHNCQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBLHdCQUFtQjtPQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHlCQUFtQjtPQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHdCQUFtQjtPQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHFCQUFtQjtPQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHVCQUFtQjtPQUFuQjtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQSx1QkFBbUI7RUFBbkIsdURBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUEsdUJBQW1CO0VBQW5CLG9EQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHVCQUFtQjtFQUFuQiwrREFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSx1QkFBbUI7RUFBbkIsOERBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUEsd0JBQW1CO0VBQW5CLGtFQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHNCQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHNCQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHNCQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUEsc0JBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUEsc0JBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBLGtCQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLGtCQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLGtCQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxzQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxxQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxxQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxtQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxpQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxtQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxpQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxxQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxpQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxtQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUEsaUJBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUEsbUJBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUEsa0JBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUEsa0JBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBLG9CQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLG9CQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLG9CQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLG9CQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLG9CQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLG9CQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLG9CQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLG9CQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLG9CQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLG9CQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLG9CQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLG9CQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQSwwRUFBbUI7RUFBbkIsOEZBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUEsMENBQW1CO0VBQW5CLHVEQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLGdGQUFtQjtFQUFuQixvR0FBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSwyR0FBbUI7RUFBbkIseUdBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUEsMkdBQW1CO0VBQW5CLHlHQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUEsb0JBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUEsb0JBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUEsb0JBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUEsb0JBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQSwwQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSx3QkFBbUI7RUFBbkIsd0RBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUEsNEJBQW1CO0VBQW5CLHdEQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBRm5CO0VBQUEsb0JBR0E7RUFIQTtBQUdBO0FBSEE7RUFBQSxvQkFHQTtFQUhBO0FBR0E7QUFIQTtFQUFBLHNCQUdBO0VBSEE7QUFHQTtBQUhBO0VBQUEsa0JBR0E7RUFIQTtBQUdBO0FBSEE7RUFBQSxrQkFHQTtFQUhBO0FBR0E7QUFIQTtFQUFBLGtCQUdBO0VBSEE7QUFHQTtBQUhBO0VBQUE7QUFHQTtBQUhBO0VBQUEsb0JBR0E7RUFIQTtBQUdBO0FBSEE7RUFBQSxvQkFHQTtFQUhBO0FBR0E7QUFIQTtFQUFBLG9CQUdBO0VBSEE7QUFHQTtBQUhBO0VBQUEsMkdBR0E7RUFIQSx5R0FHQTtFQUhBO0FBR0E7QUFIQTtFQUFBO0FBR0E7QUFIQTtFQUFBLG9CQUdBO0VBSEE7QUFHQTtBQUhBO0VBQUE7QUFHQTtBQUhBO0VBQUE7QUFHQTtBQUhBO0VBQUE7QUFHQTtBQUhBO0VBQUE7QUFHQTtBQUhBO0VBQUE7QUFHQTtBQUhBO0VBQUE7QUFHQTtBQUhBO0VBQUE7QUFHQTtBQUhBO0VBQUEsb0JBR0E7RUFIQTtBQUdBO0FBSEE7O0VBQUE7SUFBQTtFQUdBOztFQUhBO0lBQUEsb0JBR0E7SUFIQTtFQUdBOztFQUhBO0lBQUEsaUJBR0E7SUFIQTtFQUdBOztFQUhBO0lBQUEsZ0JBR0E7SUFIQTtFQUdBOztFQUhBO0lBQUE7RUFHQTs7RUFIQTtJQUFBO0VBR0E7O0VBSEE7SUFBQTtFQUdBOztFQUhBO0lBQUE7RUFHQTs7RUFIQTtJQUFBO0VBR0E7O0VBSEE7SUFBQTtFQUdBOztFQUhBO0lBQUE7RUFHQTs7RUFIQTtJQUFBLHFCQUdBO0lBSEE7RUFHQTs7RUFIQTtJQUFBLGVBR0E7SUFIQSxlQUdBO0lBSEE7RUFHQTs7RUFIQTtJQUFBLGlCQUdBO0lBSEEsaUJBR0E7SUFIQTtFQUdBOztFQUhBO0lBQUE7RUFHQTs7RUFIQTtJQUFBO0VBR0E7O0VBSEE7SUFBQTtFQUdBOztFQUhBO0lBQUE7RUFHQTs7RUFIQTtJQUFBO0VBR0E7O0VBSEE7SUFBQTtFQUdBOztFQUhBO0lBQUEsaUJBR0E7SUFIQTtFQUdBOztFQUhBO0lBQUEsa0JBR0E7SUFIQTtFQUdBOztFQUhBO0lBQUEsb0JBR0E7SUFIQTtFQUdBOztFQUhBO0lBQUE7RUFHQTs7RUFIQTtJQUFBO0VBR0E7O0VBSEE7SUFBQSxtQkFHQTtJQUhBO0VBR0E7O0VBSEE7SUFBQTtFQUdBO0FBQUE7QUFIQTs7RUFBQTtJQUFBO0VBR0E7O0VBSEE7SUFBQTtFQUdBO0FBQUE7QUFIQTs7RUFBQTtJQUFBO0VBR0E7O0VBSEE7SUFBQSxRQUdBO0lBSEE7RUFHQTs7RUFIQTtJQUFBO0VBR0E7O0VBSEE7SUFBQSxrQkFHQTtJQUhBO0VBR0E7O0VBSEE7SUFBQTtFQUdBOztFQUhBO0lBQUE7RUFHQTs7RUFIQTtJQUFBO0VBR0E7O0VBSEE7SUFBQTtFQUdBOztFQUhBO0lBQUEsa0JBR0E7SUFIQTtFQUdBOztFQUhBO0lBQUE7RUFHQTtBQUFBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4vYXNzZXRzL2FwcC5jc3MiXSwic291cmNlc0NvbnRlbnQiOlsiQHRhaWx3aW5kIGJhc2U7XG5AdGFpbHdpbmQgY29tcG9uZW50cztcbkB0YWlsd2luZCB1dGlsaXRpZXM7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=*/ \ No newline at end of file +/*# sourceMappingURL=data:application/json;charset=utf-8;base64,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bUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBLHFCQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHNCQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBLHdCQUFtQjtPQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHlCQUFtQjtPQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHdCQUFtQjtPQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHFCQUFtQjtPQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHVCQUFtQjtPQUFuQjtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQSx1QkFBbUI7RUFBbkIsdURBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUEsdUJBQW1CO0VBQW5CLG9EQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHVCQUFtQjtFQUFuQiwrREFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSx1QkFBbUI7RUFBbkIsOERBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUEsd0JBQW1CO0VBQW5CLGtFQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHNCQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHNCQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLHNCQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUEsc0JBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUEsc0JBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxzQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxxQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxrQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxxQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxtQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxpQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxtQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxpQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxxQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxpQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxtQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBLGlCQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLG1CQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLGtCQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLGtCQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxvQkFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUEsMEVBQW1CO0VBQW5CLDhGQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLDBDQUFtQjtFQUFuQix1REFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQSxnRkFBbUI7RUFBbkIsb0dBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUEsMkdBQW1CO0VBQW5CLHlHQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLDJHQUFtQjtFQUFuQix5R0FBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBLG9CQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLG9CQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLG9CQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLG9CQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUEsMEJBQW1CO0VBQW5CO0FBQW1CO0FBQW5CO0VBQUEsd0JBQW1CO0VBQW5CLHdEQUFtQjtFQUFuQjtBQUFtQjtBQUFuQjtFQUFBLDRCQUFtQjtFQUFuQix3REFBbUI7RUFBbkI7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUFuQjtFQUFBO0FBQW1CO0FBQW5CO0VBQUE7QUFBbUI7QUFBbkI7RUFBQTtBQUFtQjtBQUZuQjtFQUFBLG9CQUdBO0VBSEE7QUFHQTtBQUhBO0VBQUEsb0JBR0E7RUFIQTtBQUdBO0FBSEE7RUFBQSxzQkFHQTtFQUhBO0FBR0E7QUFIQTtFQUFBLGtCQUdBO0VBSEE7QUFHQTtBQUhBO0VBQUEsa0JBR0E7RUFIQTtBQUdBO0FBSEE7RUFBQSxrQkFHQTtFQUhBO0FBR0E7QUFIQTtFQUFBO0FBR0E7QUFIQTtFQUFBLG9CQUdBO0VBSEE7QUFHQTtBQUhBO0VBQUEsb0JBR0E7RUFIQTtBQUdBO0FBSEE7RUFBQSxvQkFHQTtFQUhBO0FBR0E7QUFIQTtFQUFBLDJHQUdBO0VBSEEseUdBR0E7RUFIQTtBQUdBO0FBSEE7RUFBQTtBQUdBO0FBSEE7RUFBQSxvQkFHQTtFQUhBO0FBR0E7QUFIQTtFQUFBO0FBR0E7QUFIQTtFQUFBO0FBR0E7QUFIQTtFQUFBO0FBR0E7QUFIQTtFQUFBO0FBR0E7QUFIQTtFQUFBO0FBR0E7QUFIQTtFQUFBO0FBR0E7QUFIQTtFQUFBO0FBR0E7QUFIQTtFQUFBLG9CQUdBO0VBSEE7QUFHQTtBQUhBOztFQUFBO0lBQUE7RUFHQTs7RUFIQTtJQUFBLG9CQUdBO0lBSEE7RUFHQTs7RUFIQTtJQUFBLGlCQUdBO0lBSEE7RUFHQTs7RUFIQTtJQUFBLGdCQUdBO0lBSEE7RUFHQTs7RUFIQTtJQUFBO0VBR0E7O0VBSEE7SUFBQTtFQUdBOztFQUhBO0lBQUE7RUFHQTs7RUFIQTtJQUFBO0VBR0E7O0VBSEE7SUFBQTtFQUdBOztFQUhBO0lBQUE7RUFHQTs7RUFIQTtJQUFBO0VBR0E7O0VBSEE7SUFBQSxxQkFHQTtJQUhBO0VBR0E7O0VBSEE7SUFBQSxlQUdBO0lBSEEsZUFHQTtJQUhBO0VBR0E7O0VBSEE7SUFBQSxpQkFHQTtJQUhBLGlCQUdBO0lBSEE7RUFHQTs7RUFIQTtJQUFBO0VBR0E7O0VBSEE7SUFBQTtFQUdBOztFQUhBO0lBQUE7RUFHQTs7RUFIQTtJQUFBO0VBR0E7O0VBSEE7SUFBQTtFQUdBOztFQUhBO0lBQUE7RUFHQTs7RUFIQTtJQUFBLGlCQUdBO0lBSEE7RUFHQTs7RUFIQTtJQUFBLGtCQUdBO0lBSEE7RUFHQTs7RUFIQTtJQUFBLG9CQUdBO0lBSEE7RUFHQTs7RUFIQTtJQUFBO0VBR0E7O0VBSEE7SUFBQTtFQUdBOztFQUhBO0lBQUEsbUJBR0E7SUFIQTtFQUdBOztFQUhBO0lBQUE7RUFHQTtBQUFBO0FBSEE7O0VBQUE7SUFBQTtFQUdBOztFQUhBO0lBQUE7RUFHQTtBQUFBO0FBSEE7O0VBQUE7SUFBQTtFQUdBOztFQUhBO0lBQUEsUUFHQTtJQUhBO0VBR0E7O0VBSEE7SUFBQTtFQUdBOztFQUhBO0lBQUEsa0JBR0E7SUFIQTtFQUdBOztFQUhBO0lBQUE7RUFHQTs7RUFIQTtJQUFBO0VBR0E7O0VBSEE7SUFBQTtFQUdBOztFQUhBO0lBQUE7RUFHQTs7RUFIQTtJQUFBLGtCQUdBO0lBSEE7RUFHQTs7RUFIQTtJQUFBO0VBR0E7QUFBQSIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL2Fzc2V0cy9hcHAuY3NzIl0sInNvdXJjZXNDb250ZW50IjpbIkB0YWlsd2luZCBiYXNlO1xuQHRhaWx3aW5kIGNvbXBvbmVudHM7XG5AdGFpbHdpbmQgdXRpbGl0aWVzO1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9*/ \ No newline at end of file diff --git a/src/Controller/EventController.php b/src/Controller/EventController.php index 0321317..6ff0535 100644 --- a/src/Controller/EventController.php +++ b/src/Controller/EventController.php @@ -9,6 +9,8 @@ use Patchlevel\EventSourcing\EventBus\ListenerProvider; use Patchlevel\EventSourcing\Metadata\Event\EventRegistry; use Patchlevel\EventSourcing\Metadata\Projector\ProjectorMetadataFactory; +use Patchlevel\EventSourcingAdminBundle\Projection\Node; +use Patchlevel\EventSourcingAdminBundle\Projection\TraceProjector; use Symfony\Component\HttpFoundation\Response; use Twig\Environment; @@ -23,6 +25,7 @@ public function __construct( private readonly ListenerProvider $listenerProvider, private readonly iterable $projectors, private readonly ProjectorMetadataFactory $projectorMetadataFactory, + private readonly TraceProjector|null $traceProjector, ) { } @@ -35,11 +38,9 @@ public function indexAction(): Response $events[] = [ 'name' => $eventName, 'class' => $eventClass, - 'listeners' => array_map( - static fn(ListenerDescriptor $listener) => $listener->name(), - $this->listenerProvider->listenersForEvent($eventClass), - ), + 'listeners' => $this->listenerMethods($eventClass), 'projectors' => $this->projectorsMethods($eventClass), + 'sources' => $this->source($eventClass), ]; } @@ -48,6 +49,14 @@ public function indexAction(): Response ])); } + private function listenerMethods(string $eventClass): array + { + return array_map( + static fn(ListenerDescriptor $listener) => $listener->name(), + $this->listenerProvider->listenersForEvent($eventClass), + ); + } + private function projectorsMethods(string $eventClass): array { $result = []; @@ -70,4 +79,74 @@ private function projectorsMethods(string $eventClass): array return $result; } + + /** + * @param string $eventClass + * @return list + */ + private function source(string $eventClass): array + { + $node = $this->findNodeByEventClass($eventClass); + + if (!$node) { + return []; + } + + return $this->findSources($node); + } + + private function findNodeByEventClass(string $eventClass): Node|null + { + if ($this->traceProjector === null) { + return null; + } + + $nodes = $this->traceProjector->nodes(); + + $name = $this->eventRegistry->eventName($eventClass); + + foreach ($nodes as $node) { + if ($node->name === $name) { + return $node; + } + } + + return null; + } + + private function findNodeById(string $id): Node|null + { + if ($this->traceProjector === null) { + return null; + } + + $nodes = $this->traceProjector->nodes(); + + foreach ($nodes as $node) { + if ($node->id === $id) { + return $node; + } + } + + return null; + } + + /** + * @param Node $node + * @return list + */ + private function findSources(Node $node): array + { + $links = $this->traceProjector->links(); + + $result = []; + + foreach ($links as $link) { + if ($link->toId === $node->id) { + $result[] = $this->findNodeById($link->fromId); + } + } + + return $result; + } } diff --git a/src/Controller/ProjectionController.php b/src/Controller/ProjectionController.php index 4df0435..b73d0e0 100644 --- a/src/Controller/ProjectionController.php +++ b/src/Controller/ProjectionController.php @@ -4,10 +4,10 @@ namespace Patchlevel\EventSourcingAdminBundle\Controller; -use Patchlevel\EventSourcing\Projection\Projection\ProjectionStatus; -use Patchlevel\EventSourcing\Projection\Projection\RunMode; -use Patchlevel\EventSourcing\Projection\Projectionist\Projectionist; -use Patchlevel\EventSourcing\Projection\Projectionist\ProjectionistCriteria; +use Patchlevel\EventSourcing\Subscription\Status; +use Patchlevel\EventSourcing\Subscription\RunMode; +use Patchlevel\EventSourcing\Subscription\Engine\SubscriptionEngine; +use Patchlevel\EventSourcing\Subscription\Engine\SubscriptionEngineCriteria; use Patchlevel\EventSourcing\Store\Store; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; @@ -19,7 +19,7 @@ final class ProjectionController { public function __construct( private readonly Environment $twig, - private readonly Projectionist $projectionist, + private readonly SubscriptionEngine $engine, private readonly Store $store, private readonly RouterInterface $router, ) { @@ -27,13 +27,13 @@ public function __construct( public function showAction(Request $request): Response { - $projections = $this->projectionist->projections(); + $subscriptions = $this->engine->subscriptions(); $messageCount = $this->store->count(); $groups = []; - foreach ($projections as $projection) { - $groups[$projection->group()] = true; + foreach ($subscriptions as $subscription) { + $groups[$subscription->group()] = true; } $filteredProjections = []; @@ -43,31 +43,31 @@ public function showAction(Request $request): Response $status = $request->get('status'); - foreach ($projections as $projection) { - if ($search && !str_contains($projection->id(), $search)) { + foreach ($subscriptions as $subscription) { + if ($search && !str_contains($subscription->id(), $search)) { continue; } - if ($group && $projection->group() !== $group) { + if ($group && $subscription->group() !== $group) { continue; } - if ($mode && $projection->runMode()->value !== $mode) { + if ($mode && $subscription->runMode()->value !== $mode) { continue; } - if ($status && $projection->status()->value !== $status) { + if ($status && $subscription->status()->value !== $status) { continue; } - $filteredProjections[] = $projection; + $filteredProjections[] = $subscription; } return new Response( $this->twig->render('@PatchlevelEventSourcingAdmin/projection/show.html.twig', [ 'projections' => $filteredProjections, 'messageCount' => $messageCount, - 'statuses' => array_map(fn (ProjectionStatus $status) => $status->value, ProjectionStatus::cases()), + 'statuses' => array_map(fn (Status $status) => $status->value, Status::cases()), 'modes' => array_map(fn (RunMode $mode) => $mode->value, RunMode::cases()), 'groups' => array_keys($groups), ]), @@ -76,10 +76,10 @@ public function showAction(Request $request): Response public function rebuildAction(string $id): Response { - $criteria = new ProjectionistCriteria([$id]); + $criteria = new SubscriptionEngineCriteria([$id]); - $this->projectionist->remove($criteria); - $this->projectionist->boot($criteria); + $this->engine->remove($criteria); + $this->engine->boot($criteria); return new RedirectResponse( $this->router->generate('patchlevel_event_sourcing_admin_projection_show'), @@ -88,9 +88,9 @@ public function rebuildAction(string $id): Response public function pauseAction(string $id): Response { - $criteria = new ProjectionistCriteria([$id]); + $criteria = new SubscriptionEngineCriteria([$id]); - $this->projectionist->pause($criteria); + $this->engine->pause($criteria); return new RedirectResponse( $this->router->generate('patchlevel_event_sourcing_admin_projection_show'), @@ -99,9 +99,9 @@ public function pauseAction(string $id): Response public function bootAction(string $id): Response { - $criteria = new ProjectionistCriteria([$id]); + $criteria = new SubscriptionEngineCriteria([$id]); - $this->projectionist->boot($criteria); + $this->engine->boot($criteria); return new RedirectResponse( $this->router->generate('patchlevel_event_sourcing_admin_projection_show'), @@ -110,9 +110,9 @@ public function bootAction(string $id): Response public function reactivateAction(string $id): Response { - $criteria = new ProjectionistCriteria([$id]); + $criteria = new SubscriptionEngineCriteria([$id]); - $this->projectionist->reactivate($criteria); + $this->engine->reactivate($criteria); return new RedirectResponse( $this->router->generate('patchlevel_event_sourcing_admin_projection_show'), @@ -121,9 +121,9 @@ public function reactivateAction(string $id): Response public function removeAction(string $id): Response { - $criteria = new ProjectionistCriteria([$id]); + $criteria = new SubscriptionEngineCriteria([$id]); - $this->projectionist->remove($criteria); + $this->engine->remove($criteria); return new RedirectResponse( $this->router->generate('patchlevel_event_sourcing_admin_projection_show'), diff --git a/src/Decorator/RequestIdDecorator.php b/src/Decorator/RequestIdDecorator.php index 73195ca..64cbb60 100644 --- a/src/Decorator/RequestIdDecorator.php +++ b/src/Decorator/RequestIdDecorator.php @@ -3,7 +3,7 @@ namespace Patchlevel\EventSourcingAdminBundle\Decorator; use Patchlevel\EventSourcing\Repository\MessageDecorator\MessageDecorator; -use Patchlevel\EventSourcing\EventBus\Message; +use Patchlevel\EventSourcing\Message\Message; use Patchlevel\EventSourcingAdminBundle\Listener\RequestIdListener; use Symfony\Component\HttpFoundation\RequestStack; diff --git a/src/DependencyInjection/PatchlevelEventSourcingAdminExtension.php b/src/DependencyInjection/PatchlevelEventSourcingAdminExtension.php index d15854a..4dece91 100644 --- a/src/DependencyInjection/PatchlevelEventSourcingAdminExtension.php +++ b/src/DependencyInjection/PatchlevelEventSourcingAdminExtension.php @@ -8,27 +8,29 @@ use Patchlevel\EventSourcing\Metadata\AggregateRoot\AggregateRootMetadataFactory; use Patchlevel\EventSourcing\Metadata\AggregateRoot\AggregateRootRegistry; use Patchlevel\EventSourcing\Metadata\Event\EventRegistry; -use Patchlevel\EventSourcing\Metadata\Projector\ProjectorMetadataFactory; -use Patchlevel\EventSourcing\Projection\Projectionist\Projectionist; +use Patchlevel\EventSourcing\Metadata\Subscriber\SubscriberMetadataFactory; use Patchlevel\EventSourcing\Serializer\EventSerializer; use Patchlevel\EventSourcing\Snapshot\SnapshotStore; use Patchlevel\EventSourcing\Store\Store; +use Patchlevel\EventSourcing\Subscription\Engine\SubscriptionEngine; use Patchlevel\EventSourcingAdminBundle\Controller\DefaultController; use Patchlevel\EventSourcingAdminBundle\Controller\EventController; +use Patchlevel\EventSourcingAdminBundle\Controller\GraphController; use Patchlevel\EventSourcingAdminBundle\Controller\InspectionController; use Patchlevel\EventSourcingAdminBundle\Controller\ProjectionController; use Patchlevel\EventSourcingAdminBundle\Controller\StoreController; use Patchlevel\EventSourcingAdminBundle\Decorator\RequestIdDecorator; use Patchlevel\EventSourcingAdminBundle\Listener\RequestIdListener; use Patchlevel\EventSourcingAdminBundle\Listener\TokenMapperListener; +use Patchlevel\EventSourcingAdminBundle\Projection\TraceProjector; use Patchlevel\EventSourcingAdminBundle\TokenMapper; use Patchlevel\EventSourcingAdminBundle\Twig\EventSourcingAdminExtension; use Patchlevel\EventSourcingAdminBundle\Twig\HeroiconsExtension; use Patchlevel\EventSourcingAdminBundle\Twig\InspectionExtension; use Patchlevel\Hydrator\Hydrator; -use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Parameter; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; @@ -83,7 +85,7 @@ public function load(array $configs, ContainerBuilder $container): void $container->register(ProjectionController::class) ->setArguments([ new Reference('twig'), - new Reference(Projectionist::class), + new Reference(SubscriptionEngine::class), new Reference(Store::class), new Reference(RouterInterface::class), ]) @@ -95,7 +97,8 @@ public function load(array $configs, ContainerBuilder $container): void new Reference(EventRegistry::class), new Reference(ListenerProvider::class), new TaggedIteratorArgument('event_sourcing.projector'), - new Reference(ProjectorMetadataFactory::class), + new Reference(SubscriberMetadataFactory::class), + new Reference(TraceProjector::class, ContainerInterface::NULL_ON_INVALID_REFERENCE), ]) ->addTag('controller.service_arguments'); @@ -146,5 +149,12 @@ public function load(array $configs, ContainerBuilder $container): void 'method' => '__invoke', 'priority' => -200, ]); + + $container->register(TraceProjector::class) + ->setArguments([ + new Reference('doctrine.dbal.projection_connection'), + new Reference(EventRegistry::class), + ]) + ->addTag('event_sourcing.projector'); } } diff --git a/src/Projection/Link.php b/src/Projection/Link.php new file mode 100644 index 0000000..c50869a --- /dev/null +++ b/src/Projection/Link.php @@ -0,0 +1,30 @@ +id = sha1($fromId . '->' . $toId); + } + + public function __toString(): string + { + return $this->fromId . ' -> ' . $this->toId; + } + + public function jsonSerialize(): array + { + return [ + 'fromId' => $this->fromId, + 'toId' => $this->toId, + ]; + } +} diff --git a/src/Projection/Node.php b/src/Projection/Node.php new file mode 100644 index 0000000..6586b86 --- /dev/null +++ b/src/Projection/Node.php @@ -0,0 +1,31 @@ +id = sha1($category . '#' . $name); + } + + public function __toString(): string + { + return $this->id; + } + + public function jsonSerialize(): array + { + return [ + 'id' => $this->id, + 'name' => $this->name, + 'category' => $this->category, + ]; + } +} diff --git a/src/Projection/TraceProjector.php b/src/Projection/TraceProjector.php new file mode 100644 index 0000000..ef0ab39 --- /dev/null +++ b/src/Projection/TraceProjector.php @@ -0,0 +1,203 @@ + + */ + private array $nodes = []; + + /** + * @var array + */ + private array $links = []; + + public function __construct( + private readonly Connection $connection, + private readonly EventRegistry $eventRegistry, + ) + { + } + + #[Subscribe('*')] + public function handleAll(Message $message): void + { + $this->init(); + + $toId = $this->insertMessageAsNode($message); + + try { + /** + * @var list $traces + */ + $traces = $message->header('trace'); + } catch (HeaderNotFound) { + return; + } + + foreach ($traces as $trace) { + $fromId = $this->insertTrace($trace); + $this->insertLink($fromId, $toId); + } + } + + private function insertMessageAsNode(Message $message): Node + { + $name = $this->eventRegistry->eventName($message->event()::class); + $category = 'aggregate/' . $message->aggregateName(); + + return $this->addNode($name, $category); + } + + /** + * @param array{name: string, category: string} $trace + */ + private function insertTrace(array $trace): Node + { + return $this->addNode($trace['name'], $trace['category']); + } + + private function insertLink(Node $from, Node $to): Link + { + $link = new Link($from->id, $to->id); + + if (array_key_exists($link->id, $this->links)) { + return $this->links[$link->id]; + } + + $this->connection->insert( + self::LINK_TABLE, + [ + 'from_id' => $link->fromId, + 'to_id' => $link->toId, + ] + ); + + $this->links[$link->id] = $link; + + return $link; + } + + private function addNode(string $name, string $category): Node + { + $node = new Node( + $name, + $category, + ); + + if (array_key_exists($node->id, $this->nodes)) { + return $this->nodes[$node->id]; + } + + $this->connection->insert( + self::NODE_TABLE, + [ + 'id' => $node->id, + 'name' => $node->name, + 'category' => $node->category, + ] + ); + + $this->nodes[$node->id] = $node; + + return $node; + } + + #[Setup] + public function setup(): void + { + $schemaManager = $this->connection->createSchemaManager(); + + $table = new Table(self::NODE_TABLE); + $table->addColumn('id', 'string', ['length' => 255]); + $table->addColumn('name', 'string', ['length' => 255]); + $table->addColumn('category', 'string', ['length' => 255]); + $table->setPrimaryKey(['id']); + + $schemaManager->createTable($table); + + $table = new Table(self::LINK_TABLE); + $table->addColumn('from_id', 'string', ['length' => 255]); + $table->addColumn('to_id', 'string', ['length' => 255]); + + $table->setPrimaryKey(['from_id', 'to_id']); + $table->addForeignKeyConstraint(self::NODE_TABLE, ['from_id'], ['id']); + $table->addForeignKeyConstraint(self::NODE_TABLE, ['to_id'], ['id']); + + $schemaManager->createTable($table); + } + + #[Teardown] + public function teardown(): void + { + $schemaManager = $this->connection->createSchemaManager(); + + $schemaManager->dropTable(self::LINK_TABLE); + $schemaManager->dropTable(self::NODE_TABLE); + } + + /** + * @return list + */ + public function nodes(): array + { + $this->init(); + + return array_values($this->nodes); + } + + /** + * @return list + */ + public function links(): array + { + $this->init(); + + return array_values($this->links); + } + + private function init(): void + { + if ($this->nodes === []) { + $result = $this->connection->fetchAllAssociative('SELECT id, name, category FROM ' . self::NODE_TABLE); + + foreach ($result as $row) { + $node = new Node( + $row['name'], + $row['category'], + ); + + $this->nodes[$node->id] = $node; + } + } + + if ($this->links === []) { + $result = $this->connection->fetchAllAssociative('SELECT from_id, to_id FROM ' . self::LINK_TABLE); + + foreach ($result as $row) { + $link = new Link( + $row['from_id'], + $row['to_id'], + ); + + $this->links[$link->id] = $link; + } + } + } +} diff --git a/templates/event/index.html.twig b/templates/event/index.html.twig index 3744594..481859e 100644 --- a/templates/event/index.html.twig +++ b/templates/event/index.html.twig @@ -64,14 +64,14 @@
- Listeners ({{ event.listeners|length }}) + Sources ({{ event.sources|length }})
    - {% for listener in event.listeners %} - {{ _self.subscriber(listener) }} + {% for node in event.sources|sort((a, b) => a.name <=> b.name)|sort((a, b) => a.category <=> b.category) %} + {{ _self.node(node) }} {% else %} -
  • no listeners
  • +
  • unknown sources
  • {% endfor %}
@@ -87,6 +87,18 @@ {% endfor %} +
+ Listeners ({{ event.listeners|length }}) +
+ +
    + {% for listener in event.listeners %} + {{ _self.subscriber(listener) }} + {% else %} +
  • no listeners
  • + {% endfor %} +
+ {% endif %} {% endfor %} @@ -100,8 +112,9 @@ {% endif %} - + +