Add audit logging and subject conversion for accompanying periods

- Added `AccompanyingPeriodSubjectConverter` to handle subject conversion for accompanying periods.
- Integrated `AuditEvent` dispatching into `AccompanyingCourseController` for key actions (e.g., create, view, update, delete, reopen).
- Extended translations to include audit-related messages for accompanying periods.
- Introduced tests for `AccompanyingPeriodSubjectConverter` to ensure proper functionality.
This commit is contained in:
2026-01-28 17:32:27 +01:00
parent 624cad8818
commit d2f5b49131
4 changed files with 174 additions and 0 deletions

View File

@@ -12,6 +12,8 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Controller;
use Chill\ActivityBundle\Entity\Activity;
use Chill\MainBundle\Audit\AuditEvent;
use Chill\MainBundle\Entity\AuditTrail;
use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Household\Household;
@@ -20,6 +22,7 @@ use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepos
use Chill\PersonBundle\Repository\PersonRepository;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Psr\EventDispatcher\EventDispatcherInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
@@ -27,6 +30,7 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Translation\TranslatableMessage;
use Symfony\Component\Validator\ConstraintViolationInterface;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
@@ -46,6 +50,7 @@ final class AccompanyingCourseController extends \Symfony\Bundle\FrameworkBundle
private readonly Security $security,
private readonly PersonRepository $personRepository,
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
private readonly EventDispatcherInterface $eventDispatcher,
) {}
/**
@@ -72,6 +77,15 @@ final class AccompanyingCourseController extends \Symfony\Bundle\FrameworkBundle
$em->flush();
$this->eventDispatcher->dispatch(
new AuditEvent(
AuditTrail::AUDIT_UPDATE,
[$accompanyingCourse],
new TranslatableMessage('accompanying_period.audit.close'),
['action' => 'close']
)
);
return $this->redirectToRoute('chill_person_accompanying_course_index', [
'accompanying_period_id' => $accompanyingCourse->getId(),
]);
@@ -119,6 +133,8 @@ final class AccompanyingCourseController extends \Symfony\Bundle\FrameworkBundle
$em->remove($accompanyingCourse);
$em->flush();
$this->eventDispatcher->dispatch(new AuditEvent(AuditTrail::AUDIT_DELETE, [$accompanyingCourse]));
$this->addFlash('success', $this->translator
->trans('The accompanying course has been successfully removed.'));
@@ -157,6 +173,13 @@ final class AccompanyingCourseController extends \Symfony\Bundle\FrameworkBundle
{
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::EDIT, $accompanyingCourse);
$this->eventDispatcher->dispatch(new AuditEvent(
AuditTrail::AUDIT_VIEW,
[$accompanyingCourse],
new TranslatableMessage('accompanying_period.audit.show_edit_page'),
['action' => 'show_edit_page']
));
return $this->render('@ChillPerson/AccompanyingCourse/edit.html.twig', [
'accompanyingCourse' => $accompanyingCourse,
]);
@@ -189,6 +212,8 @@ final class AccompanyingCourseController extends \Symfony\Bundle\FrameworkBundle
{
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $accompanyingCourse);
$this->eventDispatcher->dispatch(new AuditEvent(AuditTrail::AUDIT_VIEW, [$accompanyingCourse]));
// compute some warnings
// get persons without household
$withoutHousehold = [];
@@ -258,6 +283,8 @@ final class AccompanyingCourseController extends \Symfony\Bundle\FrameworkBundle
$em->persist($period);
$em->flush();
$this->eventDispatcher->dispatch(new AuditEvent(AuditTrail::AUDIT_CREATE, [$period]));
return $this->redirectToRoute('chill_person_accompanying_course_edit', [
'accompanying_period_id' => $period->getId(),
]);
@@ -295,6 +322,8 @@ final class AccompanyingCourseController extends \Symfony\Bundle\FrameworkBundle
$em->persist($period);
$em->flush();
$this->eventDispatcher->dispatch(new AuditEvent(AuditTrail::AUDIT_CREATE, [$period]));
return $this->redirectToRoute('chill_person_accompanying_course_edit', [
'accompanying_period_id' => $period->getId(),
]);
@@ -319,6 +348,8 @@ 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']));
return $this->redirectToRoute('chill_person_accompanying_course_index', [
'accompanying_period_id' => $accompanyingCourse->getId(),
]);