PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_PERSISTENT => true, PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES " . DB_CHARSET . " COLLATE utf8mb4_unicode_ci" ]; $this->pdo = new PDO($dsn, DB_USER, DB_PASS, $options); } catch (PDOException $e) { error_log("Database connection failed: " . $e->getMessage()); throw new Exception("Error de conexión a la base de datos"); } } public static function getInstance() { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } public function getConnection() { return $this->pdo; } public function query($sql, $params = []) { try { $stmt = $this->pdo->prepare($sql); $stmt->execute($params); return $stmt; } catch (PDOException $e) { error_log("Query failed: " . $e->getMessage() . " SQL: " . $sql); throw new Exception("Error en la consulta a la base de datos"); } } public function fetch($sql, $params = []) { $stmt = $this->query($sql, $params); return $stmt->fetch(); } public function fetchAll($sql, $params = []) { $stmt = $this->query($sql, $params); return $stmt->fetchAll(); } public function insert($table, $data) { $keys = array_keys($data); $fields = implode(',', $keys); $placeholders = ':' . implode(', :', $keys); $sql = "INSERT INTO {$table} ({$fields}) VALUES ({$placeholders})"; $stmt = $this->query($sql, $data); return $this->pdo->lastInsertId(); } public function update($table, $data, $where, $whereParams = []) { $fields = []; foreach (array_keys($data) as $key) { $fields[] = "{$key} = :{$key}"; } $fieldsStr = implode(', ', $fields); $sql = "UPDATE {$table} SET {$fieldsStr} WHERE {$where}"; $params = array_merge($data, $whereParams); return $this->query($sql, $params); } public function delete($table, $where, $params = []) { $sql = "DELETE FROM {$table} WHERE {$where}"; return $this->query($sql, $params); } public function beginTransaction() { return $this->pdo->beginTransaction(); } public function commit() { return $this->pdo->commit(); } public function rollback() { return $this->pdo->rollback(); } public function lastInsertId() { return $this->pdo->lastInsertId(); } // Prevenir clonación private function __clone() {} // Prevenir deserialización public function __wakeup() { throw new Exception("Cannot unserialize singleton"); } } ?>