db = Database::getInstance(); $this->appConfig = AppConfig::getInstance(); } /** * Crée une nouvelle entité (amicale) si elle n'existe pas déjà avec le code postal spécifié * * @param string $name Nom de l'amicale * @param string $postalCode Code postal * @param string $cityName Nom de la ville * @return array|false Tableau contenant l'ID de l'entité créée ou false en cas d'erreur * @throws Exception Si une entité existe déjà avec ce code postal */ public function createEntite(string $name, string $postalCode, string $cityName): array|false { try { // Vérification que le code postal n'existe pas déjà $stmt = $this->db->prepare('SELECT id FROM entites WHERE code_postal = ?'); $stmt->execute([$postalCode]); if ($stmt->fetch()) { throw new Exception('Une amicale existe déjà sur ce code postal'); } // Chiffrement du nom $encryptedName = ApiService::encryptData($name); // Insertion de la nouvelle entité $stmt = $this->db->prepare(' INSERT INTO entites ( encrypted_name, code_postal, ville, fk_type, created_at, chk_active ) VALUES (?, ?, ?, 1, NOW(), 1) '); $stmt->execute([ $encryptedName, $postalCode, $cityName ]); $entiteId = $this->db->lastInsertId(); if (!$entiteId) { throw new Exception('Erreur lors de la création de l\'entité'); } LogService::log('Création d\'une nouvelle entité GeoSector', [ 'level' => 'info', 'entiteId' => $entiteId, 'name' => $name, 'postalCode' => $postalCode, 'cityName' => $cityName ]); return [ 'id' => $entiteId, 'name' => $name, 'postalCode' => $postalCode, 'cityName' => $cityName ]; } catch (Exception $e) { LogService::log('Erreur lors de la création de l\'entité GeoSector', [ 'level' => 'error', 'error' => $e->getMessage(), 'name' => $name, 'postalCode' => $postalCode, 'cityName' => $cityName ]); throw $e; } } /** * Récupère une entité par son ID * * @param int $id ID de l'entité * @return array|false Données de l'entité ou false si non trouvée */ public function getEntiteById(int $id): array|false { try { $stmt = $this->db->prepare(' SELECT id, encrypted_name, code_postal, ville, fk_type, chk_active FROM entites WHERE id = ? AND chk_active = 1 '); $stmt->execute([$id]); $entite = $stmt->fetch(PDO::FETCH_ASSOC); if (!$entite) { return false; } // Déchiffrement du nom $entite['name'] = ApiService::decryptData($entite['encrypted_name']); unset($entite['encrypted_name']); return $entite; } catch (Exception $e) { LogService::log('Erreur lors de la récupération de l\'entité GeoSector', [ 'level' => 'error', 'error' => $e->getMessage(), 'id' => $id ]); return false; } } /** * Récupère une entité par son code postal * * @param string $postalCode Code postal * @return array|false Données de l'entité ou false si non trouvée */ public function getEntiteByPostalCode(string $postalCode): array|false { try { $stmt = $this->db->prepare(' SELECT id, encrypted_name, code_postal, ville, fk_type, chk_active FROM entites WHERE code_postal = ? AND chk_active = 1 '); $stmt->execute([$postalCode]); $entite = $stmt->fetch(PDO::FETCH_ASSOC); if (!$entite) { return false; } // Déchiffrement du nom $entite['name'] = ApiService::decryptData($entite['encrypted_name']); unset($entite['encrypted_name']); return $entite; } catch (Exception $e) { LogService::log('Erreur lors de la récupération de l\'entité GeoSector par code postal', [ 'level' => 'error', 'error' => $e->getMessage(), 'postalCode' => $postalCode ]); return false; } } /** * Vérifie si une entité existe avec le code postal spécifié, et en crée une nouvelle si nécessaire * * @param string $name Nom de l'amicale * @param string $postalCode Code postal * @return int ID de l'entité créée ou existante * @throws Exception Si une entité existe déjà avec ce code postal */ public function getOrCreateEntiteByPostalCode(string $name, string $postalCode): int { try { // Vérification que le code postal n'existe pas déjà $stmt = $this->db->prepare('SELECT COUNT(*) as count FROM entites WHERE code_postal = ?'); $stmt->execute([$postalCode]); $result = $stmt->fetch(PDO::FETCH_ASSOC); if ($result && $result['count'] > 0) { throw new Exception('Une amicale est déjà inscrite à ce code postal'); } // Chiffrement du nom $encryptedName = ApiService::encryptData($name); // Insertion de la nouvelle entité $stmt = $this->db->prepare(' INSERT INTO entites ( encrypted_name, code_postal, ville, fk_type, created_at, chk_active ) VALUES (?, ?, "", 1, NOW(), 1) '); $stmt->execute([ $encryptedName, $postalCode ]); $entiteId = (int)$this->db->lastInsertId(); if (!$entiteId) { throw new Exception('Erreur lors de la création de l\'entité'); } LogService::log('Création d\'une nouvelle entité GeoSector via getOrCreateEntiteByPostalCode', [ 'level' => 'info', 'entiteId' => $entiteId, 'name' => $name, 'postalCode' => $postalCode ]); return $entiteId; } catch (Exception $e) { LogService::log('Erreur lors de la vérification/création de l\'entité GeoSector', [ 'level' => 'error', 'error' => $e->getMessage(), 'name' => $name, 'postalCode' => $postalCode ]); throw $e; } } /** * Récupère toutes les entités actives * * @return array Liste des entités */ public function getEntites(): void { try { $stmt = $this->db->prepare(' SELECT id, encrypted_name, code_postal, ville, fk_type, chk_active FROM entites WHERE chk_active = 1 ORDER BY code_postal ASC '); $stmt->execute(); $entites = $stmt->fetchAll(PDO::FETCH_ASSOC); $result = []; foreach ($entites as $entite) { // Déchiffrement du nom pour chaque entité $entite['name'] = ApiService::decryptData($entite['encrypted_name']); unset($entite['encrypted_name']); $result[] = $entite; } Response::json([ 'status' => 'success', 'entites' => $result ], 200); } catch (Exception $e) { LogService::log('Erreur lors de la récupération des entités GeoSector', [ 'level' => 'error', 'error' => $e->getMessage() ]); Response::json([ 'status' => 'error', 'message' => 'Erreur lors de la récupération des entités' ], 500); } } /** * Recherche les coordonnées GPS d'une caserne de pompiers à partir d'une adresse * * @param string $address Adresse complète (adresse + code postal + ville) * @param string $postalCode Code postal * @param string $city Ville * @return array|null Tableau contenant les coordonnées GPS [lat, lng] ou null si non trouvé */ private function findFireStationCoordinates(string $address, string $postalCode, string $city): ?array { try { // Construire l'adresse complète $fullAddress = urlencode($address . ' ' . $postalCode . ' ' . $city); // Mots-clés pour rechercher une caserne de pompiers $keywords = ['pompiers', 'sapeurs-pompiers', 'sdis', 'caserne', 'centre de secours']; foreach ($keywords as $keyword) { // Construire l'URL de recherche $searchUrl = "https://api-adresse.data.gouv.fr/search/?q=" . urlencode($keyword) . "&postcode=$postalCode&limit=1"; // Effectuer la requête $response = file_get_contents($searchUrl); if ($response) { $data = json_decode($response, true); // Vérifier si des résultats ont été trouvés if (isset($data['features']) && count($data['features']) > 0) { $feature = $data['features'][0]; // Vérifier si les coordonnées sont disponibles if (isset($feature['geometry']['coordinates'])) { $coordinates = $feature['geometry']['coordinates']; // Les coordonnées sont au format [longitude, latitude] return [ 'lat' => $coordinates[1], 'lng' => $coordinates[0] ]; } } } } // Si aucune caserne n'a été trouvée, essayer avec l'adresse de la mairie $searchUrl = "https://api-adresse.data.gouv.fr/search/?q=mairie&postcode=$postalCode&limit=1"; $response = file_get_contents($searchUrl); if ($response) { $data = json_decode($response, true); if (isset($data['features']) && count($data['features']) > 0) { $feature = $data['features'][0]; if (isset($feature['geometry']['coordinates'])) { $coordinates = $feature['geometry']['coordinates']; return [ 'lat' => $coordinates[1], 'lng' => $coordinates[0] ]; } } } // Si toujours rien, essayer avec l'adresse complète $searchUrl = "https://api-adresse.data.gouv.fr/search/?q=$fullAddress&limit=1"; $response = file_get_contents($searchUrl); if ($response) { $data = json_decode($response, true); if (isset($data['features']) && count($data['features']) > 0) { $feature = $data['features'][0]; if (isset($feature['geometry']['coordinates'])) { $coordinates = $feature['geometry']['coordinates']; return [ 'lat' => $coordinates[1], 'lng' => $coordinates[0] ]; } } } // Aucune coordonnée trouvée return null; } catch (Exception $e) { LogService::log('Erreur lors de la recherche des coordonnées GPS', [ 'level' => 'error', 'error' => $e->getMessage(), 'address' => $address, 'postalCode' => $postalCode, 'city' => $city ]); return null; } } /** * Met à jour une entité existante avec les données fournies * Seuls les administrateurs (rôle > 2) peuvent modifier certains champs * * @return void */ public function updateEntite(): void { try { // Vérifier l'authentification et les droits d'accès $userId = Session::getUserId(); if (!$userId) { Response::json([ 'status' => 'error', 'message' => 'Vous devez être connecté pour effectuer cette action' ], 401); return; } // Récupérer le rôle de l'utilisateur $stmt = $this->db->prepare('SELECT fk_role FROM users WHERE id = ?'); $stmt->execute([$userId]); $user = $stmt->fetch(PDO::FETCH_ASSOC); if (!$user) { Response::json([ 'status' => 'error', 'message' => 'Utilisateur non trouvé' ], 404); return; } $userRole = (int)$user['fk_role']; $isAdmin = $userRole > 2; // Récupérer les données de la requête $data = Request::getJson(); if (!isset($data['id']) || empty($data['id'])) { Response::json([ 'status' => 'error', 'message' => 'ID de l\'entité requis' ], 400); return; } $entiteId = (int)$data['id']; // Récupérer les données actuelles de l'entité pour vérifier si l'adresse a changé $stmt = $this->db->prepare('SELECT adresse1, adresse2, code_postal, ville FROM entites WHERE id = ?'); $stmt->execute([$entiteId]); $currentEntite = $stmt->fetch(PDO::FETCH_ASSOC); if (!$currentEntite) { Response::json([ 'status' => 'error', 'message' => 'Entité non trouvée' ], 404); return; } // Vérifier si l'adresse a changé $addressChanged = false; $newAdresse1 = $data['adresse1'] ?? $currentEntite['adresse1']; $newAdresse2 = $data['adresse2'] ?? $currentEntite['adresse2']; $newCodePostal = $data['code_postal'] ?? $currentEntite['code_postal']; $newVille = $data['ville'] ?? $currentEntite['ville']; // Vérifier si l'adresse a changé if ( $newAdresse1 !== $currentEntite['adresse1'] || $newAdresse2 !== $currentEntite['adresse2'] || $newCodePostal !== $currentEntite['code_postal'] || $newVille !== $currentEntite['ville'] ) { $addressChanged = true; } // Si l'adresse a changé, recalculer les coordonnées GPS if ($addressChanged) { // Construire l'adresse complète $fullAddress = $newAdresse1; if (!empty($newAdresse2)) { $fullAddress .= ' ' . $newAdresse2; } // Rechercher les coordonnées GPS de la caserne de pompiers $coordinates = $this->findFireStationCoordinates($fullAddress, $newCodePostal, $newVille); // Si des coordonnées ont été trouvées, les ajouter aux champs à mettre à jour if ($coordinates) { $data['gps_lat'] = $coordinates['lat']; $data['gps_lng'] = $coordinates['lng']; LogService::log('Coordonnées GPS mises à jour suite à un changement d\'adresse', [ 'level' => 'info', 'entiteId' => $entiteId, 'lat' => $coordinates['lat'], 'lng' => $coordinates['lng'] ]); } } // Préparer les champs à mettre à jour $updateFields = []; $params = []; // Champs modifiables par tous les utilisateurs if (isset($data['name']) && !empty($data['name'])) { $updateFields[] = 'encrypted_name = ?'; $params[] = ApiService::encryptData($data['name']); } if (isset($data['adresse1'])) { $updateFields[] = 'adresse1 = ?'; $params[] = $data['adresse1']; } if (isset($data['adresse2'])) { $updateFields[] = 'adresse2 = ?'; $params[] = $data['adresse2']; } if (isset($data['code_postal']) && !empty($data['code_postal'])) { $updateFields[] = 'code_postal = ?'; $params[] = $data['code_postal']; } if (isset($data['ville'])) { $updateFields[] = 'ville = ?'; $params[] = $data['ville']; } if (isset($data['fk_region'])) { $updateFields[] = 'fk_region = ?'; $params[] = $data['fk_region']; } if (isset($data['phone'])) { $updateFields[] = 'encrypted_phone = ?'; $params[] = ApiService::encryptData($data['phone']); } if (isset($data['mobile'])) { $updateFields[] = 'encrypted_mobile = ?'; $params[] = ApiService::encryptData($data['mobile']); } if (isset($data['email']) && !empty($data['email'])) { $updateFields[] = 'encrypted_email = ?'; $params[] = ApiService::encryptSearchableData($data['email']); } if (isset($data['chk_copie_mail_recu'])) { $updateFields[] = 'chk_copie_mail_recu = ?'; $params[] = $data['chk_copie_mail_recu'] ? 1 : 0; } if (isset($data['chk_accept_sms'])) { $updateFields[] = 'chk_accept_sms = ?'; $params[] = $data['chk_accept_sms'] ? 1 : 0; } // Champs modifiables uniquement par les administrateurs if ($isAdmin) { if (isset($data['gps_lat'])) { $updateFields[] = 'gps_lat = ?'; $params[] = $data['gps_lat']; } if (isset($data['gps_lng'])) { $updateFields[] = 'gps_lng = ?'; $params[] = $data['gps_lng']; } if (isset($data['stripe_id'])) { $updateFields[] = 'encrypted_stripe_id = ?'; $params[] = ApiService::encryptData($data['stripe_id']); } if (isset($data['chk_demo'])) { $updateFields[] = 'chk_demo = ?'; $params[] = $data['chk_demo'] ? 1 : 0; } if (isset($data['chk_active'])) { $updateFields[] = 'chk_active = ?'; $params[] = $data['chk_active'] ? 1 : 0; } if (isset($data['chk_stripe'])) { $updateFields[] = 'chk_stripe = ?'; $params[] = $data['chk_stripe'] ? 1 : 0; } } // Si aucun champ à mettre à jour, retourner une erreur if (empty($updateFields)) { Response::json([ 'status' => 'error', 'message' => 'Aucune donnée à mettre à jour' ], 400); return; } // Ajouter la date de mise à jour $updateFields[] = 'updated_at = NOW()'; // Construire la requête SQL $sql = 'UPDATE entites SET ' . implode(', ', $updateFields) . ' WHERE id = ?'; $params[] = $entiteId; // Exécuter la requête $stmt = $this->db->prepare($sql); $stmt->execute($params); // Vérifier si la mise à jour a réussi if ($stmt->rowCount() === 0) { Response::json([ 'status' => 'warning', 'message' => 'Aucune modification effectuée' ], 200); return; } LogService::log('Mise à jour d\'une entité GeoSector', [ 'level' => 'info', 'userId' => $userId, 'entiteId' => $entiteId, 'isAdmin' => $isAdmin ]); Response::json([ 'status' => 'success', 'message' => 'Entité mise à jour avec succès' ], 200); } catch (Exception $e) { LogService::log('Erreur lors de la mise à jour de l\'entité GeoSector', [ 'level' => 'error', 'error' => $e->getMessage() ]); Response::json([ 'status' => 'error', 'message' => 'Erreur lors de la mise à jour de l\'entité' ], 500); } } }