From 56f62c45bb91ee93941d5e626ad785ed1c7e674b Mon Sep 17 00:00:00 2001 From: Tykayn Date: Sat, 5 Jul 2025 12:37:01 +0200 Subject: [PATCH] map on home --- bin/console | 5 + config/packages/doctrine.yaml | 5 + config/packages/framework.yaml | 11 +- public/index.php | 5 + src/Controller/AdminController.php | 61 +++- src/Controller/PublicController.php | 57 +++- .../admin/followup_embed_graph.html.twig | 2 +- .../admin/followup_global_graph.html.twig | 6 +- templates/admin/followup_graph.html.twig | 2 +- .../admin/followup_theme_graph.html.twig | 275 ++++++++++++++++++ templates/admin/stats.html.twig | 10 +- templates/admin/stats_history.html.twig | 2 +- templates/public/home.html.twig | 161 ++++++++++ templates/public/nav.html.twig | 1 + 14 files changed, 588 insertions(+), 15 deletions(-) create mode 100644 templates/admin/followup_theme_graph.html.twig diff --git a/bin/console b/bin/console index d8d530e2..b536509e 100755 --- a/bin/console +++ b/bin/console @@ -12,6 +12,11 @@ if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) { throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".'); } +// Optimisations pour éviter les timeouts +ini_set('max_execution_time', 300); +ini_set('memory_limit', '512M'); +set_time_limit(300); + require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; return function (array $context) { diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index d8fd9aa4..02ffbd2b 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -4,6 +4,11 @@ doctrine: options: 1002: "SET NAMES utf8mb4" 1000: true + # Optimisations pour éviter les timeouts + PDO::ATTR_TIMEOUT: 300 + PDO::ATTR_PERSISTENT: false + PDO::MYSQL_ATTR_USE_BUFFERED_QUERY: true + PDO::MYSQL_ATTR_INIT_COMMAND: "SET SESSION wait_timeout=300, interactive_timeout=300" # IMPORTANT: You MUST configure your server version, # either here or in the DATABASE_URL env var (see .env file) diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml index c03e419c..ffce95e4 100644 --- a/config/packages/framework.yaml +++ b/config/packages/framework.yaml @@ -5,7 +5,16 @@ framework: http_method_override: false handle_all_throwables: true - + # Optimisations pour éviter les timeouts + cache: + app: cache.adapter.filesystem + system: cache.adapter.system + directory: '%kernel.cache_dir%/pools/app' + default_redis_provider: 'redis://localhost' + default_memcached_provider: 'memcached://localhost' + default_doctrine_dbal_provider: database_connection + default_pdo_provider: null + pools: { } # Enables session support. Note that the session will ONLY be started if you read or write from it. # Remove or comment this section to explicitly disable session support. diff --git a/public/index.php b/public/index.php index 9982c218..3938415b 100644 --- a/public/index.php +++ b/public/index.php @@ -4,6 +4,11 @@ use App\Kernel; require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; +// Optimisations pour éviter les timeouts +ini_set('max_execution_time', 300); +ini_set('memory_limit', '1024M'); +set_time_limit(300); + return function (array $context) { return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); }; diff --git a/src/Controller/AdminController.php b/src/Controller/AdminController.php index 53d7bb80..d5f61b4c 100644 --- a/src/Controller/AdminController.php +++ b/src/Controller/AdminController.php @@ -471,6 +471,61 @@ final class AdminController extends AbstractController ]); } + #[Route('/admin/stats/{insee_code}/followup-graph/{theme}', name: 'admin_followup_theme_graph', requirements: ['insee_code' => '\\d+'])] + public function followupThemeGraph(string $insee_code, string $theme): Response + { + $stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $insee_code]); + if (!$stats) { + $this->addFlash('error', 'Aucune stats trouvée pour ce code INSEE.'); + return $this->redirectToRoute('app_admin'); + } + + $themes = \App\Service\FollowUpService::getFollowUpThemes(); + if (!isset($themes[$theme])) { + $this->addFlash('error', 'Thème non reconnu.'); + return $this->redirectToRoute('app_admin_stats', ['insee_code' => $insee_code]); + } + + // Récupérer toutes les données de followup pour ce thème + $followups = $stats->getCityFollowUps(); + $countData = []; + $completionData = []; + + foreach ($followups as $fu) { + if ($fu->getName() === $theme . '_count') { + $countData[] = [ + 'date' => $fu->getDate()->format('Y-m-d'), + 'value' => $fu->getMeasure() + ]; + } + if ($fu->getName() === $theme . '_completion') { + $completionData[] = [ + 'date' => $fu->getDate()->format('Y-m-d'), + 'value' => $fu->getMeasure() + ]; + } + } + + // Trier par date + usort($countData, fn($a, $b) => $a['date'] <=> $b['date']); + usort($completionData, fn($a, $b) => $a['date'] <=> $b['date']); + + $this->actionLogger->log('followup_theme_graph', [ + 'insee_code' => $insee_code, + 'theme' => $theme, + 'theme_label' => $themes[$theme] ?? 'Unknown' + ]); + + return $this->render('admin/followup_theme_graph.html.twig', [ + 'stats' => $stats, + 'theme' => $theme, + 'theme_label' => $themes[$theme], + 'count_data' => json_encode($countData), + 'completion_data' => json_encode($completionData), + 'icons' => \App\Service\FollowUpService::getFollowUpIcons(), + ]); + } + #[Route('/admin/placeType/{osm_kind}/{osm_id}', name: 'app_admin_by_osm_id')] public function placeType(string $osm_kind, string $osm_id): Response { @@ -484,11 +539,7 @@ final class AdminController extends AbstractController ]); return $this->redirectToRoute('app_admin_commerce', ['id' => $place->getId()]); } else { - $this->actionLogger->log('ERROR_admin/placeType', ['osm_kind' => $osm_kind, 'osm_id' => $osm_id, - 'name' => $place->getName(), - 'code_insee' => $place->getZipCode(), - 'uuid' => $place->getUuidForUrl() - ]); + $this->actionLogger->log('ERROR_admin/placeType', ['osm_kind' => $osm_kind, 'osm_id' => $osm_id]); $this->addFlash('error', 'Le lieu n\'existe pas.'); $this->actionLogger->log('ERROR_admin/placeType', ['osm_kind' => $osm_kind, 'osm_id' => $osm_id]); return $this->redirectToRoute('app_public_index'); diff --git a/src/Controller/PublicController.php b/src/Controller/PublicController.php index 37466873..fcbf9ab6 100644 --- a/src/Controller/PublicController.php +++ b/src/Controller/PublicController.php @@ -120,12 +120,67 @@ class PublicController extends AbstractController { $stats = $this->entityManager->getRepository(Stats::class)->findAll(); + // Préparer les données pour la carte + $citiesForMap = []; + foreach ($stats as $stat) { + if ($stat->getZone() && $stat->getZone() !== 'undefined' && preg_match('/^\d+$/', $stat->getZone())) { + // Récupérer les coordonnées de la ville via l'API Nominatim + $cityName = $stat->getName() ?: $stat->getZone(); + $coordinates = $this->getCityCoordinates($cityName, $stat->getZone()); + + if ($coordinates) { + $citiesForMap[] = [ + 'name' => $cityName, + 'zone' => $stat->getZone(), + 'coordinates' => $coordinates, + 'placesCount' => $stat->getPlacesCount(), + 'completionPercent' => $stat->getCompletionPercent(), + 'population' => $stat->getPopulation(), + 'url' => $this->generateUrl('app_admin_stats', ['insee_code' => $stat->getZone()]) + ]; + } + } + } + return $this->render('public/home.html.twig', [ 'controller_name' => 'PublicController', - 'stats' => $stats + 'stats' => $stats, + 'citiesForMap' => $citiesForMap, + 'maptiler_token' => $_ENV['MAPTILER_TOKEN'] ?? null ]); } + /** + * Récupère les coordonnées d'une ville via l'API Nominatim + */ + private function getCityCoordinates(string $cityName, string $inseeCode): ?array + { + // Cache simple pour éviter trop d'appels API + $cacheKey = 'city_coords_' . $inseeCode; + + // Vérifier le cache (ici on utilise une approche simple) + // En production, vous pourriez utiliser le cache Symfony + + $query = urlencode($cityName . ', France'); + $url = "https://nominatim.openstreetmap.org/search?q={$query}&format=json&limit=1&countrycodes=fr"; + + try { + $response = file_get_contents($url); + $data = json_decode($response, true); + + if (!empty($data) && isset($data[0]['lat']) && isset($data[0]['lon'])) { + return [ + 'lat' => (float) $data[0]['lat'], + 'lon' => (float) $data[0]['lon'] + ]; + } + } catch (\Exception $e) { + // En cas d'erreur, on retourne null + } + + return null; + } + #[Route('/edit/{zipcode}/{name}/{uuid}', name: 'app_public_edit')] public function edit_with_uuid($zipcode, $name, $uuid): Response { diff --git a/templates/admin/followup_embed_graph.html.twig b/templates/admin/followup_embed_graph.html.twig index fb22b5ce..70cb046b 100644 --- a/templates/admin/followup_embed_graph.html.twig +++ b/templates/admin/followup_embed_graph.html.twig @@ -5,7 +5,7 @@ {% block body %}

{{ label }} - {{ stats.name }}

- +

Nombre de villes et complétion moyenne

- +

Suivi par thématique

@@ -23,8 +23,8 @@ {{ label }} - - + +
diff --git a/templates/admin/followup_graph.html.twig b/templates/admin/followup_graph.html.twig index eabbe92e..fecf8ce1 100644 --- a/templates/admin/followup_graph.html.twig +++ b/templates/admin/followup_graph.html.twig @@ -22,7 +22,7 @@

Historique des objets suivis (nombre et complétion).

{% for type, label in followup_labels %}

{{ label }}

- +
{% set overpass_query = '[out:json][timeout:60];\narea["ref:INSEE"="' ~ stats.zone ~ '"]->.searchArea;\n(' ~ followup_overpass[type]|default('') ~ ');\n\n(._;>;);\n\nout meta;\n>;' %} diff --git a/templates/admin/followup_theme_graph.html.twig b/templates/admin/followup_theme_graph.html.twig new file mode 100644 index 00000000..c3328fab --- /dev/null +++ b/templates/admin/followup_theme_graph.html.twig @@ -0,0 +1,275 @@ +{% extends 'base_embed.html.twig' %} + +{% block title %}Graphique {{ theme_label }} - {{ stats.name }}{% endblock %} + +{% block stylesheets %} + {{ parent() }} + +{% endblock %} + +{% block body %} +
+
+

+ + {{ theme_label }} - {{ stats.name }} +

+

Code INSEE: {{ stats.zone }}

+
+ +
+
+
-
+
Nombre actuel
+
+
+
-
+
Complétion actuelle
+
+
+
-
+
Points de données
+
+
+
-
+
Dernière mise à jour
+
+
+ +
+ + +
+ +
+
+ +
+
+ +
+
+ +
+
+
+{% endblock %} + +{% block javascripts %} + {{ parent() }} + + + + +{% endblock %} \ No newline at end of file diff --git a/templates/admin/stats.html.twig b/templates/admin/stats.html.twig index 099b0eca..1af11855 100644 --- a/templates/admin/stats.html.twig +++ b/templates/admin/stats.html.twig @@ -170,6 +170,9 @@

{{ followup_labels[type]|default(type|capitalize) }}
+ + +
{{ data.count is defined ? data.count.getMeasure() : '?' }}
{{ completion is not null ? completion : '?' }}% {% if progression7Days[type] is defined %} @@ -200,6 +203,9 @@

{{ followup_labels[type]|default(type|capitalize) }}
+ + Graphique +
N = ?
?%
@@ -280,7 +286,7 @@
- +
@@ -303,7 +309,7 @@
{% include 'admin/stats_history.html.twig' with {stat: stats} %} - +
diff --git a/templates/admin/stats_history.html.twig b/templates/admin/stats_history.html.twig index c588b4ce..39584145 100644 --- a/templates/admin/stats_history.html.twig +++ b/templates/admin/stats_history.html.twig @@ -3,7 +3,7 @@

Évolution du taux de complétion

- +
diff --git a/templates/public/home.html.twig b/templates/public/home.html.twig index cd3b15ff..1bf49332 100644 --- a/templates/public/home.html.twig +++ b/templates/public/home.html.twig @@ -4,8 +4,46 @@ {% block stylesheets %} {{ parent() }} +