feat: Version 3.3.4 - Nouvelle architecture pages, optimisations widgets Flutter et API
- Mise à jour VERSION vers 3.3.4 - Optimisations et révisions architecture API (deploy-api.sh, scripts de migration) - Ajout documentation Stripe Tap to Pay complète - Migration vers polices Inter Variable pour Flutter - Optimisations build Android et nettoyage fichiers temporaires - Amélioration système de déploiement avec gestion backups - Ajout scripts CRON et migrations base de données 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -544,24 +544,85 @@ class SectorController
|
||||
$stmt->execute($params);
|
||||
}
|
||||
|
||||
// Gestion des membres
|
||||
if (isset($data['membres'])) {
|
||||
// Gestion des membres (reçus comme 'users' depuis Flutter)
|
||||
if (isset($data['users'])) {
|
||||
$this->logService->info('[UPDATE USERS] Début modification des membres', [
|
||||
'sector_id' => $id,
|
||||
'users_demandes' => $data['users'],
|
||||
'nb_users' => count($data['users'])
|
||||
]);
|
||||
|
||||
// Récupérer l'opération du secteur pour l'INSERT
|
||||
$opQuery = "SELECT fk_operation FROM ope_sectors WHERE id = :sector_id";
|
||||
$this->logService->info('[UPDATE USERS] SQL - Récupération fk_operation', [
|
||||
'query' => $opQuery,
|
||||
'params' => ['sector_id' => $id]
|
||||
]);
|
||||
$opStmt = $this->db->prepare($opQuery);
|
||||
$opStmt->execute(['sector_id' => $id]);
|
||||
$operationId = $opStmt->fetch()['fk_operation'];
|
||||
$this->logService->info('[UPDATE USERS] fk_operation récupéré', [
|
||||
'operation_id' => $operationId
|
||||
]);
|
||||
|
||||
// Supprimer les affectations existantes
|
||||
$deleteQuery = "DELETE FROM ope_users_sectors WHERE fk_sector = :sector_id";
|
||||
$this->logService->info('[UPDATE USERS] SQL - Suppression des anciens membres', [
|
||||
'query' => $deleteQuery,
|
||||
'params' => ['sector_id' => $id]
|
||||
]);
|
||||
$deleteStmt = $this->db->prepare($deleteQuery);
|
||||
$deleteStmt->execute(['sector_id' => $id]);
|
||||
|
||||
$deletedCount = $deleteStmt->rowCount();
|
||||
$this->logService->info('[UPDATE USERS] Membres supprimés', [
|
||||
'nb_deleted' => $deletedCount
|
||||
]);
|
||||
|
||||
// Ajouter les nouvelles affectations
|
||||
if (!empty($data['membres'])) {
|
||||
$insertQuery = "INSERT INTO ope_users_sectors (fk_user, fk_sector) VALUES (:user_id, :sector_id)";
|
||||
if (!empty($data['users'])) {
|
||||
$insertQuery = "INSERT INTO ope_users_sectors (fk_operation, fk_user, fk_sector, created_at, fk_user_creat, chk_active)
|
||||
VALUES (:operation_id, :user_id, :sector_id, NOW(), :user_creat, 1)";
|
||||
$this->logService->info('[UPDATE USERS] SQL - Requête INSERT préparée', [
|
||||
'query' => $insertQuery
|
||||
]);
|
||||
$insertStmt = $this->db->prepare($insertQuery);
|
||||
|
||||
foreach ($data['membres'] as $memberId) {
|
||||
$insertStmt->execute([
|
||||
'user_id' => $memberId,
|
||||
'sector_id' => $id
|
||||
]);
|
||||
|
||||
$insertedUsers = [];
|
||||
$failedUsers = [];
|
||||
foreach ($data['users'] as $memberId) {
|
||||
try {
|
||||
$params = [
|
||||
'operation_id' => $operationId,
|
||||
'user_id' => $memberId,
|
||||
'sector_id' => $id,
|
||||
'user_creat' => $_SESSION['user_id'] ?? null
|
||||
];
|
||||
$this->logService->info('[UPDATE USERS] SQL - INSERT user', [
|
||||
'params' => $params
|
||||
]);
|
||||
$insertStmt->execute($params);
|
||||
$insertedUsers[] = $memberId;
|
||||
$this->logService->info('[UPDATE USERS] User inséré avec succès', [
|
||||
'user_id' => $memberId
|
||||
]);
|
||||
} catch (\PDOException $e) {
|
||||
$failedUsers[] = $memberId;
|
||||
$this->logService->warning('[UPDATE USERS] ERREUR insertion user', [
|
||||
'sector_id' => $id,
|
||||
'user_id' => $memberId,
|
||||
'error' => $e->getMessage(),
|
||||
'error_code' => $e->getCode()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->logService->info('[UPDATE USERS] Résultat des insertions', [
|
||||
'users_demandes' => $data['users'],
|
||||
'users_inseres' => $insertedUsers,
|
||||
'users_echoues' => $failedUsers,
|
||||
'nb_succes' => count($insertedUsers),
|
||||
'nb_echecs' => count($failedUsers)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -651,7 +712,8 @@ class SectorController
|
||||
$this->logService->info('[UPDATE] Début mise à jour des passages', ['sector_id' => $id]);
|
||||
$passageCounters = $this->updatePassagesForSector($id, $data['sector']);
|
||||
}
|
||||
|
||||
|
||||
// Commit des modifications (users et/ou secteur)
|
||||
$this->db->commit();
|
||||
|
||||
// Récupérer le secteur mis à jour
|
||||
@@ -711,14 +773,29 @@ class SectorController
|
||||
$passagesDecrypted[] = $passage;
|
||||
}
|
||||
|
||||
// Récupérer les users affectés
|
||||
// Récupérer les users affectés (avec READ UNCOMMITTED pour forcer la lecture des données fraîches)
|
||||
$usersQuery = "SELECT u.id, u.first_name, u.sect_name, u.encrypted_name, ous.fk_sector
|
||||
FROM ope_users_sectors ous
|
||||
JOIN users u ON ous.fk_user = u.id
|
||||
WHERE ous.fk_sector = :sector_id";
|
||||
WHERE ous.fk_sector = :sector_id
|
||||
ORDER BY u.id";
|
||||
|
||||
$this->logService->info('[UPDATE USERS] SQL - Récupération finale des users', [
|
||||
'query' => $usersQuery,
|
||||
'params' => ['sector_id' => $id]
|
||||
]);
|
||||
|
||||
$usersStmt = $this->db->prepare($usersQuery);
|
||||
$usersStmt->execute(['sector_id' => $id]);
|
||||
$usersSectors = $usersStmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
$userIds = array_column($usersSectors, 'id');
|
||||
$this->logService->info('[UPDATE USERS] Users récupérés après commit', [
|
||||
'sector_id' => $id,
|
||||
'users_ids' => $userIds,
|
||||
'nb_users' => count($userIds),
|
||||
'users_demandes_initialement' => $data['users'] ?? []
|
||||
]);
|
||||
|
||||
// Déchiffrer les noms des utilisateurs
|
||||
$usersDecrypted = [];
|
||||
@@ -1066,6 +1143,7 @@ class SectorController
|
||||
|
||||
/**
|
||||
* Mettre à jour les passages affectés à un secteur lors de la modification du périmètre
|
||||
* VERSION OPTIMISÉE avec requêtes groupées
|
||||
* Retourne un tableau avec les compteurs détaillés
|
||||
*/
|
||||
private function updatePassagesForSector($sectorId, $newSectorCoords): array
|
||||
@@ -1080,18 +1158,18 @@ class SectorController
|
||||
|
||||
try {
|
||||
// Récupérer l'opération et l'entité du secteur
|
||||
$sectorQuery = "SELECT o.id as operation_id, o.fk_entite, s.fk_operation
|
||||
$sectorQuery = "SELECT o.id as operation_id, o.fk_entite, s.fk_operation
|
||||
FROM ope_sectors s
|
||||
JOIN operations o ON s.fk_operation = o.id
|
||||
WHERE s.id = :sector_id";
|
||||
$sectorStmt = $this->db->prepare($sectorQuery);
|
||||
$sectorStmt->execute(['sector_id' => $sectorId]);
|
||||
$sectorInfo = $sectorStmt->fetch();
|
||||
|
||||
|
||||
if (!$sectorInfo) {
|
||||
return 0;
|
||||
return $counters;
|
||||
}
|
||||
|
||||
|
||||
$operationId = $sectorInfo['operation_id'];
|
||||
$entityId = $sectorInfo['fk_entite'];
|
||||
|
||||
@@ -1099,7 +1177,7 @@ class SectorController
|
||||
$points = explode('#', rtrim($newSectorCoords, '#'));
|
||||
$coordinates = [];
|
||||
$polygonPoints = [];
|
||||
|
||||
|
||||
foreach ($points as $point) {
|
||||
if (!empty($point)) {
|
||||
list($lat, $lng) = explode('/', $point);
|
||||
@@ -1110,170 +1188,249 @@ class SectorController
|
||||
$polygonPoints[] = $polygonPoints[0]; // Fermer le polygone
|
||||
$polygonString = 'POLYGON((' . implode(',', $polygonPoints) . '))';
|
||||
|
||||
// 1. VÉRIFICATION GÉOGRAPHIQUE DES PASSAGES EXISTANTS
|
||||
$checkPassagesQuery = "SELECT id, gps_lat, gps_lng, fk_type, encrypted_name
|
||||
FROM ope_pass
|
||||
WHERE fk_sector = :sector_id
|
||||
AND gps_lat IS NOT NULL
|
||||
AND gps_lng IS NOT NULL";
|
||||
// 1. VÉRIFICATION GÉOGRAPHIQUE DES PASSAGES EXISTANTS (OPTIMISÉE)
|
||||
// Utiliser une seule requête pour vérifier tous les passages
|
||||
$checkPassagesQuery = "
|
||||
SELECT
|
||||
p.id,
|
||||
p.gps_lat,
|
||||
p.gps_lng,
|
||||
p.fk_type,
|
||||
p.encrypted_name,
|
||||
ST_Contains(ST_GeomFromText(:polygon, 4326),
|
||||
POINT(CAST(p.gps_lng AS DECIMAL(10,8)),
|
||||
CAST(p.gps_lat AS DECIMAL(10,8)))) as is_inside
|
||||
FROM ope_pass p
|
||||
WHERE p.fk_sector = :sector_id
|
||||
AND p.gps_lat IS NOT NULL
|
||||
AND p.gps_lng IS NOT NULL";
|
||||
|
||||
$checkStmt = $this->db->prepare($checkPassagesQuery);
|
||||
$checkStmt->execute(['sector_id' => $sectorId]);
|
||||
$checkStmt->execute([
|
||||
'sector_id' => $sectorId,
|
||||
'polygon' => $polygonString
|
||||
]);
|
||||
$existingPassages = $checkStmt->fetchAll();
|
||||
|
||||
|
||||
$passagesToDelete = [];
|
||||
|
||||
$passagesToOrphan = [];
|
||||
|
||||
foreach ($existingPassages as $passage) {
|
||||
// Vérifier si le passage est dans le nouveau polygone
|
||||
$pointInPolygonQuery = "SELECT ST_Contains(ST_GeomFromText(:polygon, 4326),
|
||||
POINT(CAST(:lng AS DECIMAL(10,8)),
|
||||
CAST(:lat AS DECIMAL(10,8)))) as is_inside";
|
||||
$pointStmt = $this->db->prepare($pointInPolygonQuery);
|
||||
$pointStmt->execute([
|
||||
'polygon' => $polygonString,
|
||||
'lng' => $passage['gps_lng'],
|
||||
'lat' => $passage['gps_lat']
|
||||
]);
|
||||
$result = $pointStmt->fetch();
|
||||
|
||||
if ($result['is_inside'] == 0) {
|
||||
if ($passage['is_inside'] == 0) {
|
||||
// Le passage est hors du nouveau périmètre
|
||||
// Vérifier si c'est un passage non visité (fk_type=2 ET encrypted_name vide)
|
||||
if ($passage['fk_type'] == 2 && ($passage['encrypted_name'] === '' || $passage['encrypted_name'] === null)) {
|
||||
// Passage non visité : à supprimer
|
||||
$passagesToDelete[] = $passage['id'];
|
||||
$counters['passages_deleted'] = ($counters['passages_deleted'] ?? 0) + 1;
|
||||
$counters['passages_deleted']++;
|
||||
} else {
|
||||
// Passage visité : mettre en orphelin
|
||||
$orphanQuery = "UPDATE ope_pass SET fk_sector = NULL WHERE id = :passage_id";
|
||||
$orphanStmt = $this->db->prepare($orphanQuery);
|
||||
$orphanStmt->execute(['passage_id' => $passage['id']]);
|
||||
// Passage visité : à mettre en orphelin
|
||||
$passagesToOrphan[] = $passage['id'];
|
||||
$counters['passages_orphaned']++;
|
||||
}
|
||||
} else {
|
||||
$counters['passages_kept']++;
|
||||
}
|
||||
}
|
||||
|
||||
// Supprimer les passages non visités qui sont hors zone
|
||||
|
||||
// Supprimer les passages non visités en une seule requête
|
||||
if (!empty($passagesToDelete)) {
|
||||
$deleteQuery = "DELETE FROM ope_pass WHERE id IN (" . implode(',', $passagesToDelete) . ")";
|
||||
$this->db->exec($deleteQuery);
|
||||
$placeholders = str_repeat('?,', count($passagesToDelete) - 1) . '?';
|
||||
$deleteQuery = "DELETE FROM ope_pass WHERE id IN ($placeholders)";
|
||||
$deleteStmt = $this->db->prepare($deleteQuery);
|
||||
$deleteStmt->execute($passagesToDelete);
|
||||
}
|
||||
|
||||
// Mettre en orphelin les passages visités en une seule requête
|
||||
if (!empty($passagesToOrphan)) {
|
||||
$placeholders = str_repeat('?,', count($passagesToOrphan) - 1) . '?';
|
||||
$orphanQuery = "UPDATE ope_pass SET fk_sector = NULL WHERE id IN ($placeholders)";
|
||||
$orphanStmt = $this->db->prepare($orphanQuery);
|
||||
$orphanStmt->execute($passagesToOrphan);
|
||||
}
|
||||
|
||||
// 2. CRÉATION/MISE À JOUR DES PASSAGES POUR LES NOUVELLES ADRESSES
|
||||
// 2. CRÉATION/MISE À JOUR DES PASSAGES POUR LES NOUVELLES ADRESSES (OPTIMISÉE)
|
||||
// Récupérer toutes les adresses du secteur depuis sectors_adresses
|
||||
$addressesQuery = "SELECT * FROM sectors_adresses WHERE fk_sector = :sector_id";
|
||||
$addressesStmt = $this->db->prepare($addressesQuery);
|
||||
$addressesStmt->execute(['sector_id' => $sectorId]);
|
||||
$addresses = $addressesStmt->fetchAll();
|
||||
|
||||
|
||||
$this->logService->info('[updatePassagesForSector] Adresses dans sectors_adresses', [
|
||||
'sector_id' => $sectorId,
|
||||
'nb_addresses' => count($addresses)
|
||||
]);
|
||||
|
||||
|
||||
// Récupérer le premier utilisateur affecté au secteur
|
||||
$userQuery = "SELECT fk_user FROM ope_users_sectors WHERE fk_sector = :sector_id LIMIT 1";
|
||||
$userStmt = $this->db->prepare($userQuery);
|
||||
$userStmt->execute(['sector_id' => $sectorId]);
|
||||
$firstUser = $userStmt->fetch();
|
||||
$firstUserId = $firstUser ? $firstUser['fk_user'] : null;
|
||||
|
||||
|
||||
if ($firstUserId && !empty($addresses)) {
|
||||
$this->logService->info('[updatePassagesForSector] Création passages pour user', [
|
||||
$this->logService->info('[updatePassagesForSector] Optimisation passages', [
|
||||
'user_id' => $firstUserId,
|
||||
'nb_addresses_to_process' => count($addresses)
|
||||
'nb_addresses' => count($addresses)
|
||||
]);
|
||||
// Préparer la requête de création de passage (même format que dans create)
|
||||
$createPassageQuery = "INSERT INTO ope_pass (
|
||||
fk_operation, fk_sector, fk_user, fk_adresse,
|
||||
numero, rue, rue_bis, ville,
|
||||
gps_lat, gps_lng, fk_type, encrypted_name,
|
||||
created_at, fk_user_creat, chk_active
|
||||
) VALUES (
|
||||
:operation_id, :sector_id, :user_id, :fk_adresse,
|
||||
:numero, :rue, :rue_bis, :ville,
|
||||
:gps_lat, :gps_lng, 2, '',
|
||||
NOW(), :user_creat, 1
|
||||
)";
|
||||
$createStmt = $this->db->prepare($createPassageQuery);
|
||||
|
||||
|
||||
// OPTIMISATION : Récupérer TOUS les passages existants en UNE requête
|
||||
$addressIds = array_filter(array_column($addresses, 'fk_adresse'));
|
||||
|
||||
// Construire la requête pour récupérer tous les passages existants
|
||||
$existingQuery = "
|
||||
SELECT id, fk_adresse, numero, rue, rue_bis, ville
|
||||
FROM ope_pass
|
||||
WHERE fk_operation = :operation_id
|
||||
AND (";
|
||||
|
||||
$params = ['operation_id' => $operationId];
|
||||
$conditions = [];
|
||||
|
||||
// Condition pour les fk_adresse
|
||||
if (!empty($addressIds)) {
|
||||
$placeholders = [];
|
||||
foreach ($addressIds as $idx => $addrId) {
|
||||
$key = 'addr_' . $idx;
|
||||
$placeholders[] = ':' . $key;
|
||||
$params[$key] = $addrId;
|
||||
}
|
||||
$conditions[] = "fk_adresse IN (" . implode(',', $placeholders) . ")";
|
||||
}
|
||||
|
||||
// Condition pour les données d'adresse (numero, rue, ville)
|
||||
$addressConditions = [];
|
||||
foreach ($addresses as $idx => $addr) {
|
||||
$numKey = 'num_' . $idx;
|
||||
$rueKey = 'rue_' . $idx;
|
||||
$bisKey = 'bis_' . $idx;
|
||||
$villeKey = 'ville_' . $idx;
|
||||
|
||||
$addressConditions[] = "(numero = :$numKey AND rue = :$rueKey AND rue_bis = :$bisKey AND ville = :$villeKey)";
|
||||
$params[$numKey] = $addr['numero'];
|
||||
$params[$rueKey] = $addr['rue'];
|
||||
$params[$bisKey] = $addr['rue_bis'];
|
||||
$params[$villeKey] = $addr['ville'];
|
||||
}
|
||||
|
||||
if (!empty($addressConditions)) {
|
||||
$conditions[] = "(" . implode(' OR ', $addressConditions) . ")";
|
||||
}
|
||||
|
||||
$existingQuery .= implode(' OR ', $conditions) . ")";
|
||||
|
||||
$existingStmt = $this->db->prepare($existingQuery);
|
||||
$existingStmt->execute($params);
|
||||
$existingPassages = $existingStmt->fetchAll();
|
||||
|
||||
// Indexer les passages existants pour recherche rapide
|
||||
$passagesByAddress = [];
|
||||
$passagesByData = [];
|
||||
foreach ($existingPassages as $p) {
|
||||
if (!empty($p['fk_adresse'])) {
|
||||
$passagesByAddress[$p['fk_adresse']] = $p;
|
||||
}
|
||||
$dataKey = $p['numero'] . '|' . $p['rue'] . '|' . $p['rue_bis'] . '|' . $p['ville'];
|
||||
$passagesByData[$dataKey] = $p;
|
||||
}
|
||||
|
||||
// Préparer les listes pour batch insert/update
|
||||
$toInsert = [];
|
||||
$toUpdate = [];
|
||||
|
||||
foreach ($addresses as $address) {
|
||||
// 2.1 Vérification primaire par fk_adresse
|
||||
if (!empty($address['fk_adresse'])) {
|
||||
$checkByAddressQuery = "SELECT id FROM ope_pass
|
||||
WHERE fk_operation = :operation_id
|
||||
AND fk_adresse = :fk_adresse";
|
||||
$checkByAddressStmt = $this->db->prepare($checkByAddressQuery);
|
||||
$checkByAddressStmt->execute([
|
||||
'operation_id' => $operationId,
|
||||
'fk_adresse' => $address['fk_adresse']
|
||||
]);
|
||||
|
||||
if ($checkByAddressStmt->fetch()) {
|
||||
continue; // Passage déjà existant, passer au suivant
|
||||
}
|
||||
// Vérification en mémoire PHP (0 requête)
|
||||
if (!empty($address['fk_adresse']) && isset($passagesByAddress[$address['fk_adresse']])) {
|
||||
continue; // Déjà existant avec bon fk_adresse
|
||||
}
|
||||
|
||||
// 2.2 Vérification secondaire par données d'adresse
|
||||
$checkByDataQuery = "SELECT id FROM ope_pass
|
||||
WHERE fk_operation = :operation_id
|
||||
AND numero = :numero
|
||||
AND rue_bis = :rue_bis
|
||||
AND rue = :rue
|
||||
AND ville = :ville";
|
||||
$checkByDataStmt = $this->db->prepare($checkByDataQuery);
|
||||
$checkByDataStmt->execute([
|
||||
'operation_id' => $operationId,
|
||||
'numero' => $address['numero'],
|
||||
'rue_bis' => $address['rue_bis'],
|
||||
'rue' => $address['rue'],
|
||||
'ville' => $address['ville']
|
||||
]);
|
||||
|
||||
$matchingPassages = $checkByDataStmt->fetchAll();
|
||||
|
||||
if (!empty($matchingPassages)) {
|
||||
// Mettre à jour les passages trouvés avec le fk_adresse
|
||||
if (!empty($address['fk_adresse'])) {
|
||||
$updateQuery = "UPDATE ope_pass SET fk_adresse = :fk_adresse WHERE id = :passage_id";
|
||||
$updateStmt = $this->db->prepare($updateQuery);
|
||||
|
||||
foreach ($matchingPassages as $matchingPassage) {
|
||||
$updateStmt->execute([
|
||||
'fk_adresse' => $address['fk_adresse'],
|
||||
'passage_id' => $matchingPassage['id']
|
||||
]);
|
||||
$counters['passages_updated']++;
|
||||
}
|
||||
|
||||
$dataKey = $address['numero'] . '|' . $address['rue'] . '|' . $address['rue_bis'] . '|' . $address['ville'];
|
||||
if (isset($passagesByData[$dataKey])) {
|
||||
// Passage existant mais sans fk_adresse ou avec fk_adresse différent
|
||||
if (!empty($address['fk_adresse']) && $passagesByData[$dataKey]['fk_adresse'] != $address['fk_adresse']) {
|
||||
$toUpdate[] = [
|
||||
'id' => $passagesByData[$dataKey]['id'],
|
||||
'fk_adresse' => $address['fk_adresse']
|
||||
];
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
// Nouveau passage à créer
|
||||
$toInsert[] = $address;
|
||||
}
|
||||
|
||||
// 2.3 Création du passage (aucun passage existant trouvé)
|
||||
}
|
||||
|
||||
// INSERT MULTIPLE en une seule requête
|
||||
if (!empty($toInsert)) {
|
||||
$values = [];
|
||||
$insertParams = [];
|
||||
$paramIndex = 0;
|
||||
|
||||
foreach ($toInsert as $addr) {
|
||||
$values[] = "(:op$paramIndex, :sect$paramIndex, :usr$paramIndex, :addr$paramIndex,
|
||||
:num$paramIndex, :rue$paramIndex, :bis$paramIndex, :ville$paramIndex,
|
||||
:lat$paramIndex, :lng$paramIndex, 2, '', NOW(), :creat$paramIndex, 1)";
|
||||
|
||||
$insertParams["op$paramIndex"] = $operationId;
|
||||
$insertParams["sect$paramIndex"] = $sectorId;
|
||||
$insertParams["usr$paramIndex"] = $firstUserId;
|
||||
$insertParams["addr$paramIndex"] = $addr['fk_adresse'];
|
||||
$insertParams["num$paramIndex"] = $addr['numero'];
|
||||
$insertParams["rue$paramIndex"] = $addr['rue'];
|
||||
$insertParams["bis$paramIndex"] = $addr['rue_bis'];
|
||||
$insertParams["ville$paramIndex"] = $addr['ville'];
|
||||
$insertParams["lat$paramIndex"] = $addr['gps_lat'];
|
||||
$insertParams["lng$paramIndex"] = $addr['gps_lng'];
|
||||
$insertParams["creat$paramIndex"] = $_SESSION['user_id'] ?? null;
|
||||
|
||||
$paramIndex++;
|
||||
}
|
||||
|
||||
$insertQuery = "INSERT INTO ope_pass
|
||||
(fk_operation, fk_sector, fk_user, fk_adresse, numero, rue, rue_bis,
|
||||
ville, gps_lat, gps_lng, fk_type, encrypted_name, created_at, fk_user_creat, chk_active)
|
||||
VALUES " . implode(',', $values);
|
||||
|
||||
try {
|
||||
$createStmt->execute([
|
||||
'operation_id' => $operationId,
|
||||
'sector_id' => $sectorId,
|
||||
'user_id' => $firstUserId,
|
||||
'fk_adresse' => $address['fk_adresse'],
|
||||
'numero' => $address['numero'],
|
||||
'rue' => $address['rue'],
|
||||
'rue_bis' => $address['rue_bis'],
|
||||
'ville' => $address['ville'],
|
||||
'gps_lat' => $address['gps_lat'],
|
||||
'gps_lng' => $address['gps_lng'],
|
||||
'user_creat' => $_SESSION['user_id'] ?? null
|
||||
]);
|
||||
$counters['passages_created']++;
|
||||
$insertStmt = $this->db->prepare($insertQuery);
|
||||
$insertStmt->execute($insertParams);
|
||||
$counters['passages_created'] = count($toInsert);
|
||||
} catch (\Exception $e) {
|
||||
$this->logService->warning('Erreur lors de la création d\'un passage pendant update', [
|
||||
$this->logService->error('Erreur lors de l\'insertion multiple des passages', [
|
||||
'sector_id' => $sectorId,
|
||||
'address' => $address,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// UPDATE MULTIPLE avec CASE WHEN
|
||||
if (!empty($toUpdate)) {
|
||||
$updateIds = array_column($toUpdate, 'id');
|
||||
$placeholders = str_repeat('?,', count($updateIds) - 1) . '?';
|
||||
|
||||
$caseWhen = [];
|
||||
$updateParams = [];
|
||||
|
||||
foreach ($toUpdate as $upd) {
|
||||
$caseWhen[] = "WHEN id = ? THEN ?";
|
||||
$updateParams[] = $upd['id'];
|
||||
$updateParams[] = $upd['fk_adresse'];
|
||||
}
|
||||
|
||||
$updateQuery = "UPDATE ope_pass
|
||||
SET fk_adresse = CASE " . implode(' ', $caseWhen) . " END
|
||||
WHERE id IN ($placeholders)";
|
||||
|
||||
try {
|
||||
$updateStmt = $this->db->prepare($updateQuery);
|
||||
$updateStmt->execute(array_merge($updateParams, $updateIds));
|
||||
$counters['passages_updated'] = count($toUpdate);
|
||||
} catch (\Exception $e) {
|
||||
$this->logService->error('Erreur lors de la mise à jour multiple des passages', [
|
||||
'sector_id' => $sectorId,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->logService->warning('[updatePassagesForSector] Pas de création de passages', [
|
||||
'reason' => !$firstUserId ? 'Pas d\'utilisateur affecté' : 'Pas d\'adresses',
|
||||
|
||||
Reference in New Issue
Block a user