Le handler ChangeStudentClass exigeait une affectation existante pour l'année scolaire en cours avant de pouvoir changer la classe. Un élève créé sans ClassAssignment (import direct, année précédente) provoquait une erreur "Élève non trouvé" au lieu d'être simplement affecté. Le handler crée désormais une nouvelle affectation quand aucune n'existe, et l'erreur de changement de classe s'affiche dans la modale au lieu de la page principale.
87 lines
3.4 KiB
PHP
87 lines
3.4 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\ChangeStudentClass\ChangeStudentClassCommand;
|
|
use App\Administration\Application\Command\ChangeStudentClass\ChangeStudentClassHandler;
|
|
use App\Administration\Domain\Exception\ClasseNotFoundException;
|
|
use App\Administration\Domain\Repository\ClassRepository;
|
|
use App\Administration\Infrastructure\Api\Resource\StudentResource;
|
|
use App\Administration\Infrastructure\Security\StudentVoter;
|
|
use App\Administration\Infrastructure\Service\CurrentAcademicYearResolver;
|
|
use App\Shared\Infrastructure\Tenant\TenantContext;
|
|
use Override;
|
|
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
|
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
|
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 ChangeStudentClassProcessor implements ProcessorInterface
|
|
{
|
|
public function __construct(
|
|
private ChangeStudentClassHandler $handler,
|
|
private ClassRepository $classRepository,
|
|
private TenantContext $tenantContext,
|
|
private MessageBusInterface $eventBus,
|
|
private AuthorizationCheckerInterface $authorizationChecker,
|
|
private CurrentAcademicYearResolver $academicYearResolver,
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* @param StudentResource $data
|
|
*/
|
|
#[Override]
|
|
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): StudentResource
|
|
{
|
|
if (!$this->authorizationChecker->isGranted(StudentVoter::MANAGE)) {
|
|
throw new AccessDeniedHttpException('Vous n\'êtes pas autorisé à changer la classe d\'un élève.');
|
|
}
|
|
|
|
if (!$this->tenantContext->hasTenant()) {
|
|
throw new UnauthorizedHttpException('Bearer', 'Tenant non défini.');
|
|
}
|
|
|
|
$tenantId = (string) $this->tenantContext->getCurrentTenantId();
|
|
/** @var string $studentId */
|
|
$studentId = $uriVariables['id'] ?? '';
|
|
$academicYearId = $this->academicYearResolver->resolve('current')
|
|
?? throw new BadRequestHttpException('Impossible de résoudre l\'année scolaire courante.');
|
|
|
|
try {
|
|
$command = new ChangeStudentClassCommand(
|
|
tenantId: $tenantId,
|
|
studentId: $studentId,
|
|
newClassId: $data->classId ?? '',
|
|
academicYearId: $academicYearId,
|
|
);
|
|
|
|
$assignment = ($this->handler)($command);
|
|
|
|
// Dispatch domain events
|
|
foreach ($assignment->pullDomainEvents() as $event) {
|
|
$this->eventBus->dispatch($event);
|
|
}
|
|
|
|
// Update the resource with new class info
|
|
$newClass = $this->classRepository->get($assignment->classId);
|
|
$data->classId = (string) $assignment->classId;
|
|
$data->className = (string) $newClass->name;
|
|
$data->classLevel = $newClass->level?->value;
|
|
|
|
return $data;
|
|
} catch (ClasseNotFoundException $e) {
|
|
throw new NotFoundHttpException($e->getMessage());
|
|
}
|
|
}
|
|
}
|