src/Controller/CaniculeController.php line 298

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Service\MeteoFranceService;
  4. use App\DTO\StationMeteoDTO;
  5. use App\Form\StationMeteoType
  6. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  7. use Symfony\Component\HttpFoundation\JsonResponse;
  8. use Symfony\Component\HttpFoundation\Response;
  9. use Symfony\Component\Routing\Annotation\Route;
  10. use Doctrine\ORM\EntityManagerInterface;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use App\Entity\Pluviometrie;
  13. use App\Entity\StationsMeteo;
  14. set_time_limit(36000);
  15. class CaniculeController extends AbstractController {
  16.     
  17.     
  18.     
  19.     public function __construct(private MeteoFranceService $meteoServiceStationMeteoType $stationMeteoType){//, HttpClientInterface $client, CacheInterface $cache, string $apiKey, string $meteoFranceTokenUrl, string $meteoFranceApiUrl) {
  20.         $this->stationMeteoType $stationMeteoType;
  21.     }
  22.     #[Route(path'/canicule'name'canicule')]
  23.     public function canicule(Request $requestEntityManagerInterface $em): Response
  24.     {
  25.         ini_set('memory_limit''1024M'); // ou '2G' si besoin
  26.         
  27.         // Créer une instance du DTO pour passer au formulaire
  28.         $stationMeteoDTO = new StationMeteoDTO();
  29.         // Créer le formulaire avec l'objet DTO
  30.         $form $this->createForm(StationMeteoType::class, $stationMeteoDTO);
  31.         // Gérer la soumission du formulaire
  32.         $form->handleRequest($request);
  33.         if ($form->isSubmitted() && $form->isValid()) {
  34.             // Récupérer les données du formulaire
  35.             $data $form->getData();
  36.             // Tu as directement accès à l'objet StationMeteoDTO ici
  37.             $apikey $data->getApikey();  // Accès via la méthode getter
  38.             $stationAPI $data->getStationAPI();  // Accès via la méthode getter
  39.             // Appeler le service pour obtenir les données météo
  40.             $stationsData = [];
  41.             $commandeArray = []; // Initialisation pour éviter l'erreur Undefined variable
  42.             $columnDataArray = []; // Initialisation pour stocker les données des colonnes  
  43.             $AnneesEtudiees = [];
  44.             foreach (range(20022024) as $annee) {
  45.                 $AnneesEtudiees[$annee] = [
  46.                     'dateDeb' => "{$annee}-01-01T00%3A00%3A00Z",
  47.                     'dateFin' => "{$annee}-12-31T00%3A00%3A00Z",
  48.                 ];
  49.             }
  50.             foreach ($AnneesEtudiees as $annee => $AnneeEtudiee) {
  51.                 $commande $this->meteoService->getStationDataHoraire($stationAPI$AnneeEtudiee$apikey);
  52.                 $commandeArray[$stationAPI][$annee] = $commande;
  53.                 // Pause pour respecter la limite de 50 requêtes par minute
  54.                 usleep(1300000); // 1,2 secondes = 1 200 000 microsecondes
  55.             }
  56.             $erreur500 null;
  57.             $extractedData = [];
  58.             // Récupération des fichiers à partir des commandes
  59.             foreach ($commandeArray as $stationAPI => $anneesData) {
  60.                 $erreur null;
  61.                 foreach ($anneesData as $AnneeEtudiee => $commandeAnnee) {
  62.                     $commandeId $commandeAnnee['elaboreProduitAvecDemandeResponse']['return'];
  63.                     $csvString $this->meteoService->getFichier($commandeId$apikey);
  64.                     // dump($csvString);
  65.                     // Pause pour respecter la limite de 50 requêtes par minute
  66.                     usleep(1300000); // 1,2 secondes = 1 200 000 microsecondes  
  67.                     if ($csvString == 'Erreur 500') {
  68.                         $erreur500[$commandeId] = $stationAPI;
  69.                         $erreur 1;
  70.                     } else {
  71.                         // Diviser la chaîne en lignes
  72.                         $lines explode("\n"$csvString);
  73.                         // Tableau pour stocker les données extraites
  74.                         $data = [];
  75.                         foreach ($lines as $index => $line) {
  76.                             // Ignorer la première ligne (en-tête)
  77.                             if ($index === 0) {
  78.                                 continue;
  79.                             }
  80.                             // Diviser chaque ligne en colonnes par le séparateur ;
  81.                             $columns explode(";"$line);
  82.                             // Vérifier qu'il y a suffisamment de colonnes
  83.                             if (count($columns) > 2) {
  84.                                 // Extraire ce qui se situe entre le 3ème et 4ème point-virgule
  85.                                 $data['date'] = str_replace(",""."$columns[1]);
  86.                                 $data['temperature'] = str_replace(",""."$columns[10]);
  87.                                 $data['vitesse'] = str_replace(",""."$columns[48]);
  88.                                 $data['direction'] = str_replace(",""."$columns[50]);
  89.                                 $extractedData[] = $data;
  90.                                 $extractedDataParAn[$AnneeEtudiee][] = $data;
  91.                             }
  92.                         }
  93.                     }
  94.                 }
  95.             }
  96.             //////////////////////////////////////////////////////////////////////////////////
  97.             // CALCUL DES CANICULES///////////////////////////////////////////////////////////
  98.             function convertirEnDonneesJournalieres($donneesHoraires) {
  99.                 $donneesJournalieres = [];
  100.                 foreach ($donneesHoraires as $donnee) {
  101.                     $dateHeure \DateTime::createFromFormat('YmdH'$donnee['date']);
  102.                     if (!$dateHeure) {
  103.                         throw new \Exception("Format de date invalide : " $donnee['date']);
  104.                     }
  105.                     $jour $dateHeure->format('Y-m-d');
  106.                     $temp floatval($donnee['temperature']);
  107.                     if (!isset($donneesJournalieres[$jour])) {
  108.                         $donneesJournalieres[$jour] = [
  109.                             'date' => $jour,
  110.                             'min' => $temp,
  111.                             'max' => $temp,
  112.                         ];
  113.                     } else {
  114.                         $donneesJournalieres[$jour]['min'] = min($donneesJournalieres[$jour]['min'], $temp);
  115.                         $donneesJournalieres[$jour]['max'] = max($donneesJournalieres[$jour]['max'], $temp);
  116.                     }
  117.                 }
  118.                 // On retourne un tableau indexé numériquement pour garder l'ordre chronologique
  119.                 return array_values($donneesJournalieres);
  120.             }
  121.             function detecterCaniculesAvecIBM(array $donneesJournalieresfloat $seuilMinfloat $seuilMax): array {
  122.     $canicules = [];
  123.     $buffer = [];
  124.     for ($i 2$i count($donneesJournalieres); $i++) {
  125.         $sous_tableau array_slice($donneesJournalieres$i 23);
  126.         $moy_min array_sum(array_column($sous_tableau'min')) / 3;
  127.         $moy_max array_sum(array_column($sous_tableau'max')) / 3;
  128.         if ($moy_min >= $seuilMin && $moy_max >= $seuilMax) {
  129.             // On ajoute tous les 3 jours du trio dans le buffer
  130.             foreach ($sous_tableau as $jour) {
  131.                 $buffer$jour['date'] ] = $jour// clé = date, pour éviter les doublons
  132.             }
  133.         } else {
  134.             if (count($buffer) >= 3) {
  135.                 $canicules[] = array_values($buffer);
  136.             }
  137.             $buffer = [];
  138.         }
  139.     }
  140.     if (count($buffer) >= 3) {
  141.         $canicules[] = array_values($buffer);
  142.     }
  143.     return $canicules;
  144. }
  145.             function analyserCanicule(array $periode): array {
  146.                 if (empty($periode)) {
  147.                     return [
  148.                         'debut' => null,
  149.                         'fin' => null,
  150.                         'duree' => 0,
  151.                         'intensite_max' => null,
  152.                         'severite' => 0,
  153.                     ];
  154.                 }
  155.                 $dates array_column($periode'date');
  156.                 $maxs array_column($periode'max');
  157.                 // Nouvelle méthode de calcul de la sévérité
  158.                 $severite array_sum(array_map(function ($jour) {
  159.                     $moyenne = ($jour['min'] + $jour['max']) / 2;
  160.                     return $moyenne 24;
  161.                 }, $periode));
  162.                 return [
  163.                     'debut' => reset($dates),
  164.                     'fin' => end($dates),
  165.                     'duree' => count($periode),
  166.                     'intensite_max' => max($maxs),
  167.                     'severite' => $severite,
  168.                 ];
  169.             }
  170.             $caniculesParAn = [];
  171.             //Préciser les seuils
  172.             $stationDB $em->getRepository(StationsMeteo::class)->findOneBy(['IdStation' => $stationAPI]);
  173.             $departement $stationDB->getDepartement();
  174.             $seuils $this->getSeuilsParDepartement()[$departement];
  175.             foreach ($extractedDataParAn as $annee => $donneesHoraires) {
  176.                 $donneesJournalieres convertirEnDonneesJournalieres($donneesHoraires);
  177.                 //dump($donneesJournalieres);
  178.                 $caniculesParAn[$annee] = detecterCaniculesAvecIBM($donneesJournalieres$seuils['seuil_nuit'], $seuils['seuil_jour']);// Adapter les seuils ici
  179.             }
  180.             $analysesParAn = [];
  181.             $severiteTotaleParAn = [];
  182.             foreach ($caniculesParAn as $annee => $canicules) {
  183.                 foreach ($canicules as $periode) {
  184.                     $analyse analyserCanicule($periode);
  185.                     $analysesParAn[$annee][] = $analyse;
  186.                     // Ajout de la sévérité à la somme annuelle
  187.                     if (!isset($severiteTotaleParAn[$annee])) {
  188.                         $severiteTotaleParAn[$annee] = 0;
  189.                     }
  190.                     $severiteTotaleParAn[$annee] += $analyse['severite'];
  191.                 }
  192.             }
  193. // Trier les années par sévérité décroissante
  194.             arsort($severiteTotaleParAn);
  195. // Extraire les 5 années les plus critiques
  196.             $top10Annees array_slice(array_keys($severiteTotaleParAn), 010true);
  197. // Affichage
  198.             $top10AnneesData = [];
  199.             foreach ($top10Annees as $annee) {
  200.                 if (!isset($analysesParAn[$annee])) {
  201.                     continue;
  202.                 }
  203.                 foreach ($analysesParAn[$annee] as $analyse) {
  204.                     if (empty($analyse['debut'])) {
  205.                         continue;
  206.                     }
  207.                     $dateDebut \DateTime::createFromFormat('Y-m-d'$analyse['debut']);
  208.                     $mois $dateDebut->format('F'); // en anglais (ex: July)
  209.                     $mois strtr($mois, [// option : traduction rapide
  210.                         'January' => 'janvier''February' => 'février''March' => 'mars',
  211.                         'April' => 'avril''May' => 'mai''June' => 'juin',
  212.                         'July' => 'juillet''August' => 'août''September' => 'septembre',
  213.                         'October' => 'octobre''November' => 'novembre''December' => 'décembre',
  214.                     ]);
  215.                     $top10AnneesData[] = [
  216.                         'annee' => $annee,
  217.                         'mois' => $mois,
  218.                         'duree' => $analyse['duree'],
  219.                         'intensite_max' => round($analyse['intensite_max'], 1),
  220.                         'severite' => round($analyse['severite']),
  221.                     ];
  222.                 }
  223.             }
  224.              $stationKey $this->getKeyById($stationAPI);
  225. // Passer les données au template
  226.             return $this->render('canicule.html.twig', [
  227.                         'form' => $form->createView(),
  228.                         'top10Canicules' => $top10AnneesData,
  229.                         'stationKey' => $stationKey,
  230.                 'seuils' => $seuils,
  231.             ]);
  232. //            } catch (\Exception $e) {
  233. //                // Gérer les erreurs
  234. //                $this->addFlash('error', 'Erreur : ' . $e->getMessage());
  235. //            }
  236.         }
  237.         // Rendre la vue du formulaire
  238.         return $this->render('caniculeFormulaire.html.twig', [
  239.                     'form' => $form->createView(),
  240.         ]);
  241.     }
  242.     // Méthode pour obtenir la clé en fonction de l'ID
  243.     public function getKeyById($id)
  244.     {
  245.         // Récupérer le tableau des stations et IDs à partir de StationMeteoType
  246.         $choices $this->stationMeteoType->getStationAPIChoices();
  247.         // Rechercher la clé correspondant à l'ID
  248.         $key array_search($id$choices);
  249.         // Si l'ID est trouvé, retourne la clé, sinon retourne null
  250.         return $key !== false $key null;
  251.     }
  252.     
  253.     public function getSeuilsParDepartement(): array {
  254.     return [
  255.     '01' => ['seuil_jour' => 35'seuil_nuit' => 20],
  256.     '02' => ['seuil_jour' => 33'seuil_nuit' => 18],
  257.     '03' => ['seuil_jour' => 34'seuil_nuit' => 18],
  258.     '04' => ['seuil_jour' => 36'seuil_nuit' => 19],
  259.     '05' => ['seuil_jour' => 34'seuil_nuit' => 18],
  260.     '06' => ['seuil_jour' => 31'seuil_nuit' => 24],
  261.     '07' => ['seuil_jour' => 35'seuil_nuit' => 20],
  262.     '08' => ['seuil_jour' => 33'seuil_nuit' => 18],
  263.     '09' => ['seuil_jour' => 34'seuil_nuit' => 19],
  264.     '10' => ['seuil_jour' => 35'seuil_nuit' => 18],
  265.     '11' => ['seuil_jour' => 35'seuil_nuit' => 22],
  266.     '12' => ['seuil_jour' => 36'seuil_nuit' => 19],
  267.     '13' => ['seuil_jour' => 35'seuil_nuit' => 24],
  268.     '14' => ['seuil_jour' => 31'seuil_nuit' => 18],
  269.     '15' => ['seuil_jour' => 32'seuil_nuit' => 18],
  270.     '16' => ['seuil_jour' => 36'seuil_nuit' => 20],
  271.     '17' => ['seuil_jour' => 35'seuil_nuit' => 20],
  272.     '18' => ['seuil_jour' => 35'seuil_nuit' => 19],
  273.     '19' => ['seuil_jour' => 36'seuil_nuit' => 19],
  274.     '20' => ['seuil_jour' => 33'seuil_nuit' => 23],
  275. //    '2B' => ['seuil_jour' => 33, 'seuil_nuit' => 23],
  276.     '21' => ['seuil_jour' => 34'seuil_nuit' => 19],
  277.     '22' => ['seuil_jour' => 31'seuil_nuit' => 18],
  278.     '23' => ['seuil_jour' => 34'seuil_nuit' => 20],
  279.     '24' => ['seuil_jour' => 36'seuil_nuit' => 20],
  280.     '25' => ['seuil_jour' => 33'seuil_nuit' => 19],
  281.     '26' => ['seuil_jour' => 36'seuil_nuit' => 21],
  282.     '27' => ['seuil_jour' => 34'seuil_nuit' => 19],
  283.     '28' => ['seuil_jour' => 34'seuil_nuit' => 18],
  284.     '29' => ['seuil_jour' => 32'seuil_nuit' => 19],
  285.     '30' => ['seuil_jour' => 36'seuil_nuit' => 23],
  286.     '31' => ['seuil_jour' => 36'seuil_nuit' => 21],
  287.     '32' => ['seuil_jour' => 36'seuil_nuit' => 20],
  288.     '33' => ['seuil_jour' => 35'seuil_nuit' => 21],
  289.     '34' => ['seuil_jour' => 35'seuil_nuit' => 22],
  290.     '35' => ['seuil_jour' => 34'seuil_nuit' => 20],
  291.     '36' => ['seuil_jour' => 35'seuil_nuit' => 19],
  292.     '37' => ['seuil_jour' => 35'seuil_nuit' => 19],
  293.     '38' => ['seuil_jour' => 34'seuil_nuit' => 19],
  294.     '39' => ['seuil_jour' => 34'seuil_nuit' => 20],
  295.     '40' => ['seuil_jour' => 35'seuil_nuit' => 20],
  296.     '41' => ['seuil_jour' => 35'seuil_nuit' => 19],
  297.     '42' => ['seuil_jour' => 35'seuil_nuit' => 19],
  298.     '43' => ['seuil_jour' => 32'seuil_nuit' => 18],
  299.     '44' => ['seuil_jour' => 34'seuil_nuit' => 20],
  300.     '45' => ['seuil_jour' => 34'seuil_nuit' => 19],
  301.     '46' => ['seuil_jour' => 36'seuil_nuit' => 20],
  302.     '47' => ['seuil_jour' => 36'seuil_nuit' => 20],
  303.     '48' => ['seuil_jour' => 33'seuil_nuit' => 18],
  304.     '49' => ['seuil_jour' => 34'seuil_nuit' => 20],
  305.     '50' => ['seuil_jour' => 31'seuil_nuit' => 18],
  306.     '51' => ['seuil_jour' => 34'seuil_nuit' => 18],
  307.     '52' => ['seuil_jour' => 34'seuil_nuit' => 19],
  308.     '53' => ['seuil_jour' => 34'seuil_nuit' => 20],
  309.     '54' => ['seuil_jour' => 34'seuil_nuit' => 18],
  310.     '55' => ['seuil_jour' => 34'seuil_nuit' => 18],
  311.     '56' => ['seuil_jour' => 32'seuil_nuit' => 18],
  312.     '57' => ['seuil_jour' => 34'seuil_nuit' => 19],
  313.     '58' => ['seuil_jour' => 34'seuil_nuit' => 19],
  314.     '59' => ['seuil_jour' => 33'seuil_nuit' => 18],
  315.     '60' => ['seuil_jour' => 34'seuil_nuit' => 18],
  316.     '61' => ['seuil_jour' => 34'seuil_nuit' => 19],
  317.     '62' => ['seuil_jour' => 33'seuil_nuit' => 18],
  318.     '63' => ['seuil_jour' => 34'seuil_nuit' => 19],
  319.     '64' => ['seuil_jour' => 34'seuil_nuit' => 20],
  320.     '65' => ['seuil_jour' => 34'seuil_nuit' => 19],
  321.     '66' => ['seuil_jour' => 35'seuil_nuit' => 23],
  322.     '67' => ['seuil_jour' => 34'seuil_nuit' => 19],
  323.     '68' => ['seuil_jour' => 35'seuil_nuit' => 19],
  324.     '69' => ['seuil_jour' => 34'seuil_nuit' => 20],
  325.     '70' => ['seuil_jour' => 34'seuil_nuit' => 18],
  326.     '71' => ['seuil_jour' => 34'seuil_nuit' => 20],
  327.     '72' => ['seuil_jour' => 35'seuil_nuit' => 20],
  328.     '73' => ['seuil_jour' => 34'seuil_nuit' => 19],
  329.     '74' => ['seuil_jour' => 34'seuil_nuit' => 19],
  330.     '75' => ['seuil_jour' => 31'seuil_nuit' => 21],
  331.     '76' => ['seuil_jour' => 33'seuil_nuit' => 18],
  332.     '77' => ['seuil_jour' => 34'seuil_nuit' => 18],
  333.     '78' => ['seuil_jour' => 33'seuil_nuit' => 20],
  334.     '79' => ['seuil_jour' => 35'seuil_nuit' => 20],
  335.     '80' => ['seuil_jour' => 33'seuil_nuit' => 18],
  336.     '81' => ['seuil_jour' => 36'seuil_nuit' => 21],
  337.     '82' => ['seuil_jour' => 36'seuil_nuit' => 21],
  338.     '83' => ['seuil_jour' => 35'seuil_nuit' => 23],
  339.     '84' => ['seuil_jour' => 36'seuil_nuit' => 21],
  340.     '85' => ['seuil_jour' => 34'seuil_nuit' => 20],
  341.     '86' => ['seuil_jour' => 34'seuil_nuit' => 20],
  342.     '87' => ['seuil_jour' => 35'seuil_nuit' => 19],
  343.     '88' => ['seuil_jour' => 34'seuil_nuit' => 18],
  344.     '89' => ['seuil_jour' => 35'seuil_nuit' => 19],
  345.     '90' => ['seuil_jour' => 33'seuil_nuit' => 18],
  346.     '91' => ['seuil_jour' => 35'seuil_nuit' => 20],
  347.     '92' => ['seuil_jour' => 31'seuil_nuit' => 21],
  348.     '93' => ['seuil_jour' => 31'seuil_nuit' => 21],
  349.     '94' => ['seuil_jour' => 31'seuil_nuit' => 21],
  350.     '95' => ['seuil_jour' => 35'seuil_nuit' => 20],
  351. ];
  352. }
  353.  
  354.     
  355.     
  356. }