src/Controller/CaniculeController.php line 300

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