query("SELECT m.id, m.nis, m.nisn, m.nama_lengkap, m.jenis_kelamin, m.email, m.foto, k.nama_kelas FROM murid m LEFT JOIN kelas k ON m.kelas_id = k.id ORDER BY m.nama_lengkap ASC"); return $stmt->fetchAll(PDO::FETCH_ASSOC); } function get_murid_by_id($id) { $pdo = db(); $stmt = $pdo->prepare("SELECT * FROM murid WHERE id = ?"); $stmt->execute([$id]); return $stmt->fetch(PDO::FETCH_ASSOC); } function handle_murid_action() { $action = $_POST['action'] ?? $_GET['action'] ?? ''; // Handle Delete Action via GET first as it redirects if ($action === 'delete' && isset($_GET['id'])) { $id = $_GET['id']; $murid = get_murid_by_id($id); // Get murid data to delete foto $pdo = db(); try { // Delete old photo if exists if (!empty($murid['foto'])) { $photo_path = 'assets/uploads/murid/' . $murid['foto']; if (file_exists($photo_path)) { unlink($photo_path); } } $stmt = $pdo->prepare("DELETE FROM murid WHERE id = ?"); $stmt->execute([$id]); header("Location: index.php?page=murid&status=deleted"); exit(); } catch (PDOException $e) { header("Location: index.php?page=murid&status=error"); exit(); } } // Only proceed with POST actions from here if ($_SERVER['REQUEST_METHOD'] !== 'POST') { return null; } $pdo = db(); $id = $_POST['id'] ?? null; // Handle Import if ($action === 'import') { if (isset($_FILES['file_murid']) && $_FILES['file_murid']['error'] === UPLOAD_ERR_OK) { $file_tmp_path = $_FILES['file_murid']['tmp_name']; return import_murid_from_xlsx($file_tmp_path); } else { return ['success' => false, 'message' => 'Gagal mengunggah file. Silakan coba lagi.']; } } // Handle Add/Edit $nis = $_POST['nis'] ?? ''; $nisn = $_POST['nisn'] ?? ''; $nama_lengkap = $_POST['nama_lengkap'] ?? ''; $tempat_lahir = $_POST['tempat_lahir'] ?? ''; $tanggal_lahir = $_POST['tanggal_lahir'] ?? ''; $jenis_kelamin = $_POST['jenis_kelamin'] ?? ''; $alamat = $_POST['alamat'] ?? ''; $latitude = $_POST['latitude'] ?? ''; $longitude = $_POST['longitude'] ?? ''; $no_telepon = $_POST['no_telepon'] ?? ''; $email = $_POST['email'] ?? ''; $kelas_id = !empty($_POST['kelas_id']) ? $_POST['kelas_id'] : null; $foto_filename = $_POST['foto_existing'] ?? null; // Handle file upload if (isset($_FILES['foto']) && $_FILES['foto']['error'] === UPLOAD_ERR_OK) { $upload_dir = 'assets/uploads/murid/'; if (!is_dir($upload_dir)) { mkdir($upload_dir, 0777, true); } $tmp_name = $_FILES['foto']['tmp_name']; $original_name = basename($_FILES['foto']['name']); $file_ext = strtolower(pathinfo($original_name, PATHINFO_EXTENSION)); $safe_filename = preg_replace('/[^A-Za-z0-9_.-]/', '_', pathinfo($original_name, PATHINFO_FILENAME)); $foto_filename = uniqid() . '_' . $safe_filename . '.' . $file_ext; // Delete old photo if a new one is uploaded during edit if ($action === 'edit' && !empty($_POST['foto_existing'])) { $old_photo_path = $upload_dir . $_POST['foto_existing']; if (file_exists($old_photo_path)) { unlink($old_photo_path); } } if (!move_uploaded_file($tmp_name, $upload_dir . $foto_filename)) { return ['success' => false, 'message' => 'Gagal memindahkan file foto.']; } } try { if ($action === 'add') { $stmt = $pdo->prepare( "INSERT INTO murid (nis, nisn, nama_lengkap, tempat_lahir, tanggal_lahir, jenis_kelamin, alamat, foto, latitude, longitude, no_telepon, email, kelas_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" ); $stmt->execute([$nis, $nisn, $nama_lengkap, $tempat_lahir, $tanggal_lahir, $jenis_kelamin, $alamat, $foto_filename, $latitude, $longitude, $no_telepon, $email, $kelas_id]); return ['success' => true, 'message' => 'Data murid berhasil ditambahkan.']; } elseif ($action === 'edit' && $id) { $stmt = $pdo->prepare( "UPDATE murid SET nis = ?, nisn = ?, nama_lengkap = ?, tempat_lahir = ?, tanggal_lahir = ?, jenis_kelamin = ?, alamat = ?, foto = ?, latitude = ?, longitude = ?, no_telepon = ?, email = ?, kelas_id = ? WHERE id = ?" ); $stmt->execute([$nis, $nisn, $nama_lengkap, $tempat_lahir, $tanggal_lahir, $jenis_kelamin, $alamat, $foto_filename, $latitude, $longitude, $no_telepon, $email, $kelas_id, $id]); return ['success' => true, 'message' => 'Data murid berhasil diperbarui.']; } } catch (PDOException $e) { if ($e->getCode() == 23000) { // Integrity constraint violation return ['success' => false, 'message' => 'Gagal menyimpan data. NIS atau NISN sudah terdaftar.']; } return ['success' => false, 'message' => 'Terjadi kesalahan database: ' . $e->getMessage()]; } return null; } function import_murid_from_xlsx($filepath) { // Include the parser library require_once 'libs/SimpleXLSX.php'; // Check if the file exists and is readable if (!file_exists($filepath) || !is_readable($filepath)) { return ['success' => false, 'message' => 'File tidak ditemukan atau tidak bisa dibaca.']; } // Try to parse the XLSX file if ($xlsx = Shuchkin\SimpleXLSX::parse($filepath)) { $pdo = db(); $success_count = 0; $fail_count = 0; $errors = []; // Get rows as array $rows = $xlsx->rows(); // Skip header row (the first row) $is_header = true; foreach ($rows as $row) { if ($is_header) { $is_header = false; continue; } // Assign columns to variables - assuming order: NIS, NISN, Nama, Tgl Lahir, Alamat $nis = $row[0] ?? ''; $nisn = $row[1] ?? ''; $nama_lengkap = $row[2] ?? ''; $tanggal_lahir = $row[3] ?? ''; $alamat = $row[4] ?? ''; // Basic validation: skip if NIS or name is empty if (empty($nis) || empty($nama_lengkap)) { $fail_count++; $errors[] = "Baris data dengan NIS '.htmlspecialchars($nis).' dan Nama '.htmlspecialchars($nama_lengkap).' dilewati karena data tidak lengkap."; continue; } try { // Using the existing add function logic $stmt = $pdo->prepare( "INSERT INTO murid (nis, nisn, nama_lengkap, tanggal_lahir, alamat) VALUES (?, ?, ?, ?, ?)" ); $stmt->execute([$nis, $nisn, $nama_lengkap, $tanggal_lahir, $alamat]); $success_count++; } catch (PDOException $e) { $fail_count++; if ($e->getCode() == 23000) { $errors[] = "NIS atau NISN '.htmlspecialchars($nis).' sudah ada di database."; } else { $errors[] = "Gagal memasukkan data untuk NIS '.htmlspecialchars($nis).': " . $e->getMessage(); } } } $message = "Impor selesai. Berhasil: {$success_count}, Gagal: {$fail_count}."; if (!empty($errors)) { $message .= "
Detail kegagalan:
" . implode("
", $errors); } return ['success' => ($fail_count === 0), 'message' => $message]; } else { return ['success' => false, 'message' => 'Gagal memproses file XLSX: ' . Shuchkin\SimpleXLSX::parseError()]; } } function get_all_guru() { $pdo = db(); $stmt = $pdo->query("SELECT id, nip, nama, foto FROM guru ORDER BY nama ASC"); return $stmt->fetchAll(PDO::FETCH_ASSOC); } function get_guru_by_id($id) { $pdo = db(); $stmt = $pdo->prepare("SELECT * FROM guru WHERE id = ?"); $stmt->execute([$id]); return $stmt->fetch(PDO::FETCH_ASSOC); } function handle_guru_action() { $action = $_POST['action'] ?? $_GET['action'] ?? ''; if ($action === 'delete' && isset($_GET['id'])) { $id = $_GET['id']; $guru = get_guru_by_id($id); $pdo = db(); try { if (!empty($guru['foto'])) { $photo_path = 'assets/uploads/guru/' . $guru['foto']; if (file_exists($photo_path)) { unlink($photo_path); } } $stmt = $pdo->prepare("DELETE FROM guru WHERE id = ?"); $stmt->execute([$id]); header("Location: index.php?page=teachers&status=deleted"); exit(); } catch (PDOException $e) { header("Location: index.php?page=teachers&status=error"); exit(); } } if ($_SERVER['REQUEST_METHOD'] !== 'POST') { return null; } $pdo = db(); $id = $_POST['id'] ?? null; $nip = $_POST['nip'] ?? ''; $nama = $_POST['nama'] ?? ''; $alamat = $_POST['alamat'] ?? ''; $telepon = $_POST['telepon'] ?? ''; $latitude = $_POST['latitude'] ?? ''; $longitude = $_POST['longitude'] ?? ''; $foto_filename = $_POST['foto_existing'] ?? null; if (isset($_FILES['foto']) && $_FILES['foto']['error'] === UPLOAD_ERR_OK) { $upload_dir = 'assets/uploads/guru/'; if (!is_dir($upload_dir)) { mkdir($upload_dir, 0777, true); } $tmp_name = $_FILES['foto']['tmp_name']; $original_name = basename($_FILES['foto']['name']); $file_ext = strtolower(pathinfo($original_name, PATHINFO_EXTENSION)); $safe_filename = preg_replace('/[^A-Za-z0-9_.-]/', '_', pathinfo($original_name, PATHINFO_FILENAME)); $foto_filename = uniqid() . '_' . $safe_filename . '.' . $file_ext; if ($action === 'edit' && !empty($_POST['foto_existing'])) { $old_photo_path = $upload_dir . $_POST['foto_existing']; if (file_exists($old_photo_path)) { unlink($old_photo_path); } } if (!move_uploaded_file($tmp_name, $upload_dir . $foto_filename)) { return ['success' => false, 'message' => 'Gagal memindahkan file foto.']; } } try { if ($action === 'add') { $stmt = $pdo->prepare( "INSERT INTO guru (nip, nama, alamat, telepon, foto, latitude, longitude) VALUES (?, ?, ?, ?, ?, ?, ?)" ); $stmt->execute([$nip, $nama, $alamat, $telepon, $foto_filename, $latitude, $longitude]); return ['success' => true, 'message' => 'Data guru berhasil ditambahkan.']; } elseif ($action === 'edit' && $id) { $stmt = $pdo->prepare( "UPDATE guru SET nip = ?, nama = ?, alamat = ?, telepon = ?, foto = ?, latitude = ?, longitude = ? WHERE id = ?" ); $stmt->execute([$nip, $nama, $alamat, $telepon, $foto_filename, $latitude, $longitude, $id]); return ['success' => true, 'message' => 'Data guru berhasil diperbarui.']; } } catch (PDOException $e) { if ($e->getCode() == 23000) { // Integrity constraint violation return ['success' => false, 'message' => 'Gagal menyimpan data. NIP sudah terdaftar.']; } return ['success' => false, 'message' => 'Terjadi kesalahan database: ' . $e->getMessage()]; } return null; } function get_all_kelas() { $pdo = db(); $stmt = $pdo->query(" SELECT k.id, k.nama_kelas, g.nama as nama_wali_kelas FROM kelas k LEFT JOIN guru g ON k.id_wali_kelas = g.id ORDER BY k.nama_kelas ASC "); return $stmt->fetchAll(PDO::FETCH_ASSOC); } function get_kelas_by_id($id) { $pdo = db(); $stmt = $pdo->prepare("SELECT * FROM kelas WHERE id = ?"); $stmt->execute([$id]); return $stmt->fetch(PDO::FETCH_ASSOC); } function handle_kelas_action() { $action = $_POST['action'] ?? $_GET['action'] ?? ''; if ($action === 'delete' && isset($_GET['id'])) { $id = $_GET['id']; $pdo = db(); try { $stmt = $pdo->prepare("DELETE FROM kelas WHERE id = ?"); $stmt->execute([$id]); header("Location: index.php?page=classes&status=deleted"); exit(); } catch (PDOException $e) { // Foreign key constraint might fail, though ON DELETE SET NULL should prevent it. // Good to have a generic error handler. header("Location: index.php?page=classes&status=error"); exit(); } } if ($_SERVER['REQUEST_METHOD'] !== 'POST') { return null; } $pdo = db(); $id = $_POST['id'] ?? null; $nama_kelas = $_POST['nama_kelas'] ?? ''; // Use 'none' or null for the wali kelas if not selected $id_wali_kelas = !empty($_POST['id_wali_kelas']) ? $_POST['id_wali_kelas'] : null; try { if ($action === 'add') { $stmt = $pdo->prepare( "INSERT INTO kelas (nama_kelas, id_wali_kelas) VALUES (?, ?)" ); $stmt->execute([$nama_kelas, $id_wali_kelas]); return ['success' => true, 'message' => 'Data kelas berhasil ditambahkan.']; } elseif ($action === 'edit' && $id) { $stmt = $pdo->prepare( "UPDATE kelas SET nama_kelas = ?, id_wali_kelas = ? WHERE id = ?" ); $stmt->execute([$nama_kelas, $id_wali_kelas, $id]); return ['success' => true, 'message' => 'Data kelas berhasil diperbarui.']; } } catch (PDOException $e) { if ($e->getCode() == 23000) { return ['success' => false, 'message' => 'Gagal menyimpan data. Nama kelas mungkin sudah ada.']; } return ['success' => false, 'message' => 'Terjadi kesalahan database: ' . $e->getMessage()]; } return null; } function get_all_jadwal() { $pdo = db(); $stmt = $pdo->query(" SELECT j.id, j.hari, j.jam_mulai, j.jam_selesai, mp.nama_matapelajaran, k.nama_kelas, g.nama as nama_guru FROM jadwal j JOIN kelas k ON j.id_kelas = k.id JOIN guru g ON j.id_guru = g.id LEFT JOIN mata_pelajaran mp ON j.id_matapelajaran = mp.id ORDER BY k.nama_kelas, FIELD(j.hari, 'Senin', 'Selasa', 'Rabu', 'Kamis', 'Jumat', 'Sabtu', 'Minggu'), j.jam_mulai "); return $stmt->fetchAll(PDO::FETCH_ASSOC); } function get_jadwal_by_id($id) { $pdo = db(); $stmt = $pdo->prepare("SELECT * FROM jadwal WHERE id = ?"); $stmt->execute([$id]); return $stmt->fetch(PDO::FETCH_ASSOC); } function handle_jadwal_action() { $action = $_POST['action'] ?? $_GET['action'] ?? ''; if ($action === 'delete' && isset($_GET['id'])) { $id = $_GET['id']; $pdo = db(); try { $stmt = $pdo->prepare("DELETE FROM jadwal WHERE id = ?"); $stmt->execute([$id]); header("Location: index.php?page=schedule&status=deleted"); exit(); } catch (PDOException $e) { header("Location: index.php?page=schedule&status=error"); exit(); } } if ($_SERVER['REQUEST_METHOD'] !== 'POST') { return null; } $pdo = db(); $id = $_POST['id'] ?? null; $id_kelas = $_POST['id_kelas'] ?? ''; $id_guru = $_POST['id_guru'] ?? ''; $id_matapelajaran = $_POST['id_matapelajaran'] ?? ''; // New field $hari = $_POST['hari'] ?? ''; $jam_mulai = $_POST['jam_mulai'] ?? ''; $jam_selesai = $_POST['jam_selesai'] ?? ''; // Basic validation if (empty($id_kelas) || empty($id_guru) || empty($id_matapelajaran) || empty($hari) || empty($jam_mulai) || empty($jam_selesai)) { return ['success' => false, 'message' => 'Semua kolom wajib diisi.']; } try { if ($action === 'add') { $stmt = $pdo->prepare( "INSERT INTO jadwal (id_kelas, id_guru, id_matapelajaran, hari, jam_mulai, jam_selesai) VALUES (?, ?, ?, ?, ?, ?)" ); $stmt->execute([$id_kelas, $id_guru, $id_matapelajaran, $hari, $jam_mulai, $jam_selesai]); return ['success' => true, 'message' => 'Data jadwal berhasil ditambahkan.']; } elseif ($action === 'edit' && $id) { $stmt = $pdo->prepare( "UPDATE jadwal SET id_kelas = ?, id_guru = ?, id_matapelajaran = ?, hari = ?, jam_mulai = ?, jam_selesai = ? WHERE id = ?" ); $stmt->execute([$id_kelas, $id_guru, $id_matapelajaran, $hari, $jam_mulai, $jam_selesai, $id]); return ['success' => true, 'message' => 'Data jadwal berhasil diperbarui.']; } } catch (PDOException $e) { return ['success' => false, 'message' => 'Terjadi kesalahan database: ' . $e->getMessage()]; } return null; } // Attendance Functions function get_murid_by_kelas($kelas_id) { $pdo = db(); $stmt = $pdo->prepare("SELECT id, nama_lengkap FROM murid WHERE kelas_id = ? ORDER BY nama_lengkap ASC"); $stmt->execute([$kelas_id]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } function get_jadwal_by_kelas_and_hari($kelas_id, $hari) { $pdo = db(); $stmt = $pdo->prepare(" SELECT j.id, mp.nama_matapelajaran, j.jam_mulai, j.jam_selesai FROM jadwal j LEFT JOIN mata_pelajaran mp ON j.id_matapelajaran = mp.id WHERE j.id_kelas = ? AND j.hari = ? ORDER BY j.jam_mulai ASC"); $stmt->execute([$kelas_id, $hari]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } function get_absensi($id_kelas, $tanggal) { $pdo = db(); $stmt = $pdo->prepare(" SELECT murid_id, jadwal_id, status FROM absensi WHERE tanggal = ? AND jadwal_id IN (SELECT id FROM jadwal WHERE id_kelas = ?) "); $stmt->execute([$tanggal, $id_kelas]); $result = $stmt->fetchAll(PDO::FETCH_ASSOC); // Format the result for easier lookup in the template $absensi_data = []; foreach ($result as $row) { $absensi_data[$row['murid_id']][$row['jadwal_id']] = $row['status']; } return $absensi_data; } function handle_absensi_action() { if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['action']) || $_POST['action'] !== 'save_absensi') { return null; } $id_kelas = $_POST['id_kelas'] ?? ''; $tanggal = $_POST['tanggal'] ?? ''; $absensi = $_POST['absensi'] ?? []; if (empty($id_kelas) || empty($tanggal) || empty($absensi)) { return ['success' => false, 'message' => 'Data tidak lengkap. Harap pilih kelas, tanggal, dan isi absensi.']; } $pdo = db(); try { $pdo->beginTransaction(); // Prepare statement for inserting/updating attendance $stmt = $pdo->prepare(" INSERT INTO absensi (jadwal_id, murid_id, tanggal, status) VALUES (:jadwal_id, :murid_id, :tanggal, :status) ON DUPLICATE KEY UPDATE status = :status "); foreach ($absensi as $murid_id => $jadwal_absensi) { foreach ($jadwal_absensi as $jadwal_id => $status) { if (!empty($status)) { $stmt->execute([ ':jadwal_id' => $jadwal_id, ':murid_id' => $murid_id, ':tanggal' => $tanggal, ':status' => $status ]); } } } $pdo->commit(); return ['success' => true, 'message' => 'Absensi berhasil disimpan.']; } catch (PDOException $e) { $pdo->rollBack(); return ['success' => false, 'message' => 'Gagal menyimpan absensi: ' . $e->getMessage()]; } } function get_rekap_absensi($id_kelas, $start_date, $end_date) { $pdo = db(); // Validate input dates if (empty($id_kelas) || empty($start_date) || empty($end_date)) { return []; } $sql = " SELECT m.id as murid_id, m.nis, m.nama_lengkap, COUNT(a.id) as total_absensi, SUM(CASE WHEN a.status = 'Hadir' THEN 1 ELSE 0 END) as total_hadir, SUM(CASE WHEN a.status = 'Sakit' THEN 1 ELSE 0 END) as total_sakit, SUM(CASE WHEN a.status = 'Izin' THEN 1 ELSE 0 END) as total_izin, SUM(CASE WHEN a.status = 'Alpa' THEN 1 ELSE 0 END) as total_alpa FROM murid m LEFT JOIN absensi a ON m.id = a.murid_id WHERE m.kelas_id = :id_kelas AND a.tanggal BETWEEN :start_date AND :end_date GROUP BY m.id, m.nis, m.nama_lengkap ORDER BY m.nama_lengkap ASC; "; try { $stmt = $pdo->prepare($sql); $stmt->execute([ ':id_kelas' => $id_kelas, ':start_date' => $start_date, ':end_date' => $end_date ]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $e) { // Log error or handle it as needed error_log("Rekap Absensi Error: " . $e->getMessage()); return []; } } // Subject (Mata Pelajaran) Functions function get_all_matapelajaran() { $pdo = db(); $stmt = $pdo->query("SELECT * FROM mata_pelajaran ORDER BY nama_matapelajaran ASC"); return $stmt->fetchAll(PDO::FETCH_ASSOC); } function get_matapelajaran_by_id($id) { $pdo = db(); $stmt = $pdo->prepare("SELECT * FROM mata_pelajaran WHERE id = ?"); $stmt->execute([$id]); return $stmt->fetch(PDO::FETCH_ASSOC); } function handle_matapelajaran_action() { $action = $_POST['action'] ?? $_GET['action'] ?? ''; if ($action === 'delete' && isset($_GET['id'])) { $id = $_GET['id']; $pdo = db(); try { $stmt = $pdo->prepare("DELETE FROM mata_pelajaran WHERE id = ?"); $stmt->execute([$id]); header("Location: index.php?page=subjects&status=deleted"); exit(); } catch (PDOException $e) { header("Location: index.php?page=subjects&status=error&err_msg=" . urlencode($e->getMessage())); exit(); } } if ($_SERVER['REQUEST_METHOD'] !== 'POST') { return null; } $pdo = db(); $id = $_POST['id'] ?? null; $nama_matapelajaran = $_POST['nama_matapelajaran'] ?? ''; try { if ($action === 'add') { $stmt = $pdo->prepare("INSERT INTO mata_pelajaran (nama_matapelajaran) VALUES (?)"); $stmt->execute([$nama_matapelajaran]); return ['success' => true, 'message' => 'Data mata pelajaran berhasil ditambahkan.']; } elseif ($action === 'edit' && $id) { $stmt = $pdo->prepare("UPDATE mata_pelajaran SET nama_matapelajaran = ? WHERE id = ?"); $stmt->execute([$nama_matapelajaran, $id]); return ['success' => true, 'message' => 'Data mata pelajaran berhasil diperbarui.']; } } catch (PDOException $e) { if ($e->getCode() == 23000) { return ['success' => false, 'message' => 'Gagal menyimpan data. Nama mata pelajaran mungkin sudah ada.']; } return ['success' => false, 'message' => 'Terjadi kesalahan database: ' . $e->getMessage()]; } return null; } ?>