mirror of
https://forge.chapril.org/tykayn/osm-commerces
synced 2025-10-04 17:04:53 +02:00
up historique
This commit is contained in:
parent
ad4170db14
commit
c274fd6a63
12 changed files with 448 additions and 616 deletions
|
@ -11,6 +11,7 @@ use App\Entity\Stats;
|
|||
use App\Entity\StatsHistory;
|
||||
use App\Service\Motocultrice;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use function uuid_create;
|
||||
|
||||
final class AdminController extends AbstractController
|
||||
|
@ -234,102 +235,18 @@ final class AdminController extends AbstractController
|
|||
public function calculer_stats(string $insee_code): Response
|
||||
{
|
||||
// Récupérer tous les commerces de la zone
|
||||
$commerces = $this->entityManager->getRepository(Place::class)->findBy(['zip_code' => $insee_code]);
|
||||
$commerces = $this->entityManager->getRepository(Place::class)->findBy(['zip_code' => $insee_code, 'dead' => false]);
|
||||
|
||||
// Récupérer les stats existantes pour la zone
|
||||
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]);
|
||||
if(!$stats) {
|
||||
// Si aucune stat n'existe, on en crée une vide pour éviter les erreurs, mais sans la sauvegarder
|
||||
$stats = new Stats();
|
||||
$stats->setZone($insee_code);
|
||||
$stats->setName('Nouvelle zone non labourée');
|
||||
}
|
||||
|
||||
$urls = $stats->getAllCTCUrlsMap();
|
||||
|
||||
// Calculer les statistiques
|
||||
$calculatedStats = $this->motocultrice->calculateStats($commerces);
|
||||
|
||||
// Mettre à jour les stats pour la zone donnée
|
||||
$stats->setPlacesCount($calculatedStats['places_count']);
|
||||
$stats->setAvecHoraires($calculatedStats['counters']['avec_horaires']);
|
||||
$stats->setAvecAdresse($calculatedStats['counters']['avec_adresse']);
|
||||
$stats->setAvecSite($calculatedStats['counters']['avec_site']);
|
||||
$stats->setAvecAccessibilite($calculatedStats['counters']['avec_accessibilite']);
|
||||
$stats->setAvecNote($calculatedStats['counters']['avec_note']);
|
||||
$stats->setCompletionPercent($calculatedStats['completion_percent']);
|
||||
|
||||
// Associer les stats à chaque commerce
|
||||
foreach ($commerces as $commerce) {
|
||||
$commerce->setStats($stats);
|
||||
$this->entityManager->persist($commerce);
|
||||
}
|
||||
|
||||
$this->entityManager->persist($stats);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$stats->computeCompletionPercent();
|
||||
|
||||
// Calculer les statistiques de fraîcheur des données OSM
|
||||
$timestamps = [];
|
||||
foreach ($stats->getPlaces() as $place) {
|
||||
if ($place->getOsmDataDate()) {
|
||||
$timestamps[] = $place->getOsmDataDate()->getTimestamp();
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($timestamps)) {
|
||||
// Date la plus ancienne (min)
|
||||
$minTimestamp = min($timestamps);
|
||||
$stats->setOsmDataDateMin(new \DateTime('@' . $minTimestamp));
|
||||
|
||||
// Date la plus récente (max)
|
||||
$maxTimestamp = max($timestamps);
|
||||
$stats->setOsmDataDateMax(new \DateTime('@' . $maxTimestamp));
|
||||
|
||||
// Date moyenne
|
||||
$avgTimestamp = array_sum($timestamps) / count($timestamps);
|
||||
$stats->setOsmDataDateAvg(new \DateTime('@' . (int)$avgTimestamp));
|
||||
}
|
||||
|
||||
if($stats->getDateCreated() == null) {
|
||||
$stats->setDateCreated(new \DateTime());
|
||||
}
|
||||
|
||||
$stats->setDateModified(new \DateTime());
|
||||
|
||||
// Créer un historique des statistiques
|
||||
$statsHistory = new StatsHistory();
|
||||
$statsHistory->setDate(new \DateTime())
|
||||
->setStats($stats);
|
||||
|
||||
// Compter les Places avec email et SIRET
|
||||
$placesWithEmail = 0;
|
||||
$placesWithSiret = 0;
|
||||
foreach ($stats->getPlaces() as $place) {
|
||||
if ($place->getEmail() && $place->getEmail() !== '') {
|
||||
$placesWithEmail++;
|
||||
}
|
||||
if ($place->getSiret() && $place->getSiret() !== '') {
|
||||
$placesWithSiret++;
|
||||
}
|
||||
}
|
||||
|
||||
$statsHistory->setPlacesCount($stats->getPlaces()->count())
|
||||
->setOpeningHoursCount($stats->getAvecHoraires())
|
||||
->setAddressCount($stats->getAvecAdresse())
|
||||
->setWebsiteCount($stats->getAvecSite())
|
||||
->setSiretCount($placesWithSiret)
|
||||
->setEmailsCount($placesWithEmail)
|
||||
// ->setAccessibiliteCount($stats->getAvecAccessibilite())
|
||||
// ->setNoteCount($stats->getAvecNote())
|
||||
->setCompletionPercent($stats->getCompletionPercent())
|
||||
->setStats($stats);
|
||||
|
||||
$this->entityManager->persist($statsHistory);
|
||||
|
||||
|
||||
$this->entityManager->persist($stats);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$urls = $stats->getAllCTCUrlsMap();
|
||||
$statsHistory = $this->entityManager->getRepository(StatsHistory::class)
|
||||
->createQueryBuilder('sh')
|
||||
->where('sh.stats = :stats')
|
||||
|
@ -339,13 +256,54 @@ final class AdminController extends AbstractController
|
|||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
/*
|
||||
// La page de statistiques ne doit pas modifier les données, seulement les afficher.
|
||||
// La mise à jour des statistiques se fait lors du labourage.
|
||||
|
||||
// Calculer les statistiques
|
||||
$calculatedStats = $this->motocultrice->calculateStats($commerces);
|
||||
|
||||
// Mettre à jour les stats pour la zone donnée
|
||||
$stats->setPlacesCount($calculatedStats['places_count']);
|
||||
// ... (plus de setters) ...
|
||||
$stats->setCompletionPercent($calculatedStats['completion_percent']);
|
||||
|
||||
// ... (boucle foreach sur commerces) ...
|
||||
|
||||
$stats->computeCompletionPercent();
|
||||
|
||||
$this->entityManager->persist($stats);
|
||||
$this->entityManager->flush();
|
||||
*/
|
||||
|
||||
// Données pour le graphique des modifications par trimestre
|
||||
$modificationsByQuarter = [];
|
||||
foreach ($stats->getPlaces() as $commerce) {
|
||||
if ($commerce->getOsmDataDate()) {
|
||||
$date = $commerce->getOsmDataDate();
|
||||
$year = $date->format('Y');
|
||||
$quarter = ceil($date->format('n') / 3);
|
||||
$key = $year . '-Q' . $quarter;
|
||||
if (!isset($modificationsByQuarter[$key])) {
|
||||
$modificationsByQuarter[$key] = 0;
|
||||
}
|
||||
$modificationsByQuarter[$key]++;
|
||||
}
|
||||
}
|
||||
ksort($modificationsByQuarter); // Trier par clé (année-trimestre)
|
||||
|
||||
$overpass_query = $this->motocultrice->get_query_places($insee_code);
|
||||
$overpass_query_url = "https://overpass-turbo.eu/?Q=" . urlencode($overpass_query);
|
||||
|
||||
return $this->render('admin/stats.html.twig', [
|
||||
'stats' => $stats,
|
||||
'insee_code' => $insee_code,
|
||||
'query_places' => $this->motocultrice->get_query_places($insee_code),
|
||||
'counters' => $calculatedStats['counters'],
|
||||
'commerces' => $commerces,
|
||||
'urls' => $urls,
|
||||
'query_places' => $overpass_query,
|
||||
'overpass_query' => $overpass_query,
|
||||
'overpass_query_url' => $overpass_query_url,
|
||||
'modificationsByQuarter' => json_encode($modificationsByQuarter),
|
||||
'maptiler_token' => $_ENV['MAPTILER_TOKEN'],
|
||||
'mapbox_token' => $_ENV['MAPBOX_TOKEN'],
|
||||
'statsHistory' => $statsHistory,
|
||||
'CTC_urls' => $urls,
|
||||
]);
|
||||
|
@ -396,8 +354,9 @@ final class AdminController extends AbstractController
|
|||
* récupérer les commerces de la zone selon le code INSEE, créer les nouveaux lieux, et mettre à jour les existants
|
||||
*/
|
||||
#[Route('/admin/labourer/{insee_code}', name: 'app_admin_labourer')]
|
||||
public function labourer(string $insee_code, bool $updateExisting = true): Response
|
||||
public function labourer(Request $request, string $insee_code, bool $updateExisting = true): Response
|
||||
{
|
||||
$deleteMissing = $request->query->getBoolean('deleteMissing', true);
|
||||
|
||||
// Vérifier si le code INSEE est valide (composé uniquement de chiffres)
|
||||
if (!ctype_digit($insee_code) || $insee_code == 'undefined' || $insee_code == '') {
|
||||
|
@ -503,12 +462,14 @@ final class AdminController extends AbstractController
|
|||
}
|
||||
}
|
||||
|
||||
// Supprimer les lieux qui ne sont plus dans la réponse Overpass
|
||||
$db_places = $this->entityManager->getRepository(Place::class)->findBy(['zip_code' => $insee_code]);
|
||||
foreach ($db_places as $db_place) {
|
||||
if (!in_array($db_place->getOsmId(), $overpass_osm_ids)) {
|
||||
$this->entityManager->remove($db_place);
|
||||
$deletedCount++;
|
||||
// Supprimer les lieux qui ne sont plus dans la réponse Overpass, si activé
|
||||
if ($deleteMissing) {
|
||||
$db_places = $this->entityManager->getRepository(Place::class)->findBy(['zip_code' => $insee_code]);
|
||||
foreach ($db_places as $db_place) {
|
||||
if (!in_array($db_place->getOsmId(), $overpass_osm_ids)) {
|
||||
$this->entityManager->remove($db_place);
|
||||
$deletedCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -652,16 +613,35 @@ final class AdminController extends AbstractController
|
|||
#[Route('/admin/delete_by_zone/{insee_code}', name: 'app_admin_delete_by_zone')]
|
||||
public function delete_by_zone(string $insee_code): Response
|
||||
{
|
||||
$commerces = $this->entityManager->getRepository(Place::class)->findBy(['zip_code' => $insee_code]);
|
||||
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]);
|
||||
|
||||
foreach ($commerces as $commerce) {
|
||||
$this->entityManager->remove($commerce);
|
||||
}
|
||||
$this->entityManager->remove($stats);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->addFlash('success', 'Tous les commerces de la zone '.$insee_code.' ont été supprimés avec succès de OSM Mes commerces, mais pas dans OpenStreetMap.');
|
||||
if (!$stats) {
|
||||
$this->addFlash('error', 'Aucune statistique trouvée pour la zone ' . $insee_code);
|
||||
return $this->redirectToRoute('app_public_dashboard');
|
||||
}
|
||||
|
||||
try {
|
||||
// 1. Supprimer tous les StatsHistory associés
|
||||
foreach ($stats->getStatsHistories() as $history) {
|
||||
$this->entityManager->remove($history);
|
||||
}
|
||||
|
||||
// 2. Supprimer tous les Places associées
|
||||
foreach ($stats->getPlaces() as $place) {
|
||||
$this->entityManager->remove($place);
|
||||
}
|
||||
|
||||
// 3. Supprimer l'objet Stats lui-même
|
||||
$this->entityManager->remove($stats);
|
||||
|
||||
// 4. Appliquer les changements à la base de données
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->addFlash('success', 'La zone ' . $insee_code . ' et toutes les données associées ont été supprimées avec succès.');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->addFlash('error', 'Une erreur est survenue lors de la suppression de la zone ' . $insee_code . ': ' . $e->getMessage());
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('app_public_dashboard');
|
||||
}
|
||||
|
|
|
@ -173,17 +173,28 @@ class PublicController extends AbstractController
|
|||
public function dashboard(): Response
|
||||
{
|
||||
|
||||
$stats = $this->entityManager->getRepository(Stats::class)->findAll();
|
||||
$stats_repo = $this->entityManager->getRepository(Stats::class)->findAll();
|
||||
|
||||
$stats_for_chart = [];
|
||||
foreach ($stats_repo as $stat) {
|
||||
if ($stat->getPlacesCount() > 0 && $stat->getName() !== null && $stat->getPopulation() > 0) {
|
||||
$stats_for_chart[] = [
|
||||
'name' => $stat->getName(),
|
||||
'placesCount' => $stat->getPlacesCount(),
|
||||
'completionPercent' => $stat->getCompletionPercent(),
|
||||
'population' => $stat->getPopulation(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Compter le nombre total de lieux
|
||||
$placesCount = $this->entityManager->getRepository(Place::class)->count([]);
|
||||
return $this->render('public/dashboard.html.twig', [
|
||||
'controller_name' => 'PublicController',
|
||||
'mapbox_token' => $_ENV['MAPBOX_TOKEN'],
|
||||
'maptiler_token' => $_ENV['MAPTILER_TOKEN'],
|
||||
'stats' => $stats,
|
||||
|
||||
'mapbox_token' => $_ENV['MAPBOX_TOKEN'] ?? null,
|
||||
'maptiler_token' => $_ENV['MAPTILER_TOKEN'] ?? null,
|
||||
'stats' => json_encode($stats_for_chart),
|
||||
'stats_list' => $stats_repo,
|
||||
'places_count' => $placesCount,
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
namespace App\Service;
|
||||
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
class Motocultrice
|
||||
{
|
||||
private $overpassApiUrl = 'https://overpass-api.de/api/interpreter';
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue