Les parents doivent pouvoir suivre la scolarité de leurs enfants (notes, emploi du temps, devoirs). Cela nécessite un lien formalisé entre le compte parent et le compte élève, géré par les administrateurs. Le lien est établi soit manuellement via l'interface d'administration, soit automatiquement lors de l'activation du compte parent lorsque l'invitation inclut un élève cible. Ce lien conditionne l'accès aux données scolaires de l'enfant (autorisations vérifiées par un voter dédié).
102 lines
3.6 KiB
PHP
102 lines
3.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Unit\Administration\Application\Command\UnlinkParentFromStudent;
|
|
|
|
use App\Administration\Application\Command\UnlinkParentFromStudent\UnlinkParentFromStudentCommand;
|
|
use App\Administration\Application\Command\UnlinkParentFromStudent\UnlinkParentFromStudentHandler;
|
|
use App\Administration\Domain\Event\ParentDelieDEleve;
|
|
use App\Administration\Domain\Exception\StudentGuardianNotFoundException;
|
|
use App\Administration\Domain\Model\StudentGuardian\RelationshipType;
|
|
use App\Administration\Domain\Model\StudentGuardian\StudentGuardian;
|
|
use App\Administration\Domain\Model\User\UserId;
|
|
use App\Administration\Infrastructure\Persistence\InMemory\InMemoryStudentGuardianRepository;
|
|
use App\Shared\Domain\Clock;
|
|
use App\Shared\Domain\Tenant\TenantId;
|
|
use DateTimeImmutable;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class UnlinkParentFromStudentHandlerTest extends TestCase
|
|
{
|
|
private const string TENANT_ID = '550e8400-e29b-41d4-a716-446655440001';
|
|
private const string STUDENT_ID = '550e8400-e29b-41d4-a716-446655440002';
|
|
private const string GUARDIAN_ID = '550e8400-e29b-41d4-a716-446655440003';
|
|
|
|
private InMemoryStudentGuardianRepository $repository;
|
|
private UnlinkParentFromStudentHandler $handler;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->repository = new InMemoryStudentGuardianRepository();
|
|
$clock = new class implements Clock {
|
|
public function now(): DateTimeImmutable
|
|
{
|
|
return new DateTimeImmutable('2026-02-10 10:00:00');
|
|
}
|
|
};
|
|
$this->handler = new UnlinkParentFromStudentHandler($this->repository, $clock);
|
|
}
|
|
|
|
#[Test]
|
|
public function unlinkRemovesExistingLink(): void
|
|
{
|
|
$link = $this->createAndSaveLink();
|
|
|
|
($this->handler)(new UnlinkParentFromStudentCommand(
|
|
linkId: (string) $link->id,
|
|
tenantId: self::TENANT_ID,
|
|
));
|
|
|
|
self::assertSame(0, $this->repository->countGuardiansForStudent(
|
|
$link->studentId,
|
|
$link->tenantId,
|
|
));
|
|
}
|
|
|
|
#[Test]
|
|
public function unlinkRecordsParentDelieDEleveEvent(): void
|
|
{
|
|
$link = $this->createAndSaveLink();
|
|
|
|
$result = ($this->handler)(new UnlinkParentFromStudentCommand(
|
|
linkId: (string) $link->id,
|
|
tenantId: self::TENANT_ID,
|
|
));
|
|
|
|
$events = $result->pullDomainEvents();
|
|
self::assertCount(1, $events);
|
|
self::assertInstanceOf(ParentDelieDEleve::class, $events[0]);
|
|
self::assertTrue($events[0]->studentId->equals($link->studentId));
|
|
self::assertTrue($events[0]->guardianId->equals($link->guardianId));
|
|
}
|
|
|
|
#[Test]
|
|
public function throwsWhenLinkNotFound(): void
|
|
{
|
|
$this->expectException(StudentGuardianNotFoundException::class);
|
|
|
|
($this->handler)(new UnlinkParentFromStudentCommand(
|
|
linkId: '550e8400-e29b-41d4-a716-446655440099',
|
|
tenantId: self::TENANT_ID,
|
|
));
|
|
}
|
|
|
|
private function createAndSaveLink(): StudentGuardian
|
|
{
|
|
$link = StudentGuardian::lier(
|
|
studentId: UserId::fromString(self::STUDENT_ID),
|
|
guardianId: UserId::fromString(self::GUARDIAN_ID),
|
|
relationshipType: RelationshipType::FATHER,
|
|
tenantId: TenantId::fromString(self::TENANT_ID),
|
|
createdAt: new DateTimeImmutable('2026-02-10 10:00:00'),
|
|
);
|
|
// Drain lier() events so only delier() events are tested
|
|
$link->pullDomainEvents();
|
|
$this->repository->save($link);
|
|
|
|
return $link;
|
|
}
|
|
}
|