From 27fb44ae4b8edac2b7cc6b803bd1ce0a658b4d8f Mon Sep 17 00:00:00 2001 From: Jose Andres Tejerina Date: Fri, 28 Nov 2025 17:17:28 -0300 Subject: [PATCH 1/3] feat: add presentationtrackchairformatter --- app/Audit/AuditLogFormatterFactory.php | 35 +++----- ...tationTrackChairScoreAuditLogFormatter.php | 54 +++++++++++++ ...nTrackChairRatingTypeAuditLogFormatter.php | 62 +++++++++++++++ ...onTrackChairScoreTypeAuditLogFormatter.php | 67 ++++++++++++++++ .../SummitTrackChairAuditLogFormatter.php | 79 +++++++++++++++++++ config/audit_log.php | 14 +++- 6 files changed, 288 insertions(+), 23 deletions(-) create mode 100644 app/Audit/ConcreteFormatters/ChildEntityFormatters/PresentationTrackChairScoreAuditLogFormatter.php create mode 100644 app/Audit/ConcreteFormatters/PresentationTrackChairRatingTypeAuditLogFormatter.php create mode 100644 app/Audit/ConcreteFormatters/PresentationTrackChairScoreTypeAuditLogFormatter.php create mode 100644 app/Audit/ConcreteFormatters/SummitTrackChairAuditLogFormatter.php diff --git a/app/Audit/AuditLogFormatterFactory.php b/app/Audit/AuditLogFormatterFactory.php index 4536bbfd0..150d8e237 100644 --- a/app/Audit/AuditLogFormatterFactory.php +++ b/app/Audit/AuditLogFormatterFactory.php @@ -29,13 +29,6 @@ public function __construct() $this->config = config('audit_log', []); } - public function getStrategyClass(object $subject, string $event_type): ?IAuditLogFormatter - { - $class = get_class($subject); - $cls = $this->config['entities'][$class]['strategy'] ?? null; - return !is_null($cls) ? new $cls($event_type):null; - } - public function make(AuditContext $ctx, $subject, $eventType): ?IAuditLogFormatter { $formatter = null; @@ -53,18 +46,12 @@ public function make(AuditContext $ctx, $subject, $eventType): ?IAuditLogFormatt break; case IAuditStrategy::EVENT_ENTITY_CREATION: $formatter = $this->getFormatterByContext($subject, $eventType, $ctx); - if (is_null($formatter)) { - $formatter = $this->getStrategyClass($subject, $eventType); - } if(is_null($formatter)) { $formatter = new EntityCreationAuditLogFormatter(); } break; case IAuditStrategy::EVENT_ENTITY_DELETION: $formatter = $this->getFormatterByContext($subject, $eventType, $ctx); - if (is_null($formatter)) { - $formatter = $this->getStrategyClass($subject, $eventType); - } if(is_null($formatter)) { $child_entity_formatter = ChildEntityFormatterFactory::build($subject); $formatter = new EntityDeletionAuditLogFormatter($child_entity_formatter); @@ -72,9 +59,6 @@ public function make(AuditContext $ctx, $subject, $eventType): ?IAuditLogFormatt break; case IAuditStrategy::EVENT_ENTITY_UPDATE: $formatter = $this->getFormatterByContext($subject, $eventType, $ctx); - if (is_null($formatter)) { - $formatter = $this->getStrategyClass($subject, $eventType); - } if(is_null($formatter)) { $child_entity_formatter = ChildEntityFormatterFactory::build($subject); $formatter = new EntityUpdateAuditLogFormatter($child_entity_formatter); @@ -90,17 +74,24 @@ private function getFormatterByContext(object $subject, string $event_type, Audi $class = get_class($subject); $entity_config = $this->config['entities'][$class] ?? null; - if (!$entity_config || !isset($entity_config['strategies'])) { + if (!$entity_config) { return null; } - foreach ($entity_config['strategies'] as $strategy) { - if (!$this->matchesStrategy($strategy, $ctx)) { - continue; + if (isset($entity_config['strategies'])) { + foreach ($entity_config['strategies'] as $strategy) { + if (!$this->matchesStrategy($strategy, $ctx)) { + continue; + } + + $formatter_class = $strategy['formatter'] ?? null; + return $formatter_class ? new $formatter_class($event_type) : null; } + } - $formatter_class = $strategy['formatter'] ?? null; - return $formatter_class ? new $formatter_class($event_type) : null; + if (isset($entity_config['strategy'])) { + $strategy_class = $entity_config['strategy']; + return new $strategy_class($event_type); } return null; diff --git a/app/Audit/ConcreteFormatters/ChildEntityFormatters/PresentationTrackChairScoreAuditLogFormatter.php b/app/Audit/ConcreteFormatters/ChildEntityFormatters/PresentationTrackChairScoreAuditLogFormatter.php new file mode 100644 index 000000000..bbd728c2d --- /dev/null +++ b/app/Audit/ConcreteFormatters/ChildEntityFormatters/PresentationTrackChairScoreAuditLogFormatter.php @@ -0,0 +1,54 @@ +getScoreType(); + $score_label = $score_type ? $score_type->getLabel() : 'Unknown Score'; + + $presentation = $subject->getPresentation(); + $presentation_title = $presentation ? $presentation->getTitle() : 'Unknown Presentation'; + + $created_by = $subject->getCreatedBy(); + $chair_name = $created_by + ? sprintf("%s %s", $created_by->getFirstName(), $created_by->getLastName()) + : 'Unknown Chair'; + + switch ($child_entity_action_type) { + case self::CHILD_ENTITY_CREATION: + return sprintf( + "Track Chair '%s' scored '%s' on presentation '%s'", + $chair_name, + $score_label, + $presentation_title + ); + case self::CHILD_ENTITY_DELETION: + return sprintf( + "Score removed for Track Chair '%s' from presentation '%s'", + $chair_name, + $presentation_title + ); + case self::CHILD_ENTITY_UPDATE: + return sprintf( + "Track Chair '%s' score updated to '%s' on presentation '%s'", + $chair_name, + $score_label, + $presentation_title + ); + } + } catch (\Exception $ex) { + Log::warning("PresentationTrackChairScoreAuditLogFormatter error: " . $ex->getMessage()); + } + + return null; + } +} diff --git a/app/Audit/ConcreteFormatters/PresentationTrackChairRatingTypeAuditLogFormatter.php b/app/Audit/ConcreteFormatters/PresentationTrackChairRatingTypeAuditLogFormatter.php new file mode 100644 index 000000000..f3ab79104 --- /dev/null +++ b/app/Audit/ConcreteFormatters/PresentationTrackChairRatingTypeAuditLogFormatter.php @@ -0,0 +1,62 @@ +event_type = $event_type; + } + + public function format($subject, array $change_set): ?string + { + if (!$subject instanceof PresentationTrackChairRatingType) { + return null; + } + + try { + $name = $subject->getName() ?? 'Unknown'; + $selection_plan = $subject->getSelectionPlan(); + $plan_name = $selection_plan ? $selection_plan->getName() : 'Unknown'; + + switch ($this->event_type) { + case IAuditStrategy::EVENT_ENTITY_CREATION: + return sprintf( + "Track Chair Rating Type '%s' created for Selection Plan '%s'", + $name, + $plan_name + ); + + case IAuditStrategy::EVENT_ENTITY_UPDATE: + $changed_fields = []; + if (isset($change_set['name'])) { + $changed_fields[] = "name"; + } + + $fields_str = !empty($changed_fields) ? implode(', ', $changed_fields) : 'properties'; + return sprintf( + "Track Chair Rating Type '%s' updated (%s changed)", + $name, + $fields_str + ); + + case IAuditStrategy::EVENT_ENTITY_DELETION: + return sprintf( + "Track Chair Rating Type '%s' deleted from Selection Plan '%s'", + $name, + $plan_name + ); + } + } catch (\Exception $ex) { + Log::warning("PresentationTrackChairRatingTypeAuditLogFormatter error: " . $ex->getMessage()); + } + + return null; + } +} diff --git a/app/Audit/ConcreteFormatters/PresentationTrackChairScoreTypeAuditLogFormatter.php b/app/Audit/ConcreteFormatters/PresentationTrackChairScoreTypeAuditLogFormatter.php new file mode 100644 index 000000000..03760e4cc --- /dev/null +++ b/app/Audit/ConcreteFormatters/PresentationTrackChairScoreTypeAuditLogFormatter.php @@ -0,0 +1,67 @@ +event_type = $event_type; + } + + public function format($subject, array $change_set): ?string + { + if (!$subject instanceof PresentationTrackChairScoreType) { + return null; + } + + try { + $label = $subject->getLabel() ?? 'Unknown'; + $score = $subject->getScore() ?? 'unknown'; + $rating_type = $subject->getRatingType(); + $rating_type_name = $rating_type ? $rating_type->getName() : 'Unknown'; + + switch ($this->event_type) { + case IAuditStrategy::EVENT_ENTITY_CREATION: + return sprintf( + "Score Type '%s' (value: %s) added to Rating Type '%s'", + $label, + $score, + $rating_type_name + ); + + case IAuditStrategy::EVENT_ENTITY_UPDATE: + $changed_fields = []; + if (isset($change_set['label'])) { + $changed_fields[] = "label"; + } + if (isset($change_set['score'])) { + $changed_fields[] = "score"; + } + + $fields_str = !empty($changed_fields) ? implode(', ', $changed_fields) : 'properties'; + return sprintf( + "Score Type '%s' updated (%s changed)", + $label, + $fields_str + ); + + case IAuditStrategy::EVENT_ENTITY_DELETION: + return sprintf( + "Score Type '%s' removed from Rating Type '%s'", + $label, + $rating_type_name + ); + } + } catch (\Exception $ex) { + Log::warning("PresentationTrackChairScoreTypeAuditLogFormatter error: " . $ex->getMessage()); + } + + return null; + } +} diff --git a/app/Audit/ConcreteFormatters/SummitTrackChairAuditLogFormatter.php b/app/Audit/ConcreteFormatters/SummitTrackChairAuditLogFormatter.php new file mode 100644 index 000000000..6009edb58 --- /dev/null +++ b/app/Audit/ConcreteFormatters/SummitTrackChairAuditLogFormatter.php @@ -0,0 +1,79 @@ +event_type = $event_type; + } + + public function format($subject, array $change_set): ?string + { + if (!$subject instanceof SummitTrackChair) { + return null; + } + + try { + $member = $subject->getMember(); + $member_name = $member ? sprintf("%s %s", $member->getFirstName(), $member->getLastName()) : 'Unknown'; + $member_id = $member ? $member->getId() : 'unknown'; + + switch ($this->event_type) { + case IAuditStrategy::EVENT_ENTITY_CREATION: + $categories = []; + foreach ($subject->getCategories() as $category) { + $categories[] = $category->getTitle(); + } + $tracks_list = !empty($categories) ? implode(', ', $categories) : 'No tracks assigned'; + return sprintf( + "Track Chair '%s' (%d) assigned with tracks: %s", + $member_name, + $member_id, + $tracks_list + ); + + case IAuditStrategy::EVENT_ENTITY_UPDATE: + if (isset($change_set['categories'])) { + $old_cats = $change_set['categories'][0] ?? []; + $new_cats = $change_set['categories'][1] ?? []; + + $old_names = is_array($old_cats) + ? array_map(fn($c) => $c->getTitle() ?? 'Unknown', $old_cats) + : []; + $new_names = is_array($new_cats) + ? array_map(fn($c) => $c->getTitle() ?? 'Unknown', $new_cats) + : []; + + $old_str = !empty($old_names) ? implode(', ', $old_names) : 'None'; + $new_str = !empty($new_names) ? implode(', ', $new_names) : 'None'; + + return sprintf( + "Track Chair '%s' tracks changed: [%s] → [%s]", + $member_name, + $old_str, + $new_str + ); + } + return sprintf("Track Chair '%s' updated", $member_name); + + case IAuditStrategy::EVENT_ENTITY_DELETION: + return sprintf( + "Track Chair '%s' (%d) removed from summit", + $member_name, + $member_id + ); + } + } catch (\Exception $ex) { + Log::warning("SummitTrackChairAuditLogFormatter error: " . $ex->getMessage()); + } + + return null; + } +} diff --git a/config/audit_log.php b/config/audit_log.php index 9b576c608..23e9de21b 100644 --- a/config/audit_log.php +++ b/config/audit_log.php @@ -50,6 +50,18 @@ \models\summit\PresentationSpeakerSummitAssistanceConfirmationRequest::class => [ 'enabled' => true, 'strategy' => \App\Audit\ConcreteFormatters\SpeakerAssistanceAuditLogFormatter::class, - ] + ], + \models\summit\SummitTrackChair::class => [ + 'enabled' => true, + 'strategy' => \App\Audit\ConcreteFormatters\SummitTrackChairAuditLogFormatter::class, + ], + \App\Models\Foundation\Summit\Events\Presentations\TrackChairs\PresentationTrackChairRatingType::class => [ + 'enabled' => true, + 'strategy' => \App\Audit\ConcreteFormatters\PresentationTrackChairRatingTypeAuditLogFormatter::class, + ], + \App\Models\Foundation\Summit\Events\Presentations\TrackChairs\PresentationTrackChairScoreType::class => [ + 'enabled' => true, + 'strategy' => \App\Audit\ConcreteFormatters\PresentationTrackChairScoreTypeAuditLogFormatter::class, + ], ] ]; From c0df3933d389106f5ca5bc0e8cb516d1563e290e Mon Sep 17 00:00:00 2001 From: Jose Andres Tejerina Date: Wed, 3 Dec 2025 17:06:30 -0300 Subject: [PATCH 2/3] chore: replace the otlp interface with abstractFactory feat: add the user context to the formatters --- ...nTrackChairRatingTypeAuditLogFormatter.php | 53 +++++++++++++++--- ...onTrackChairScoreTypeAuditLogFormatter.php | 53 +++++++++++++++--- .../SummitTrackChairAuditLogFormatter.php | 55 +++++++++++++++---- 3 files changed, 133 insertions(+), 28 deletions(-) diff --git a/app/Audit/ConcreteFormatters/PresentationTrackChairRatingTypeAuditLogFormatter.php b/app/Audit/ConcreteFormatters/PresentationTrackChairRatingTypeAuditLogFormatter.php index f3ab79104..d3d84c5c1 100644 --- a/app/Audit/ConcreteFormatters/PresentationTrackChairRatingTypeAuditLogFormatter.php +++ b/app/Audit/ConcreteFormatters/PresentationTrackChairRatingTypeAuditLogFormatter.php @@ -1,11 +1,26 @@ -event_type = $event_type; } + private function getUserInfo(): string + { + if (!$this->ctx) { + return 'Unknown (unknown)'; + } + + $user_name = 'Unknown'; + if ($this->ctx->userFirstName || $this->ctx->userLastName) { + $user_name = trim(sprintf("%s %s", $this->ctx->userFirstName ?? '', $this->ctx->userLastName ?? '')) ?: 'Unknown'; + } elseif ($this->ctx->userEmail) { + $user_name = $this->ctx->userEmail; + } + + $user_id = $this->ctx->userId ?? 'unknown'; + return sprintf("%s (%s)", $user_name, $user_id); + } + public function format($subject, array $change_set): ?string { if (!$subject instanceof PresentationTrackChairRatingType) { @@ -28,9 +60,10 @@ public function format($subject, array $change_set): ?string switch ($this->event_type) { case IAuditStrategy::EVENT_ENTITY_CREATION: return sprintf( - "Track Chair Rating Type '%s' created for Selection Plan '%s'", + "Track Chair Rating Type '%s' created for Selection Plan '%s' by user %s", $name, - $plan_name + $plan_name, + $this->getUserInfo() ); case IAuditStrategy::EVENT_ENTITY_UPDATE: @@ -41,16 +74,18 @@ public function format($subject, array $change_set): ?string $fields_str = !empty($changed_fields) ? implode(', ', $changed_fields) : 'properties'; return sprintf( - "Track Chair Rating Type '%s' updated (%s changed)", + "Track Chair Rating Type '%s' updated (%s changed) by user %s", $name, - $fields_str + $fields_str, + $this->getUserInfo() ); case IAuditStrategy::EVENT_ENTITY_DELETION: return sprintf( - "Track Chair Rating Type '%s' deleted from Selection Plan '%s'", + "Track Chair Rating Type '%s' deleted from Selection Plan '%s' by user %s", $name, - $plan_name + $plan_name, + $this->getUserInfo() ); } } catch (\Exception $ex) { diff --git a/app/Audit/ConcreteFormatters/PresentationTrackChairScoreTypeAuditLogFormatter.php b/app/Audit/ConcreteFormatters/PresentationTrackChairScoreTypeAuditLogFormatter.php index 03760e4cc..2e388419f 100644 --- a/app/Audit/ConcreteFormatters/PresentationTrackChairScoreTypeAuditLogFormatter.php +++ b/app/Audit/ConcreteFormatters/PresentationTrackChairScoreTypeAuditLogFormatter.php @@ -1,11 +1,26 @@ -event_type = $event_type; } + private function getUserInfo(): string + { + if (!$this->ctx) { + return 'Unknown (unknown)'; + } + + $user_name = 'Unknown'; + if ($this->ctx->userFirstName || $this->ctx->userLastName) { + $user_name = trim(sprintf("%s %s", $this->ctx->userFirstName ?? '', $this->ctx->userLastName ?? '')) ?: 'Unknown'; + } elseif ($this->ctx->userEmail) { + $user_name = $this->ctx->userEmail; + } + + $user_id = $this->ctx->userId ?? 'unknown'; + return sprintf("%s (%s)", $user_name, $user_id); + } + public function format($subject, array $change_set): ?string { if (!$subject instanceof PresentationTrackChairScoreType) { @@ -29,10 +61,11 @@ public function format($subject, array $change_set): ?string switch ($this->event_type) { case IAuditStrategy::EVENT_ENTITY_CREATION: return sprintf( - "Score Type '%s' (value: %s) added to Rating Type '%s'", + "Score Type '%s' (value: %s) added to Rating Type '%s' by user %s", $label, $score, - $rating_type_name + $rating_type_name, + $this->getUserInfo() ); case IAuditStrategy::EVENT_ENTITY_UPDATE: @@ -46,16 +79,18 @@ public function format($subject, array $change_set): ?string $fields_str = !empty($changed_fields) ? implode(', ', $changed_fields) : 'properties'; return sprintf( - "Score Type '%s' updated (%s changed)", + "Score Type '%s' updated (%s changed) by user %s", $label, - $fields_str + $fields_str, + $this->getUserInfo() ); case IAuditStrategy::EVENT_ENTITY_DELETION: return sprintf( - "Score Type '%s' removed from Rating Type '%s'", + "Score Type '%s' removed from Rating Type '%s' by user %s", $label, - $rating_type_name + $rating_type_name, + $this->getUserInfo() ); } } catch (\Exception $ex) { diff --git a/app/Audit/ConcreteFormatters/SummitTrackChairAuditLogFormatter.php b/app/Audit/ConcreteFormatters/SummitTrackChairAuditLogFormatter.php index 6009edb58..64f08b171 100644 --- a/app/Audit/ConcreteFormatters/SummitTrackChairAuditLogFormatter.php +++ b/app/Audit/ConcreteFormatters/SummitTrackChairAuditLogFormatter.php @@ -1,11 +1,26 @@ -event_type = $event_type; } + private function getUserInfo(): string + { + if (!$this->ctx) { + return 'Unknown (unknown)'; + } + + $user_name = 'Unknown'; + if ($this->ctx->userFirstName || $this->ctx->userLastName) { + $user_name = trim(sprintf("%s %s", $this->ctx->userFirstName ?? '', $this->ctx->userLastName ?? '')) ?: 'Unknown'; + } elseif ($this->ctx->userEmail) { + $user_name = $this->ctx->userEmail; + } + + $user_id = $this->ctx->userId ?? 'unknown'; + return sprintf("%s (%s)", $user_name, $user_id); + } + public function format($subject, array $change_set): ?string { if (!$subject instanceof SummitTrackChair) { @@ -33,10 +65,11 @@ public function format($subject, array $change_set): ?string } $tracks_list = !empty($categories) ? implode(', ', $categories) : 'No tracks assigned'; return sprintf( - "Track Chair '%s' (%d) assigned with tracks: %s", + "Track Chair '%s' (%d) assigned with tracks: %s by user %s", $member_name, $member_id, - $tracks_list + $tracks_list, + $this->getUserInfo() ); case IAuditStrategy::EVENT_ENTITY_UPDATE: @@ -55,19 +88,21 @@ public function format($subject, array $change_set): ?string $new_str = !empty($new_names) ? implode(', ', $new_names) : 'None'; return sprintf( - "Track Chair '%s' tracks changed: [%s] → [%s]", + "Track Chair '%s' tracks changed: [%s] → [%s] by user %s", $member_name, $old_str, - $new_str + $new_str, + $this->getUserInfo() ); } - return sprintf("Track Chair '%s' updated", $member_name); + return sprintf("Track Chair '%s' updated by user %s", $member_name, $this->getUserInfo()); case IAuditStrategy::EVENT_ENTITY_DELETION: return sprintf( - "Track Chair '%s' (%d) removed from summit", + "Track Chair '%s' (%d) removed from summit by user %s", $member_name, - $member_id + $member_id, + $this->getUserInfo() ); } } catch (\Exception $ex) { From 22e219b09a98420731b1ae4643ce91776f75baa2 Mon Sep 17 00:00:00 2001 From: Jose Andres Tejerina Date: Thu, 4 Dec 2025 16:44:52 -0300 Subject: [PATCH 3/3] chore: refactor getUserInfo to AbstractAuditLog --- ...ionTrackChairRatingTypeAuditLogFormatter.php | 17 ----------------- ...tionTrackChairScoreTypeAuditLogFormatter.php | 17 ----------------- .../SummitTrackChairAuditLogFormatter.php | 17 ----------------- 3 files changed, 51 deletions(-) diff --git a/app/Audit/ConcreteFormatters/PresentationTrackChairRatingTypeAuditLogFormatter.php b/app/Audit/ConcreteFormatters/PresentationTrackChairRatingTypeAuditLogFormatter.php index d3d84c5c1..4fb260e97 100644 --- a/app/Audit/ConcreteFormatters/PresentationTrackChairRatingTypeAuditLogFormatter.php +++ b/app/Audit/ConcreteFormatters/PresentationTrackChairRatingTypeAuditLogFormatter.php @@ -29,23 +29,6 @@ public function __construct(string $event_type) $this->event_type = $event_type; } - private function getUserInfo(): string - { - if (!$this->ctx) { - return 'Unknown (unknown)'; - } - - $user_name = 'Unknown'; - if ($this->ctx->userFirstName || $this->ctx->userLastName) { - $user_name = trim(sprintf("%s %s", $this->ctx->userFirstName ?? '', $this->ctx->userLastName ?? '')) ?: 'Unknown'; - } elseif ($this->ctx->userEmail) { - $user_name = $this->ctx->userEmail; - } - - $user_id = $this->ctx->userId ?? 'unknown'; - return sprintf("%s (%s)", $user_name, $user_id); - } - public function format($subject, array $change_set): ?string { if (!$subject instanceof PresentationTrackChairRatingType) { diff --git a/app/Audit/ConcreteFormatters/PresentationTrackChairScoreTypeAuditLogFormatter.php b/app/Audit/ConcreteFormatters/PresentationTrackChairScoreTypeAuditLogFormatter.php index 2e388419f..abc722245 100644 --- a/app/Audit/ConcreteFormatters/PresentationTrackChairScoreTypeAuditLogFormatter.php +++ b/app/Audit/ConcreteFormatters/PresentationTrackChairScoreTypeAuditLogFormatter.php @@ -29,23 +29,6 @@ public function __construct(string $event_type) $this->event_type = $event_type; } - private function getUserInfo(): string - { - if (!$this->ctx) { - return 'Unknown (unknown)'; - } - - $user_name = 'Unknown'; - if ($this->ctx->userFirstName || $this->ctx->userLastName) { - $user_name = trim(sprintf("%s %s", $this->ctx->userFirstName ?? '', $this->ctx->userLastName ?? '')) ?: 'Unknown'; - } elseif ($this->ctx->userEmail) { - $user_name = $this->ctx->userEmail; - } - - $user_id = $this->ctx->userId ?? 'unknown'; - return sprintf("%s (%s)", $user_name, $user_id); - } - public function format($subject, array $change_set): ?string { if (!$subject instanceof PresentationTrackChairScoreType) { diff --git a/app/Audit/ConcreteFormatters/SummitTrackChairAuditLogFormatter.php b/app/Audit/ConcreteFormatters/SummitTrackChairAuditLogFormatter.php index 64f08b171..2fbe1ad4f 100644 --- a/app/Audit/ConcreteFormatters/SummitTrackChairAuditLogFormatter.php +++ b/app/Audit/ConcreteFormatters/SummitTrackChairAuditLogFormatter.php @@ -29,23 +29,6 @@ public function __construct(string $event_type) $this->event_type = $event_type; } - private function getUserInfo(): string - { - if (!$this->ctx) { - return 'Unknown (unknown)'; - } - - $user_name = 'Unknown'; - if ($this->ctx->userFirstName || $this->ctx->userLastName) { - $user_name = trim(sprintf("%s %s", $this->ctx->userFirstName ?? '', $this->ctx->userLastName ?? '')) ?: 'Unknown'; - } elseif ($this->ctx->userEmail) { - $user_name = $this->ctx->userEmail; - } - - $user_id = $this->ctx->userId ?? 'unknown'; - return sprintf("%s (%s)", $user_name, $user_id); - } - public function format($subject, array $change_set): ?string { if (!$subject instanceof SummitTrackChair) {