pour prod
This commit is contained in:
170
app/Controllers/VacationController.php
Normal file
170
app/Controllers/VacationController.php
Normal file
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Core\Access;
|
||||
use App\Core\Csrf;
|
||||
use App\Core\JsonResponse;
|
||||
use App\Core\Request;
|
||||
use App\Models\VacationModel;
|
||||
use App\Services\SchoolHolidayApiService;
|
||||
use DateTimeImmutable;
|
||||
use PDO;
|
||||
use Throwable;
|
||||
|
||||
final class VacationController
|
||||
{
|
||||
private VacationModel $vacationModel;
|
||||
private Access $access;
|
||||
|
||||
public function __construct(private PDO $pdo)
|
||||
{
|
||||
$this->vacationModel = new VacationModel($pdo);
|
||||
$this->access = new Access($pdo);
|
||||
}
|
||||
|
||||
public function index(): void
|
||||
{
|
||||
$this->access->requireService();
|
||||
$schoolYear = trim((string) ($_GET['school_year'] ?? ''));
|
||||
if ($schoolYear !== '' && !$this->isSchoolYear($schoolYear)) {
|
||||
JsonResponse::send(422, ['error' => 'Année scolaire invalide. Format attendu : 2026-2027.']);
|
||||
}
|
||||
|
||||
JsonResponse::send(200, [
|
||||
'periods' => $this->vacationModel->all($schoolYear !== '' ? $schoolYear : null),
|
||||
]);
|
||||
}
|
||||
|
||||
public function preview(): void
|
||||
{
|
||||
$this->access->requireService();
|
||||
$academy = trim((string) ($_GET['academy'] ?? ''));
|
||||
$calendarYearRaw = trim((string) ($_GET['year'] ?? ''));
|
||||
|
||||
if ($academy === '' || (function_exists('mb_strlen') ? mb_strlen($academy, 'UTF-8') : strlen($academy)) > 100) {
|
||||
JsonResponse::send(422, ['error' => 'Renseignez une académie valide.']);
|
||||
}
|
||||
|
||||
if (!preg_match('/^\d{4}$/', $calendarYearRaw)) {
|
||||
JsonResponse::send(422, ['error' => 'Année civile invalide. Format attendu : 2026.']);
|
||||
}
|
||||
$calendarYear = (int) $calendarYearRaw;
|
||||
if ($calendarYear < 2000 || $calendarYear > 2100) {
|
||||
JsonResponse::send(422, ['error' => 'Année civile invalide.']);
|
||||
}
|
||||
|
||||
try {
|
||||
$result = (new SchoolHolidayApiService())->previewCalendarYearDetailed($academy, $calendarYear);
|
||||
$periods = $result['periods'];
|
||||
$warnings = $result['warnings'];
|
||||
} catch (Throwable $e) {
|
||||
JsonResponse::send(502, [
|
||||
'error' => 'Impossible de charger les propositions depuis l’API officielle.',
|
||||
'details' => (getenv('PTA_DEBUG') ?: '1') !== '0' ? $e->getMessage() : null,
|
||||
]);
|
||||
}
|
||||
|
||||
JsonResponse::send(200, [
|
||||
'academy' => $academy,
|
||||
'year' => $calendarYear,
|
||||
'periods' => $periods,
|
||||
'warnings' => $warnings ?? [],
|
||||
'message' => $periods === []
|
||||
? 'Aucune période n’a été trouvée pour l’année ' . $calendarYear . '.'
|
||||
: sprintf('%d période%s proposée%s pour toute l’année %d. Aucune donnée n’a été enregistrée en base.', count($periods), count($periods) > 1 ? 's' : '', count($periods) > 1 ? 's' : '', $calendarYear),
|
||||
]);
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
$this->access->requireService();
|
||||
Request::requireMethod('POST');
|
||||
$payload = Request::json();
|
||||
Csrf::assertPayload($payload);
|
||||
|
||||
$rawPeriods = $payload['periods'] ?? [];
|
||||
if (!is_array($rawPeriods) || $rawPeriods === []) {
|
||||
JsonResponse::send(422, ['error' => 'Sélectionnez au moins une période à enregistrer.']);
|
||||
}
|
||||
if (count($rawPeriods) > 50) {
|
||||
JsonResponse::send(422, ['error' => 'Trop de périodes ont été envoyées en une seule fois.']);
|
||||
}
|
||||
|
||||
$periods = [];
|
||||
foreach ($rawPeriods as $index => $raw) {
|
||||
if (!is_array($raw)) {
|
||||
JsonResponse::send(422, ['error' => 'Période invalide à la ligne ' . ($index + 1) . '.']);
|
||||
}
|
||||
|
||||
$label = trim((string) ($raw['libelle'] ?? ''));
|
||||
$start = trim((string) ($raw['date_debut'] ?? ''));
|
||||
$end = trim((string) ($raw['date_fin'] ?? ''));
|
||||
$schoolYear = trim((string) ($raw['annee_scolaire'] ?? ''));
|
||||
$academy = trim((string) ($raw['academie'] ?? ''));
|
||||
$zone = trim((string) ($raw['zone'] ?? ''));
|
||||
$source = strtoupper(trim((string) ($raw['source'] ?? 'MANUEL')));
|
||||
|
||||
if ($label === '' || (function_exists('mb_strlen') ? mb_strlen($label, 'UTF-8') : strlen($label)) > 150 || !$this->isDate($start) || !$this->isDate($end) || $end < $start) {
|
||||
JsonResponse::send(422, ['error' => 'Dates ou libellé invalides à la ligne ' . ($index + 1) . '.']);
|
||||
}
|
||||
if (!$this->isSchoolYear($schoolYear)) {
|
||||
JsonResponse::send(422, ['error' => 'Année scolaire invalide à la ligne ' . ($index + 1) . '.']);
|
||||
}
|
||||
if (!in_array($source, ['MANUEL', 'DATA_GOUV'], true)) {
|
||||
$source = 'MANUEL';
|
||||
}
|
||||
|
||||
$periods[] = [
|
||||
'libelle' => $label,
|
||||
'date_debut' => $start,
|
||||
'date_fin' => $end,
|
||||
'annee_scolaire' => $schoolYear,
|
||||
'academie' => function_exists('mb_substr') ? mb_substr($academy, 0, 100, 'UTF-8') : substr($academy, 0, 100),
|
||||
'zone' => function_exists('mb_substr') ? mb_substr($zone, 0, 50, 'UTF-8') : substr($zone, 0, 50),
|
||||
'source' => $source,
|
||||
];
|
||||
}
|
||||
|
||||
$count = $this->vacationModel->saveMany($periods);
|
||||
JsonResponse::send(200, [
|
||||
'success' => true,
|
||||
'count' => $count,
|
||||
'message' => sprintf('%d période%s de vacances enregistrée%s après validation manuelle.', $count, $count > 1 ? 's' : '', $count > 1 ? 's' : ''),
|
||||
]);
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
{
|
||||
$this->access->requireService();
|
||||
Request::requireMethod('POST');
|
||||
$payload = Request::json();
|
||||
Csrf::assertPayload($payload);
|
||||
|
||||
$id = filter_var($payload['period_id'] ?? null, FILTER_VALIDATE_INT);
|
||||
if (!$id) {
|
||||
JsonResponse::send(422, ['error' => 'Période invalide.']);
|
||||
}
|
||||
if (!$this->vacationModel->delete((int) $id)) {
|
||||
JsonResponse::send(404, ['error' => 'Période introuvable.']);
|
||||
}
|
||||
|
||||
JsonResponse::send(200, ['success' => true, 'message' => 'Période supprimée.']);
|
||||
}
|
||||
|
||||
private function isDate(string $value): bool
|
||||
{
|
||||
$date = DateTimeImmutable::createFromFormat('!Y-m-d', $value);
|
||||
return $date !== false && $date->format('Y-m-d') === $value;
|
||||
}
|
||||
|
||||
private function isSchoolYear(string $value): bool
|
||||
{
|
||||
if (!preg_match('/^(\d{4})-(\d{4})$/', $value, $matches)) {
|
||||
return false;
|
||||
}
|
||||
return (int) $matches[2] === (int) $matches[1] + 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user