add bubble chart, fix dashboard perf

This commit is contained in:
Tykayn 2025-06-21 10:26:55 +02:00 committed by tykayn
parent ca00f8c0be
commit ad4170db14
8 changed files with 335 additions and 248 deletions

View file

@ -97,6 +97,7 @@ final class AdminController extends AbstractController
} elseif ($updateExisting) {
// Mettre à jour les données depuis Overpass uniquement si updateExisting est true
$existingPlace->update_place_from_overpass_data($placeData);
$stats->addPlace($existingPlace);
$this->entityManager->persist($existingPlace);
$updatedCount++;
}
@ -452,11 +453,14 @@ final class AdminController extends AbstractController
}
// Récupérer toutes les données
$places = $this->motocultrice->labourer($insee_code);
$places_overpass = $this->motocultrice->labourer($insee_code);
$processedCount = 0;
$updatedCount = 0;
foreach ($places as $placeData) {
$deletedCount = 0;
$overpass_osm_ids = array_map(fn($place) => $place['id'], $places_overpass);
foreach ($places_overpass as $placeData) {
// Vérifier si le lieu existe déjà
$existingPlace = $this->entityManager->getRepository(Place::class)
->findOneBy(['osmId' => $placeData['id']]);
@ -477,8 +481,11 @@ final class AdminController extends AbstractController
->setSiret($this->motocultrice->find_siret($placeData['tags']) ?? '')
->setAskedHumainsSupport(false)
->setLastContactAttemptDate(null)
->setNote('')
->setPlaceCount(0);
->setNote($this->motocultrice->find_tag($placeData['tags'], 'note') ? true : false)
->setNoteContent($this->motocultrice->find_tag($placeData['tags'], 'note') ?? '')
->setPlaceCount(0)
// ->setOsmData($placeData['modified'] ?? null)
;
// Mettre à jour les données depuis Overpass
$place->update_place_from_overpass_data($placeData);
@ -487,17 +494,63 @@ final class AdminController extends AbstractController
$stats->addPlace($place);
$processedCount++;
} elseif ($updateExisting) {
// Mettre à jour les données depuis Overpass uniquement si updateExisting est true
// Mettre à jour les données depuis Overpass et s'assurer qu'il est marqué comme "vivant"
$existingPlace->setDead(false);
$existingPlace->update_place_from_overpass_data($placeData);
$stats->addPlace($existingPlace);
$this->entityManager->persist($existingPlace);
$updatedCount++;
}
}
// Flush final
$this->entityManager->flush();
// 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++;
}
}
// Récupérer tous les commerces de la zone qui n'ont pas été supprimés
$commerces = $this->entityManager->getRepository(Place::class)->findBy(['zip_code' => $insee_code]);
// Récupérer les stats existantes pour la zone
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]);
if(!$stats) {
$stats = new Stats();
$stats->setZone($insee_code);
}
$urls = $stats->getAllCTCUrlsMap();
// Mettre à jour les statistiques finales
$statsHistory = $this->entityManager->getRepository(StatsHistory::class)
->createQueryBuilder('sh')
->where('sh.stats = :stats')
->setParameter('stats', $stats)
->orderBy('sh.id', 'DESC')
->setMaxResults(365)
->getQuery()
->getResult();
// 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);
}
$stats->computeCompletionPercent();
// Calculer les statistiques de fraîcheur des données OSM
@ -564,8 +617,12 @@ final class AdminController extends AbstractController
$message = 'Labourage terminé avec succès. ' . $processedCount . ' nouveaux lieux traités.';
if ($updateExisting) {
$message .= ' ' . $updatedCount . ' lieux existants mis à jour pour la zone '.$stats->getName().' ('.$stats->getZone().').';
$message .= ' ' . $updatedCount . ' lieux existants mis à jour.';
}
if ($deletedCount > 0) {
$message .= ' ' . $deletedCount . ' lieux ont été supprimés.';
}
$message .= ' Zone : '.$stats->getName().' ('.$stats->getZone().').';
$this->addFlash('success', $message);
} catch (\Exception $e) {
$this->addFlash('error', 'Erreur lors du labourage : ' . $e->getMessage());

View file

@ -162,16 +162,33 @@ out meta;';
public function labourer(string $zone): array
{
$query = $this->get_query_places($zone);
$url = 'https://overpass-api.de/api/interpreter?data=' . urlencode($query);
try {
$query = $this->get_query_places($zone);
$response = $this->client->request('POST', $this->overpassApiUrl, [
'body' => ['data' => $query]
$response = $this->client->request('GET', $url, [
'timeout' => 90, // Augmenter le timeout pour les zones très denses
]);
if ($response->getStatusCode() !== 200) {
throw new \Exception('L\'API Overpass a retourné un code de statut non-200 : ' . $response->getStatusCode());
}
$data = json_decode($response->getContent(), true);
if (json_last_error() !== JSON_ERROR_NONE) {
// Tenter de récupérer le corps de la réponse brute en cas d'erreur JSON pour le débogage
$rawResponse = $response->getContent(false); // ne pas lancer d'exception si la réponse n'est pas décodable
throw new \Exception('Réponse JSON invalide depuis l\'API Overpass. Erreur: ' . json_last_error_msg() . '. Réponse brute : ' . substr($rawResponse, 0, 500));
}
$places = [];
if (isset($data['elements'])) {
if (count($data['elements']) === 0) {
// Ce n'est pas une erreur, juste aucun lieu trouvé. On retourne un tableau vide.
return [];
}
foreach ($data['elements'] as $element) {
if (isset($element['tags'])) {
$places[] = [
@ -198,8 +215,13 @@ out meta;';
gc_collect_cycles();
return $places;
} catch (\Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface $e) {
// Gérer spécifiquement les erreurs de transport (timeout, problème de connexion)
throw new \Exception('Erreur de communication avec l\'API Overpass (le service est peut-être indisponible ou la requête a expiré) : ' . $e->getMessage(), 0, $e);
} catch (\Exception $e) {
throw new \Exception("Erreur lors de la requête Overpass : " . $e->getMessage());
// Rattraper et relancer les autres exceptions (y compris celles que nous avons définies)
throw $e;
}
}