initial commit
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
// api/penduduk_miskin.php
|
||||
require_once __DIR__ . '/config/database.php';
|
||||
require_once __DIR__ . '/helpers/response.php';
|
||||
setCORSHeaders();
|
||||
|
||||
$db = getDB();
|
||||
$method = getMethod();
|
||||
requireWriteAuth($method);
|
||||
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||||
|
||||
// Endpoint khusus: recalc proximity semua penduduk miskin sekaligus
|
||||
if ($method === 'POST' && isset($_GET['action']) && $_GET['action'] === 'recalc_all') {
|
||||
requireWriteAuth('POST');
|
||||
$allPm = $db->query("SELECT id, latitude, longitude FROM penduduk_miskin");
|
||||
$updated = 0;
|
||||
while ($pm = $allPm->fetch_assoc()) {
|
||||
$prox = hitungProximity($db, (float)$pm['latitude'], (float)$pm['longitude']);
|
||||
$statusP = $prox['status'];
|
||||
$riId = $prox['rumah_ibadah_id'];
|
||||
$stmt = $db->prepare(
|
||||
"UPDATE penduduk_miskin SET status_proximity=?, rumah_ibadah_id=? WHERE id=?"
|
||||
);
|
||||
$stmt->bind_param('sii', $statusP, $riId, $pm['id']);
|
||||
$stmt->execute();
|
||||
$updated++;
|
||||
}
|
||||
sendSuccess(['updated' => $updated], "Proximity $updated data diperbarui");
|
||||
}
|
||||
|
||||
switch ($method) {
|
||||
|
||||
// ── GET ───────────────────────────────────────────────────────────
|
||||
case 'GET':
|
||||
if ($id > 0) {
|
||||
$stmt = $db->prepare(
|
||||
"SELECT pm.*,
|
||||
ri.nama AS nama_rumah_ibadah,
|
||||
ri.jenis AS jenis_rumah_ibadah
|
||||
FROM penduduk_miskin pm
|
||||
LEFT JOIN rumah_ibadah ri ON ri.id = pm.rumah_ibadah_id
|
||||
WHERE pm.id = ?"
|
||||
);
|
||||
$stmt->bind_param('i', $id);
|
||||
$stmt->execute();
|
||||
$row = $stmt->get_result()->fetch_assoc();
|
||||
if (!$row) sendError('Data tidak ditemukan', 404);
|
||||
$row['latitude'] = (float)$row['latitude'];
|
||||
$row['longitude'] = (float)$row['longitude'];
|
||||
|
||||
// Ambil ringkasan log bantuan
|
||||
$stmtLog = $db->prepare(
|
||||
"SELECT tipe_bantuan, COUNT(*) AS jumlah
|
||||
FROM log_bantuan
|
||||
WHERE penduduk_miskin_id = ?
|
||||
GROUP BY tipe_bantuan"
|
||||
);
|
||||
$stmtLog->bind_param('i', $id);
|
||||
$stmtLog->execute();
|
||||
$logs = [];
|
||||
$resLog = $stmtLog->get_result();
|
||||
while ($l = $resLog->fetch_assoc()) $logs[] = $l;
|
||||
$row['ringkasan_bantuan'] = $logs;
|
||||
|
||||
sendSuccess($row);
|
||||
} else {
|
||||
// GET semua + proximity recalculation cache
|
||||
$sql = "SELECT pm.id, pm.nama, pm.no_wa, pm.nik, pm.alamat,
|
||||
pm.jumlah_anggota, pm.latitude, pm.longitude,
|
||||
pm.status_proximity, pm.rumah_ibadah_id,
|
||||
ri.nama AS nama_rumah_ibadah,
|
||||
-- hitung berapa kali dapat bantuan
|
||||
(SELECT COUNT(*) FROM log_bantuan lb
|
||||
WHERE lb.penduduk_miskin_id = pm.id) AS total_bantuan,
|
||||
(SELECT COUNT(*) FROM log_bantuan lb
|
||||
WHERE lb.penduduk_miskin_id = pm.id
|
||||
AND lb.tipe_bantuan = 'Pemberdayaan') AS bantuan_pemberdayaan,
|
||||
(SELECT COUNT(*) FROM log_bantuan lb
|
||||
WHERE lb.penduduk_miskin_id = pm.id
|
||||
AND lb.tipe_bantuan = 'Konsumtif') AS bantuan_konsumtif
|
||||
FROM penduduk_miskin pm
|
||||
LEFT JOIN rumah_ibadah ri ON ri.id = pm.rumah_ibadah_id
|
||||
ORDER BY pm.created_at DESC";
|
||||
$result = $db->query($sql);
|
||||
$rows = [];
|
||||
while ($r = $result->fetch_assoc()) {
|
||||
$r['latitude'] = (float)$r['latitude'];
|
||||
$r['longitude'] = (float)$r['longitude'];
|
||||
$r['total_bantuan'] = (int)$r['total_bantuan'];
|
||||
$r['bantuan_pemberdayaan'] = (int)$r['bantuan_pemberdayaan'];
|
||||
$r['bantuan_konsumtif'] = (int)$r['bantuan_konsumtif'];
|
||||
$rows[] = $r;
|
||||
}
|
||||
sendSuccess($rows);
|
||||
}
|
||||
break;
|
||||
|
||||
// ── POST ──────────────────────────────────────────────────────────
|
||||
case 'POST':
|
||||
$body = getBody();
|
||||
foreach (['nama', 'latitude', 'longitude'] as $f) {
|
||||
if (empty($body[$f]) && $body[$f] !== 0) sendError("Field '$f' wajib diisi");
|
||||
}
|
||||
|
||||
// Hitung proximity ke semua rumah ibadah
|
||||
$proximity = hitungProximity($db, $body['latitude'], $body['longitude']);
|
||||
|
||||
$stmt = $db->prepare(
|
||||
"INSERT INTO penduduk_miskin
|
||||
(nama, no_wa, nik, alamat, jumlah_anggota,
|
||||
latitude, longitude, status_proximity, rumah_ibadah_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
||||
);
|
||||
$jumlah = isset($body['jumlah_anggota']) ? (int)$body['jumlah_anggota'] : 1;
|
||||
$statusP = $proximity['status'];
|
||||
$riId = $proximity['rumah_ibadah_id'];
|
||||
|
||||
$stmt->bind_param(
|
||||
'ssssiddsi',
|
||||
$body['nama'], $body['no_wa'], $body['nik'],
|
||||
$body['alamat'], $jumlah,
|
||||
$body['latitude'], $body['longitude'],
|
||||
$statusP, $riId
|
||||
);
|
||||
executeOrFail($stmt, 'Gagal menyimpan data penduduk miskin');
|
||||
$newId = $db->insert_id;
|
||||
sendSuccess(
|
||||
['id' => $newId, 'proximity' => $proximity],
|
||||
'Penduduk Miskin berhasil disimpan',
|
||||
201
|
||||
);
|
||||
break;
|
||||
|
||||
// ── PUT ───────────────────────────────────────────────────────────
|
||||
case 'PUT':
|
||||
if ($id <= 0) sendError('ID wajib disertakan');
|
||||
$body = getBody();
|
||||
$proximity = hitungProximity($db, $body['latitude'], $body['longitude']);
|
||||
$statusP = $proximity['status'];
|
||||
$riId = $proximity['rumah_ibadah_id'];
|
||||
$jumlah = isset($body['jumlah_anggota']) ? (int)$body['jumlah_anggota'] : 1;
|
||||
|
||||
$stmt = $db->prepare(
|
||||
"UPDATE penduduk_miskin
|
||||
SET nama=?, no_wa=?, nik=?, alamat=?, jumlah_anggota=?,
|
||||
latitude=?, longitude=?, status_proximity=?, rumah_ibadah_id=?
|
||||
WHERE id=?"
|
||||
);
|
||||
$stmt->bind_param(
|
||||
'ssssiddsii',
|
||||
$body['nama'], $body['no_wa'], $body['nik'],
|
||||
$body['alamat'], $jumlah,
|
||||
$body['latitude'], $body['longitude'],
|
||||
$statusP, $riId, $id
|
||||
);
|
||||
executeOrFail($stmt, 'Gagal memperbarui data penduduk miskin');
|
||||
sendSuccess(['proximity' => $proximity], 'Data berhasil diperbarui');
|
||||
break;
|
||||
|
||||
// ── DELETE ────────────────────────────────────────────────────────
|
||||
case 'DELETE':
|
||||
if ($id <= 0) sendError('ID wajib disertakan');
|
||||
$stmt = $db->prepare("DELETE FROM penduduk_miskin WHERE id=?");
|
||||
$stmt->bind_param('i', $id);
|
||||
executeOrFail($stmt, 'Gagal menghapus data penduduk miskin');
|
||||
$stmt->affected_rows > 0
|
||||
? sendSuccess(null, 'Data berhasil dihapus')
|
||||
: sendError('Data tidak ditemukan', 404);
|
||||
break;
|
||||
|
||||
default:
|
||||
sendError('Method tidak diizinkan', 405);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// HELPER: Hitung proximity penduduk miskin terhadap semua rumah ibadah
|
||||
// Menggunakan Haversine formula di PHP untuk validasi server-side
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
function hitungProximity(mysqli $db, float $lat, float $lng): array {
|
||||
$result = $db->query(
|
||||
"SELECT id, nama, latitude, longitude, radius_meter FROM rumah_ibadah"
|
||||
);
|
||||
$status = 'luar_radius';
|
||||
$riId = null;
|
||||
$riNama = null;
|
||||
$minDistAll = PHP_INT_MAX; // jarak ke RI terdekat (apapun statusnya)
|
||||
$minDistIn = PHP_INT_MAX; // jarak ke RI terdekat yang dalam radius
|
||||
|
||||
while ($ri = $result->fetch_assoc()) {
|
||||
$dist = haversine($lat, $lng, (float)$ri['latitude'], (float)$ri['longitude']);
|
||||
|
||||
// Lacak jarak terdekat secara keseluruhan (untuk field jarak_meter)
|
||||
if ($dist < $minDistAll) {
|
||||
$minDistAll = $dist;
|
||||
}
|
||||
|
||||
// Cek apakah titik ini masuk dalam radius RI ini
|
||||
if ($dist <= (int)$ri['radius_meter'] && $dist < $minDistIn) {
|
||||
$minDistIn = $dist;
|
||||
$status = 'dalam_radius';
|
||||
$riId = (int)$ri['id'];
|
||||
$riNama = $ri['nama'];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => $status,
|
||||
'rumah_ibadah_id' => $riId,
|
||||
'nama_rumah_ibadah' => $riNama,
|
||||
'jarak_meter' => round($minDistAll, 2)
|
||||
];
|
||||
}
|
||||
|
||||
function haversine(float $lat1, float $lng1, float $lat2, float $lng2): float {
|
||||
$R = 6371000; // radius bumi dalam meter
|
||||
$dLat = deg2rad($lat2 - $lat1);
|
||||
$dLng = deg2rad($lng2 - $lng1);
|
||||
$a = sin($dLat/2)**2
|
||||
+ cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLng/2)**2;
|
||||
return $R * 2 * atan2(sqrt($a), sqrt(1-$a));
|
||||
}
|
||||
Reference in New Issue
Block a user