classRepository = new InMemoryClassRepository(); $this->clock = new class implements Clock { public function now(): DateTimeImmutable { return new DateTimeImmutable('2026-02-01 10:00:00'); } }; } #[Test] public function itArchivesEmptyClass(): void { $class = $this->createAndSaveClass(); $queryBus = $this->createQueryBusReturning(0); $handler = new ArchiveClassHandler($this->classRepository, $queryBus, $this->clock); $command = new ArchiveClassCommand(classId: (string) $class->id); $handler($command); $archivedClass = $this->classRepository->get($class->id); self::assertSame(ClassStatus::ARCHIVED, $archivedClass->status); self::assertNotNull($archivedClass->deletedAt); } #[Test] public function itThrowsExceptionWhenStudentsAreAffected(): void { $class = $this->createAndSaveClass(); $queryBus = $this->createQueryBusReturning(5); $handler = new ArchiveClassHandler($this->classRepository, $queryBus, $this->clock); $command = new ArchiveClassCommand(classId: (string) $class->id); $this->expectException(ClasseNonSupprimableException::class); $this->expectExceptionMessage('5 élève(s)'); $handler($command); } #[Test] public function itDoesNotModifyStatusWhenAlreadyArchived(): void { $class = $this->createAndSaveClass(); $archiveTime = new DateTimeImmutable('2026-01-20 10:00:00'); $class->archiver($archiveTime); $this->classRepository->save($class); $queryBus = $this->createQueryBusReturning(0); $handler = new ArchiveClassHandler($this->classRepository, $queryBus, $this->clock); $command = new ArchiveClassCommand(classId: (string) $class->id); $handler($command); $archivedClass = $this->classRepository->get($class->id); // deletedAt should not have changed self::assertEquals($archiveTime, $archivedClass->deletedAt); } private function createAndSaveClass(): SchoolClass { $class = SchoolClass::creer( tenantId: TenantId::fromString(self::TENANT_ID), schoolId: SchoolId::fromString(self::SCHOOL_ID), academicYearId: AcademicYearId::fromString(self::ACADEMIC_YEAR_ID), name: new ClassName('6ème A'), level: SchoolLevel::SIXIEME, capacity: 30, createdAt: new DateTimeImmutable('2026-01-15 10:00:00'), ); $this->classRepository->save($class); return $class; } private function createQueryBusReturning(int $studentCount): MessageBusInterface { return new class($studentCount) implements MessageBusInterface { public function __construct(private readonly int $studentCount) { } public function dispatch(object $message, array $stamps = []): Envelope { if (!$message instanceof HasStudentsInClassQuery) { throw new RuntimeException('Unexpected message type'); } $envelope = new Envelope($message); return $envelope->with(new HandledStamp($this->studentCount, 'handler')); } }; } }