Files
Classeo/backend/src/Scolarite/Infrastructure/Api/Provider/TeacherStatisticsExportProvider.php
Mathias STRASSER 18c54e6d67
Some checks failed
CI / Backend Tests (push) Has been cancelled
CI / Frontend Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Naming Conventions (push) Has been cancelled
CI / Build Check (push) Has been cancelled
feat: Provisionner automatiquement un nouvel établissement
Lorsqu'un super-admin crée un établissement via l'interface, le système
doit automatiquement créer la base tenant, exécuter les migrations,
créer le premier utilisateur admin et envoyer l'invitation — le tout
de manière asynchrone pour ne pas bloquer la réponse HTTP.

Ce mécanisme rend chaque établissement opérationnel dès sa création
sans intervention manuelle sur l'infrastructure.
2026-04-11 20:52:41 +02:00

106 lines
3.7 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Scolarite\Infrastructure\Api\Provider;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Administration\Domain\Model\User\Role;
use App\Administration\Infrastructure\Security\SecurityUser;
use App\Scolarite\Application\Query\GetClassStatisticsDetail\ClassStatisticsDetailDto;
use App\Scolarite\Application\Query\GetClassStatisticsDetail\GetClassStatisticsDetailQuery;
use App\Scolarite\Application\Service\StatisticsExporter;
use App\Shared\Infrastructure\Tenant\TenantContext;
use function in_array;
use function is_string;
use Override;
use function sprintf;
use function str_replace;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Symfony\Component\Messenger\HandleTrait;
use Symfony\Component\Messenger\MessageBusInterface;
/**
* @implements ProviderInterface<Response>
*/
final class TeacherStatisticsExportProvider implements ProviderInterface
{
use HandleTrait;
public function __construct(
MessageBusInterface $queryBus,
private readonly TenantContext $tenantContext,
private readonly Security $security,
private readonly StatisticsExporter $exporter,
) {
$this->messageBus = $queryBus;
}
#[Override]
public function provide(Operation $operation, array $uriVariables = [], array $context = []): Response
{
if (!$this->tenantContext->hasTenant()) {
throw new UnauthorizedHttpException('Bearer', 'Tenant non défini.');
}
$user = $this->security->getUser();
if (!$user instanceof SecurityUser) {
throw new UnauthorizedHttpException('Bearer', 'Authentification requise.');
}
if (!in_array(Role::PROF->value, $user->getRoles(), true)) {
throw new AccessDeniedHttpException('Accès réservé aux enseignants.');
}
/** @var array<string, mixed> $filters */
$filters = $context['filters'] ?? [];
/** @var string|null $classId */
$classId = $filters['classId'] ?? null;
/** @var string|null $subjectId */
$subjectId = $filters['subjectId'] ?? null;
/** @var string|null $className */
$className = $filters['className'] ?? 'Classe';
/** @var string|null $subjectName */
$subjectName = $filters['subjectName'] ?? 'Matière';
if (!is_string($classId) || $classId === '') {
throw new BadRequestHttpException('Le paramètre classId est requis.');
}
if (!is_string($subjectId) || $subjectId === '') {
throw new BadRequestHttpException('Le paramètre subjectId est requis.');
}
/** @var ClassStatisticsDetailDto $dto */
$dto = $this->handle(new GetClassStatisticsDetailQuery(
teacherId: $user->userId(),
classId: $classId,
subjectId: $subjectId,
tenantId: (string) $this->tenantContext->getCurrentTenantId(),
));
$csv = $this->exporter->exportClassToCsv($dto, (string) $className, (string) $subjectName);
// Sanitize filename: remove characters dangerous in Content-Disposition
$safeFilename = str_replace(['"', "\r", "\n", '/', '\\'], '', sprintf('statistiques-%s-%s.csv', $className, $subjectName));
return new Response(
content: $csv,
headers: [
'Content-Type' => 'text/csv; charset=UTF-8',
'Content-Disposition' => sprintf('attachment; filename="%s"', $safeFilename),
],
);
}
}