# Tutorial Hari 5: CRUD Peta (GeoJSON)

## 🎯 Tujuan
- Memahami format GeoJSON
- Membuat fungsi CRUD untuk peta
- Membuat bagian pertama library spatial.php
- Memahami koordinat geografis

---

## 📚 Teori: Format GeoJSON

### Apa itu GeoJSON?

GeoJSON adalah format standar untuk menyimpan data geografis dalam bentuk JSON. Format ini digunakan oleh hampir semua library peta seperti Leaflet, Google Maps, dll.

### Struktur GeoJSON

```json
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": { "nama": "Batas Desa" },
      "geometry": {
        "type": "Polygon",
        "coordinates": [[[lng, lat], [lng, lat], ...]]
      }
    }
  ]
}
```

### Tipe Geometry GeoJSON

| Tipe | Kegunaan | Contoh |
|------|----------|--------|
| **Point** | Titik tunggal | Lokasi sekolah, masjid |
| **LineString** | Garis/jalur | Jalan, sungai |
| **Polygon** | Area tertutup | Batas desa, sawah |
| **MultiPoint** | Banyak titik | Cluster fasilitas |
| **MultiPolygon** | Banyak area | Desa dengan enclave |

### Format Koordinat

> ⚠️ **PENTING:** GeoJSON menggunakan format `[longitude, latitude]` bukan `[latitude, longitude]`!

| Format | Urutan | Contoh Jakarta |
|--------|--------|----------------|
| GPS biasa | lat, lng | -6.2, 106.8 |
| **GeoJSON** | **lng, lat** | **106.8, -6.2** |

### Contoh Point (Titik)

```json
{
  "type": "Feature",
  "properties": {
    "nama": "SDN 01 Bogor",
    "jenis": "pendidikan"
  },
  "geometry": {
    "type": "Point",
    "coordinates": [106.7952, -6.5891]
  }
}
```

### Contoh Polygon (Area)

```json
{
  "type": "Feature",
  "properties": { "nama": "Batas Desa" },
  "geometry": {
    "type": "Polygon",
    "coordinates": [[
      [106.79, -6.58],
      [106.80, -6.58],
      [106.80, -6.59],
      [106.79, -6.59],
      [106.79, -6.58]
    ]]
  }
}
```

> 💡 Polygon harus **tertutup** - titik pertama dan terakhir harus sama!

---

## 📚 Teori: CRUD Pattern

### Apa itu CRUD?

CRUD adalah singkatan dari operasi dasar database:

| Huruf | Operasi | SQL | HTTP Method |
|-------|---------|-----|-------------|
| **C** | Create | INSERT | POST |
| **R** | Read | SELECT | GET |
| **U** | Update | UPDATE | PUT/PATCH |
| **D** | Delete | DELETE | DELETE |

### Flow CRUD

```
User → Controller → Model → Database
  ↑                           ↓
  └───────── Response ←───────┘
```

---

## 1. Buat File spatial.php (Bagian Peta)

### Langkah 1: Buat file baru

1. Klik kanan folder **lib**
2. New File → `spatial.php`

### Langkah 2: Tulis Kode

