compute stats for completion by zone, have base tags, split categories
This commit is contained in:
parent
f15fec6d18
commit
f69b7824af
16 changed files with 1257 additions and 118 deletions
|
@ -6,7 +6,7 @@ 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;
|
||||
|
@ -29,6 +29,48 @@ final class AdminController extends AbstractController
|
|||
]);
|
||||
}
|
||||
|
||||
#[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();
|
||||
|
||||
return $this->render('admin/stats.html.twig', [
|
||||
'stats' => $stats,
|
||||
'zip_code' => $zip_code,
|
||||
'counters' => $calculatedStats['counters']
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/admin/labourer/{zip_code}', name: 'app_admin_labourer')]
|
||||
public function labourer_zone(string $zip_code): Response
|
||||
{
|
||||
|
@ -39,10 +81,71 @@ final class AdminController extends AbstractController
|
|||
|
||||
// Récupérer les commerces existants dans la base de données pour cette zone
|
||||
$commerces = $this->entityManager->getRepository(Place::class)->findBy(['zip_code' => $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);
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if ($commerces) {
|
||||
// Extraire les osm_object_ids des commerces existants
|
||||
$osm_object_ids = array_map(function($commerce) {
|
||||
return $commerce->getOsmId();
|
||||
|
@ -53,7 +156,7 @@ final class AdminController extends AbstractController
|
|||
$results = array_filter($results, function($commerce) use ($osm_object_ids) {
|
||||
return !in_array($commerce['id'], $osm_object_ids);
|
||||
});
|
||||
|
||||
|
||||
// on crée un commerce pour chaque résultat qui reste
|
||||
foreach ($results as $result) {
|
||||
$commerce = new Place();
|
||||
|
@ -65,11 +168,18 @@ final class AdminController extends AbstractController
|
|||
->setUuidForUrl($this->motocultrice->uuid_create())
|
||||
->setOptedOut(false)
|
||||
->setDead(false)
|
||||
->setNote($result['note'] ?? null)
|
||||
|
||||
->setModifiedDate(new \DateTime())
|
||||
->setAskedHumainsSupport(false)
|
||||
->setLastContactAttemptDate(null)
|
||||
->setStats(null);
|
||||
->setStats(null)
|
||||
->setNote($result['tags'] && isset($result['tags']['note']) ? isset($result['tags']['note']) : null)
|
||||
->setHasOpeningHours($result['tags'] && isset($result['tags']['opening_hours']) ? isset($result['tags']['opening_hours']) : null)
|
||||
->setHasAddress(($result['tags'] && isset($result['tags']['address']) || $result['tags'] && isset($result['tags']['contact:address'])) ? isset($result['tags']['address']) : null)
|
||||
->setHasWebsite($result['tags'] && isset($result['tags']['website']) ? $result['tags']['website'] : null)
|
||||
->setHasWheelchair($result['tags'] && isset($result['tags']['wheelchair']) ? $result['tags']['wheelchair'] : null)
|
||||
->setHasNote($result['tags'] && isset($result['tags']['note']) ? $result['tags']['note'] : null)
|
||||
;
|
||||
$this->entityManager->persist($commerce);
|
||||
}
|
||||
|
||||
|
@ -77,7 +187,99 @@ final class AdminController extends AbstractController
|
|||
|
||||
return $this->render('admin/labourage_results.html.twig', [
|
||||
'results' => $results,
|
||||
'commerces' => $commerces,
|
||||
'zone' => $zip_code,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/admin/delete/{id}', name: 'app_admin_delete')]
|
||||
public function delete(int $id): Response
|
||||
{
|
||||
$commerce = $this->entityManager->getRepository(Place::class)->find($id);
|
||||
$name = $commerce->getName();
|
||||
$this->entityManager->remove($commerce);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->addFlash('success', 'Le lieu '.$name.' a été supprimé avec succès de OSM Mes commerces, mais pas dans OpenStreetMap.');
|
||||
|
||||
return $this->redirectToRoute('app_admin_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]);
|
||||
|
||||
foreach ($commerces as $commerce) {
|
||||
$this->entityManager->remove($commerce);
|
||||
}
|
||||
$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.');
|
||||
|
||||
return $this->redirectToRoute('app_admin_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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,12 +40,31 @@ class PublicController extends AbstractController
|
|||
{
|
||||
$place = $this->entityManager->getRepository(Place::class)->findOneBy(['uuid_for_url' => $uuid]);
|
||||
if (!$place) {
|
||||
$this->addFlash('warning', 'Ce lien de modification n\'existe pas.');
|
||||
return $this->redirectToRoute('app_public_index');
|
||||
}
|
||||
$commerce = $this->motocultrice->get_osm_object_data($place->getOsmKind(), $place->getOsmId());
|
||||
|
||||
if ($place->getOsmKind() === 'relation') {
|
||||
$this->addFlash('warning', 'Les objets OSM de type "relation" ne sont pas gérés dans cet outil.');
|
||||
return $this->redirectToRoute('app_public_index');
|
||||
}
|
||||
|
||||
// récupérer les tags de base
|
||||
$base_tags = $this->motocultrice->base_tags;
|
||||
$base_tags = array_fill_keys($base_tags, '');
|
||||
|
||||
$commerce_overpass = $this->motocultrice->get_osm_object_data($place->getOsmKind(), $place->getOsmId());
|
||||
// Fusionner les tags de base avec les tags existants
|
||||
|
||||
$commerce_overpass['tags_converted'] = array_merge($base_tags, $commerce_overpass['tags_converted']);
|
||||
|
||||
// Trier les tags par ordre alphabétique des clés
|
||||
ksort($commerce_overpass['tags_converted']);
|
||||
|
||||
return $this->render('public/edit.html.twig', [
|
||||
'commerce' => $commerce,
|
||||
'commerce_overpass' => $commerce_overpass,
|
||||
'name' => $name,
|
||||
'commerce' => $place,
|
||||
'osm_kind' => $place->getOsmKind(),
|
||||
"mapbox_token" => $_ENV['MAPBOX_TOKEN'],
|
||||
"maptiler_token" => $_ENV['MAPTILER_TOKEN'],
|
||||
|
@ -57,7 +76,8 @@ class PublicController extends AbstractController
|
|||
{
|
||||
// get stats
|
||||
$stats = $this->entityManager->getRepository(Stats::class)->findAll();
|
||||
$places = $this->entityManager->getRepository(Place::class)->findAll();
|
||||
|
||||
$places = $this->entityManager->getRepository(Place::class)->findBy([], ['zip_code' => 'ASC', 'name' => 'ASC']);
|
||||
return $this->render('public/dashboard.html.twig', [
|
||||
'controller_name' => 'PublicController',
|
||||
'stats' => $stats,
|
||||
|
@ -108,6 +128,9 @@ class PublicController extends AbstractController
|
|||
// Récupérer le token OSM depuis les variables d'environnement
|
||||
$osm_api_token = $_ENV['APP_OSM_BEARER'];
|
||||
|
||||
|
||||
$exception = false;
|
||||
$exception_message = "";
|
||||
try {
|
||||
$client = new Client();
|
||||
|
||||
|
@ -186,6 +209,8 @@ class PublicController extends AbstractController
|
|||
}
|
||||
} catch (\Exception $e) {
|
||||
$status = "Erreur lors de la communication avec l'API OSM: " . $e->getMessage();
|
||||
$exception = true;
|
||||
$exception_message = $e->getMessage();
|
||||
// Debug de la réponse en cas d'erreur
|
||||
if (method_exists($e, 'getResponse')) {
|
||||
var_dump($e->getResponse()->getBody()->getContents());
|
||||
|
@ -199,6 +224,8 @@ class PublicController extends AbstractController
|
|||
'controller_name' => 'PublicController',
|
||||
'commerce' => $commerce,
|
||||
'status' => $status,
|
||||
'exception' => $exception,
|
||||
'exception_message' => $exception_message,
|
||||
'mapbox_token' => $_ENV['MAPBOX_TOKEN'],
|
||||
'maptiler_token' => $_ENV['MAPTILER_TOKEN'],
|
||||
]);
|
||||
|
|
|
@ -21,7 +21,7 @@ class HistoryFixtures extends Fixture
|
|||
// Créer quelques places de test
|
||||
for ($i = 0; $i < 15; $i++) {
|
||||
$place = new Place();
|
||||
$place->setName($faker->company)
|
||||
$place->setName($faker->company . ' (mock)')
|
||||
->setUuidForUrl($faker->uuid)
|
||||
->setOsmId((string)$faker->numberBetween(1000000, 9999999))
|
||||
->setOsmKind($faker->randomElement(['node', 'way', 'relation']))
|
||||
|
@ -48,7 +48,7 @@ class HistoryFixtures extends Fixture
|
|||
// Créer des statistiques de test
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$stat = new Stats();
|
||||
$stat->setZone($faker->city)
|
||||
$stat->setZone($faker->city . ' (mock)')
|
||||
->setCompletionPercent($faker->numberBetween(0, 100))
|
||||
->addPlace( $faker->randomElement($places_list))
|
||||
->addPlace( $faker->randomElement($places_list))
|
||||
|
|
|
@ -61,6 +61,21 @@ class Place
|
|||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $name = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?bool $has_opening_hours = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?bool $has_address = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?bool $has_website = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?bool $has_wheelchair = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?bool $has_note = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->histories = new ArrayCollection();
|
||||
|
@ -256,4 +271,77 @@ class Place
|
|||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasOpeningHours(): ?bool
|
||||
{
|
||||
return $this->has_opening_hours;
|
||||
}
|
||||
|
||||
public function setHasOpeningHours(?bool $has_opening_hours): static
|
||||
{
|
||||
$this->has_opening_hours = $has_opening_hours;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasAddress(): ?bool
|
||||
{
|
||||
return $this->has_address;
|
||||
}
|
||||
|
||||
public function setHasAddress(?bool $has_address): static
|
||||
{
|
||||
$this->has_address = $has_address;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasWebsite(): ?bool
|
||||
{
|
||||
return $this->has_website;
|
||||
}
|
||||
|
||||
public function setHasWebsite(?bool $has_website): static
|
||||
{
|
||||
$this->has_website = $has_website;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasWheelchair(): ?bool
|
||||
{
|
||||
return $this->has_wheelchair;
|
||||
}
|
||||
|
||||
public function setHasWheelchair(?bool $has_wheelchair): static
|
||||
{
|
||||
$this->has_wheelchair = $has_wheelchair;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasNote(): ?bool
|
||||
{
|
||||
return $this->has_note;
|
||||
}
|
||||
|
||||
public function setHasNote(?bool $has_note): static
|
||||
{
|
||||
$this->has_note = $has_note;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getPlaceCount(): ?int
|
||||
{
|
||||
return $this->place_count;
|
||||
}
|
||||
|
||||
public function setPlaceCount(int $place_count): static
|
||||
{
|
||||
$this->place_count = $place_count;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,9 +28,54 @@ class Stats
|
|||
#[ORM\OneToMany(targetEntity: Place::class, mappedBy: 'stats')]
|
||||
private Collection $places;
|
||||
|
||||
#[ORM\Column(type: Types::SMALLINT)]
|
||||
// nombre de commerces dans la zone
|
||||
#[ORM\Column(type: Types::SMALLINT, nullable: true)]
|
||||
private ?int $places_count = null;
|
||||
|
||||
// nombre de commerces avec horaires
|
||||
#[ORM\Column(type: Types::SMALLINT, nullable: true)]
|
||||
private ?int $avec_horaires = null;
|
||||
|
||||
// nombre de commerces avec adresse
|
||||
#[ORM\Column(type: Types::SMALLINT, nullable: true)]
|
||||
private ?int $avec_adresse = null;
|
||||
|
||||
// nombre de commerces avec site
|
||||
#[ORM\Column(type: Types::SMALLINT, nullable: true)]
|
||||
private ?int $avec_site = null;
|
||||
|
||||
// nombre de commerces avec accessibilité
|
||||
#[ORM\Column(type: Types::SMALLINT, nullable: true)]
|
||||
private ?int $avec_accessibilite = null;
|
||||
|
||||
// nombre de commerces avec note
|
||||
#[ORM\Column(type: Types::SMALLINT, nullable: true)]
|
||||
private ?int $avec_note = null;
|
||||
|
||||
// calcule le pourcentage de complétion de la zone
|
||||
public function computeCompletionPercent(): ?int
|
||||
{
|
||||
// Si aucun commerce, on retourne 0
|
||||
if ($this->places_count === 0 || $this->places_count === null) {
|
||||
$this->setCompletionPercent(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// On prend le maximum entre les différents critères
|
||||
$max = max(
|
||||
$this->avec_horaires ?? 0,
|
||||
$this->avec_adresse ?? 0,
|
||||
$this->avec_site ?? 0,
|
||||
$this->avec_accessibilite ?? 0,
|
||||
$this->avec_note ?? 0
|
||||
);
|
||||
$computed = round(($max) / $this->places_count * 100);
|
||||
$this->setCompletionPercent($computed);
|
||||
return $this->completion_percent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->places = new ArrayCollection();
|
||||
|
@ -106,4 +151,66 @@ class Stats
|
|||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
public function getAvecHoraires(): ?int
|
||||
{
|
||||
return $this->avec_horaires;
|
||||
}
|
||||
|
||||
public function setAvecHoraires(int $avec_horaires): static
|
||||
{
|
||||
$this->avec_horaires = $avec_horaires;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAvecAdresse(): ?int
|
||||
{
|
||||
return $this->avec_adresse;
|
||||
}
|
||||
|
||||
public function setAvecAdresse(int $avec_adresse): static
|
||||
{
|
||||
$this->avec_adresse = $avec_adresse;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAvecSite(): ?int
|
||||
{
|
||||
return $this->avec_site;
|
||||
}
|
||||
|
||||
public function setAvecSite(int $avec_site): static
|
||||
{
|
||||
$this->avec_site = $avec_site;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAvecAccessibilite(): ?int
|
||||
{
|
||||
return $this->avec_accessibilite;
|
||||
}
|
||||
|
||||
public function setAvecAccessibilite(int $avec_accessibilite): static
|
||||
{
|
||||
$this->avec_accessibilite = $avec_accessibilite;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAvecNote(): ?int
|
||||
{
|
||||
return $this->avec_note;
|
||||
}
|
||||
|
||||
public function setAvecNote(int $avec_note): static
|
||||
{
|
||||
$this->avec_note = $avec_note;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -10,12 +10,26 @@ class Motocultrice
|
|||
private $overpassApiUrl = 'https://overpass-api.de/api/interpreter';
|
||||
private $osmApiUrl = 'https://www.openstreetmap.org/api/0.6';
|
||||
|
||||
public $base_tags = [
|
||||
'name',
|
||||
'opening_hours',
|
||||
'contact:email',
|
||||
'contact:phone',
|
||||
'wheelchair',
|
||||
'addr:housenumber',
|
||||
'addr:street',
|
||||
'contact:website',
|
||||
'contact:mastodon',
|
||||
// 'EEEEEEEEEEEEEEEEEEE'
|
||||
];
|
||||
private $more_tags = ['image', 'ref:FR:SIRET'];
|
||||
public function __construct(
|
||||
private HttpClientInterface $client,
|
||||
private EntityManagerInterface $entityManager
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
public function labourer(string $zone): array
|
||||
{
|
||||
if (!$zone) {
|
||||
|
@ -58,6 +72,9 @@ QUERY;
|
|||
if (isset($data['elements'])) {
|
||||
foreach ($data['elements'] as $element) {
|
||||
if (isset($element['tags'])) {
|
||||
|
||||
|
||||
|
||||
$email = $element['tags']['contact:email'] ?? $element['tags']['email'] ?? null;
|
||||
// On passe si pas d'email
|
||||
if (!$email) {
|
||||
|
@ -86,6 +103,8 @@ QUERY;
|
|||
public function get_osm_object_data($osm_kind = 'node', $osm_object_id = 12855459190)
|
||||
{
|
||||
$object_id = "https://www.openstreetmap.org/api/0.6/".$osm_kind."/".$osm_object_id;
|
||||
// dump($object_id);
|
||||
// die();
|
||||
|
||||
try {
|
||||
$response = $this->client->request('GET', $object_id);
|
||||
|
@ -96,8 +115,8 @@ QUERY;
|
|||
throw new \Exception("Impossible de récupérer les données OSM : " . $e->getMessage());
|
||||
}
|
||||
|
||||
// convertir les tags en clés et valeurs
|
||||
$osm_object_data['tags_converted'] = [];
|
||||
// convertir les tags en clés et valeurs, remplir avec les tags de base
|
||||
$osm_object_data['tags_converted'] = $this->base_tags;
|
||||
// Initialiser le tableau des tags convertis
|
||||
if (isset($osm_object_data['node'])) {
|
||||
$osm_object_data['node']['tags_converted'] = [];
|
||||
|
@ -236,4 +255,48 @@ QUERY;
|
|||
throw new \Exception("Erreur lors de la communication avec l'API OSM : " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function calculateStats(array $places): array
|
||||
{
|
||||
$counters = [
|
||||
'avec_horaires' => 0,
|
||||
'avec_adresse' => 0,
|
||||
'avec_site' => 0,
|
||||
'avec_accessibilite' => 0,
|
||||
'avec_note' => 0
|
||||
];
|
||||
|
||||
foreach ($places as $place) {
|
||||
if ($place->hasOpeningHours()) {
|
||||
$counters['avec_horaires']++;
|
||||
}
|
||||
if ($place->hasAddress()) {
|
||||
$counters['avec_adresse']++;
|
||||
}
|
||||
if ($place->hasWebsite()) {
|
||||
$counters['avec_site']++;
|
||||
}
|
||||
if ($place->hasWheelchair()) {
|
||||
$counters['avec_accessibilite']++;
|
||||
}
|
||||
if ($place->hasNote()) {
|
||||
$counters['avec_note']++;
|
||||
}
|
||||
}
|
||||
|
||||
$totalPlaces = count($places);
|
||||
$completionPercent = 0;
|
||||
|
||||
if ($totalPlaces > 0) {
|
||||
$totalCriteria = 5; // nombre total de critères
|
||||
$totalCompleted = array_sum($counters);
|
||||
$completionPercent = round(($totalCompleted / ($totalPlaces * $totalCriteria)) * 100);
|
||||
}
|
||||
|
||||
return [
|
||||
'places_count' => $totalPlaces,
|
||||
'completion_percent' => $completionPercent,
|
||||
'counters' => $counters
|
||||
];
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue