Files
Classeo/backend/src/Administration/Infrastructure/Api/Processor/CreateStudentProcessor.php
Mathias STRASSER ba80e8cb57 fix: Permettre l'activation des comptes élèves de moins de 15 ans créés par l'admin
Lorsqu'un admin créait un élève de moins de 15 ans avec une date de
naissance, le compte ne pouvait pas être activé car le consentement
parental RGPD n'avait jamais été enregistré — aucun mécanisme ne le
permettait dans le parcours admin.

Ajout d'une case « Consentement parental obtenu » dans le formulaire
de création d'élève, affichée conditionnellement quand la date de
naissance indique un âge < 15 ans. L'admin confirme que l'établissement
a recueilli le consentement, qui est alors enregistré côté backend
lors de la création du compte.
2026-03-07 21:14:04 +01:00

117 lines
4.9 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Administration\Infrastructure\Api\Processor;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\Administration\Application\Command\CreateStudent\CreateStudentCommand;
use App\Administration\Application\Command\CreateStudent\CreateStudentHandler;
use App\Administration\Domain\Exception\ClasseNotFoundException;
use App\Administration\Domain\Exception\EmailDejaUtiliseeException;
use App\Administration\Domain\Model\SchoolClass\ClassId;
use App\Administration\Domain\Repository\ClassRepository;
use App\Administration\Infrastructure\Api\Resource\StudentResource;
use App\Administration\Infrastructure\Security\SecurityUser;
use App\Administration\Infrastructure\Security\StudentVoter;
use App\Administration\Infrastructure\Service\CurrentAcademicYearResolver;
use App\Shared\Infrastructure\Tenant\TenantContext;
use Override;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
/**
* @implements ProcessorInterface<StudentResource, StudentResource>
*/
final readonly class CreateStudentProcessor implements ProcessorInterface
{
public function __construct(
private CreateStudentHandler $handler,
private ClassRepository $classRepository,
private TenantContext $tenantContext,
private MessageBusInterface $eventBus,
private AuthorizationCheckerInterface $authorizationChecker,
private CurrentAcademicYearResolver $academicYearResolver,
private Security $security,
) {
}
/**
* @param StudentResource $data
*/
#[Override]
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): StudentResource
{
if (!$this->authorizationChecker->isGranted(StudentVoter::CREATE)) {
throw new AccessDeniedHttpException('Vous n\'êtes pas autorisé à créer un élève.');
}
if (!$this->tenantContext->hasTenant()) {
throw new UnauthorizedHttpException('Bearer', 'Tenant non défini.');
}
$tenantId = (string) $this->tenantContext->getCurrentTenantId();
$tenantConfig = $this->tenantContext->getCurrentTenantConfig();
$academicYearId = $this->academicYearResolver->resolve('current')
?? throw new BadRequestHttpException('Impossible de résoudre l\'année scolaire courante.');
try {
$adminUserId = null;
$securityUser = $this->security->getUser();
if ($securityUser instanceof SecurityUser) {
$adminUserId = $securityUser->userId();
}
$command = new CreateStudentCommand(
tenantId: $tenantId,
schoolName: $tenantConfig->subdomain,
firstName: $data->firstName ?? '',
lastName: $data->lastName ?? '',
classId: $data->classId ?? '',
academicYearId: $academicYearId,
email: $data->email,
dateNaissance: $data->dateNaissance,
studentNumber: $data->studentNumber,
parentalConsent: $data->parentalConsent,
consentRecordedBy: $adminUserId,
);
$user = ($this->handler)($command);
// Dispatch domain events
foreach ($user->pullDomainEvents() as $event) {
$this->eventBus->dispatch($event);
}
// Build the response from the created user and class info
$class = $this->classRepository->get(ClassId::fromString($data->classId ?? ''));
$resource = new StudentResource();
$resource->id = (string) $user->id;
$resource->firstName = $user->firstName;
$resource->lastName = $user->lastName;
$resource->email = $user->email !== null ? (string) $user->email : null;
$resource->statut = $user->statut->value;
$resource->classId = $data->classId;
$resource->className = (string) $class->name;
$resource->classLevel = $class->level?->value;
$resource->studentNumber = $user->studentNumber;
$resource->dateNaissance = $user->dateNaissance?->format('Y-m-d');
return $resource;
} catch (EmailDejaUtiliseeException $e) {
throw new ConflictHttpException($e->getMessage());
} catch (ClasseNotFoundException $e) {
throw new NotFoundHttpException($e->getMessage());
}
}
}