```php
<?php
/**
 * ==========================================
 * Spatial Functions Library
 * ==========================================
 * Library untuk operasi data spasial
 * Bagian 1: CRUD Peta
 * ==========================================
 */

require_once __DIR__ . '/../config/database.php';

// ==========================================
// CRUD PETA
// ==========================================

/**
 * Ambil semua peta milik user tertentu
 * 
 * @param int $userId - ID user
 * @return array - Daftar peta
 */
function getUserPeta($userId) {
    try {
        $stmt = db()->prepare("
            SELECT id, nama_peta, deskripsi, center_lat, center_lng, 
                   zoom_level, created_at, updated_at
            FROM peta_desa 
            WHERE user_id = ? 
            ORDER BY updated_at DESC
        ");
        $stmt->execute([$userId]);
        return $stmt->fetchAll();
        
    } catch (Exception $e) {
        return [];
    }
}

/**
 * Ambil satu peta berdasarkan ID
 * 
 * @param int $petaId - ID peta
 * @param int|null $userId - ID user (untuk verifikasi)
 * @return array|null - Data peta atau null
 */
function getPetaById($petaId, $userId = null) {
    try {
        $sql = "SELECT * FROM peta_desa WHERE id = ?";
        $params = [$petaId];
        
        // Filter by user jika diberikan
        if ($userId !== null) {
            $sql .= " AND user_id = ?";
            $params[] = $userId;
        }
        
        $stmt = db()->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetch();
        
    } catch (Exception $e) {
        return null;
    }
}

/**
 * Buat peta baru
 * 
 * @param int $userId - ID user pemilik
 * @param string $namaPeta - Nama peta
 * @param string $deskripsi - Deskripsi (opsional)
 * @return array - ['success' => bool, 'message' => string, 'peta_id' => int]
 */
function createPeta($userId, $namaPeta, $deskripsi = '') {
    try {
        $stmt = db()->prepare("
            INSERT INTO peta_desa (user_id, nama_peta, deskripsi)
            VALUES (?, ?, ?)
        ");
        $stmt->execute([$userId, $namaPeta, $deskripsi]);
        
        return [
            'success' => true,
            'peta_id' => db()->lastInsertId(),
            'message' => 'Peta berhasil dibuat'
        ];
        
    } catch (Exception $e) {
        return [
            'success' => false, 
            'message' => 'Gagal membuat peta: ' . $e->getMessage()
        ];
    }
}

/**
 * Update data peta
 * 
 * @param int $petaId - ID peta
 * @param int $userId - ID user (verifikasi)
 * @param array $data - Data yang mau diupdate
 * @return array - ['success' => bool, 'message' => string]
 */
function updatePeta($petaId, $userId, $data) {
    try {
        $fields = [];
        $params = [];
        
        // Daftar field yang boleh diupdate
        $allowedFields = [
            'nama_peta', 
            'deskripsi', 
            'geojson_data', 
            'center_lat', 
            'center_lng', 
            'zoom_level'
        ];
        
        // Loop data, hanya ambil yang diizinkan
        foreach ($allowedFields as $field) {
            if (isset($data[$field])) {
                $fields[] = "$field = ?";
                $params[] = $data[$field];
            }
        }
        
        if (empty($fields)) {
            return ['success' => false, 'message' => 'Tidak ada data yang diupdate'];
        }
        
        // Tambahkan ID untuk WHERE clause
        $params[] = $petaId;
        $params[] = $userId;
        
        $sql = "UPDATE peta_desa SET " . implode(', ', $fields) . 
               " WHERE id = ? AND user_id = ?";
        
        $stmt = db()->prepare($sql);
        $stmt->execute($params);
        
        return ['success' => true, 'message' => 'Peta berhasil diupdate'];
        
    } catch (Exception $e) {
        return ['success' => false, 'message' => 'Gagal update: ' . $e->getMessage()];
    }
}

/**
 * Hapus peta
 * 
 * @param int $petaId - ID peta
 * @param int $userId - ID user (verifikasi)
 * @return array - ['success' => bool, 'message' => string]
 */
function deletePeta($petaId, $userId) {
    try {
        $stmt = db()->prepare("DELETE FROM peta_desa WHERE id = ? AND user_id = ?");
        $stmt->execute([$petaId, $userId]);
        
        return ['success' => true, 'message' => 'Peta berhasil dihapus'];
        
    } catch (Exception $e) {
        return ['success' => false, 'message' => 'Gagal menghapus peta'];
    }
}
```

### Daftar Fungsi Peta

| Fungsi | Operasi | Parameter | Return |
|--------|---------|-----------|--------|
| `getUserPeta()` | READ | `$userId` | array peta |
| `getPetaById()` | READ | `$petaId, $userId` | array atau null |
| `createPeta()` | CREATE | `$userId, $nama, $desc` | array status |
| `updatePeta()` | UPDATE | `$petaId, $userId, $data` | array status |
| `deletePeta()` | DELETE | `$petaId, $userId` | array status |

---

## 📚 Teori: Dynamic SQL

### Kenapa Dynamic Update?

Saat update, tidak semua field berubah. Contoh:
- User hanya ubah nama → kirim nama saja
- User ubah nama + deskripsi → kirim keduanya

```php
// ❌ TIDAK EFISIEN - update semua field
UPDATE peta_desa SET 
  nama = ?, deskripsi = ?, center_lat = ?, center_lng = ?
WHERE id = ?

// ✅ EFISIEN - hanya update yang berubah
UPDATE peta_desa SET nama = ? WHERE id = ?
```

