up stats par rue et dans le temps

This commit is contained in:
Tykayn 2025-07-12 12:03:40 +02:00 committed by tykayn
parent cd6c14c378
commit 7355600e6b
8 changed files with 409 additions and 5 deletions

View file

@ -716,4 +716,128 @@ class PublicController extends AbstractController
{
return $this->render('public/faq.html.twig');
}
#[Route('/ville/{cityId}/rue/{streetName}', name: 'app_public_street')]
public function streetView(string $cityId, string $streetName): Response
{
$cityStats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $cityId]);
if (!$cityStats) {
throw $this->createNotFoundException('Ville non trouvée');
}
// Décodage du nom de la rue depuis l'URL
$streetName = urldecode($streetName);
// On récupère tous les lieux dont le stats.zone correspond à cityId et la rue correspondante
$places = $this->entityManager->getRepository(Place::class)->createQueryBuilder('p')
->leftJoin('p.stats', 's')
->where('s.zone = :cityId')
->andWhere('p.street = :streetName')
->setParameter('cityId', $cityId)
->setParameter('streetName', $streetName)
->getQuery()
->getResult();
// Conversion des entités Place en tableau associatif pour le JS
$placesArray = array_map(fn($place) => $place->toArray(), $places);
// Préparer la répartition de complétion pour le graphe
$completionBuckets = [
'0-20%' => 0,
'20-40%' => 0,
'40-60%' => 0,
'60-80%' => 0,
'80-100%' => 0
];
foreach ($places as $place) {
$c = $place->getCompletionPercentage();
if ($c < 20) $completionBuckets['0-20%']++;
elseif ($c < 40) $completionBuckets['20-40%']++;
elseif ($c < 60) $completionBuckets['40-60%']++;
elseif ($c < 80) $completionBuckets['60-80%']++;
else $completionBuckets['80-100%']++;
}
return $this->render('public/street.html.twig', [
'city' => $cityStats->getName(),
'city_id' => $cityId,
'street' => $streetName,
'places' => $places, // objets Place pour le HTML
'places_js' => $placesArray, // pour le JS si besoin
'completion_buckets' => $completionBuckets,
'completion_buckets_values' => array_values($completionBuckets),
'stats_url' => $this->generateUrl('app_admin_stats', ['insee_code' => $cityId]),
'maptiler_token' => $_ENV['MAPTILER_TOKEN'] ?? null
]);
}
#[Route('/stats/{insee_code}/evolutions', name: 'app_public_stats_evolutions')]
public function statsEvolutions(string $insee_code): Response
{
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]);
if (!$stats) {
throw $this->createNotFoundException('Ville non trouvée');
}
$now = new \DateTime();
$periods = [
'7j' => (clone $now)->modify('-7 days'),
'30j' => (clone $now)->modify('-30 days'),
'6mois' => (clone $now)->modify('-6 months'),
];
$followups = $stats->getCityFollowUps();
$types = [];
foreach ($followups as $fu) {
$name = $fu->getName();
if (str_ends_with($name, '_count')) {
$type = substr($name, 0, -6);
$types[$type][] = $fu;
}
}
$evolutions = [];
foreach ($types as $type => $fus) {
usort($fus, fn($a, $b) => $a->getDate() <=> $b->getDate());
$latest = end($fus);
$evolutions[$type] = [
'now' => $latest ? $latest->getMeasure() : null
];
foreach ($periods as $label => $date) {
$past = null;
foreach ($fus as $fu) {
if ($fu->getDate() >= $date) {
$past = $fu->getMeasure();
break;
}
}
$evolutions[$type][$label] = $past !== null && $latest ? $latest->getMeasure() - $past : null;
}
}
// Grouper les lieux par date de modification
$places = $stats->getPlaces();
$now = new \DateTime();
$places_7j = [];
$places_30j = [];
$places_6mois = [];
foreach ($places as $place) {
$mod = $place->getModifiedDate();
if (!$mod) continue;
$diff = $now->diff($mod);
$days = (int)$diff->format('%a');
if ($days <= 7) {
$places_7j[] = $place;
} elseif ($days <= 30) {
$places_30j[] = $place;
} elseif ($days <= 180) {
$places_6mois[] = $place;
}
}
// Tri décroissant par date
usort($places_7j, fn($a, $b) => $b->getModifiedDate() <=> $a->getModifiedDate());
usort($places_30j, fn($a, $b) => $b->getModifiedDate() <=> $a->getModifiedDate());
usort($places_6mois, fn($a, $b) => $b->getModifiedDate() <=> $a->getModifiedDate());
return $this->render('public/stats_evolutions.html.twig', [
'stats' => $stats,
'evolutions' => $evolutions,
'periods' => array_keys($periods),
'places_7j' => $places_7j,
'places_30j' => $places_30j,
'places_6mois' => $places_6mois,
]);
}
}

View file

@ -752,4 +752,17 @@ class Place
$this->emailContent = $emailContent;
return $this;
}
public function toArray(): array
{
return [
'name' => $this->getName(),
'mainTag' => $this->getMainTag(),
'housenumber' => $this->getHousenumber(),
'street' => $this->getStreet(),
'completionPercentage' => $this->getCompletionPercentage(),
'lat' => $this->getLat(),
'lon' => $this->getLon(),
];
}
}