osm-commerces/src/Controller/AdminController.php

399 lines
15 KiB
PHP
Raw Normal View History

2025-05-26 11:55:44 +02:00
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use App\Entity\Place;
use App\Entity\Stats;
use App\Service\Motocultrice;
use Doctrine\ORM\EntityManagerInterface;
use function uuid_create;
2025-05-26 11:55:44 +02:00
final class AdminController extends AbstractController
{
public function __construct(
private EntityManagerInterface $entityManager,
private Motocultrice $motocultrice
) {
}
2025-05-26 11:55:44 +02:00
#[Route('/admin', name: 'app_admin')]
public function index(): Response
{
return $this->render('admin/index.html.twig', [
'controller_name' => 'AdminController',
]);
}
#[Route('/admin/stats/{zip_code}', name: 'app_admin_stats')]
public function calculer_stats(string $zip_code): Response
{
// Récupérer tous les commerces de la zone
$commerces = $this->entityManager->getRepository(Place::class)->findBy(['zip_code' => $zip_code]);
// Récupérer les stats existantes pour la zone
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $zip_code]);
if(!$stats) {
$stats = new Stats();
$stats->setZone($zip_code);
}
// 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();
2025-05-27 12:17:46 +02:00
$stats->computeCompletionPercent();
$this->entityManager->persist($stats);
$this->entityManager->flush();
return $this->render('admin/stats.html.twig', [
'stats' => $stats,
'zip_code' => $zip_code,
2025-06-03 12:51:20 +02:00
'query_places' => $this->motocultrice->get_query_places($zip_code),
'counters' => $calculatedStats['counters'],
'maptiler_token' => $_ENV['MAPTILER_TOKEN'],
'mapbox_token' => $_ENV['MAPBOX_TOKEN'],
]);
}
2025-06-01 23:35:15 +02:00
#[Route('/admin/placeType/{osm_kind}/{osm_id}', name: 'app_admin_by_osm_id')]
public function placeType(string $osm_kind, string $osm_id): Response
{
$place = $this->entityManager->getRepository(Place::class)->findOneBy(['osm_kind' => $osm_kind, 'osmId' => $osm_id]);
if($place) {
return $this->redirectToRoute('app_admin_commerce', ['id' => $place->getId()]);
} else {
$this->addFlash('error', 'Le lieu n\'existe pas.');
return $this->redirectToRoute('app_public_index');
}
}
/**
* rediriger vers l'url unique quand on est admin
*/
2025-05-28 16:24:34 +02:00
#[Route('/admin/commerce/{id}', name: 'app_admin_commerce')]
public function commerce(int $id): Response
{
// Vérifier si on est en prod
if ($this->getParameter('kernel.environment') === 'prod') {
$this->addFlash('error', 'Vous n\'avez pas accès à cette page en production.');
return $this->redirectToRoute('app_public_index');
}
$commerce = $this->entityManager->getRepository(Place::class)->find($id);
if (!$commerce) {
throw $this->createNotFoundException('Commerce non trouvé');
}
// Redirection vers la page de modification avec les paramètres nécessaires
return $this->redirectToRoute('app_public_edit', [
'zipcode' => $commerce->getZipCode(),
'name' => $commerce->getName()!='' ? $commerce->getName() : '?',
2025-05-28 16:24:34 +02:00
'uuid' => $commerce->getUuidForUrl()
]);
}
/**
* récupérer les commerces de la zone, créer les nouveaux lieux, et mettre à jour les existants
*/
#[Route('/admin/labourer/{zip_code}', name: 'app_admin_labourer')]
public function labourer_zone(string $zip_code): Response
{
2025-06-03 12:51:20 +02:00
$results = [];
$results = $this->motocultrice->labourer($zip_code);
// Récupérer ou créer les stats pour cette zone
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $zip_code]);
if (!$stats) {
$stats = new Stats();
$stats->setZone($zip_code);
// Récupérer les commerces existants dans la base de données pour cette zone
}
$commerces = $stats->getPlaces();
// for commerce, set stats
foreach ($commerces as $commerce) {
$commerce->setStats($stats);
$this->entityManager->persist($commerce);
$stats->addPlace($commerce);
}
// rebuild et persist
$stats->computeCompletionPercent();
$this->entityManager->persist($stats);
$this->entityManager->flush();
2025-06-03 12:51:20 +02:00
// Si le nom de la zone n'est pas défini, le récupérer via OSM
if (!$stats->getName()) {
$city_name = $this->motocultrice->get_city_osm_from_zip_code($zip_code);
if ($city_name) {
$stats->setName($city_name);
$this->entityManager->persist($stats);
$this->entityManager->flush();
}
}
// Initialiser les compteurs
$counters = [
'avec_horaires' => 0,
'avec_adresse' => 0,
'avec_site' => 0,
'avec_accessibilite' => 0,
'avec_note' => 0
];
// Compter les différents critères pour chaque commerce
foreach ($commerces as $commerce) {
if ($commerce->hasOpeningHours()) {
$counters['avec_horaires']++;
}
if ($commerce->hasAddress()) {
$counters['avec_adresse']++;
}
if ($commerce->hasWebsite()) {
$counters['avec_site']++;
}
if ($commerce->hasWheelchair()) {
$counters['avec_accessibilite']++;
}
if ($commerce->hasNote()) {
$counters['avec_note']++;
}
$commerce->setStats($stats);
}
// Mettre à jour les statistiques
$stats->setPlacesCount(count($commerces));
$stats->setAvecHoraires($counters['avec_horaires']);
$stats->setAvecAdresse($counters['avec_adresse']);
$stats->setAvecSite($counters['avec_site']);
$stats->setAvecAccessibilite($counters['avec_accessibilite']);
$stats->setAvecNote($counters['avec_note']);
$stats->computeCompletionPercent();
$this->entityManager->persist($stats);
$this->entityManager->flush();
$osm_object_ids = [];
if ($commerces) {
// Extraire les osm_object_ids des commerces existants
foreach ($commerces as $commerce) {
$osm_object_ids[] = $commerce->getOsmKind() . '_' . $commerce->getOsmId();
}
}
// pour chaque résultat, vérifier que l'on a pas déjà un commerce avec le même osm_object_id
2025-06-03 16:19:07 +02:00
$new_places_list = array_filter($results, function($commerce) use ($osm_object_ids) {
return !in_array($commerce['type'] . '_' . $commerce['id'], $osm_object_ids);
});
2025-06-03 16:19:07 +02:00
$existing_places_list = array_filter($results, function($commerce) use ($osm_object_ids) {
return in_array($commerce['type'] . '_' . $commerce['id'], $osm_object_ids);
2025-06-03 16:19:07 +02:00
});
$new_places_counter = 0;
// var_dump($osm_object_ids);
// var_dump($new_places_list);
// var_dump($existing_places_list);
// die();
// on crée un commerce pour chaque résultat qui reste
2025-06-03 16:19:07 +02:00
foreach ($new_places_list as $np) {
if( !in_array($np['id'] . '_' . $np['type'] , $osm_object_ids )) {
$new_place = new Place();
$main_tag = $this->motocultrice->find_main_tag($np['tags']);
$fullMainTag = $main_tag && isset($np['tags'][$main_tag]) ? $main_tag.'='.$np['tags'][$main_tag] : "";
var_dump($fullMainTag);
$new_place
->setUuidForUrl($this->motocultrice->uuid_create())
->setModifiedDate(new \DateTime())
->setStats($stats)
->setDead(false)
->setOptedOut(false)
->setZipCode($zip_code)
->setOsmId($np['id'])
->setMainTag($fullMainTag)
->setOsmKind($np['type'])
->setAskedHumainsSupport(false)
->setLastContactAttemptDate(null)
->update_place_from_overpass_data($np);
$this->entityManager->persist($new_place);
$new_place->setStats($stats);
$stats->addPlace($new_place);
$new_places_counter++;
}
2025-06-03 16:19:07 +02:00
}
2025-06-03 16:19:07 +02:00
// Mise à jour des commerces existants avec les données Overpass
foreach ($commerces as $existing_place) {
2025-06-03 16:19:07 +02:00
foreach ($results as $result) {
if ($existing_place->getOsmId() == $result['id'] && $existing_place->getOsmKind() == $result['type']) {
$existing_place->update_place_from_overpass_data($result);
$existing_place->setStats($stats);
$this->entityManager->persist($existing_place);
2025-06-03 16:19:07 +02:00
break;
}
}
}
$this->entityManager->persist($stats);
$this->entityManager->flush();
2025-06-03 11:37:27 +02:00
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $zip_code]);
return $this->render('admin/labourage_results.html.twig', [
'results' => $results,
'commerces' => $stats->getPlaces(),
'zone' => $zip_code,
2025-06-03 11:37:27 +02:00
'stats' => $stats,
'new_places_counter' => $new_places_counter,
]);
}
#[Route('/admin/delete/{id}', name: 'app_admin_delete')]
public function delete(int $id): Response
{
$commerce = $this->entityManager->getRepository(Place::class)->find($id);
2025-05-28 16:24:34 +02:00
if($commerce) {
$this->entityManager->remove($commerce);
$this->entityManager->flush();
2025-05-28 16:24:34 +02:00
$this->addFlash('success', 'Le lieu '.$commerce->getName().' a été supprimé avec succès de OSM Mes commerces, mais pas dans OpenStreetMap.');
} else {
$this->addFlash('error', 'Le lieu n\'existe pas.');
}
2025-05-28 16:24:34 +02:00
return $this->redirectToRoute('app_public_dashboard');
}
#[Route('/admin/delete_by_zone/{zip_code}', name: 'app_admin_delete_by_zone')]
public function delete_by_zone(string $zip_code): Response
{
$commerces = $this->entityManager->getRepository(Place::class)->findBy(['zip_code' => $zip_code]);
2025-06-01 19:52:56 +02:00
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $zip_code]);
foreach ($commerces as $commerce) {
$this->entityManager->remove($commerce);
}
2025-06-01 19:52:56 +02:00
$this->entityManager->remove($stats);
$this->entityManager->flush();
$this->addFlash('success', 'Tous les commerces de la zone '.$zip_code.' ont été supprimés avec succès de OSM Mes commerces, mais pas dans OpenStreetMap.');
2025-05-28 16:24:34 +02:00
return $this->redirectToRoute('app_public_dashboard');
}
#[Route('/admin/export', name: 'app_admin_export')]
public function export(): Response
{
$places = $this->entityManager->getRepository(Place::class)->findAll();
$csvData = [];
$csvData[] = [
'Nom',
'Email',
'Code postal',
'ID OSM',
'Type OSM',
'Date de modification',
'Date dernier contact',
'Note',
'Désabonné',
'Inactif',
'Support humain demandé',
'A des horaires',
'A une adresse',
'A un site web',
'A accessibilité',
'A une note'
];
foreach ($places as $place) {
$csvData[] = [
$place->getName(),
$place->getEmail(),
$place->getZipCode(),
$place->getOsmId(),
$place->getOsmKind(),
$place->getModifiedDate() ? $place->getModifiedDate()->format('Y-m-d H:i:s') : '',
$place->getLastContactAttemptDate() ? $place->getLastContactAttemptDate()->format('Y-m-d H:i:s') : '',
$place->getNote(),
$place->isOptedOut() ? 'Oui' : 'Non',
$place->isDead() ? 'Oui' : 'Non',
$place->isAskedHumainsSupport() ? 'Oui' : 'Non',
$place->hasOpeningHours() ? 'Oui' : 'Non',
$place->hasAddress() ? 'Oui' : 'Non',
$place->hasWebsite() ? 'Oui' : 'Non',
$place->hasWheelchair() ? 'Oui' : 'Non',
$place->hasNote() ? 'Oui' : 'Non'
];
}
$response = new Response();
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename="export_places.csv"');
$handle = fopen('php://temp', 'r+');
foreach ($csvData as $row) {
fputcsv($handle, $row, ';');
}
rewind($handle);
$response->setContent(stream_get_contents($handle));
fclose($handle);
return $response;
}
2025-06-03 13:04:09 +02:00
#[Route('/admin/export_csv/{zip_code}', name: 'app_admin_export_csv')]
public function export_csv(string $zip_code): Response
{
$stats = $this->entityManager->getRepository(Stats::class)->findOneBy(['zone' => $zip_code]);
$response = new Response($this->motocultrice->export($zip_code));
$response->headers->set('Content-Type', 'text/csv');
$slug_name = str_replace(' ', '-', $stats->getName());
2025-06-03 16:19:07 +02:00
2025-06-03 13:04:09 +02:00
$response->headers->set('Content-Disposition', 'attachment; filename="osm-commerces-export_' . $zip_code . '_' . $slug_name . '_' . date('Y-m-d_H-i-s') . '.csv"');
return $response;
}
2025-05-26 11:55:44 +02:00
}