sourceDb = $sourceDb; $this->targetDb = $targetDb; $this->logger = $logger; $this->userMigrator = $userMigrator; $this->sectorMigrator = $sectorMigrator; } /** * Récupère les opérations à migrer pour une entité * - 1 opération active * - 2 dernières opérations inactives avec au moins 10 passages effectués * * @param int $entityId ID de l'entité * @return array Liste des IDs d'opérations à migrer */ public function getOperationsToMigrate(int $entityId): array { $operationIds = []; // 1. Récupérer l'opération active (pour vérification) $stmt = $this->sourceDb->prepare(" SELECT rowid FROM operations WHERE fk_entite = :entity_id AND active = 1 LIMIT 1 "); $stmt->execute([':entity_id' => $entityId]); $activeOp = $stmt->fetch(PDO::FETCH_COLUMN); // 2. Récupérer les 2 dernières opérations inactives avec >= 10 passages effectués // ORDER BY DESC pour avoir les plus récentes, puis on inverse $stmt = $this->sourceDb->prepare(" SELECT o.rowid, COUNT(p.rowid) as nb_passages FROM operations o LEFT JOIN ope_pass p ON p.fk_operation = o.rowid AND p.fk_type = 1 WHERE o.fk_entite = :entity_id AND o.active = 0 " . ($activeOp ? "AND o.rowid != :active_id" : "") . " GROUP BY o.rowid HAVING nb_passages >= 10 ORDER BY o.rowid DESC LIMIT 2 "); $params = [':entity_id' => $entityId]; if ($activeOp) { $params[':active_id'] = $activeOp; } $stmt->execute($params); $inactiveOps = $stmt->fetchAll(PDO::FETCH_ASSOC); // Inverser pour avoir l'ordre chronologique (plus ancienne → plus récente) $inactiveOps = array_reverse($inactiveOps); foreach ($inactiveOps as $op) { $operationIds[] = $op['rowid']; $this->logger->info("✓ Opération inactive trouvée: {$op['rowid']} ({$op['nb_passages']} passages)"); } // 3. Ajouter l'opération active EN DERNIER if ($activeOp) { $operationIds[] = $activeOp; $this->logger->info("✓ Opération active trouvée: {$activeOp}"); } $this->logger->info("📊 Total: " . count($operationIds) . " opération(s) à migrer"); return $operationIds; } /** * Migre une opération complète avec tous ses utilisateurs et secteurs * * @param int $oldOperationId ID de l'opération dans l'ancienne base * @return array|null Tableau de statistiques ou null en cas d'erreur */ public function migrateOperation(int $oldOperationId): ?array { $this->logger->separator(); $this->logger->info("🔄 Migration de l'opération ID: {$oldOperationId}"); try { // 1. Récupérer l'opération source $stmt = $this->sourceDb->prepare(" SELECT * FROM operations WHERE rowid = :id "); $stmt->execute([':id' => $oldOperationId]); $operation = $stmt->fetch(PDO::FETCH_ASSOC); if (!$operation) { $this->logger->warning("Opération {$oldOperationId} non trouvée"); return null; } // 2. Créer l'opération dans la nouvelle base $newOperationId = $this->createOperation($operation); if (!$newOperationId) { return null; } $this->logger->success("✓ Opération créée avec ID: {$newOperationId}"); // 3. Migrer les utilisateurs de l'opération // Pour opération active : tous les users actifs de l'entité // Pour opération inactive : uniquement ceux dans ope_users_sectors $entityId = (int)$operation['fk_entite']; $isActiveOperation = (int)$operation['active'] === 1; $userResult = $this->userMigrator->migrateOperationUsers( $oldOperationId, $newOperationId, $entityId, $isActiveOperation ); $userMapping = $userResult['mapping']; $usersCount = $userResult['count']; if (empty($userMapping)) { $this->logger->warning("Aucun utilisateur migré, abandon de l'opération {$oldOperationId}"); return null; } // 4. Récupérer les secteurs DISTINCTS de l'opération $stmt = $this->sourceDb->prepare(" SELECT DISTINCT fk_sector FROM ope_users_sectors WHERE fk_operation = :operation_id AND active = 1 "); $stmt->execute([':operation_id' => $oldOperationId]); $sectors = $stmt->fetchAll(PDO::FETCH_COLUMN); $this->logger->info("📍 " . count($sectors) . " secteur(s) distinct(s) à migrer"); // 5. Migrer chaque secteur et collecter les stats $sectorsDetail = []; $totalPassages = 0; foreach ($sectors as $oldSectorId) { $sectorStats = $this->sectorMigrator->migrateSector( $oldOperationId, $newOperationId, $oldSectorId, $userMapping ); if ($sectorStats) { $sectorsDetail[] = $sectorStats; $totalPassages += $sectorStats['passages']; } } // 6. Migrer les médias de l'opération (support='operations') $this->migrateOperationMedias($oldOperationId, $newOperationId); $this->logger->success("✅ Migration de l'opération {$oldOperationId} terminée"); // 7. Retourner les statistiques return [ 'id' => $newOperationId, 'name' => $operation['libelle'], 'users' => $usersCount, 'sectors' => count($sectorsDetail), 'total_passages' => $totalPassages, 'sectors_detail' => $sectorsDetail ]; } catch (Exception $e) { $this->logger->error("❌ Erreur migration opération {$oldOperationId}: " . $e->getMessage()); return null; } } /** * Crée une opération dans la nouvelle base * * @param array $operation Données de l'opération * @return int|null ID de la nouvelle opération ou null en cas d'erreur */ private function createOperation(array $operation): ?int { try { $stmt = $this->targetDb->prepare(" INSERT INTO operations ( fk_entite, libelle, date_deb, date_fin, chk_distinct_sectors, created_at, fk_user_creat, updated_at, fk_user_modif, chk_active ) VALUES ( :fk_entite, :libelle, :date_deb, :date_fin, :chk_distinct_sectors, :created_at, :fk_user_creat, :updated_at, :fk_user_modif, :chk_active ) "); $stmt->execute([ ':fk_entite' => $operation['fk_entite'], ':libelle' => $operation['libelle'], ':date_deb' => $operation['date_deb'], ':date_fin' => $operation['date_fin'], ':chk_distinct_sectors' => $operation['chk_distinct_sectors'], ':created_at' => $operation['date_creat'], ':fk_user_creat' => $operation['fk_user_creat'], ':updated_at' => $operation['date_modif'], ':fk_user_modif' => $operation['fk_user_modif'] ?? 0, ':chk_active' => $operation['active'] ]); return (int)$this->targetDb->lastInsertId(); } catch (Exception $e) { $this->logger->error("❌ Erreur création opération: " . $e->getMessage()); return null; } } /** * Migre les médias d'une opération * * @param int $oldOperationId ID ancienne opération * @param int $newOperationId ID nouvelle opération * @return int Nombre de médias migrés */ private function migrateOperationMedias(int $oldOperationId, int $newOperationId): int { $stmt = $this->sourceDb->prepare(" SELECT * FROM medias WHERE support = 'operations' AND support_rowid = :operation_id "); $stmt->execute([':operation_id' => $oldOperationId]); $medias = $stmt->fetchAll(PDO::FETCH_ASSOC); if (empty($medias)) { return 0; } $count = 0; foreach ($medias as $media) { $stmt = $this->targetDb->prepare(" INSERT INTO medias ( dir0, dir1, dir2, support, support_rowid, fichier, type_fichier, description, position, hauteur, largeur, niveaugris, created_at, fk_user_creat, updated_at, fk_user_modif ) VALUES ( :dir0, :dir1, :dir2, :support, :support_rowid, :fichier, :type_fichier, :description, :position, :hauteur, :largeur, :niveaugris, :created_at, :fk_user_creat, :updated_at, :fk_user_modif ) "); $stmt->execute([ ':dir0' => $media['dir0'], ':dir1' => $media['dir1'], ':dir2' => $media['dir2'], ':support' => $media['support'], ':support_rowid' => $newOperationId, ':fichier' => $media['fichier'], ':type_fichier' => $media['type_fichier'], ':description' => $media['description'], ':position' => $media['position'], ':hauteur' => $media['hauteur'], ':largeur' => $media['largeur'], ':niveaugris' => $media['niveaugris'], ':created_at' => $media['date_creat'], ':fk_user_creat' => $media['fk_user_creat'], ':updated_at' => $media['date_modif'], ':fk_user_modif' => $media['fk_user_modif'] ]); $count++; } $this->logger->success("✓ {$count} média(s) migré(s)"); return $count; } }