false, 'message' => 'Metodo non consentito.']); exit; } $pdo = DBHandlerSelect::getInstance()->getConnection(); $id = (int)($_POST['id'] ?? 0); $name = trim($_POST['name'] ?? ''); $description = trim($_POST['description'] ?? ''); $freqRaw = $_POST['default_frequency_months'] ?? ''; $remRaw = $_POST['default_reminder_days'] ?? ''; $sort_order = isset($_POST['sort_order']) && $_POST['sort_order'] !== '' ? (int)$_POST['sort_order'] : 999; $is_active = isset($_POST['is_active']) ? ((int)$_POST['is_active'] === 1 ? 1 : 0) : 1; $is_mandatory = isset($_POST['is_mandatory']) && (int)$_POST['is_mandatory'] === 1 ? 1 : 0; $freq = ($freqRaw === '' || $freqRaw === null) ? null : max(0, (int)$freqRaw); $rem = ($remRaw === '' || $remRaw === null) ? 30 : max(0, (int)$remRaw); /* Coperture: corsi assorbiti da questo */ $coveredIds = isset($_POST['covered_ids']) ? (array)$_POST['covered_ids'] : []; $coveredIds = array_values(array_unique(array_filter(array_map('intval', $coveredIds), function ($v) { return $v > 0; }))); if ($name === '') { echo json_encode(['success' => false, 'message' => 'Il nome del corso è obbligatorio.']); exit; } /** * Riscrive le coperture del corso: cancella le vecchie e inserisce le nuove, * scartando auto-copertura e relazioni che creerebbero un ciclo. */ function saveCoverage(PDO $pdo, int $topicId, array $coveredIds): array { $skipped = []; $pdo->prepare("DELETE FROM training_topic_coverage WHERE topic_id = :tid") ->execute(['tid' => $topicId]); if (!$coveredIds) return $skipped; $ins = $pdo->prepare(" INSERT IGNORE INTO training_topic_coverage (topic_id, covered_topic_id, inherit_expiry, created_at) VALUES (:tid, :cid, 'own', NOW()) "); foreach ($coveredIds as $cid) { if ($cid === $topicId) { continue; } if (tc_wouldCreateCycle($pdo, $topicId, $cid)) { $skipped[] = $cid; continue; } $ins->execute(['tid' => $topicId, 'cid' => $cid]); } return $skipped; } try { $pdo->beginTransaction(); if ($id > 0) { $check = $pdo->prepare("SELECT COUNT(*) FROM training_topics WHERE name = :name AND id <> :id"); $check->execute(['name' => $name, 'id' => $id]); if ((int)$check->fetchColumn() > 0) { $pdo->rollBack(); echo json_encode(['success' => false, 'message' => 'Esiste già un altro corso con questo nome.']); exit; } $stmt = $pdo->prepare(" UPDATE training_topics SET name = :name, description = :description, default_frequency_months = :freq, default_reminder_days = :rem, sort_order = :sort_order, is_active = :is_active, is_mandatory = :is_mandatory, updated_at = NOW() WHERE id = :id "); $stmt->execute([ 'name' => $name, 'description' => $description !== '' ? $description : null, 'freq' => $freq, 'rem' => $rem, 'sort_order' => $sort_order, 'is_active' => $is_active, 'is_mandatory' => $is_mandatory, 'id' => $id, ]); $skipped = saveCoverage($pdo, $id, $coveredIds); $pdo->commit(); $msg = $skipped ? 'Corso aggiornato. Alcune coperture sono state ignorate perché avrebbero creato un riferimento circolare.' : null; echo json_encode(array_filter([ 'success' => true, 'id' => $id, 'message' => $msg, ], function ($v) { return $v !== null; })); exit; } $check = $pdo->prepare("SELECT COUNT(*) FROM training_topics WHERE name = :name"); $check->execute(['name' => $name]); if ((int)$check->fetchColumn() > 0) { $pdo->rollBack(); echo json_encode(['success' => false, 'message' => 'Esiste già un corso con questo nome.']); exit; } $stmt = $pdo->prepare(" INSERT INTO training_topics (name, description, default_frequency_months, default_reminder_days, sort_order, is_active, is_mandatory, created_at, updated_at) VALUES (:name, :description, :freq, :rem, :sort_order, :is_active, :is_mandatory, NOW(), NOW()) "); $stmt->execute([ 'name' => $name, 'description' => $description !== '' ? $description : null, 'freq' => $freq, 'rem' => $rem, 'sort_order' => $sort_order, 'is_active' => $is_active, 'is_mandatory' => $is_mandatory, ]); $newId = (int)$pdo->lastInsertId(); saveCoverage($pdo, $newId, $coveredIds); $pdo->commit(); echo json_encode(['success' => true, 'id' => $newId]); } catch (Exception $e) { if ($pdo->inTransaction()) { $pdo->rollBack(); } echo json_encode(['success' => false, 'message' => $e->getMessage()]); }