ajout thème rnb

This commit is contained in:
Tykayn 2025-07-15 21:22:02 +02:00 committed by tykayn
parent 3d767ffaae
commit aae37c6ce0
9 changed files with 119 additions and 26 deletions

1
#stats_export.json# Normal file

File diff suppressed because one or more lines are too long

View file

@ -99,7 +99,7 @@ class ExportStatsCommand extends Command
'avecAccessibilite' => $stat->getAvecAccessibilite(), 'avecAccessibilite' => $stat->getAvecAccessibilite(),
'avecNote' => $stat->getAvecNote(), 'avecNote' => $stat->getAvecNote(),
'completionPercent' => $stat->getCompletionPercent(), 'completionPercent' => $stat->getCompletionPercent(),
'placesCountReal' => $stat->getPlaces()->count(), // 'placesCountReal' => $stat->getPlaces()->count(), // SUPPRIMÉ
], ],
'followups' => [] 'followups' => []
]; ];

View file

@ -0,0 +1,70 @@
<?php
namespace App\Command;
use App\Entity\Stats;
use App\Service\Motocultrice;
use App\Service\FollowUpService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(
name: 'app:update-city-followup',
description: 'Met à jour les CityFollowUp d\'une ville à partir de son code INSEE'
)]
class UpdateCityFollowupCommand extends Command
{
public function __construct(
private EntityManagerInterface $entityManager,
private Motocultrice $motocultrice,
private FollowUpService $followUpService
) {
parent::__construct();
}
protected function configure(): void
{
$this
->addArgument('ville', InputArgument::REQUIRED, 'Code INSEE ou nom de la ville à mettre à jour');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$inputVille = $input->getArgument('ville');
$stats = null;
if (ctype_digit($inputVille)) {
// Recherche par code INSEE
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $inputVille]);
if (!$stats) {
$io->error("Aucune stats trouvée pour le code INSEE $inputVille.");
return Command::FAILURE;
}
} else {
// Recherche par nom (insensible à la casse)
$qb = $this->entityManager->getRepository(Stats::class)->createQueryBuilder('s');
$qb->where('LOWER(s.name) = :name')
->setParameter('name', mb_strtolower($inputVille));
$results = $qb->getQuery()->getResult();
if (count($results) === 0) {
$io->error("Aucune ville trouvée avec le nom '$inputVille'.");
return Command::FAILURE;
} elseif (count($results) > 1) {
$io->error("Plusieurs villes trouvées pour le nom '$inputVille'. Veuillez préciser le code INSEE.");
foreach ($results as $stat) {
$io->text("- " . $stat->getName() . " (" . $stat->getZone() . ")");
}
return Command::FAILURE;
}
$stats = $results[0];
}
$this->followUpService->generateCityFollowUps($stats, $this->motocultrice, $this->entityManager);
$io->success("Les CityFollowUp de la ville " . $stats->getName() . " (" . $stats->getZone() . ") ont été mis à jour.");
return Command::SUCCESS;
}
}

View file

