Files
Classeo/backend/src/Scolarite/Infrastructure/EventHandler/RecalculerMoyennesOnEvaluationSupprimeeHandler.php
Mathias STRASSER aedde6707e
Some checks failed
CI / Backend Tests (push) Has been cancelled
CI / Frontend Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Naming Conventions (push) Has been cancelled
CI / Build Check (push) Has been cancelled
feat: Calculer automatiquement les moyennes après chaque saisie de notes
Les enseignants ont besoin de moyennes à jour immédiatement après la
publication ou modification des notes, sans attendre un batch nocturne.

Le système recalcule via Domain Events synchrones : statistiques
d'évaluation (min/max/moyenne/médiane), moyennes matières pondérées
(normalisation /20), et moyenne générale par élève. Les résultats sont
stockés dans des tables dénormalisées avec cache Redis (TTL 5 min).

Trois endpoints API exposent les données avec contrôle d'accès par rôle.
Une commande console permet le backfill des données historiques au
déploiement.
2026-03-31 16:43:10 +02:00

74 lines
2.4 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Scolarite\Infrastructure\EventHandler;
use App\Scolarite\Application\Port\PeriodFinder;
use App\Scolarite\Application\Service\RecalculerMoyennesService;
use App\Scolarite\Domain\Event\EvaluationSupprimee;
use App\Scolarite\Domain\Repository\EvaluationRepository;
use App\Scolarite\Domain\Repository\EvaluationStatisticsRepository;
use App\Scolarite\Domain\Repository\GradeRepository;
use App\Shared\Infrastructure\Tenant\TenantContext;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
#[AsMessageHandler(bus: 'event.bus')]
final readonly class RecalculerMoyennesOnEvaluationSupprimeeHandler
{
public function __construct(
private TenantContext $tenantContext,
private EvaluationRepository $evaluationRepository,
private GradeRepository $gradeRepository,
private EvaluationStatisticsRepository $evaluationStatisticsRepository,
private PeriodFinder $periodFinder,
private RecalculerMoyennesService $service,
) {
}
public function __invoke(EvaluationSupprimee $event): void
{
$tenantId = $this->tenantContext->getCurrentTenantId();
$evaluationId = $event->evaluationId;
// Charger l'évaluation (encore accessible même en DELETED)
$evaluation = $this->evaluationRepository->findById($evaluationId, $tenantId);
if ($evaluation === null) {
return;
}
// Supprimer les stats de l'évaluation
$this->evaluationStatisticsRepository->delete($evaluationId);
// Si les notes étaient publiées, recalculer les moyennes des élèves affectés
if ($evaluation->gradesPublishedAt === null) {
return;
}
$period = $this->periodFinder->findForDate($evaluation->evaluationDate, $tenantId);
if ($period === null) {
return;
}
$grades = $this->gradeRepository->findByEvaluation($evaluationId, $tenantId);
$studentIds = [];
foreach ($grades as $g) {
$studentIds[(string) $g->studentId] = $g->studentId;
}
// Recalculer : l'évaluation DELETED sera exclue par findWithPublishedGrades...
foreach ($studentIds as $studentId) {
$this->service->recalculerMoyenneEleve(
$studentId,
$evaluation->subjectId,
$evaluation->classId,
$period,
$tenantId,
);
}
}
}