Files
geo/api/src/Controllers/EntiteController.php

633 lines
22 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Controllers;
require_once __DIR__ . '/../Services/LogService.php';
require_once __DIR__ . '/../Services/ApiService.php';
use PDO;
use PDOException;
use Database;
use AppConfig;
use Request;
use Response;
use Session;
use LogService;
use ApiService;
use Exception;
class EntiteController {
private PDO $db;
private AppConfig $appConfig;
public function __construct() {
$this->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);
}
}
}