Add audit functionality for HouseholdComposition actions

- Introduced `HouseholdCompositionDisplayer` and `HouseholdCompositionSubjectConverter` to handle audit display and conversion logic.
- Integrated audit triggers for create, view, and delete actions in `HouseholdCompositionController`.
- Added French translations for audit-related messages and household composition labels.
This commit is contained in:
2026-02-26 16:28:46 +01:00
parent 5eaf3ee828
commit 298065bd41
5 changed files with 119 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Audit\Displayer;
use Chill\MainBundle\Audit\Subject;
use Chill\MainBundle\Audit\SubjectDisplayerInterface;
use Chill\PersonBundle\Repository\Household\HouseholdCompositionRepositoryInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
final readonly class HouseholdCompositionDisplayer implements SubjectDisplayerInterface
{
public function __construct(private TranslatorInterface $translator, private HouseholdCompositionRepositoryInterface $compositionRepository) {}
public function supportsDisplay(Subject $subject, array $optons = []): bool
{
return 'household_composition' === $subject->type;
}
public function display(Subject $subject, string $format = 'html', array $options = []): string
{
$composition = $this->compositionRepository->find($subject->identifiers['id']);
if (null === $composition) {
$message = $this->translator->trans('audit.household_composition.unknown_composition', [
'id' => $subject->identifiers['id'],
]);
} else {
$message = match (is_null($composition->getEndDate())) {
true => $this->translator->trans('audit.household_composition.display_active', [
'id' => $subject->identifiers['id'],
'from' => $composition->getStartDate(),
]),
false => $this->translator->trans('audit.household_composition.display', [
'id' => $subject->identifiers['id'],
'from' => $composition->getStartDate(),
'to' => $composition->getEndDate(),
]),
};
}
if ('html' === $format) {
return '<span>'.$message.'</span>';
}
return $message;
}
}

View File

@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Audit\SubjectConverter;
use Chill\MainBundle\Audit\Subject;
use Chill\MainBundle\Audit\SubjectBag;
use Chill\MainBundle\Audit\SubjectConverterInterface;
use Chill\MainBundle\Audit\SubjectConverterManagerAwareInterface;
use Chill\MainBundle\Audit\SubjectConverterManagerAwareTrait;
use Chill\PersonBundle\Entity\Household\HouseholdComposition;
class HouseholdCompositionSubjectConverter implements SubjectConverterInterface, SubjectConverterManagerAwareInterface
{
use SubjectConverterManagerAwareTrait;
public function convert(mixed $subject, bool $includeAssociated = false): SubjectBag
{
/** @var HouseholdComposition $subject */
$bag = new SubjectBag(new Subject('household_composition', ['id' => $subject->getId()]));
$bag->append($this->subjectConverterManager->getSubjectsForEntity($subject->getHousehold()));
return $bag;
}
public function supportsConvert(mixed $subject): bool
{
return $subject instanceof HouseholdComposition;
}
public static function getDefaultPriority(): int
{
return 0;
}
}

View File

@@ -11,6 +11,8 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\Audit\TriggerAuditInterface;
use Chill\MainBundle\Entity\AuditTrail;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Household\HouseholdComposition;
@@ -30,6 +32,7 @@ use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Translation\TranslatableMessage;
use Symfony\Contracts\Translation\TranslatorInterface;
class HouseholdCompositionController extends AbstractController
@@ -44,6 +47,7 @@ class HouseholdCompositionController extends AbstractController
private readonly TranslatorInterface $translator,
private readonly \Twig\Environment $engine,
private readonly UrlGeneratorInterface $urlGenerator,
private readonly TriggerAuditInterface $triggerAudit,
) {}
#[Route(path: '/{_locale}/person/household/{household_id}/composition/{composition_id}/delete', name: 'chill_person_household_composition_delete')]
@@ -70,6 +74,7 @@ class HouseholdCompositionController extends AbstractController
$form->handleRequest($request);
if ($form->isValid()) {
$this->triggerAudit->triggerAudit(AuditTrail::AUDIT_DELETE, $composition);
$this->entityManager->remove($composition);
$this->entityManager->flush();
@@ -99,6 +104,8 @@ class HouseholdCompositionController extends AbstractController
throw new AccessDeniedException('not allowed to edit a household');
}
$this->triggerAudit->triggerAudit(AuditTrail::AUDIT_VIEW, $household, description: new TranslatableMessage('audit.household.list_composition'));
$count = $this->householdCompositionRepository->countByHousehold($household);
$paginator = $this->paginatorFactory->create($count);
$compositions = $this->householdCompositionRepository->findByHousehold(
@@ -146,6 +153,8 @@ class HouseholdCompositionController extends AbstractController
$this->entityManager->flush();
$this->triggerAudit->triggerAudit(AuditTrail::AUDIT_CREATE, $householdComposition);
$request->getSession()->getFlashBag()->add(
'success',
$this->translator->trans('household_composition.Composition added')

View File

@@ -209,3 +209,12 @@ accompanying_course_evaluation_document:
accompanying_period_work:
title: Action d'accompagnement (n°{id}) - {action_title}
audit:
household_composition:
display: >-
Composition n°{id} du {from, date, long} à {to, date, long}
display_active: >-
Composition n°{id} du {from, date, long} (toujours active)
unknown_composition: >-
Composition inconnue avec identifiant {id}

View File

@@ -1597,6 +1597,7 @@ audit:
list_person_file: Liste des ménages d'un usager
edit_participation: "Modification d'une participation au ménage"
household_not_found_with_id: 'Ménage non trouvé avec identifiant {id}'
list_composition: 'Liste des compositions de ménage'
household_member:
not_found_with_id: 'Membre du ménage non trouvé avec identifiant {id}'
member_in_household: 'membre du ménage'