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.
106 lines
3.7 KiB
PHP
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),
|
|
],
|
|
);
|
|
}
|
|
}
|