templateRepository = new InMemoryAppreciationTemplateRepository(); $this->clock = new class implements Clock { public function now(): DateTimeImmutable { return new DateTimeImmutable('2026-03-31 10:00:00'); } }; } #[Test] public function itUpdatesTemplate(): void { $template = $this->seedTemplate(); $handler = new UpdateAppreciationTemplateHandler($this->templateRepository, $this->clock); $updated = $handler(new UpdateAppreciationTemplateCommand( tenantId: self::TENANT_ID, teacherId: self::TEACHER_ID, templateId: (string) $template->id, title: 'Titre modifié', content: 'Contenu modifié', category: 'improvement', )); self::assertSame('Titre modifié', $updated->title); self::assertSame('Contenu modifié', $updated->content); self::assertSame(AppreciationCategory::IMPROVEMENT, $updated->category); } #[Test] public function itPersistsUpdatedTemplate(): void { $template = $this->seedTemplate(); $handler = new UpdateAppreciationTemplateHandler($this->templateRepository, $this->clock); $handler(new UpdateAppreciationTemplateCommand( tenantId: self::TENANT_ID, teacherId: self::TEACHER_ID, templateId: (string) $template->id, title: 'Persisté', content: 'Contenu persisté', category: null, )); $found = $this->templateRepository->findById( $template->id, TenantId::fromString(self::TENANT_ID), ); self::assertNotNull($found); self::assertSame('Persisté', $found->title); self::assertNull($found->category); } #[Test] public function itThrowsWhenTemplateNotFound(): void { $handler = new UpdateAppreciationTemplateHandler($this->templateRepository, $this->clock); $this->expectException(AppreciationTemplateNonTrouveeException::class); $handler(new UpdateAppreciationTemplateCommand( tenantId: self::TENANT_ID, teacherId: self::TEACHER_ID, templateId: '550e8400-e29b-41d4-a716-446655440099', title: 'Test', content: 'Contenu', category: null, )); } #[Test] public function itThrowsWhenTeacherNotOwner(): void { $template = $this->seedTemplate(); $handler = new UpdateAppreciationTemplateHandler($this->templateRepository, $this->clock); $this->expectException(NonProprietaireDuModeleException::class); $handler(new UpdateAppreciationTemplateCommand( tenantId: self::TENANT_ID, teacherId: '550e8400-e29b-41d4-a716-446655440099', templateId: (string) $template->id, title: 'Hijack', content: 'Contenu', category: null, )); } #[Test] public function itThrowsWhenCategoryInvalid(): void { $template = $this->seedTemplate(); $handler = new UpdateAppreciationTemplateHandler($this->templateRepository, $this->clock); $this->expectException(CategorieAppreciationInvalideException::class); $handler(new UpdateAppreciationTemplateCommand( tenantId: self::TENANT_ID, teacherId: self::TEACHER_ID, templateId: (string) $template->id, title: 'Test', content: 'Contenu', category: 'invalid_category', )); } #[Test] public function itUpdatesTemplateWithNullCategory(): void { $template = $this->seedTemplate(); $handler = new UpdateAppreciationTemplateHandler($this->templateRepository, $this->clock); $updated = $handler(new UpdateAppreciationTemplateCommand( tenantId: self::TENANT_ID, teacherId: self::TEACHER_ID, templateId: (string) $template->id, title: 'Sans catégorie', content: 'Contenu mis à jour', category: null, )); self::assertNull($updated->category); self::assertSame('Sans catégorie', $updated->title); } private function seedTemplate(): AppreciationTemplate { $template = AppreciationTemplate::creer( tenantId: TenantId::fromString(self::TENANT_ID), teacherId: UserId::fromString(self::TEACHER_ID), title: 'Template original', content: 'Contenu original', category: AppreciationCategory::POSITIVE, now: $this->clock->now(), ); $this->templateRepository->save($template); return $template; } }