createSubject(); self::assertSame(SubjectStatus::ACTIVE, $subject->status); self::assertTrue($subject->estActive()); self::assertTrue($subject->peutEtreUtilisee()); } #[Test] public function creerRecordsMatiereCreeeEvent(): void { $subject = $this->createSubject(); $events = $subject->pullDomainEvents(); self::assertCount(1, $events); self::assertInstanceOf(MatiereCreee::class, $events[0]); self::assertSame($subject->id, $events[0]->subjectId); self::assertSame($subject->tenantId, $events[0]->tenantId); self::assertSame($subject->name, $events[0]->name); self::assertSame($subject->code, $events[0]->code); } #[Test] public function creerSetsAllProperties(): void { $tenantId = TenantId::fromString(self::TENANT_ID); $schoolId = SchoolId::fromString(self::SCHOOL_ID); $name = new SubjectName('Mathématiques'); $code = new SubjectCode('MATH'); $color = new SubjectColor('#3B82F6'); $createdAt = new DateTimeImmutable('2026-01-15 10:00:00'); $subject = Subject::creer( tenantId: $tenantId, schoolId: $schoolId, name: $name, code: $code, color: $color, createdAt: $createdAt, ); self::assertTrue($subject->tenantId->equals($tenantId)); self::assertTrue($subject->schoolId->equals($schoolId)); self::assertTrue($subject->name->equals($name)); self::assertTrue($subject->code->equals($code)); self::assertNotNull($subject->color); self::assertTrue($subject->color->equals($color)); self::assertEquals($createdAt, $subject->createdAt); self::assertEquals($createdAt, $subject->updatedAt); self::assertNull($subject->deletedAt); self::assertNull($subject->description); } #[Test] public function creerWithNullColor(): void { $subject = Subject::creer( tenantId: TenantId::fromString(self::TENANT_ID), schoolId: SchoolId::fromString(self::SCHOOL_ID), name: new SubjectName('Arts plastiques'), code: new SubjectCode('ART'), color: null, createdAt: new DateTimeImmutable(), ); self::assertNull($subject->color); } #[Test] public function renommerChangesNameAndRecordsEvent(): void { $subject = $this->createSubject(); $subject->pullDomainEvents(); $ancienNom = $subject->name; $nouveauNom = new SubjectName('Mathématiques avancées'); $at = new DateTimeImmutable('2026-02-01 10:00:00'); $subject->renommer($nouveauNom, $at); self::assertTrue($subject->name->equals($nouveauNom)); self::assertEquals($at, $subject->updatedAt); $events = $subject->pullDomainEvents(); self::assertCount(1, $events); self::assertInstanceOf(MatiereModifiee::class, $events[0]); self::assertSame('nom', $events[0]->champ); self::assertSame((string) $ancienNom, $events[0]->ancienneValeur); self::assertSame((string) $nouveauNom, $events[0]->nouvelleValeur); } #[Test] public function renommerWithSameNameDoesNothing(): void { $subject = $this->createSubject(); $subject->pullDomainEvents(); $originalUpdatedAt = $subject->updatedAt; $subject->renommer(new SubjectName('Mathématiques'), new DateTimeImmutable('2026-02-01 10:00:00')); self::assertEquals($originalUpdatedAt, $subject->updatedAt); self::assertEmpty($subject->pullDomainEvents()); } #[Test] public function changerCodeUpdatesCodeAndRecordsEvent(): void { $subject = $this->createSubject(); $subject->pullDomainEvents(); $at = new DateTimeImmutable('2026-02-01 10:00:00'); $nouveauCode = new SubjectCode('MATHS'); $subject->changerCode($nouveauCode, $at); self::assertTrue($subject->code->equals($nouveauCode)); self::assertEquals($at, $subject->updatedAt); $events = $subject->pullDomainEvents(); self::assertCount(1, $events); self::assertInstanceOf(MatiereModifiee::class, $events[0]); self::assertSame('code', $events[0]->champ); self::assertSame('MATH', $events[0]->ancienneValeur); self::assertSame('MATHS', $events[0]->nouvelleValeur); } #[Test] public function changerCodeWithSameCodeDoesNothing(): void { $subject = $this->createSubject(); $subject->pullDomainEvents(); $originalUpdatedAt = $subject->updatedAt; $subject->changerCode(new SubjectCode('MATH'), new DateTimeImmutable('2026-02-01 10:00:00')); self::assertEquals($originalUpdatedAt, $subject->updatedAt); self::assertEmpty($subject->pullDomainEvents()); } #[Test] public function changerCouleurUpdatesColorAndRecordsEvent(): void { $subject = $this->createSubject(); $subject->pullDomainEvents(); $at = new DateTimeImmutable('2026-02-01 10:00:00'); $nouvelleCouleur = new SubjectColor('#EF4444'); $subject->changerCouleur($nouvelleCouleur, $at); self::assertNotNull($subject->color); self::assertTrue($subject->color->equals($nouvelleCouleur)); self::assertEquals($at, $subject->updatedAt); $events = $subject->pullDomainEvents(); self::assertCount(1, $events); self::assertInstanceOf(MatiereModifiee::class, $events[0]); self::assertSame('couleur', $events[0]->champ); self::assertSame('#3B82F6', $events[0]->ancienneValeur); self::assertSame('#EF4444', $events[0]->nouvelleValeur); } #[Test] public function changerCouleurToNullRemovesColorAndRecordsEvent(): void { $subject = $this->createSubject(); $subject->pullDomainEvents(); $at = new DateTimeImmutable('2026-02-01 10:00:00'); $subject->changerCouleur(null, $at); self::assertNull($subject->color); self::assertEquals($at, $subject->updatedAt); $events = $subject->pullDomainEvents(); self::assertCount(1, $events); self::assertInstanceOf(MatiereModifiee::class, $events[0]); self::assertSame('couleur', $events[0]->champ); self::assertSame('#3B82F6', $events[0]->ancienneValeur); self::assertNull($events[0]->nouvelleValeur); } #[Test] public function changerCouleurWithSameColorDoesNothing(): void { $subject = $this->createSubject(); $subject->pullDomainEvents(); $originalUpdatedAt = $subject->updatedAt; $subject->changerCouleur(new SubjectColor('#3B82F6'), new DateTimeImmutable('2026-02-01 10:00:00')); self::assertEquals($originalUpdatedAt, $subject->updatedAt); self::assertEmpty($subject->pullDomainEvents()); } #[Test] public function decrireUpdatesDescriptionAndRecordsEvent(): void { $subject = $this->createSubject(); $subject->pullDomainEvents(); $at = new DateTimeImmutable('2026-02-01 10:00:00'); $subject->decrire('Cours de mathématiques généralistes', $at); self::assertSame('Cours de mathématiques généralistes', $subject->description); self::assertEquals($at, $subject->updatedAt); $events = $subject->pullDomainEvents(); self::assertCount(1, $events); self::assertInstanceOf(MatiereModifiee::class, $events[0]); self::assertSame('description', $events[0]->champ); self::assertNull($events[0]->ancienneValeur); self::assertSame('Cours de mathématiques généralistes', $events[0]->nouvelleValeur); } #[Test] public function archiverChangesStatusAndRecordsEvent(): void { $subject = $this->createSubject(); $subject->pullDomainEvents(); $at = new DateTimeImmutable('2026-02-01 10:00:00'); $subject->archiver($at); self::assertSame(SubjectStatus::ARCHIVED, $subject->status); self::assertFalse($subject->estActive()); self::assertFalse($subject->peutEtreUtilisee()); self::assertEquals($at, $subject->deletedAt); self::assertEquals($at, $subject->updatedAt); $events = $subject->pullDomainEvents(); self::assertCount(1, $events); self::assertInstanceOf(MatiereSupprimee::class, $events[0]); } #[Test] public function archiverAlreadyArchivedSubjectDoesNothing(): void { $subject = $this->createSubject(); $subject->archiver(new DateTimeImmutable('2026-02-01 10:00:00')); $subject->pullDomainEvents(); $originalDeletedAt = $subject->deletedAt; $subject->archiver(new DateTimeImmutable('2026-02-02 10:00:00')); self::assertEquals($originalDeletedAt, $subject->deletedAt); self::assertEmpty($subject->pullDomainEvents()); } #[Test] public function reconstituteRestoresAllProperties(): void { $id = SubjectId::generate(); $tenantId = TenantId::fromString(self::TENANT_ID); $schoolId = SchoolId::fromString(self::SCHOOL_ID); $name = new SubjectName('Mathématiques'); $code = new SubjectCode('MATH'); $color = new SubjectColor('#3B82F6'); $status = SubjectStatus::ARCHIVED; $description = 'Test description'; $createdAt = new DateTimeImmutable('2026-01-15 10:00:00'); $updatedAt = new DateTimeImmutable('2026-02-01 10:00:00'); $deletedAt = new DateTimeImmutable('2026-02-01 10:00:00'); $subject = Subject::reconstitute( id: $id, tenantId: $tenantId, schoolId: $schoolId, name: $name, code: $code, color: $color, status: $status, description: $description, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, ); self::assertTrue($subject->id->equals($id)); self::assertTrue($subject->tenantId->equals($tenantId)); self::assertTrue($subject->schoolId->equals($schoolId)); self::assertTrue($subject->name->equals($name)); self::assertTrue($subject->code->equals($code)); self::assertNotNull($subject->color); self::assertTrue($subject->color->equals($color)); self::assertSame($status, $subject->status); self::assertSame($description, $subject->description); self::assertEquals($createdAt, $subject->createdAt); self::assertEquals($updatedAt, $subject->updatedAt); self::assertEquals($deletedAt, $subject->deletedAt); self::assertEmpty($subject->pullDomainEvents()); } private function createSubject(): Subject { return Subject::creer( tenantId: TenantId::fromString(self::TENANT_ID), schoolId: SchoolId::fromString(self::SCHOOL_ID), name: new SubjectName('Mathématiques'), code: new SubjectCode('MATH'), color: new SubjectColor('#3B82F6'), createdAt: new DateTimeImmutable('2026-01-15 10:00:00'), ); } }