Files
WebGIS_PovertyMap/Leaflet2/api/penduduk_feature_helper.php
T

180 lines
6.4 KiB
PHP

<?php
declare(strict_types=1);
function ensurePendudukFeatureSchema(PDO $pdo): void
{
$columns = [
'kategori_kebutuhan' => "ALTER TABLE penduduk_miskin ADD COLUMN kategori_kebutuhan VARCHAR(100) NULL AFTER status_bantuan",
'deskripsi_kebutuhan' => "ALTER TABLE penduduk_miskin ADD COLUMN deskripsi_kebutuhan TEXT NULL AFTER kategori_kebutuhan",
'tindak_lanjut' => "ALTER TABLE penduduk_miskin ADD COLUMN tindak_lanjut VARCHAR(60) NOT NULL DEFAULT 'Belum disurvei' AFTER deskripsi_kebutuhan",
'kondisi_rumah' => "ALTER TABLE penduduk_miskin ADD COLUMN kondisi_rumah VARCHAR(80) NULL AFTER tindak_lanjut",
'penghasilan' => "ALTER TABLE penduduk_miskin ADD COLUMN penghasilan INT NULL AFTER kondisi_rumah",
'catatan_survei' => "ALTER TABLE penduduk_miskin ADD COLUMN catatan_survei TEXT NULL AFTER penghasilan",
'bukti_file' => "ALTER TABLE penduduk_miskin ADD COLUMN bukti_file VARCHAR(255) NULL AFTER catatan_survei",
'skor_prioritas' => "ALTER TABLE penduduk_miskin ADD COLUMN skor_prioritas INT NOT NULL DEFAULT 0 AFTER bukti_file",
];
foreach ($columns as $column => $sql) {
$stmt = $pdo->query("SHOW COLUMNS FROM penduduk_miskin LIKE " . $pdo->quote($column));
if ($stmt->fetch() === false) {
$pdo->exec($sql);
}
}
$pdo->exec("
CREATE TABLE IF NOT EXISTS riwayat_bantuan (
id INT AUTO_INCREMENT PRIMARY KEY,
penduduk_id INT NOT NULL,
jenis_bantuan VARCHAR(120) NOT NULL,
tanggal_bantuan DATE NOT NULL,
nilai_bantuan VARCHAR(80) NULL,
pemberi_bantuan VARCHAR(120) NULL,
catatan TEXT NULL,
bukti_file VARCHAR(255) NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (penduduk_id) REFERENCES penduduk_miskin(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
");
}
function normalizeDateOrNull(?string $value): ?string
{
$value = trim((string)$value);
return $value === '' || $value === '0000-00-00' ? null : $value;
}
function normalizeNonNegativeIntOrNull(mixed $value, string $label): ?int
{
$value = trim((string)$value);
if ($value === '') {
return null;
}
if (!is_numeric($value) || (float)$value < 0) {
throw new InvalidArgumentException($label . ' tidak boleh bernilai negatif.');
}
return (int)$value;
}
function calculatePriorityScore(array $penduduk, array $anggota = []): int
{
$score = 0;
$anggotaCount = count($anggota);
$penghasilan = isset($penduduk['penghasilan']) ? (int)$penduduk['penghasilan'] : 0;
if (($penduduk['status_bantuan'] ?? '') === 'Belum dibantu') $score += 30;
if (($penduduk['status_bantuan'] ?? '') === 'Menunggu verifikasi') $score += 15;
if ((int)($penduduk['is_blank_spot'] ?? 0) === 1) $score += 15;
$score += min(20, $anggotaCount * 4);
foreach ($anggota as $a) {
$umur = isset($a['umur']) ? (int)$a['umur'] : null;
if ($umur !== null && ($umur < 6 || $umur >= 60)) {
$score += 5;
}
}
if ($penghasilan > 0 && $penghasilan <= 1000000) $score += 15;
elseif ($penghasilan > 1000000 && $penghasilan <= 2000000) $score += 8;
$kondisi = strtolower((string)($penduduk['kondisi_rumah'] ?? ''));
if (str_contains($kondisi, 'tidak layak')) $score += 15;
elseif (str_contains($kondisi, 'rentan')) $score += 8;
$kebutuhan = strtolower((string)($penduduk['kategori_kebutuhan'] ?? ''));
if (in_array($kebutuhan, ['kesehatan', 'rumah tidak layak', 'bantuan darurat'], true)) $score += 10;
return min(100, max(0, $score));
}
function getPriorityLabel(int $score): string
{
if ($score >= 70) return 'Prioritas Tinggi';
if ($score >= 40) return 'Prioritas Sedang';
return 'Prioritas Rendah';
}
function saveUploadedEvidence(string $fieldName): ?string
{
if (empty($_FILES[$fieldName]) || !is_array($_FILES[$fieldName])) {
return null;
}
$file = $_FILES[$fieldName];
if (($file['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) {
return null;
}
if (($file['error'] ?? UPLOAD_ERR_OK) !== UPLOAD_ERR_OK) {
throw new RuntimeException('Upload bukti gagal.');
}
if (($file['size'] ?? 0) > 3 * 1024 * 1024) {
throw new RuntimeException('Ukuran bukti maksimal 3 MB.');
}
$allowed = [
'image/jpeg' => 'jpg',
'image/png' => 'png',
'image/webp' => 'webp',
'application/pdf' => 'pdf',
];
$mime = mime_content_type($file['tmp_name']);
if (!isset($allowed[$mime])) {
throw new RuntimeException('Format bukti harus JPG, PNG, WEBP, atau PDF.');
}
$dir = __DIR__ . '/../uploads/bukti';
if (!is_dir($dir) && !mkdir($dir, 0775, true) && !is_dir($dir)) {
throw new RuntimeException('Folder upload tidak bisa dibuat.');
}
$filename = date('YmdHis') . '-' . bin2hex(random_bytes(6)) . '.' . $allowed[$mime];
$target = $dir . '/' . $filename;
if (!move_uploaded_file($file['tmp_name'], $target)) {
throw new RuntimeException('Bukti tidak bisa disimpan.');
}
return 'uploads/bukti/' . $filename;
}
function readPendudukInput(): array
{
if (str_starts_with((string)($_SERVER['CONTENT_TYPE'] ?? ''), 'multipart/form-data')) {
$input = $_POST;
$input['anggota'] = json_decode((string)($_POST['anggota'] ?? '[]'), true) ?: [];
return $input;
}
return json_decode(file_get_contents('php://input'), true) ?: [];
}
function updatePendudukPriority(PDO $pdo, int $pendudukId): void
{
$stmt = $pdo->prepare("SELECT * FROM penduduk_miskin WHERE id = ?");
$stmt->execute([$pendudukId]);
$penduduk = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$penduduk) return;
$stmtAnggota = $pdo->prepare("SELECT * FROM anggota_keluarga WHERE penduduk_id = ?");
$stmtAnggota->execute([$pendudukId]);
$anggota = $stmtAnggota->fetchAll(PDO::FETCH_ASSOC);
$score = calculatePriorityScore($penduduk, $anggota);
$update = $pdo->prepare("UPDATE penduduk_miskin SET skor_prioritas = ? WHERE id = ?");
$update->execute([$score, $pendudukId]);
}
function refreshAllPriorityScores(PDO $pdo): void
{
ensurePendudukFeatureSchema($pdo);
$ids = $pdo->query("SELECT id FROM penduduk_miskin")->fetchAll(PDO::FETCH_COLUMN);
foreach ($ids as $id) {
updatePendudukPriority($pdo, (int)$id);
}
}