### Cara Kerja Dynamic Update

```php
$fields = [];   // Menyimpan "field = ?"
$params = [];   // Menyimpan nilai

// Jika 'nama_peta' ada di $data
if (isset($data['nama_peta'])) {
    $fields[] = "nama_peta = ?";
    $params[] = $data['nama_peta'];
}

// Build SQL
$sql = "UPDATE peta SET " . implode(', ', $fields) . " WHERE id = ?";
// Hasil: "UPDATE peta SET nama_peta = ? WHERE id = ?"
```

---

## 2. Test Fungsi Peta

### Langkah 1: Update test.php

```php
<?php
/**
 * Test Spatial Functions - Peta
 */

require_once 'config/database.php';
require_once 'lib/spatial.php';

echo "<h2>🧪 Test CRUD Peta</h2>";

$userId = 1; // User demo

// ===== TEST 1: Create Peta =====
echo "<h3>Test 1: createPeta()</h3>";
$result = createPeta($userId, 'Peta Desa Test', 'Deskripsi peta untuk testing');

if ($result['success']) {
    echo "<p style='color: green;'>✅ Peta dibuat dengan ID: " . $result['peta_id'] . "</p>";
    $petaId = $result['peta_id'];
} else {
    echo "<p style='color: red;'>❌ " . $result['message'] . "</p>";
    exit;
}

// ===== TEST 2: Get User Peta =====
echo "<h3>Test 2: getUserPeta()</h3>";
$petaList = getUserPeta($userId);
echo "<p>Jumlah peta: <strong>" . count($petaList) . "</strong></p>";

echo "<table border='1' cellpadding='10'>";
echo "<tr><th>ID</th><th>Nama</th><th>Deskripsi</th><th>Created</th></tr>";
foreach ($petaList as $peta) {
    echo "<tr>";
    echo "<td>" . $peta['id'] . "</td>";
    echo "<td>" . $peta['nama_peta'] . "</td>";
    echo "<td>" . $peta['deskripsi'] . "</td>";
    echo "<td>" . $peta['created_at'] . "</td>";
    echo "</tr>";
}
echo "</table>";

// ===== TEST 3: Get Peta By ID =====
echo "<h3>Test 3: getPetaById()</h3>";
$peta = getPetaById($petaId, $userId);
if ($peta) {
    echo "<p style='color: green;'>✅ Peta ditemukan: " . $peta['nama_peta'] . "</p>";
} else {
    echo "<p style='color: red;'>❌ Peta tidak ditemukan</p>";
}

// ===== TEST 4: Update Peta =====
echo "<h3>Test 4: updatePeta()</h3>";
$result = updatePeta($petaId, $userId, [
    'nama_peta' => 'Peta Desa Updated',
    'center_lat' => -6.5,
    'center_lng' => 106.6
]);

if ($result['success']) {
    $peta = getPetaById($petaId, $userId);
    echo "<p style='color: green;'>✅ Update berhasil!</p>";
    echo "<p>Nama baru: <strong>" . $peta['nama_peta'] . "</strong></p>";
    echo "<p>Center: <strong>" . $peta['center_lat'] . ", " . $peta['center_lng'] . "</strong></p>";
} else {
    echo "<p style='color: red;'>❌ " . $result['message'] . "</p>";
}

// ===== TEST 5: Delete Peta =====
echo "<h3>Test 5: deletePeta()</h3>";
$result = deletePeta($petaId, $userId);

if ($result['success']) {
    echo "<p style='color: green;'>✅ Peta berhasil dihapus</p>";
} else {
    echo "<p style='color: red;'>❌ " . $result['message'] . "</p>";
}

echo "<hr>";
echo "<p style='color: green;'>✅ Semua test CRUD Peta selesai!</p>";
```

### Langkah 2: Jalankan Test

1. Buka: `http://localhost/pemetaan-desa/test.php`
2. Pastikan semua test ✅

---

## 📁 Struktur Akhir Hari 5

```
📁 pemetaan-desa/
├── 📁 lib/
│   ├── 📄 auth.php
│   ├── 📄 helpers.php
│   └── 📄 spatial.php    ← BARU (bagian peta)
└── 📄 test.php           ← UPDATED
```

---

**← [Hari 4: Autentikasi](hari4.md) | [Hari 6: CRUD Fasilitas](hari6.md) →**