@ -20,6 +20,7 @@ use Twig\Environment;
use App\Service\ActionLogger; use App\Service\ActionLogger;
use DateTime; use DateTime;
use App\Service\FollowUpService; use App\Service\FollowUpService;
use phpDocumentor\Reflection\DocBlock\Tags\Var_;
final class AdminController extends AbstractController final class AdminController extends AbstractController
{ {
@ -129,9 +130,14 @@ final class AdminController extends AbstractController
$commerces = $this->entityManager->getRepository(Place::class)->findBy(['zip_code' => $insee_code]); $commerces = $this->entityManager->getRepository(Place::class)->findBy(['zip_code' => $insee_code]);
// Récupérer les stats existantes pour la zone // Récupérer les stats existantes pour la zone
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]); $stats_exist = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]);
if (!$stats) { if ($stats_exist) {
$stats = $stats_exist;
} else {
$stats = new Stats(); $stats = new Stats();
dump('nouvelle stat', $insee_code);
die();
$stats->setZone($insee_code); $stats->setZone($insee_code);
} }
@ -270,7 +276,7 @@ final class AdminController extends AbstractController
{ {
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]); $stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]);
if (!$stats) { if (!$stats) {
$this->addFlash('error', 'Aucune stats trouvée pour ce code INSEE. Veuillez d\'abord ajouter la ville.'); $this->addFlash('error', '1 Aucune stats trouvée pour ce code INSEE. Veuillez d\'abord ajouter la ville.');
return $this->redirectToRoute('app_admin_import_stats'); return $this->redirectToRoute('app_admin_import_stats');
} }
$followups = $stats->getCityFollowUps(); $followups = $stats->getCityFollowUps();
@ -504,7 +510,7 @@ final class AdminController extends AbstractController
{ {
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]); $stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]);
if (!$stats) { if (!$stats) {
$this->addFlash('error', 'Aucune stats trouvée pour ce code INSEE.'); $this->addFlash('error', '2 Aucune stats trouvée pour ce code INSEE.');
return $this->redirectToRoute('app_admin'); return $this->redirectToRoute('app_admin');
} }
@ -737,7 +743,7 @@ final class AdminController extends AbstractController
} }
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]); $stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]);
if (!$stats) { if (!$stats) {
$this->addFlash('error', 'Aucune stats trouvée pour ce code INSEE.'); $this->addFlash('error', '3 Aucune stats trouvée pour ce code INSEE.');
return $this->redirectToRoute('app_public_index'); return $this->redirectToRoute('app_public_index');
} }
// Mettre à jour la date de requête de labourage // Mettre à jour la date de requête de labourage
@ -1487,7 +1493,7 @@ final class AdminController extends AbstractController
$error = $e->getMessage(); $error = $e->getMessage();
} }
} else { } else {
$error = "Aucune stats trouvée pour ce code INSEE."; $error = "4 Aucune stats trouvée pour ce code INSEE.";
} }
} }
return $this->render('admin/test_ctc.html.twig', [ return $this->render('admin/test_ctc.html.twig', [
@ -1589,7 +1595,7 @@ final class AdminController extends AbstractController
{ {
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]); $stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]);
if (!$stats) { if (!$stats) {
$this->addFlash('error', 'Aucune stats trouvée pour ce code INSEE.'); $this->addFlash('error', '5 Aucune stats trouvée pour ce code INSEE.');
return $this->redirectToRoute('app_admin'); return $this->redirectToRoute('app_admin');
} }
@ -1730,7 +1736,7 @@ final class AdminController extends AbstractController
$ctc_completion_series = []; $ctc_completion_series = [];
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]); $stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]);
if (!$stats) { if (!$stats) {
$this->addFlash('error', 'Aucune stats trouvée pour ce code INSEE.'); $this->addFlash('error', '6 Aucune stats trouvée pour ce code INSEE.');
return $this->render('admin/followup_graph.html.twig', [ return $this->render('admin/followup_graph.html.twig', [
'stats' => null, 'stats' => null,
'completion_tags' => \App\Service\FollowUpService::getFollowUpCompletionTags(), 'completion_tags' => \App\Service\FollowUpService::getFollowUpCompletionTags(),
@ -1782,7 +1788,7 @@ final class AdminController extends AbstractController
{ {
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]); $stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]);
if (!$stats) { if (!$stats) {
$this->addFlash('error', 'Aucune stats trouvée pour ce code INSEE.'); $this->addFlash('error', '7 Aucune stats trouvée pour ce code INSEE.');
return $this->redirectToRoute('app_admin'); return $this->redirectToRoute('app_admin');
} }
$places = $stats->getPlaces(); $places = $stats->getPlaces();
@ -1819,7 +1825,7 @@ final class AdminController extends AbstractController
{ {
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]); $stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]);
if (!$stats) { if (!$stats) {
$this->addFlash('error', 'Aucune stats trouvée pour ce code INSEE. Veuillez d\'abord ajouter la ville.'); $this->addFlash('error', '8 Aucune stats trouvée pour ce code INSEE. Veuillez d\'abord ajouter la ville.');
return $this->redirectToRoute('app_admin_import_stats'); return $this->redirectToRoute('app_admin_import_stats');
} }
// Tags attendus pour la complétion // Tags attendus pour la complétion

View file

@ -26,7 +26,7 @@ class FollowUpController extends AbstractController
public function deleteFollowups(string $insee_code, EntityManagerInterface $em): Response { public function deleteFollowups(string $insee_code, EntityManagerInterface $em): Response {
$stats = $em->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]); $stats = $em->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]);
if (!$stats) { if (!$stats) {
$this->addFlash('error', 'Aucune stats trouvée pour ce code INSEE.'); $this->addFlash('error', '9 Aucune stats trouvée pour ce code INSEE.');
return $this->redirectToRoute('app_admin'); return $this->redirectToRoute('app_admin');
} }
$followups = $stats->getCityFollowUps(); $followups = $stats->getCityFollowUps();
@ -46,7 +46,7 @@ class FollowUpController extends AbstractController
): Response { ): Response {
$stats = $em->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]); $stats = $em->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]);
if (!$stats) { if (!$stats) {
$this->addFlash('error', 'Aucune stats trouvée pour ce code INSEE.'); $this->addFlash('error', '10 Aucune stats trouvée pour ce code INSEE.');
return $this->redirectToRoute('app_admin'); return $this->redirectToRoute('app_admin');
} }
$this->followUpService->generateCityFollowUps($stats, $motocultrice, $em); $this->followUpService->generateCityFollowUps($stats, $motocultrice, $em);
@ -62,7 +62,7 @@ class FollowUpController extends AbstractController
) { ) {
$stats = $em->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]); $stats = $em->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]);
if (!$stats) { if (!$stats) {
$this->addFlash('error', 'Aucune stats trouvée pour ce code INSEE.'); $this->addFlash('error', '11 Aucune stats trouvée pour ce code INSEE.');
return $this->redirectToRoute('app_admin'); return $this->redirectToRoute('app_admin');
} }
$followups = $stats->getCityFollowUps(); $followups = $stats->getCityFollowUps();
@ -248,7 +248,7 @@ class FollowUpController extends AbstractController
) { ) {
$stats = $em->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]); $stats = $em->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]);
if (!$stats) { if (!$stats) {
$this->addFlash('error', 'Aucune stats trouvée pour ce code INSEE.'); $this->addFlash('error', '12 Aucune stats trouvée pour ce code INSEE.');
return $this->redirectToRoute('app_admin'); return $this->redirectToRoute('app_admin');
} }
$followups = $stats->getCityFollowUps(); $followups = $stats->getCityFollowUps();

