osm-commerces/src/Controller/FraicheurController.php
2025-06-24 12:30:39 +02:00

322 lines
No EOL
14 KiB
PHP

<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Filesystem\Filesystem;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\Place;
use App\Entity\Stats;
use App\Service\BudgetService;
class FraicheurController extends AbstractController
{
public function __construct(
private EntityManagerInterface $entityManager,
private BudgetService $budgetService
) {}
#[Route('/admin/fraicheur/histogramme', name: 'admin_fraicheur_histogramme')]
public function showFraicheurHistogramme(): Response
{
$jsonPath = $this->getParameter('kernel.project_dir') . '/var/fraicheur_osm.json';
if (!file_exists($jsonPath)) {
$this->calculateFraicheur();
}
return $this->render('admin/fraicheur_histogramme.html.twig');
}
#[Route('/admin/fraicheur/calculate', name: 'admin_fraicheur_calculate')]
public function calculateFraicheur(): Response
{
$filesystem = new Filesystem();
$jsonPath = $this->getParameter('kernel.project_dir') . '/var/fraicheur_osm.json';
$now = new \DateTime();
$placeRepo = $this->entityManager->getRepository(Place::class);
$query = $placeRepo->createQueryBuilder('p')->getQuery();
$places = $query->toIterable();
$histogram = [];
$total = 0;
foreach ($places as $place) {
$date = $place->getOsmDataDate();
if ($date) {
$key = $date->format('Y-m');
if (!isset($histogram[$key])) {
$histogram[$key] = 0;
}
$histogram[$key]++;
$total++;
}
$this->entityManager->detach($place);
}
ksort($histogram);
$data = [
'generated_at' => $now->format('c'),
'total' => $total,
'histogram' => $histogram
];
$filesystem->dumpFile($jsonPath, json_encode($data, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
// --- Distribution villes selon lieux/habitants ---
$distJsonPath = $this->getParameter('kernel.project_dir') . '/var/distribution_villes_lieux_par_habitant.json';
$statsRepo = $this->entityManager->getRepository(Stats::class);
$queryStats = $statsRepo->createQueryBuilder('s')->getQuery();
$allStats = $queryStats->toIterable();
$histogram_lieux_par_habitant = [];
$histogram_habitants_par_lieu = [];
$villesByBinLph = [];
$villesByBinHpl = [];
$totalVilles = 0;
foreach ($allStats as $stat) {
$places = $stat->getPlacesCount();
$population = $stat->getPopulation();
$name = $stat->getName();
if ($places && $population && $population > 0 && $name) {
// lieux par habitant (pas de 0.01)
$ratio_lph = $places / $population;
$bin_lph = number_format(floor($ratio_lph / 0.01) * 0.01, 2, '.', '');
if (!isset($histogram_lieux_par_habitant[$bin_lph])) $histogram_lieux_par_habitant[$bin_lph] = 0;
$histogram_lieux_par_habitant[$bin_lph]++;
if (!isset($villesByBinLph[$bin_lph])) $villesByBinLph[$bin_lph] = [];
$villesByBinLph[$bin_lph][] = $name;
// habitants par lieu (pas de 10)
$ratio_hpl = $population / $places;
$bin_hpl = (string)(ceil($ratio_hpl / 10) * 10);
if (!isset($histogram_habitants_par_lieu[$bin_hpl])) $histogram_habitants_par_lieu[$bin_hpl] = 0;
$histogram_habitants_par_lieu[$bin_hpl]++;
if (!isset($villesByBinHpl[$bin_hpl])) $villesByBinHpl[$bin_hpl] = [];
$villesByBinHpl[$bin_hpl][] = $name;
$totalVilles++;
}
$this->entityManager->detach($stat);
}
ksort($histogram_lieux_par_habitant);
ksort($histogram_habitants_par_lieu);
ksort($villesByBinLph);
ksort($villesByBinHpl);
$distData = [
'generated_at' => $now->format('c'),
'total_villes' => $totalVilles,
'histogram_001' => $histogram_lieux_par_habitant,
'histogram_10' => $histogram_habitants_par_lieu,
'villes_by_bin_001' => $villesByBinLph,
'villes_by_bin_10' => $villesByBinHpl
];
$filesystem->dumpFile($distJsonPath, json_encode($distData, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
// --- Statistiques budgétaires ---
// Remplir les budgets manquants avant le calcul
$this->budgetService->fillMissingBudgetsForAllStats($this->entityManager);
$this->calculateBudgetStats();
return $this->redirectToRoute('admin_fraicheur_histogramme');
}
/**
* Calcule les statistiques liées au budget des villes
*/
private function calculateBudgetStats(): void
{
$filesystem = new Filesystem();
$budgetJsonPath = $this->getParameter('kernel.project_dir') . '/var/budget_stats.json';
$now = new \DateTime();
$statsRepo = $this->entityManager->getRepository(Stats::class);
$queryStats = $statsRepo->createQueryBuilder('s')->getQuery();
$allStats = $queryStats->toIterable();
$budgetParHabitant = [];
$villesAvecBudget = [];
$totalBudget = 0;
$totalPopulation = 0;
$budgetParLieu = [];
$villesByBinBudgetParLieu = [];
$histogramBudgetParLieu = [];
// Collecter les données de budget par habitant et par lieu
foreach ($allStats as $stat) {
$budgetAnnuel = $stat->getBudgetAnnuel();
$population = $stat->getPopulation();
$placesCount = $stat->getPlacesCount();
$name = $stat->getName();
if ($budgetAnnuel && $population && $population > 0 && $name) {
$budgetParHabitantValue = (float)$budgetAnnuel / $population;
$budgetParHabitant[] = [
'ville' => $name,
'code_insee' => $stat->getZone(),
'budget_annuel' => (float)$budgetAnnuel,
'population' => $population,
'budget_par_habitant' => $budgetParHabitantValue
];
$villesAvecBudget[] = $name;
$totalBudget += (float)$budgetAnnuel;
$totalPopulation += $population;
}
// Ajout budget par lieu
if ($budgetAnnuel && $placesCount && $placesCount > 0 && $name) {
$budgetParLieuValue = (float)$budgetAnnuel / $placesCount;
$budgetParLieu[] = [
'ville' => $name,
'code_insee' => $stat->getZone(),
'budget_annuel' => (float)$budgetAnnuel,
'places_count' => $placesCount,
'budget_par_lieu' => $budgetParLieuValue
];
$binBudgetParLieu = (string)(ceil($budgetParLieuValue / 5000) * 5000);
if (!isset($histogramBudgetParLieu[$binBudgetParLieu])) $histogramBudgetParLieu[$binBudgetParLieu] = 0;
$histogramBudgetParLieu[$binBudgetParLieu]++;
if (!isset($villesByBinBudgetParLieu[$binBudgetParLieu])) $villesByBinBudgetParLieu[$binBudgetParLieu] = [];
$villesByBinBudgetParLieu[$binBudgetParLieu][] = $name;
}
$this->entityManager->detach($stat);
}
// Calculer la moyenne du budget par habitant
$moyenneBudgetParHabitant = $totalPopulation > 0 ? $totalBudget / $totalPopulation : 0;
// Calculer l'écart à la moyenne pour chaque ville
$ecartsMoyenne = [];
foreach ($budgetParHabitant as $ville) {
$ecart = $this->budgetService->getEcartMoyenneBudgetParHabitant(
$ville['budget_par_habitant'],
$moyenneBudgetParHabitant
);
$ecartsMoyenne[] = [
'ville' => $ville['ville'],
'code_insee' => $ville['code_insee'],
'budget_par_habitant' => $ville['budget_par_habitant'],
'ecart_moyenne_pourcent' => $ecart
];
}
// Créer des histogrammes
$histogramBudgetParHabitant = [];
$histogramEcartMoyenne = [];
$villesByBinBudget = [];
$villesByBinEcart = [];
foreach ($budgetParHabitant as $ville) {
// Histogramme budget par habitant (pas de 100€)
$binBudget = (string)(ceil($ville['budget_par_habitant'] / 100) * 100);
if (!isset($histogramBudgetParHabitant[$binBudget])) {
$histogramBudgetParHabitant[$binBudget] = 0;
}
$histogramBudgetParHabitant[$binBudget]++;
if (!isset($villesByBinBudget[$binBudget])) {
$villesByBinBudget[$binBudget] = [];
}
$villesByBinBudget[$binBudget][] = $ville['ville'];
}
foreach ($ecartsMoyenne as $ville) {
// Histogramme écart à la moyenne (pas de 10%)
$binEcart = (string)(ceil($ville['ecart_moyenne_pourcent'] / 10) * 10);
if (!isset($histogramEcartMoyenne[$binEcart])) {
$histogramEcartMoyenne[$binEcart] = 0;
}
$histogramEcartMoyenne[$binEcart]++;
if (!isset($villesByBinEcart[$binEcart])) {
$villesByBinEcart[$binEcart] = [];
}
$villesByBinEcart[$binEcart][] = $ville['ville'];
}
ksort($histogramBudgetParHabitant);
ksort($histogramEcartMoyenne);
ksort($villesByBinBudget);
ksort($villesByBinEcart);
ksort($histogramBudgetParLieu);
ksort($villesByBinBudgetParLieu);
$budgetData = [
'generated_at' => $now->format('c'),
'total_villes_avec_budget' => count($villesAvecBudget),
'moyenne_budget_par_habitant' => $moyenneBudgetParHabitant,
'total_budget' => $totalBudget,
'total_population' => $totalPopulation,
'villes_avec_budget' => $villesAvecBudget,
'budget_par_habitant' => $budgetParHabitant,
'budget_par_lieu' => $budgetParLieu,
'ecarts_moyenne' => $ecartsMoyenne,
'histogram_budget_par_habitant' => $histogramBudgetParHabitant,
'histogram_ecart_moyenne' => $histogramEcartMoyenne,
'villes_by_bin_budget' => $villesByBinBudget,
'villes_by_bin_ecart' => $villesByBinEcart,
'histogram_budget_par_lieu' => $histogramBudgetParLieu,
'villes_by_bin_budget_par_lieu' => $villesByBinBudgetParLieu
];
$filesystem->dumpFile($budgetJsonPath, json_encode($budgetData, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
}
#[Route('/admin/fraicheur/download', name: 'admin_fraicheur_download')]
public function downloadFraicheur(): JsonResponse
{
$jsonPath = $this->getParameter('kernel.project_dir') . '/var/fraicheur_osm.json';
if (!file_exists($jsonPath)) {
return new JsonResponse(['error' => 'Fichier non généré'], 404);
}
$content = file_get_contents($jsonPath);
$data = json_decode($content, true);
return new JsonResponse($data);
}
#[Route('/admin/distribution_villes_lieux_par_habitant_download', name: 'admin_distribution_villes_lieux_par_habitant_download')]
public function downloadDistributionVillesLieuxParHabitant(): JsonResponse
{
$jsonPath = $this->getParameter('kernel.project_dir') . '/var/distribution_villes_lieux_par_habitant.json';
if (!file_exists($jsonPath)) {
$this->calculateFraicheur();
}
$content = file_get_contents($jsonPath);
$data = json_decode($content, true);
return new JsonResponse($data);
}
#[Route('/admin/distribution_villes_lieux_par_habitant_villes', name: 'admin_distribution_villes_lieux_par_habitant_villes')]
public function downloadDistributionVillesLieuxParHabitantVilles(): JsonResponse
{
$jsonPath = $this->getParameter('kernel.project_dir') . '/var/distribution_villes_lieux_par_habitant.json';
if (!file_exists($jsonPath)) {
$this->calculateFraicheur();
}
$content = file_get_contents($jsonPath);
$data = json_decode($content, true);
// On renvoie les deux listes de villes par bin
return new JsonResponse([
'villes_by_bin_001' => $data['villes_by_bin_001'] ?? [],
'villes_by_bin_10' => $data['villes_by_bin_10'] ?? []
]);
}
#[Route('/admin/budget/download', name: 'admin_budget_download')]
public function downloadBudget(): JsonResponse
{
$jsonPath = $this->getParameter('kernel.project_dir') . '/var/budget_stats.json';
if (!file_exists($jsonPath)) {
$this->calculateFraicheur();
}
$content = file_get_contents($jsonPath);
$data = json_decode($content, true);
return new JsonResponse($data);
}
#[Route('/admin/budget/villes', name: 'admin_budget_villes')]
public function downloadBudgetVilles(): JsonResponse
{
$jsonPath = $this->getParameter('kernel.project_dir') . '/var/budget_stats.json';
if (!file_exists($jsonPath)) {
$this->calculateFraicheur();
}
$content = file_get_contents($jsonPath);
$data = json_decode($content, true);
return new JsonResponse([
'villes_by_bin_budget' => $data['villes_by_bin_budget'] ?? [],
'villes_by_bin_ecart' => $data['villes_by_bin_ecart'] ?? []
]);
}
}