L'élève avait accès à ses compétences mais pas à ses notes numériques. Cette fonctionnalité lui donne une vue complète de sa progression scolaire avec moyennes par matière, détail par évaluation, statistiques de classe, et un mode "découverte" pour révéler ses notes à son rythme (FR14, FR15). Les notes ne sont visibles qu'après publication par l'enseignant, ce qui garantit que l'élève les découvre avant ses parents (délai 24h story 6.7).
219 lines
5.8 KiB
PHP
219 lines
5.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Administration\Domain\Model\SchoolClass;
|
|
|
|
use App\Administration\Domain\Event\ClasseArchivee;
|
|
use App\Administration\Domain\Event\ClasseCreee;
|
|
use App\Administration\Domain\Event\ClasseModifiee;
|
|
use App\Shared\Domain\AggregateRoot;
|
|
use App\Shared\Domain\Tenant\TenantId;
|
|
use DateTimeImmutable;
|
|
|
|
/**
|
|
* Aggregate Root représentant une classe scolaire.
|
|
*
|
|
* Une classe appartient à un établissement (tenant), une école et une année scolaire.
|
|
* Elle peut recevoir des élèves et est organisée par niveau scolaire.
|
|
*
|
|
* @see FR73: Organiser les élèves par groupes pédagogiques
|
|
*/
|
|
final class SchoolClass extends AggregateRoot
|
|
{
|
|
public private(set) ?string $description = null;
|
|
public private(set) DateTimeImmutable $updatedAt;
|
|
public private(set) ?DateTimeImmutable $deletedAt = null;
|
|
|
|
private function __construct(
|
|
public private(set) ClassId $id,
|
|
public private(set) TenantId $tenantId,
|
|
public private(set) SchoolId $schoolId,
|
|
public private(set) AcademicYearId $academicYearId,
|
|
public private(set) ClassName $name,
|
|
public private(set) ?SchoolLevel $level,
|
|
public private(set) ?int $capacity,
|
|
public private(set) ClassStatus $status,
|
|
public private(set) DateTimeImmutable $createdAt,
|
|
) {
|
|
$this->updatedAt = $createdAt;
|
|
}
|
|
|
|
/**
|
|
* Crée une nouvelle classe scolaire.
|
|
*/
|
|
public static function creer(
|
|
TenantId $tenantId,
|
|
SchoolId $schoolId,
|
|
AcademicYearId $academicYearId,
|
|
ClassName $name,
|
|
?SchoolLevel $level,
|
|
?int $capacity,
|
|
DateTimeImmutable $createdAt,
|
|
): self {
|
|
$class = new self(
|
|
id: ClassId::generate(),
|
|
tenantId: $tenantId,
|
|
schoolId: $schoolId,
|
|
academicYearId: $academicYearId,
|
|
name: $name,
|
|
level: $level,
|
|
capacity: $capacity,
|
|
status: ClassStatus::ACTIVE,
|
|
createdAt: $createdAt,
|
|
);
|
|
|
|
$class->recordEvent(new ClasseCreee(
|
|
classId: $class->id,
|
|
tenantId: $class->tenantId,
|
|
name: $class->name,
|
|
level: $class->level,
|
|
occurredOn: $createdAt,
|
|
));
|
|
|
|
return $class;
|
|
}
|
|
|
|
/**
|
|
* Renomme la classe.
|
|
*/
|
|
public function renommer(ClassName $nouveauNom, DateTimeImmutable $at): void
|
|
{
|
|
if ($this->name->equals($nouveauNom)) {
|
|
return;
|
|
}
|
|
|
|
$ancienNom = $this->name;
|
|
$this->name = $nouveauNom;
|
|
$this->updatedAt = $at;
|
|
|
|
$this->recordEvent(new ClasseModifiee(
|
|
classId: $this->id,
|
|
tenantId: $this->tenantId,
|
|
ancienNom: $ancienNom,
|
|
nouveauNom: $nouveauNom,
|
|
occurredOn: $at,
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Modifie le niveau scolaire de la classe.
|
|
*/
|
|
public function changerNiveau(?SchoolLevel $niveau, DateTimeImmutable $at): void
|
|
{
|
|
if ($this->level === $niveau) {
|
|
return;
|
|
}
|
|
|
|
$this->level = $niveau;
|
|
$this->updatedAt = $at;
|
|
|
|
$this->recordEvent(new ClasseModifiee(
|
|
classId: $this->id,
|
|
tenantId: $this->tenantId,
|
|
ancienNom: $this->name,
|
|
nouveauNom: $this->name,
|
|
occurredOn: $at,
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Modifie la capacité maximale de la classe.
|
|
*/
|
|
public function changerCapacite(?int $capacity, DateTimeImmutable $at): void
|
|
{
|
|
if ($this->capacity === $capacity) {
|
|
return;
|
|
}
|
|
|
|
$this->capacity = $capacity;
|
|
$this->updatedAt = $at;
|
|
}
|
|
|
|
/**
|
|
* Ajoute ou modifie la description de la classe.
|
|
*/
|
|
public function decrire(?string $description, DateTimeImmutable $at): void
|
|
{
|
|
$this->description = $description;
|
|
$this->updatedAt = $at;
|
|
}
|
|
|
|
/**
|
|
* Archive la classe (soft delete).
|
|
*
|
|
* Note: La vérification des élèves affectés doit être faite par l'Application Layer
|
|
* via une Query avant d'appeler cette méthode.
|
|
*/
|
|
public function archiver(DateTimeImmutable $at): void
|
|
{
|
|
if ($this->status === ClassStatus::ARCHIVED) {
|
|
return;
|
|
}
|
|
|
|
$this->status = ClassStatus::ARCHIVED;
|
|
$this->deletedAt = $at;
|
|
$this->updatedAt = $at;
|
|
|
|
$this->recordEvent(new ClasseArchivee(
|
|
classId: $this->id,
|
|
tenantId: $this->tenantId,
|
|
occurredOn: $at,
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Vérifie si la classe est active.
|
|
*/
|
|
public function estActive(): bool
|
|
{
|
|
return $this->status === ClassStatus::ACTIVE;
|
|
}
|
|
|
|
/**
|
|
* Vérifie si la classe peut recevoir des élèves.
|
|
*/
|
|
public function peutRecevoirEleves(): bool
|
|
{
|
|
return $this->status->peutRecevoirEleves();
|
|
}
|
|
|
|
/**
|
|
* Reconstitue une SchoolClass depuis le stockage.
|
|
*
|
|
* @internal Pour usage Infrastructure uniquement
|
|
*/
|
|
public static function reconstitute(
|
|
ClassId $id,
|
|
TenantId $tenantId,
|
|
SchoolId $schoolId,
|
|
AcademicYearId $academicYearId,
|
|
ClassName $name,
|
|
?SchoolLevel $level,
|
|
?int $capacity,
|
|
ClassStatus $status,
|
|
?string $description,
|
|
DateTimeImmutable $createdAt,
|
|
DateTimeImmutable $updatedAt,
|
|
?DateTimeImmutable $deletedAt,
|
|
): self {
|
|
$class = new self(
|
|
id: $id,
|
|
tenantId: $tenantId,
|
|
schoolId: $schoolId,
|
|
academicYearId: $academicYearId,
|
|
name: $name,
|
|
level: $level,
|
|
capacity: $capacity,
|
|
status: $status,
|
|
createdAt: $createdAt,
|
|
);
|
|
|
|
$class->description = $description;
|
|
$class->updatedAt = $updatedAt;
|
|
$class->deletedAt = $deletedAt;
|
|
|
|
return $class;
|
|
}
|
|
}
|