Files
UAS_WEBGIS_CindyDyraIslamay…/03PovertyMapping/api/centers/index.php
T

334 lines
12 KiB
PHP

<?php
// api/centers/index.php - FINAL VERSION
declare(strict_types=1);
require_once __DIR__ . '/../../config/bootstrap.php';
$method = $_SERVER['REQUEST_METHOD'];
$action = $_GET['action'] ?? 'list';
$id = isset($_GET['id']) ? (int)$_GET['id'] : null;
// sendJSON function removed in favor of Response::success and Response::error
try {
switch ("$method:$action") {
case 'GET:list':
case 'GET:': {
$pdo = Database::get();
$where = ['rc.is_active = 1'];
$params = [];
if (!empty($_GET['type'])) {
$allowed = ['masjid','gereja','klenteng','pura','vihara'];
if (in_array($_GET['type'], $allowed, true)) {
$where[] = 'rc.worship_type = ?';
$params[] = $_GET['type'];
}
}
if (!empty($_GET['q'])) {
$where[] = '(rc.name LIKE ? OR rc.address LIKE ?)';
$q = '%' . $_GET['q'] . '%';
$params[] = $q; $params[] = $q;
}
$whereSQL = implode(' AND ', $where);
// Query tanpa subquery yang bermasalah
$stmt = $pdo->prepare("
SELECT
rc.id, rc.name, rc.worship_type, rc.address,
rc.kelurahan, rc.kecamatan,
rc.latitude, rc.longitude, rc.radius,
rc.contact_person, rc.contact_phone, rc.notes,
rc.is_active, rc.created_at, rc.updated_at
FROM religious_centers rc
WHERE $whereSQL
ORDER BY rc.name
");
$stmt->execute($params);
$rows = $stmt->fetchAll();
// Hitung household_count dan pending_aid_count secara terpisah
foreach ($rows as &$r) {
$r['latitude'] = (float)$r['latitude'];
$r['longitude'] = (float)$r['longitude'];
$r['radius'] = (int)$r['radius'];
// Hitung jumlah rumah yang dikelola center ini
$countStmt = $pdo->prepare("
SELECT COUNT(*) FROM households
WHERE managing_center_id = ? AND is_active = 1
");
$countStmt->execute([$r['id']]);
$r['household_count'] = (int)$countStmt->fetchColumn();
// Hitung jumlah rumah yang belum terima bantuan
$pendingStmt = $pdo->prepare("
SELECT COUNT(*) FROM households
WHERE managing_center_id = ? AND is_active = 1 AND aid_status = 'not_yet'
");
$pendingStmt->execute([$r['id']]);
$r['pending_aid_count'] = (int)$pendingStmt->fetchColumn();
}
unset($r);
Response::success(['centers' => $rows, 'total' => count($rows)]);
break;
}
case 'GET:show': {
if (!$id) Response::error('ID required', 400);
$pdo = Database::get();
$stmt = $pdo->prepare("
SELECT * FROM religious_centers
WHERE id = ? AND is_active = 1
");
$stmt->execute([$id]);
$row = $stmt->fetch();
if (!$row) {
Response::notFound('Not found');
}
$row['latitude'] = (float)$row['latitude'];
$row['longitude'] = (float)$row['longitude'];
$row['radius'] = (int)$row['radius'];
Response::success($row);
break;
}
case 'GET:nearby': {
$lat = (float)($_GET['lat'] ?? 0);
$lng = (float)($_GET['lng'] ?? 0);
$km = min(50, (float)($_GET['km'] ?? 5));
if ($lat === 0.0 && $lng === 0.0) {
Response::error('lat and lng required', 400);
}
$pdo = Database::get();
$stmt = $pdo->prepare("
SELECT
id, name, worship_type, address,
latitude, longitude, radius,
(6371 * ACOS(
COS(RADIANS(?)) * COS(RADIANS(latitude)) *
COS(RADIANS(longitude) - RADIANS(?)) +
SIN(RADIANS(?)) * SIN(RADIANS(latitude))
)) AS distance_km
FROM religious_centers
WHERE is_active = 1
HAVING distance_km <= ?
ORDER BY distance_km
LIMIT 10
");
$stmt->execute([$lat, $lng, $lat, $km]);
$rows = $stmt->fetchAll();
foreach ($rows as &$r) {
$r['latitude'] = (float)$r['latitude'];
$r['longitude'] = (float)$r['longitude'];
$r['radius'] = (int)$r['radius'];
$r['distance_km'] = round((float)$r['distance_km'], 3);
}
unset($r);
Response::success(['centers' => $rows]);
break;
}
case 'GET:coverage': {
if (!$id) Response::error('ID required', 400);
$pdo = Database::get();
$center = $pdo->prepare("SELECT * FROM religious_centers WHERE id = ? AND is_active = 1");
$center->execute([$id]);
$c = $center->fetch();
if (!$c) {
Response::notFound('Center not found');
}
$stmt = $pdo->prepare("
SELECT
id, head_name, full_address, latitude, longitude,
poverty_status, aid_status
FROM households
WHERE is_active = 1
");
$stmt->execute();
$allHouseholds = $stmt->fetchAll();
$households = [];
foreach ($allHouseholds as $h) {
$distance = haversineDistance(
(float)$c['latitude'], (float)$c['longitude'],
(float)$h['latitude'], (float)$h['longitude']
);
if ($distance <= (float)$c['radius']) {
$h['distance_m'] = round($distance, 1);
$h['latitude'] = (float)$h['latitude'];
$h['longitude'] = (float)$h['longitude'];
$households[] = $h;
}
}
usort($households, function($a, $b) {
return $a['distance_m'] <=> $b['distance_m'];
});
Response::success([
'center' => $c,
'households' => $households,
'count' => count($households)
]);
break;
}
case 'POST:create': {
requireAuth();
$data = Validator::json();
$pdo = Database::get();
$stmt = $pdo->prepare("
INSERT INTO religious_centers
(name, worship_type, address, latitude, longitude, radius,
contact_person, contact_phone, notes)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
");
$stmt->execute([
$data['name'] ?? '',
$data['worship_type'] ?? 'masjid',
$data['address'] ?? '',
(float)($data['latitude'] ?? 0),
(float)($data['longitude'] ?? 0),
(int)($data['radius'] ?? 300),
$data['contact_person'] ?? null,
$data['contact_phone'] ?? null,
$data['notes'] ?? null
]);
$newId = (int)$pdo->lastInsertId();
AuditLog::record('Tambah Tempat Ibadah', 'religious_centers', $newId, null, $data);
Response::created(['id' => $newId], 'Center created');
break;
}
case 'POST:update': {
requireAuth();
if (!$id) Response::error('ID required', 400);
$data = Validator::json();
$pdo = Database::get();
$old = $pdo->prepare("SELECT * FROM religious_centers WHERE id = ? AND is_active = 1");
$old->execute([$id]);
$oldRow = $old->fetch();
if (!$oldRow) {
Response::notFound('Not found');
}
$stmt = $pdo->prepare("
UPDATE religious_centers SET
name = ?, worship_type = ?, address = ?,
latitude = ?, longitude = ?, radius = ?,
contact_person = ?, contact_phone = ?, notes = ?
WHERE id = ? AND is_active = 1
");
$stmt->execute([
$data['name'] ?? $oldRow['name'],
$data['worship_type'] ?? $oldRow['worship_type'],
$data['address'] ?? $oldRow['address'],
(float)($data['latitude'] ?? $oldRow['latitude']),
(float)($data['longitude'] ?? $oldRow['longitude']),
(int)($data['radius'] ?? $oldRow['radius']),
$data['contact_person'] ?? $oldRow['contact_person'],
$data['contact_phone'] ?? $oldRow['contact_phone'],
$data['notes'] ?? $oldRow['notes'],
$id
]);
AuditLog::record('Update Tempat Ibadah', 'religious_centers', $id, $oldRow, $data);
Response::success(null, 'Updated');
break;
}
case 'POST:patch': {
requireAuth();
if (!$id) Response::error('ID required', 400);
$data = Validator::json();
$fields = [];
$params = [];
if (isset($data['radius'])) {
$fields[] = 'radius = ?';
$params[] = (int)$data['radius'];
}
if (isset($data['latitude']) && isset($data['longitude'])) {
$fields[] = 'latitude = ?';
$params[] = (float)$data['latitude'];
$fields[] = 'longitude = ?';
$params[] = (float)$data['longitude'];
if (isset($data['address'])) {
$fields[] = 'address = ?';
$params[] = $data['address'];
}
}
if (empty($fields)) {
Response::error('No fields to update', 400);
}
$params[] = $id;
$sql = "UPDATE religious_centers SET " . implode(', ', $fields) . " WHERE id = ? AND is_active = 1";
$pdo = Database::get();
$pdo->prepare($sql)->execute($params);
AuditLog::record('Geser/Resize Tempat Ibadah', 'religious_centers', $id, null, $data);
Response::success(null, 'Patched');
break;
}
case 'POST:delete': {
requireAdmin();
if (!$id) Response::error('ID required', 400);
$pdo = Database::get();
$old = $pdo->prepare("SELECT * FROM religious_centers WHERE id = ? AND is_active = 1");
$old->execute([$id]);
$oldRow = $old->fetch();
if (!$oldRow) {
Response::notFound('Not found');
}
$pdo->prepare("UPDATE religious_centers SET is_active = 0 WHERE id = ?")->execute([$id]);
AuditLog::record('Hapus Tempat Ibadah', 'religious_centers', $id, $oldRow);
Response::success(null, 'Deleted');
break;
}
default:
Response::methodNotAllowed();
}
} catch (Exception $e) {
$message = APP_DEBUG ? $e->getMessage() : 'Internal Server Error';
Response::error($message, 500);
}
function haversineDistance($lat1, $lon1, $lat2, $lon2) {
$R = 6371000;
$dLat = deg2rad($lat2 - $lat1);
$dLon = deg2rad($lon2 - $lon1);
$a = sin($dLat/2) * sin($dLat/2) +
cos(deg2rad($lat1)) * cos(deg2rad($lat2)) *
sin($dLon/2) * sin($dLon/2);
$c = 2 * atan2(sqrt($a), sqrt(1-$a));
return $R * $c;
}