View file

@ -650,7 +650,7 @@ class PublicController extends AbstractController
{ {
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]); $stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]);
if (!$stats) { if (!$stats) {
$this->addFlash('error', 'Aucune stats trouvée pour ce code INSEE.'); $this->addFlash('error', '13 Aucune stats trouvée pour ce code INSEE.');
return $this->redirectToRoute('app_public_index'); return $this->redirectToRoute('app_public_index');
} }

View file

@ -71,7 +71,7 @@ class FollowUpService
} elseif ($type === 'manhole') { } elseif ($type === 'manhole') {
$objects = array_filter($elements, fn($el) => ($el['tags']['manhole'] ?? null) === 'manhole') ?? []; $objects = array_filter($elements, fn($el) => ($el['tags']['manhole'] ?? null) === 'manhole') ?? [];
} elseif ($type === 'little_free_library') { } elseif ($type === 'little_free_library') {
$objects = array_filter($elements, fn($el) => ($el['tags']['amenity'] ?? null) === 'little_free_library') ?? []; $objects = array_filter($elements, fn($el) => ($el['tags']['amenity'] ?? null) === 'public_bookcase') ?? [];
} elseif ($type === 'playground') { } elseif ($type === 'playground') {
$objects = array_filter($elements, fn($el) => ($el['tags']['leisure'] ?? null) === 'playground') ?? []; $objects = array_filter($elements, fn($el) => ($el['tags']['leisure'] ?? null) === 'playground') ?? [];
} else { } else {
@ -160,14 +160,24 @@ class FollowUpService
public function generateGlobalFollowUps(EntityManagerInterface $em): void public function generateGlobalFollowUps(EntityManagerInterface $em): void
{ {
// Vérifier l'existence d'un objet Stats pour la zone '00000'
$statsGlobal = $em->getRepository(\App\Entity\Stats::class)->findOneBy(['zone' => '00000']); $statsGlobal = $em->getRepository(\App\Entity\Stats::class)->findOneBy(['zone' => '00000']);
if (!$statsGlobal) { if ($statsGlobal) {
$statsGlobal = new \App\Entity\Stats(); // Si déjà existant, on le réutilise
$statsGlobal->setZone('00000'); // (optionnel : mettre à jour le nom si besoin)
if ($statsGlobal->getName() !== 'toutes les villes') {
$statsGlobal->setName('toutes les villes'); $statsGlobal->setName('toutes les villes');
$em->persist($statsGlobal); $em->persist($statsGlobal);
$em->flush(); $em->flush();
} }
} else {
// Sinon, on le crée
// $statsGlobal = new \App\Entity\Stats();
// $statsGlobal->setZone('00000');
// $statsGlobal->setName('toutes les villes');
// $em->persist($statsGlobal);
// $em->flush();
}
$now = new \DateTime(); $now = new \DateTime();
$themes = array_keys(self::getFollowUpThemes()); $themes = array_keys(self::getFollowUpThemes());
$allStats = $em->getRepository(\App\Entity\Stats::class)->findAll(); $allStats = $em->getRepository(\App\Entity\Stats::class)->findAll();
@ -262,6 +272,7 @@ class FollowUpService
'bicycle_parking' => 'Parkings vélos', 'bicycle_parking' => 'Parkings vélos',
'advertising_board' => 'Panneaux électoraux', 'advertising_board' => 'Panneaux électoraux',
'building' => 'Bâtiments', 'building' => 'Bâtiments',
'rnb' => 'RNB',
'email' => 'Objets avec email', 'email' => 'Objets avec email',
'bench' => 'Bancs', 'bench' => 'Bancs',
'waste_basket' => 'Poubelles', 'waste_basket' => 'Poubelles',
@ -294,6 +305,7 @@ class FollowUpService
'bicycle_parking' => 'bi-bicycle', 'bicycle_parking' => 'bi-bicycle',
'advertising_board' => 'bi-easel', 'advertising_board' => 'bi-easel',
'building' => 'bi-building', 'building' => 'bi-building',
'rnb' => 'bi-key',
'email' => 'bi-envelope-at', 'email' => 'bi-envelope-at',
'bench' => 'bi-badge-wc', 'bench' => 'bi-badge-wc',
'waste_basket' => 'bi-trash', 'waste_basket' => 'bi-trash',
@ -332,6 +344,7 @@ class FollowUpService
'bicycle_parking' => 'nwr["amenity"="bicycle_parking"](area.searchArea);', 'bicycle_parking' => 'nwr["amenity"="bicycle_parking"](area.searchArea);',
'advertising_board' => 'nwr["advertising"="board"]["message"="political"](area.searchArea);', 'advertising_board' => 'nwr["advertising"="board"]["message"="political"](area.searchArea);',
'building' => 'nwr["building"](area.searchArea);', 'building' => 'nwr["building"](area.searchArea);',
'rnb' => 'nwr["ref:FR:RNB"](area.searchArea);',
'email' => 'nwr["email"](area.searchArea);nwr["contact:email"](area.searchArea);', 'email' => 'nwr["email"](area.searchArea);nwr["contact:email"](area.searchArea);',
'bench' => 'nwr["amenity"="bench"](area.searchArea);', 'bench' => 'nwr["amenity"="bench"](area.searchArea);',
'waste_basket' => 'nwr["amenity"="waste_basket"](area.searchArea);', 'waste_basket' => 'nwr["amenity"="waste_basket"](area.searchArea);',
@ -340,7 +353,7 @@ class FollowUpService
'tree' => 'nwr["natural"="tree"](area.searchArea);', 'tree' => 'nwr["natural"="tree"](area.searchArea);',
'power_pole' => 'nwr["power"="pole"](area.searchArea);', 'power_pole' => 'nwr["power"="pole"](area.searchArea);',
'manhole' => 'nwr["manhole"](area.searchArea);', 'manhole' => 'nwr["manhole"](area.searchArea);',
'little_free_library' => 'nwr["amenity"="little_free_library"](area.searchArea);', 'little_free_library' => 'nwr["amenity"="public_bookcase"](area.searchArea);',
'playground' => 'nwr["leisure"="playground"](area.searchArea);', 'playground' => 'nwr["leisure"="playground"](area.searchArea);',
]; ];
} }
@ -479,7 +492,8 @@ class FollowUpService
'healthcare' => ['name', 'contact:phone', 'phone', 'email', 'contact:email'], 'healthcare' => ['name', 'contact:phone', 'phone', 'email', 'contact:email'],
'bicycle_parking' => ['capacity', 'covered'], 'bicycle_parking' => ['capacity', 'covered'],
'advertising_board' => ['operator', 'contact:phone'], 'advertising_board' => ['operator', 'contact:phone'],
'building' => ['name', 'ref'], 'building' => ['building'],
'rnb' => ['building', 'ref:FR:RNB'],
'email' => ['name', 'phone'], 'email' => ['name', 'phone'],
'bench' => ['material', 'backrest'], 'bench' => ['material', 'backrest'],
'waste_basket' => ['waste', 'recycling_type'], 'waste_basket' => ['waste', 'recycling_type'],

1
stats_export.json Normal file

File diff suppressed because one or more lines are too long

View file

@ -45,6 +45,7 @@ display:
address: 'Address' address: 'Address'
phone: 'Phone' phone: 'Phone'
building: 'Building' building: 'Building'
rnb: 'RNB'
contact:email: 'Email' contact:email: 'Email'
contact:phone: 'Contact phone' contact:phone: 'Contact phone'
address:housenumber: 'Street number' address:housenumber: 'Street number'