Refactor subject conversion handling and enhance audit logging

- Replaced `Subject|array` return types with `SubjectBag` in `SubjectConverterInterface` for more robust handling.
- Updated `getSubjectsForEntity` to include an optional `$includeAssociated` parameter for finer control over associated subject resolution.
- Refactored `AuditEvent` to differentiate `mainSubject` from associated subjects, improving clarity in audit logging.
- Introduced database schema changes to add `main_subject` and `subjects` columns in the `chill_main_audit_trail` table.
- Added `SubjectBag` class for grouped subject management and implemented deduplication logic.
- Updated all converters and test cases to use the new `SubjectBag` approach, ensuring compatibility.
- Improved event dispatching in controllers to utilize the updated `AuditEvent` structure and refined metadata handling.
This commit is contained in:
2026-02-13 16:56:04 +01:00
parent 443ee4cb1a
commit 32c5f21438
20 changed files with 332 additions and 84 deletions

View File

@@ -80,7 +80,8 @@ final class AccompanyingCourseController extends \Symfony\Bundle\FrameworkBundle
$this->eventDispatcher->dispatch(
new AuditEvent(
AuditTrail::AUDIT_UPDATE,
[$accompanyingCourse],
$accompanyingCourse,
[],
new TranslatableMessage('accompanying_period.audit.close'),
['action' => 'close']
)
@@ -133,7 +134,7 @@ final class AccompanyingCourseController extends \Symfony\Bundle\FrameworkBundle
$em->remove($accompanyingCourse);
$em->flush();
$this->eventDispatcher->dispatch(new AuditEvent(AuditTrail::AUDIT_DELETE, [$accompanyingCourse]));
$this->eventDispatcher->dispatch(new AuditEvent(AuditTrail::AUDIT_DELETE, $accompanyingCourse));
$this->addFlash('success', $this->translator
->trans('The accompanying course has been successfully removed.'));
@@ -175,9 +176,9 @@ final class AccompanyingCourseController extends \Symfony\Bundle\FrameworkBundle
$this->eventDispatcher->dispatch(new AuditEvent(
AuditTrail::AUDIT_VIEW,
[$accompanyingCourse],
new TranslatableMessage('accompanying_period.audit.show_edit_page'),
['action' => 'show_edit_page']
$accompanyingCourse,
description: new TranslatableMessage('accompanying_period.audit.show_edit_page'),
metadata: ['action' => 'show_edit_page']
));
return $this->render('@ChillPerson/AccompanyingCourse/edit.html.twig', [
@@ -212,7 +213,7 @@ final class AccompanyingCourseController extends \Symfony\Bundle\FrameworkBundle
{
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $accompanyingCourse);
$this->eventDispatcher->dispatch(new AuditEvent(AuditTrail::AUDIT_VIEW, [$accompanyingCourse]));
$this->eventDispatcher->dispatch(new AuditEvent(AuditTrail::AUDIT_VIEW, $accompanyingCourse));
// compute some warnings
// get persons without household
@@ -283,7 +284,7 @@ final class AccompanyingCourseController extends \Symfony\Bundle\FrameworkBundle
$em->persist($period);
$em->flush();
$this->eventDispatcher->dispatch(new AuditEvent(AuditTrail::AUDIT_CREATE, [$period]));
$this->eventDispatcher->dispatch(new AuditEvent(AuditTrail::AUDIT_CREATE, $period));
return $this->redirectToRoute('chill_person_accompanying_course_edit', [
'accompanying_period_id' => $period->getId(),
@@ -322,7 +323,7 @@ final class AccompanyingCourseController extends \Symfony\Bundle\FrameworkBundle
$em->persist($period);
$em->flush();
$this->eventDispatcher->dispatch(new AuditEvent(AuditTrail::AUDIT_CREATE, [$period]));
$this->eventDispatcher->dispatch(new AuditEvent(AuditTrail::AUDIT_CREATE, $period));
return $this->redirectToRoute('chill_person_accompanying_course_edit', [
'accompanying_period_id' => $period->getId(),
@@ -348,7 +349,7 @@ final class AccompanyingCourseController extends \Symfony\Bundle\FrameworkBundle
$accompanyingCourse->reOpen();
$this->managerRegistry->getManager()->flush();
$this->eventDispatcher->dispatch(new AuditEvent(AuditTrail::AUDIT_UPDATE, [$accompanyingCourse], new TranslatableMessage('accompanying_period.audit.reopen'), ['action' => 'reopen']));
$this->eventDispatcher->dispatch(new AuditEvent(AuditTrail::AUDIT_UPDATE, $accompanyingCourse, description: new TranslatableMessage('accompanying_period.audit.reopen'), metadata: ['action' => 'reopen']));
return $this->redirectToRoute('chill_person_accompanying_course_index', [
'accompanying_period_id' => $accompanyingCourse->getId(),