Pendahuluan — siapa boleh ubah catatan pinjam?

Artikel ini adalah #64 (ini) di Seri 5: Laravel Lanjutan (di roadmap sering disebut Framework-based). Domain tetap perpustakaan mini.

Di Pagination, Filter & Pencarian (#63) kamu sudah merapikan daftar panjang. Sekarang pertanyaan berikutnya: siapa boleh mengubah atau menghapus catatan pinjam orang lain? Tanpa aturan, siapa saja bisa mengubah data — berbahaya.

Awam: bayangkan kartu anggota perpustakaan. Hanya pemilik kartu (atau petugas resmi) yang boleh mengubah catatan pinjam miliknya. Itu inti aturan izin (policy).

Prasyarat: sudah baca Pagination & Pencarian (#63) dan Relasi Eloquent (#62). Pakai Laravel 11+.

Spesifikasi fitur — apa yang kita bangun?

Daftar singkat yang bisa dijelaskan ke teman:

  1. Cek pemilik — sebelum ubah/hapus, pastikan pemanggil adalah pemilik catatan (atau punya peran khusus).
  2. Jawaban jelas saat ditolak — status 403 dengan pesan awam “Tidak punya izin”.
  3. Aturan terpusat — logika “boleh/tidak” tidak tersebar di banyak tempat.

Awam: urutan kerja yang nyaman: kenali siapa memanggil -> cek pemilik -> baru ubah data. Kalau langsung ubah tanpa cek, siapa pun bisa merusak catatan orang lain.

Istilah — ringkas untuk aturan izin

Istilah Arti awam Catatan
Aturan izin / policy Daftar “siapa boleh apa” Bukan kata sandi login
Pemilik / anggota_id Anggota yang punya catatan pinjam Dari relasi di Relasi Eloquent (#62)
403 Forbidden Tidak punya izin Beda dengan “belum login”
authorize Perintah “cek aturan izin dulu” Di Laravel, sebelum aksi sensitif
Kelas Policy File tempat aturan ditulis rapi Satu tempat untuk “boleh ubah?”

Urutan belajar: array PHP dulu -> cek pemilik dengan if -> baru bungkus Laravel Policy.

Kenapa PHP biasa dulu?

Ide “hanya pemilik yang boleh ubah” lebih mudah dirasakan di array. Kalau alurnya klik, cuplikan authorize dan kelas Policy terasa bungkus yang sama.

<?php
// Mini: cek pemilik sebelum ubah status pinjam.
$pinjam = ["id" => 10, "anggota_id" => 1, "judul" => "Dasar PHP", "status" => "aktif"];
$penggunaId = 2; // bukan pemilik

if ($pinjam["anggota_id"] !== $penggunaId) {
    http_response_code(403);
    echo json_encode(["pesan" => "Tidak punya izin"], JSON_UNESCAPED_UNICODE), PHP_EOL;
    exit;
}

$pinjam["status"] = "kembali";
echo json_encode(["ok" => true, "data" => $pinjam], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), PHP_EOL;

Output saat bukan pemilik:

{
    "pesan": "Tidak punya izin"
}

Awam: anggota_id di catatan harus sama dengan siapa yang memanggil. Beda? Tolak dengan 403 — artinya “Tidak punya izin”, bukan “data hilang”.

Ubah catatan: Siapa memanggil -> Cek pemilik -> Izin / Tolak -> JSON Pemanggil kartu anggota Cek anggota_id Izin? ya / 403 JSON ok / pesan 403 = Tidak punya izin (bukan “belum login”). Setelah daftar panjang jelas, kita mengunci siapa boleh mengubah baris tertentu.
Setelah pagination jelas, #64 (ini) mengunci siapa boleh ubah catatan pinjam lewat aturan izin.

Alur izin — PHP sederhana

Pemanggil — aplikasi atau alat yang memanggil API — mengirim identitas anggota. Server membandingkan dengan anggota_id di catatan.

<?php
$pinjam = [
    ["id" => 10, "anggota_id" => 1, "judul" => "Dasar PHP", "status" => "aktif"],
    ["id" => 11, "anggota_id" => 2, "judul" => "Belajar Laravel", "status" => "aktif"],
];

function ubahStatusPinjam(array $pinjam, int $pinjamId, int $penggunaId, string $statusBaru): array
{
    $row = null;
    foreach ($pinjam as $p) {
        if ($p["id"] === $pinjamId) {
            $row = $p;
            break;
        }
    }
    if ($row === null) {
        return ["status" => 404, "body" => ["pesan" => "Catatan pinjam tidak ketemu"]];
    }
    if ($row["anggota_id"] !== $penggunaId) {
        return ["status" => 403, "body" => ["pesan" => "Tidak punya izin"]];
    }

    return [
        "status" => 200,
        "body" => ["ok" => true, "id" => $pinjamId, "status" => $statusBaru],
    ];
}

$r = ubahStatusPinjam($pinjam, 10, 2, "kembali");
http_response_code($r["status"]);
echo json_encode($r["body"], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), PHP_EOL;

Awam: 404 = catatan tidak ada. 403 = ada, tapi bukan milikmu. 200 = pemilik cocok, boleh ubah. Pola ini sama dengan ide ubah/hapus di CRUD ubah & hapus (#61), hanya ditambah cek pemilik.

Laravel — cuplikan Policy & authorize (bukan file mandiri)

Di proyek Laravel, aturan izin sering ditulis di kelas Policy, lalu dipanggil lewat authorize di pengatur kode (controller).

<?php
// Cuplikan Laravel (bukan file mandiri) — kelas Policy pinjam.
namespace App\Policies;

use App\Models\Pinjam;
use App\Models\User;

class PinjamPolicy
{
    public function update(User $user, Pinjam $pinjam): bool
    {
        return $user->id === $pinjam->anggota_id;
    }
}
<?php
// Cuplikan Laravel (bukan file mandiri) — cek izin sebelum ubah.
use App\Models\Pinjam;
use Illuminate\Http\Request;

public function update(Request $request, Pinjam $pinjam)
{
    $this->authorize('update', $pinjam);

    $pinjam->update($request->only('status'));

    return response()->json(['ok' => true, 'data' => $pinjam]);
}

Awam:

  • PinjamPolicy::update = aturan “boleh ubah kalau pemilik sama”
  • authorize('update', $pinjam) = jalankan aturan itu dulu; gagal -> Laravel otomatis jawab 403 (Tidak punya izin)
  • Aturan di satu file = lebih mudah dirawat daripada if berulang di banyak tempat

Pola Dasar — aturan izin yang rapi

  1. 1
    Kenali pemanggil
    Siapa yang login / kartu anggota mana — fondasi dari langkah sebelumnya.
  2. 2
    Temukan catatan
    Pinjam ada? Kalau tidak, jawab 404 jelas.
  3. 3
    Bandingkan pemilik
    anggota_id catatan vs pemanggil — PHP if dulu.
  4. 4
    Tolak dengan 403
    Pesan awam “Tidak punya izin” — jangan biarkan orang lain ubah.
  5. 5
    Pindah ke Policy
    Tulis aturan di kelas Policy; panggil authorize sebelum ubah.
  6. 6
    Uji tiga jalur
    Pemilik benar · bukan pemilik · catatan tidak ada.

Kode lengkap — demo mandiri aturan izin

Simpan sebagai laravel_policy_otorisasi_api_demo.php, lalu jalankan php laravel_policy_otorisasi_api_demo.php:

<?php
declare(strict_types=1);

$pinjam = [
    ["id" => 10, "anggota_id" => 1, "judul" => "Dasar PHP", "status" => "aktif"],
    ["id" => 11, "anggota_id" => 2, "judul" => "Belajar Laravel", "status" => "aktif"],
];

function ubahStatusPinjam(array $pinjam, int $pinjamId, int $penggunaId, string $statusBaru): array
{
    $row = null;
    foreach ($pinjam as $p) {
        if ($p["id"] === $pinjamId) {
            $row = $p;
            break;
        }
    }
    if ($row === null) {
        return ["status" => 404, "body" => ["pesan" => "Catatan pinjam tidak ketemu"]];
    }
    if ($row["anggota_id"] !== $penggunaId) {
        return ["status" => 403, "body" => ["pesan" => "Tidak punya izin"]];
    }

    return [
        "status" => 200,
        "body" => ["ok" => true, "id" => $pinjamId, "status" => $statusBaru],
    ];
}

function demo(string $judul, callable $aksi): void
{
    echo "=== {$judul} ===", PHP_EOL;
    $hasil = $aksi();
    echo "status: ", $hasil["status"], PHP_EOL;
    echo json_encode($hasil["body"], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), PHP_EOL, PHP_EOL;
}

demo("Bukan pemilik -> 403", function () use ($pinjam) {
    return ubahStatusPinjam($pinjam, 10, 2, "kembali");
});

demo("Pemilik benar -> 200", function () use ($pinjam) {
    return ubahStatusPinjam($pinjam, 10, 1, "kembali");
});

demo("Catatan tidak ada -> 404", function () use ($pinjam) {
    return ubahStatusPinjam($pinjam, 99, 1, "kembali");
});

Awam: demo(...) hanya membungkus output di terminal. callable = sesuatu yang bisa dipanggil seperti fungsi. declare(strict_types=1); membuat tipe lebih ketat — boleh diikuti, tidak wajib dihafal. Alur penting: bukan pemilik, pemilik benar, catatan hilang.

Kesalahan umum

Gejala Penyebab tipikal Perbaikan awam
Siapa saja bisa ubah pinjam orang lain Lupa cek anggota_id Cek pemilik sebelum ubah/hapus
403 padahal yakin pemilik ID pemanggil salah / belum login Pastikan identitas pemanggil benar
Aturan tersebar di banyak file Copy-paste if berulang Kumpulkan di kelas Policy
Pesan error membingungkan 403 tanpa penjelasan awam Tulis “Tidak punya izin” yang jelas

Latihan singkat

  1. Ubah demo: tambah kasus “pemilik benar ubah pinjam id 11” dan bandingkan dengan kasus bukan pemilik.
  2. Jelaskan ke teman: beda 403 (Tidak punya izin) dengan 404 (tidak ketemu).
  3. Tulis satu kalimat: kenapa aturan izin lebih rapi di kelas Policy daripada if di banyak tempat.

FAQ singkat

Apakah Policy menggantikan login?
Tidak. Login menjawab “siapa kamu”. Policy menjawab “apakah kamu boleh melakukan ini pada baris ini”.

Haruskah selalu pakai kelas Policy?
Untuk belajar, if PHP sudah cukup memahami ide. Di proyek Laravel nyata, Policy membantu merapikan aturan saat bertambah.

Ke mana setelah ini?
Berikutnya alami: API Resource — merapikan bentuk JSON jawaban.

Kesimpulan

Kamu sudah mengunci siapa boleh ubah: cek pemilik dengan if PHP dulu, lalu pindahkan ke aturan izin (Policy) dan authorize di Laravel. Status 403 = “Tidak punya izin” — jelas untuk pemanggil.

Seri 5 progress: langkah #64 (ini) · 4/8 Laravel Lanjutan · prasyarat: Pagination (#63) LIVE · Relasi (#62) LIVE. Berikutnya: API Resource (rapikan JSON).