Store sudah dipilih, tabel cache siap, sekarang saatnya mengoperasikannya. Operasi cache sehari-hari sebenarnya berputar pada tiga kata kerja: simpan, baca, dan hapus. Laravel menyajikan semuanya lewat Cache facade, helper global cache(), dan satu pola yang menggabungkan ketiganya — remember() — yang akan kita pakai paling sering. Pada chapter ini kita jalankan setiap operasi di store database sehingga hasilnya bisa kita lihat persis apa adanya.

put, get, dan Nilai Default #

Menulis cache memakai Cache::put() dengan tiga argumen: kunci, nilai, dan masa hidup dalam detik. Membacanya memakai Cache::get(), dengan nilai cadangan bila kunci ternyata kosong:

php
use Illuminate\Support\Facades\Cache;

Cache::put('kota', 'Bandung', 300);
echo 'get: ' . Cache::get('kota') . "\n";
echo 'default: ' . var_export(Cache::get('negara', 'Indonesia'), true) . "\n";

Output yang Dihasilkan:

text
get: Bandung
default: 'Indonesia'

Argumen kedua get() hanya dipakai saat cache miss. Nilai apa pun bisa disimpan — string, angka, array, bahkan collection — karena store database men-serialize isinya ke kolom value.

Helper cache() menawarkan jalan pintas untuk kedua arah. Dipanggil dengan array, helper menulis; dipanggil dengan string, helper membaca; dan bentuk cache()->... mengembalikan repository lengkap sehingga semua method facade tersedia:

php
cache(['menu:aktif' => 'Beranda'], 300);          // tulis
echo 'helper_put: ' . cache('menu:aktif') . "\n"; // baca

echo 'helper_remember: '
    . cache()->remember('menu:judul', 300, fn () => 'Belajar Laravel') . "\n";

Output yang Dihasilkan:

text
helper_put: menu:aktif=Beranda
helper_remember: Belajar Laravel

remember(), Kuda Beban Cache #

Pola paling penting dalam ber-cache adalah cache-aside: coba baca dulu, jika kosong jalankan komputasi lalu simpan. Cache::remember() merangkai ketiga langkah itu dalam satu panggilan. Runner berikut membuktikan closure-nya benar-benar hanya berjalan sekali:

php
$panggilan = 0;
$hitung = function () use (&$panggilan) {
    $panggilan++;

    return 'jumlah-post: 3';
};

Cache::forget('stats:jumlah-post');
$miss = Cache::remember('stats:jumlah-post', 300, $hitung);
$hit  = Cache::remember('stats:jumlah-post', 300, $hitung);

fwrite(STDERR, "remember: miss={$miss} hit={$hit} panggilan_closure={$panggilan}\n");

Output yang Dihasilkan:

text
remember: miss=jumlah-post: 3 hit=jumlah-post: 3 panggilan_closure=1

Panggilan pertama mengeksekusi closure (memicu cache miss), panggilan kedua dilayani dari cache tanpa menyentuh closure sama sekali. Dalam aplikasi nyata, panggilan remember() seperti ini biasanya tinggal di service atau controller — tepat di titik data dibutuhkan — sementara closure-nya berisi query Eloquent atau panggilan HTTP yang mahal. Berapa kali pun halaman itu dikunjungi dalam lima menit berikutnya, komputasi mahal di dalam closure tidak pernah diulang.

Untuk data yang pantas hidup selamanya, sepupunya rememberForever() menghilangkan argumen TTL, dan get() juga menerima closure sebagai nilai default sehingga kita bebas memilih gaya penulisan:

php
Cache::forget('negara');
$negara = Cache::get('negara', function () {
    return 'dihitung ulang: Indonesia';
});

echo "closure_default: {$negara}\n";

Output yang Dihasilkan:

text
closure_default: dihitung ulang: Indonesia

add() dan Operasi Hitung #

Cache::add() adalah versi sopan dari put(): hanya menulis bila kunci belum ada, dan mengembalikan true/false sebagai laporan apakah penulisan terjadi. Perilaku ini berguna untuk menandai “pekerjaan sudah dimulai” tanpa menimpa hasil yang ada:

php
Cache::forget('kota');
$add1 = Cache::add('kota', 'Bandung', 300);
$add2 = Cache::add('kota', 'Surabaya', 300);

echo 'add_pertama=' . var_export($add1, true) . ' add_kedua=' . var_export($add2, true)
    . ' nilai=' . Cache::get('kota') . "\n";

Output yang Dihasilkan:

text
add_pertama=true add_kedua=false nilai=Bandung

Penulisan kedua ditolak karena kunci sudah terisi, sehingga nilai Bandung bertahan. Selanjutnya, increment() dan decrement() mengubah angka secara atomik — operasi baca-ubah-tulis dalam satu langkah, aman dari dua request yang menghitung bersamaan:

php
Cache::forget('counter:kunjungan');
Cache::add('counter:kunjungan', 0, 300);        // pastikan kunci ada dulu
$a = Cache::increment('counter:kunjungan');      // 1
$b = Cache::increment('counter:kunjungan', 4);   // 5
$c = Cache::decrement('counter:kunjungan', 2);   // 3

echo "ret: inc={$a} inc4={$b} dec2={$c}\n";
echo 'get: ' . var_export(Cache::get('counter:kunjungan'), true) . "\n";

Output yang Dihasilkan:

text
ret: inc=1 inc4=5 dec2=3
get: 3

Operasi Massal dan pull() #

Untuk menulis banyak kunci sekaligus dengan TTL yang sama, putMany() menerima satu array, dan many() membaca beberapa kunci dalam satu panggilan:

php
Cache::forget('produk:1');
Cache::forget('produk:2');
Cache::putMany([
    'produk:1' => 'Laptop Gaming',
    'produk:2' => 'Mouse Ergonomis',
], 300);

$semua = Cache::many(['produk:1', 'produk:2', 'produk:3']);
echo 'many: ' . json_encode($semua, JSON_UNESCAPED_SLASHES) . "\n";

Output yang Dihasilkan:

text
many: {"produk:1":"Laptop Gaming","produk:2":"Mouse Ergonomis","produk:3":null}

Kunci yang tidak ada (produk:3) hadir sebagai null di hasil, bukan hilang dari array — posisi setiap nilai tetap sejajar dengan daftar kunci yang diminta, sehingga hasilnya mudah dipetakan kembali. Terakhir, pull() membaca sekaligus menghapus dalam satu langkah, pas untuk data sekali-pakai seperti token konfirmasi:

php
$nilai = Cache::pull('kota', 'kosong');
$lagi  = Cache::pull('kota', 'kosong');
echo "pull_pertama={$nilai} pull_kedua={$lagi}\n";

Output yang Dihasilkan:

text
pull_pertama=Bandung pull_kedua=kosong

Menghapus Entri #

Cache::forget() menghapus satu kunci, sedangkan Cache::flush() mengosongkan seluruh store. Artisan menyediakan keduanya dari terminal:

text
$ php artisan cache:forget kota

   INFO  The [kota] key has been removed from the cache.

Satu hal yang belum kita bahas serius adalah angka 300 yang terus muncul: berapa lama sebaiknya cache hidup, dan apa bedanya TTL berupa detik dengan objek Carbon? Itu fokus chapter Cache Expiration , dan rujukan lengkap semua method di atas ada di dokumentasi Cache .