Les établissements ont besoin de définir leur référentiel de matières pour pouvoir ensuite les associer aux enseignants et aux classes. Cette fonctionnalité permet aux administrateurs de créer, modifier et archiver les matières avec leurs propriétés (nom, code court, couleur). L'architecture suit le pattern DDD avec des Value Objects utilisant les property hooks PHP 8.5 pour garantir l'immutabilité et la validation. L'isolation multi-tenant est assurée par vérification dans les handlers.
295 lines
10 KiB
PHP
295 lines
10 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Unit\Administration\Domain\Model\Subject;
|
|
|
|
use App\Administration\Domain\Event\MatiereCreee;
|
|
use App\Administration\Domain\Event\MatiereModifiee;
|
|
use App\Administration\Domain\Event\MatiereSupprimee;
|
|
use App\Administration\Domain\Model\SchoolClass\SchoolId;
|
|
use App\Administration\Domain\Model\Subject\Subject;
|
|
use App\Administration\Domain\Model\Subject\SubjectCode;
|
|
use App\Administration\Domain\Model\Subject\SubjectColor;
|
|
use App\Administration\Domain\Model\Subject\SubjectId;
|
|
use App\Administration\Domain\Model\Subject\SubjectName;
|
|
use App\Administration\Domain\Model\Subject\SubjectStatus;
|
|
use App\Shared\Domain\Tenant\TenantId;
|
|
use DateTimeImmutable;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class SubjectTest extends TestCase
|
|
{
|
|
private const string TENANT_ID = '550e8400-e29b-41d4-a716-446655440001';
|
|
private const string SCHOOL_ID = '550e8400-e29b-41d4-a716-446655440002';
|
|
|
|
#[Test]
|
|
public function creerCreatesSubjectWithActiveStatus(): void
|
|
{
|
|
$subject = $this->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::assertTrue($events[0]->ancienNom->equals($ancienNom));
|
|
self::assertTrue($events[0]->nouveauNom->equals($nouveauNom));
|
|
}
|
|
|
|
#[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 changerCodeUpdatesCode(): void
|
|
{
|
|
$subject = $this->createSubject();
|
|
$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);
|
|
}
|
|
|
|
#[Test]
|
|
public function changerCodeWithSameCodeDoesNothing(): void
|
|
{
|
|
$subject = $this->createSubject();
|
|
$originalUpdatedAt = $subject->updatedAt;
|
|
|
|
$subject->changerCode(new SubjectCode('MATH'), new DateTimeImmutable('2026-02-01 10:00:00'));
|
|
|
|
self::assertEquals($originalUpdatedAt, $subject->updatedAt);
|
|
}
|
|
|
|
#[Test]
|
|
public function changerCouleurUpdatesColor(): void
|
|
{
|
|
$subject = $this->createSubject();
|
|
$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);
|
|
}
|
|
|
|
#[Test]
|
|
public function changerCouleurToNullRemovesColor(): void
|
|
{
|
|
$subject = $this->createSubject();
|
|
$at = new DateTimeImmutable('2026-02-01 10:00:00');
|
|
|
|
$subject->changerCouleur(null, $at);
|
|
|
|
self::assertNull($subject->color);
|
|
self::assertEquals($at, $subject->updatedAt);
|
|
}
|
|
|
|
#[Test]
|
|
public function changerCouleurWithSameColorDoesNothing(): void
|
|
{
|
|
$subject = $this->createSubject();
|
|
$originalUpdatedAt = $subject->updatedAt;
|
|
|
|
$subject->changerCouleur(new SubjectColor('#3B82F6'), new DateTimeImmutable('2026-02-01 10:00:00'));
|
|
|
|
self::assertEquals($originalUpdatedAt, $subject->updatedAt);
|
|
}
|
|
|
|
#[Test]
|
|
public function decrireUpdatesDescription(): void
|
|
{
|
|
$subject = $this->createSubject();
|
|
$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);
|
|
}
|
|
|
|
#[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'),
|
|
);
|
|
}
|
|
}
|