*/ private array $affectationResults = []; protected function setUp(): void { $this->evaluationRepository = new InMemoryEvaluationRepository(); $this->gradeRepository = new InMemoryGradeRepository(); $this->replacementRepository = new InMemoryTeacherReplacementRepository(); $this->clock = new class implements Clock { public function now(): DateTimeImmutable { return new DateTimeImmutable('2026-03-31 10:00:00'); } }; $this->affectationResults = []; $this->affectationResults[self::TEACHER_ID] = true; $this->seedEvaluationAndGrade(); } public function isTeacherAffecte(string $teacherId): bool { return $this->affectationResults[$teacherId] ?? false; } #[Test] public function itSavesAppreciation(): void { $handler = $this->createHandler(); $grade = $handler(new SaveAppreciationCommand( tenantId: self::TENANT_ID, gradeId: $this->gradeId, teacherId: self::TEACHER_ID, appreciation: 'Très bon travail', )); self::assertSame('Très bon travail', $grade->appreciation); self::assertNotNull($grade->appreciationUpdatedAt); } #[Test] public function itClearsAppreciation(): void { $handler = $this->createHandler(); $handler(new SaveAppreciationCommand( tenantId: self::TENANT_ID, gradeId: $this->gradeId, teacherId: self::TEACHER_ID, appreciation: 'Bon travail', )); $grade = $handler(new SaveAppreciationCommand( tenantId: self::TENANT_ID, gradeId: $this->gradeId, teacherId: self::TEACHER_ID, appreciation: null, )); self::assertNull($grade->appreciation); } #[Test] public function itThrowsWhenTeacherNotOwner(): void { $handler = $this->createHandler(); $this->expectException(NonProprietaireDeLEvaluationException::class); $handler(new SaveAppreciationCommand( tenantId: self::TENANT_ID, gradeId: $this->gradeId, teacherId: '550e8400-e29b-41d4-a716-446655440099', appreciation: 'Test', )); } #[Test] public function itThrowsWhenGradeNotFound(): void { $handler = $this->createHandler(); $this->expectException(GradeNotFoundException::class); $handler(new SaveAppreciationCommand( tenantId: self::TENANT_ID, gradeId: '550e8400-e29b-41d4-a716-446655440099', teacherId: self::TEACHER_ID, appreciation: 'Test', )); } #[Test] public function itThrowsWhenAppreciationTooLong(): void { $handler = $this->createHandler(); $this->expectException(AppreciationTropLongueException::class); $handler(new SaveAppreciationCommand( tenantId: self::TENANT_ID, gradeId: $this->gradeId, teacherId: self::TEACHER_ID, appreciation: str_repeat('a', 501), )); } private function createHandler(): SaveAppreciationHandler { return new SaveAppreciationHandler( $this->evaluationRepository, $this->gradeRepository, $this->createAutorisationChecker(), $this->clock, ); } private function createAutorisationChecker(): AutorisationSaisieNotesChecker { $test = $this; $affectationChecker = new class($test) implements EnseignantAffectationChecker { public function __construct(private readonly SaveAppreciationHandlerTest $test) { } public function estAffecte( UserId $teacherId, ClassId $classId, SubjectId $subjectId, TenantId $tenantId, ): bool { return $this->test->isTeacherAffecte((string) $teacherId); } }; return new AutorisationSaisieNotesChecker( $affectationChecker, $this->replacementRepository, ); } private function seedEvaluationAndGrade(): void { $tenantId = TenantId::fromString(self::TENANT_ID); $evaluation = Evaluation::reconstitute( id: EvaluationId::fromString(self::EVALUATION_ID), tenantId: $tenantId, classId: ClassId::fromString('550e8400-e29b-41d4-a716-446655440020'), subjectId: SubjectId::fromString('550e8400-e29b-41d4-a716-446655440030'), teacherId: UserId::fromString(self::TEACHER_ID), title: 'Contrôle', description: null, evaluationDate: new DateTimeImmutable('2026-04-15'), gradeScale: new GradeScale(20), coefficient: new Coefficient(1.0), status: EvaluationStatus::PUBLISHED, createdAt: new DateTimeImmutable('2026-03-12 10:00:00'), updatedAt: new DateTimeImmutable('2026-03-12 10:00:00'), ); $this->evaluationRepository->save($evaluation); $grade = Grade::saisir( tenantId: $tenantId, evaluationId: EvaluationId::fromString(self::EVALUATION_ID), studentId: UserId::fromString(self::STUDENT_ID), value: new GradeValue(15.5), status: GradeStatus::GRADED, gradeScale: new GradeScale(20), createdBy: UserId::fromString(self::TEACHER_ID), now: new DateTimeImmutable('2026-03-27 10:00:00'), ); $this->gradeRepository->save($grade); $this->gradeId = (string) $grade->id; } }